mitigate refcell conflict in state diffing (#2601)

* mitigate refcell conflict in state diffing

Also uses RefCell::get_mut in a few places.

* Add test case
This commit is contained in:
Robert Habermeier 2016-10-13 23:28:56 +02:00 committed by Arkadiy Paronyan
parent 4bcc9e3b49
commit 4581469e78

View File

@ -239,15 +239,15 @@ impl State {
/// Create a recoverable snaphot of this state. /// Create a recoverable snaphot of this state.
pub fn snapshot(&mut self) { pub fn snapshot(&mut self) {
self.snapshots.borrow_mut().push(HashMap::new()); self.snapshots.get_mut().push(HashMap::new());
} }
/// Merge last snapshot with previous. /// Merge last snapshot with previous.
pub fn discard_snapshot(&mut self) { pub fn discard_snapshot(&mut self) {
// merge with previous snapshot // merge with previous snapshot
let last = self.snapshots.borrow_mut().pop(); let last = self.snapshots.get_mut().pop();
if let Some(mut snapshot) = last { if let Some(mut snapshot) = last {
if let Some(ref mut prev) = self.snapshots.borrow_mut().last_mut() { if let Some(ref mut prev) = self.snapshots.get_mut().last_mut() {
if prev.is_empty() { if prev.is_empty() {
**prev = snapshot; **prev = snapshot;
} else { } else {
@ -261,11 +261,11 @@ impl State {
/// Revert to the last snapshot and discard it. /// Revert to the last snapshot and discard it.
pub fn revert_to_snapshot(&mut self) { pub fn revert_to_snapshot(&mut self) {
if let Some(mut snapshot) = self.snapshots.borrow_mut().pop() { if let Some(mut snapshot) = self.snapshots.get_mut().pop() {
for (k, v) in snapshot.drain() { for (k, v) in snapshot.drain() {
match v { match v {
Some(v) => { Some(v) => {
match self.cache.borrow_mut().entry(k) { match self.cache.get_mut().entry(k) {
Entry::Occupied(mut e) => { Entry::Occupied(mut e) => {
// Merge snapshotted changes back into the main account // Merge snapshotted changes back into the main account
// storage preserving the cache. // storage preserving the cache.
@ -277,7 +277,7 @@ impl State {
} }
}, },
None => { None => {
match self.cache.borrow_mut().entry(k) { match self.cache.get_mut().entry(k) {
Entry::Occupied(e) => { Entry::Occupied(e) => {
if e.get().is_dirty() { if e.get().is_dirty() {
e.remove(); e.remove();
@ -578,14 +578,14 @@ impl State {
} }
fn query_pod(&mut self, query: &PodState) { fn query_pod(&mut self, query: &PodState) {
for (address, pod_account) in query.get() { for (address, pod_account) in query.get().into_iter()
self.ensure_cached(address, RequireCache::Code, |a| { .filter(|&(ref a, _)| self.ensure_cached(a, RequireCache::Code, |a| a.is_some()))
if a.is_some() { {
for key in pod_account.storage.keys() { // needs to be split into two parts for the refcell code here
self.storage_at(address, key); // to work.
} for key in pod_account.storage.keys() {
} self.storage_at(address, key);
}); }
} }
} }
@ -1797,4 +1797,20 @@ fn create_empty() {
assert_eq!(state.root().hex(), "56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421"); assert_eq!(state.root().hex(), "56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421");
} }
#[test]
fn should_not_panic_on_state_diff_with_storage() {
let state = get_temp_state();
let mut state = state.reference().clone();
let a: Address = 0xa.into();
state.init_code(&a, b"abcdefg".to_vec());
state.add_balance(&a, &256.into());
state.set_storage(&a, 0xb.into(), 0xc.into());
let mut new_state = state.clone();
new_state.set_storage(&a, 0xb.into(), 0xd.into());
new_state.diff_from(state);
}
} }