Skip to content
This repository has been archived by the owner on Nov 6, 2020. It is now read-only.

Commit

Permalink
mitigate refcell conflict in state diffing (#2601)
Browse files Browse the repository at this point in the history
* mitigate refcell conflict in state diffing

Also uses RefCell::get_mut in a few places.

* Add test case
  • Loading branch information
rphmeier authored and arkpar committed Oct 13, 2016
1 parent 4bcc9e3 commit 4581469
Showing 1 changed file with 30 additions and 14 deletions.
44 changes: 30 additions & 14 deletions ethcore/src/state/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -239,15 +239,15 @@ impl State {

/// Create a recoverable snaphot of this state.
pub fn snapshot(&mut self) {
self.snapshots.borrow_mut().push(HashMap::new());
self.snapshots.get_mut().push(HashMap::new());
}

/// Merge last snapshot with previous.
pub fn discard_snapshot(&mut self) {
// 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(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() {
**prev = snapshot;
} else {
Expand All @@ -261,11 +261,11 @@ impl State {

/// Revert to the last snapshot and discard it.
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() {
match v {
Some(v) => {
match self.cache.borrow_mut().entry(k) {
match self.cache.get_mut().entry(k) {
Entry::Occupied(mut e) => {
// Merge snapshotted changes back into the main account
// storage preserving the cache.
Expand All @@ -277,7 +277,7 @@ impl State {
}
},
None => {
match self.cache.borrow_mut().entry(k) {
match self.cache.get_mut().entry(k) {
Entry::Occupied(e) => {
if e.get().is_dirty() {
e.remove();
Expand Down Expand Up @@ -578,14 +578,14 @@ impl State {
}

fn query_pod(&mut self, query: &PodState) {
for (address, pod_account) in query.get() {
self.ensure_cached(address, RequireCache::Code, |a| {
if a.is_some() {
for key in pod_account.storage.keys() {
self.storage_at(address, key);
}
}
});
for (address, pod_account) in query.get().into_iter()
.filter(|&(ref a, _)| self.ensure_cached(a, RequireCache::Code, |a| a.is_some()))
{
// needs to be split into two parts for the refcell code here
// to work.
for key in pod_account.storage.keys() {
self.storage_at(address, key);
}
}
}

Expand Down Expand Up @@ -1797,4 +1797,20 @@ fn create_empty() {
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);
}

}

0 comments on commit 4581469

Please sign in to comment.