mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-04-27 15:07:59 +00:00
Implement nested storage transactions (#6269)
* Add transactional storage functionality to OverlayChanges A collection already has a natural None state. No need to wrap it with an option. * Add storage transactions runtime interface * Add frame support for transactions * Fix committed typo * Rename 'changes' variable to 'overlay' * Fix renaming change * Fixed strange line break * Rename clear to clear_where * Add comment regarding delete value on mutation * Add comment which changes are covered by a transaction * Do force the arg to with_transaction return a Result * Use rust doc comments on every documentable place * Fix wording of insert_diry doc * Improve doc on start_transaction * Rename value to overlayed in close_transaction * Inline negation * Improve wording of close_transaction comments * Get rid of an expect by using get_or_insert_with * Remove trailing whitespace * Rename should to expected in tests * Rolling back a transaction must mark the overlay as dirty * Protect client initiated storage tx from being droped by runtime * Review nits * Return Err when entering or exiting runtime fails * Documentation fixup * Remove close type * Move enter/exit runtime to excute_aux in the state-machine * Rename Discard -> Rollback * Move child changeset creation to constructor * Move child spawning into the closure * Apply suggestions from code review Co-authored-by: Bastian Köcher <bkchr@users.noreply.github.com> * Fixup for code suggestion * Unify re-exports * Rename overlay_changes to mod.rs and move into subdir * Change proof wording * Adapt a new test from master to storage-tx * Suggestions from the latest round of review * Fix warning message Co-authored-by: Bastian Köcher <bkchr@users.noreply.github.com>
This commit is contained in:
committed by
GitHub
parent
6aa8965f33
commit
bb2df2122e
@@ -79,6 +79,10 @@ pub use in_memory_backend::new_in_mem;
|
||||
pub use stats::{UsageInfo, UsageUnit, StateMachineStats};
|
||||
pub use sp_core::traits::CloneableSpawn;
|
||||
|
||||
const PROOF_CLOSE_TRANSACTION: &str = "\
|
||||
Closing a transaction that was started in this function. Client initiated transactions
|
||||
are protected from being closed by the runtime. qed";
|
||||
|
||||
type CallResult<R, E> = Result<NativeOrEncoded<R>, E>;
|
||||
|
||||
/// Default handler of the execution manager.
|
||||
@@ -297,6 +301,8 @@ impl<'a, B, H, N, Exec> StateMachine<'a, B, H, N, Exec> where
|
||||
None => &mut cache,
|
||||
};
|
||||
|
||||
self.overlay.enter_runtime().expect("StateMachine is never called from the runtime; qed");
|
||||
|
||||
let mut ext = Ext::new(
|
||||
self.overlay,
|
||||
self.offchain_overlay,
|
||||
@@ -324,6 +330,9 @@ impl<'a, B, H, N, Exec> StateMachine<'a, B, H, N, Exec> where
|
||||
native_call,
|
||||
);
|
||||
|
||||
self.overlay.exit_runtime()
|
||||
.expect("Runtime is not able to call this function in the overlay; qed");
|
||||
|
||||
trace!(
|
||||
target: "state", "{:04x}: Return. Native={:?}, Result={:?}",
|
||||
id,
|
||||
@@ -347,11 +356,11 @@ impl<'a, B, H, N, Exec> StateMachine<'a, B, H, N, Exec> where
|
||||
CallResult<R, Exec::Error>,
|
||||
) -> CallResult<R, Exec::Error>
|
||||
{
|
||||
let pending_changes = self.overlay.clone_pending();
|
||||
self.overlay.start_transaction();
|
||||
let (result, was_native) = self.execute_aux(true, native_call.take());
|
||||
|
||||
if was_native {
|
||||
self.overlay.replace_pending(pending_changes);
|
||||
self.overlay.rollback_transaction().expect(PROOF_CLOSE_TRANSACTION);
|
||||
let (wasm_result, _) = self.execute_aux(
|
||||
false,
|
||||
native_call,
|
||||
@@ -366,6 +375,7 @@ impl<'a, B, H, N, Exec> StateMachine<'a, B, H, N, Exec> where
|
||||
on_consensus_failure(wasm_result, result)
|
||||
}
|
||||
} else {
|
||||
self.overlay.commit_transaction().expect(PROOF_CLOSE_TRANSACTION);
|
||||
result
|
||||
}
|
||||
}
|
||||
@@ -378,16 +388,17 @@ impl<'a, B, H, N, Exec> StateMachine<'a, B, H, N, Exec> where
|
||||
R: Decode + Encode + PartialEq,
|
||||
NC: FnOnce() -> result::Result<R, String> + UnwindSafe,
|
||||
{
|
||||
let pending_changes = self.overlay.clone_pending();
|
||||
self.overlay.start_transaction();
|
||||
let (result, was_native) = self.execute_aux(
|
||||
true,
|
||||
native_call.take(),
|
||||
);
|
||||
|
||||
if !was_native || result.is_ok() {
|
||||
self.overlay.commit_transaction().expect(PROOF_CLOSE_TRANSACTION);
|
||||
result
|
||||
} else {
|
||||
self.overlay.replace_pending(pending_changes);
|
||||
self.overlay.rollback_transaction().expect(PROOF_CLOSE_TRANSACTION);
|
||||
let (wasm_result, _) = self.execute_aux(
|
||||
false,
|
||||
native_call,
|
||||
@@ -977,7 +988,7 @@ mod tests {
|
||||
let mut overlay = OverlayedChanges::default();
|
||||
overlay.set_storage(b"aba".to_vec(), Some(b"1312".to_vec()));
|
||||
overlay.set_storage(b"bab".to_vec(), Some(b"228".to_vec()));
|
||||
overlay.commit_prospective();
|
||||
overlay.start_transaction();
|
||||
overlay.set_storage(b"abd".to_vec(), Some(b"69".to_vec()));
|
||||
overlay.set_storage(b"bbd".to_vec(), Some(b"42".to_vec()));
|
||||
|
||||
@@ -994,10 +1005,10 @@ mod tests {
|
||||
);
|
||||
ext.clear_prefix(b"ab");
|
||||
}
|
||||
overlay.commit_prospective();
|
||||
overlay.commit_transaction().unwrap();
|
||||
|
||||
assert_eq!(
|
||||
overlay.changes(None).map(|(k, v)| (k.clone(), v.value().cloned()))
|
||||
overlay.changes().map(|(k, v)| (k.clone(), v.value().cloned()))
|
||||
.collect::<HashMap<_, _>>(),
|
||||
map![
|
||||
b"abc".to_vec() => None.into(),
|
||||
@@ -1083,7 +1094,7 @@ mod tests {
|
||||
Some(vec![reference_data[0].clone()].encode()),
|
||||
);
|
||||
}
|
||||
overlay.commit_prospective();
|
||||
overlay.start_transaction();
|
||||
{
|
||||
let mut ext = Ext::new(
|
||||
&mut overlay,
|
||||
@@ -1102,7 +1113,7 @@ mod tests {
|
||||
Some(reference_data.encode()),
|
||||
);
|
||||
}
|
||||
overlay.discard_prospective();
|
||||
overlay.rollback_transaction().unwrap();
|
||||
{
|
||||
let ext = Ext::new(
|
||||
&mut overlay,
|
||||
@@ -1145,7 +1156,7 @@ mod tests {
|
||||
ext.clear_storage(key.as_slice());
|
||||
ext.storage_append(key.clone(), Item::InitializationItem.encode());
|
||||
}
|
||||
overlay.commit_prospective();
|
||||
overlay.start_transaction();
|
||||
|
||||
// For example, first transaction resulted in panic during block building
|
||||
{
|
||||
@@ -1170,7 +1181,7 @@ mod tests {
|
||||
Some(vec![Item::InitializationItem, Item::DiscardedItem].encode()),
|
||||
);
|
||||
}
|
||||
overlay.discard_prospective();
|
||||
overlay.rollback_transaction().unwrap();
|
||||
|
||||
// Then we apply next transaction which is valid this time.
|
||||
{
|
||||
@@ -1196,7 +1207,7 @@ mod tests {
|
||||
);
|
||||
|
||||
}
|
||||
overlay.commit_prospective();
|
||||
overlay.start_transaction();
|
||||
|
||||
// Then only initlaization item and second (commited) item should persist.
|
||||
{
|
||||
@@ -1317,9 +1328,11 @@ mod tests {
|
||||
let backend = state.as_trie_backend().unwrap();
|
||||
|
||||
let mut overlay = OverlayedChanges::default();
|
||||
overlay.start_transaction();
|
||||
overlay.set_storage(b"ccc".to_vec(), Some(b"".to_vec()));
|
||||
assert_eq!(overlay.storage(b"ccc"), Some(Some(&[][..])));
|
||||
overlay.commit_prospective();
|
||||
overlay.commit_transaction().unwrap();
|
||||
overlay.start_transaction();
|
||||
assert_eq!(overlay.storage(b"ccc"), Some(Some(&[][..])));
|
||||
assert_eq!(overlay.storage(b"bbb"), None);
|
||||
|
||||
@@ -1339,7 +1352,7 @@ mod tests {
|
||||
ext.clear_storage(b"ccc");
|
||||
assert_eq!(ext.storage(b"ccc"), None);
|
||||
}
|
||||
overlay.commit_prospective();
|
||||
overlay.commit_transaction().unwrap();
|
||||
assert_eq!(overlay.storage(b"ccc"), Some(None));
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user