diff --git a/primitives/state-machine/src/overlayed_changes.rs b/primitives/state-machine/src/overlayed_changes.rs index 7cbc189dfeae4..de31d01156881 100644 --- a/primitives/state-machine/src/overlayed_changes.rs +++ b/primitives/state-machine/src/overlayed_changes.rs @@ -245,19 +245,16 @@ impl OverlayedChanges { let size_write = val.as_ref().map(|x| x.len() as u64).unwrap_or(0); self.stats.tally_write_overlay(size_write); let storage_key = child_info.storage_key().to_vec(); - let tx_depth = self.transaction_depth(); - let num_client_tx = self.top.num_client_transactions(); - let exec_mode = self.top.execution_mode(); - let (overlay, info) = self.children.entry(storage_key) - .or_insert_with(|| ( - // This changeset might be created when there are already open transactions. - // We need to catch up here so it is at the same transaction depth. - OverlayedChangeSet::new(tx_depth, num_client_tx, exec_mode), + let changeset = self.top.spawn_child(); + let (changeset, info) = self.children.entry(storage_key).or_insert_with(|| + ( + changeset, child_info.to_owned() - )); + ) + ); let updatable = info.try_update(child_info); debug_assert!(updatable); - overlay.set(key, val, extrinsic_index); + changeset.set(key, val, extrinsic_index); } /// Clear child storage of given storage key. @@ -268,9 +265,14 @@ impl OverlayedChanges { child_info: &ChildInfo, ) { let extrinsic_index = self.extrinsic_index(); - let storage_key = child_info.storage_key(); - let (changeset, info) = self.children.entry(storage_key.to_vec()) - .or_insert_with(|| (Default::default(), child_info.to_owned())); + let storage_key = child_info.storage_key().to_vec(); + let changeset = self.top.spawn_child(); + let (changeset, info) = self.children.entry(storage_key).or_insert_with(|| + ( + changeset, + child_info.to_owned() + ) + ); let updatable = info.try_update(child_info); debug_assert!(updatable); changeset.clear_where(|_, _| true, extrinsic_index); @@ -292,9 +294,14 @@ impl OverlayedChanges { prefix: &[u8], ) { let extrinsic_index = self.extrinsic_index(); - let storage_key = child_info.storage_key(); - let (changeset, info) = self.children.entry(storage_key.to_vec()) - .or_insert_with(|| (Default::default(), child_info.to_owned())); + let storage_key = child_info.storage_key().to_vec(); + let changeset = self.top.spawn_child(); + let (changeset, info) = self.children.entry(storage_key).or_insert_with(|| + ( + changeset, + child_info.to_owned() + ) + ); let updatable = info.try_update(child_info); debug_assert!(updatable); changeset.clear_where(|key, _| key.starts_with(prefix), extrinsic_index); diff --git a/primitives/state-machine/src/overlayed_changes/changeset.rs b/primitives/state-machine/src/overlayed_changes/changeset.rs index 540bde4a99c11..d1b3bc2ec0d88 100644 --- a/primitives/state-machine/src/overlayed_changes/changeset.rs +++ b/primitives/state-machine/src/overlayed_changes/changeset.rs @@ -161,13 +161,16 @@ fn insert_dirty(set: &mut DirtyKeysSets, key: StorageKey) -> bool { } impl OverlayedChangeSet { - /// Create a new changeset. - pub fn new(depth: usize, num_client_transactions: usize, mode: ExecutionMode) -> Self { + /// Create a new changeset at the same transaction state but without any contents. + /// + /// This changeset might be created when there are already open transactions. + /// We need to catch up here so that the child is at the same transaction depth. + pub fn spawn_child(&self) -> Self { use std::iter::repeat; Self { - dirty_keys: repeat(HashSet::new()).take(depth).collect(), - num_client_transactions, - execution_mode: mode, + dirty_keys: repeat(HashSet::new()).take(self.transaction_depth()).collect(), + num_client_transactions: self.num_client_transactions, + execution_mode: self.execution_mode, .. Default::default() } } @@ -264,18 +267,6 @@ impl OverlayedChangeSet { self.dirty_keys.len() } - /// Returns how many of the open transactions are opened by the client. - /// - /// These are always the first transaction to open and the last to close. - pub fn num_client_transactions(&self) -> usize { - self.num_client_transactions - } - - /// Returns whether we are executing in client or runtime mode. - pub fn execution_mode(&self) -> ExecutionMode { - self.execution_mode - } - /// Call this before transfering control to the runtime. /// /// This protects all existing transactions from being removed by the runtime.