mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-04-27 17:28:00 +00:00
Implements require_transactional (#7261)
* Implements require_transactional * support wasm * only enable for debug build * remove wasm support and add feature flag * Apply suggestions from code review Co-authored-by: Bastian Köcher <bkchr@users.noreply.github.com> * only use check for debug_assertions * update per review * update docs * Apply suggestions from code review Co-authored-by: Bastian Köcher <bkchr@users.noreply.github.com> * remove duplicated tests * fix test Co-authored-by: Bastian Köcher <bkchr@users.noreply.github.com>
This commit is contained in:
@@ -30,6 +30,57 @@ pub mod child;
|
||||
pub mod generator;
|
||||
pub mod migration;
|
||||
|
||||
#[cfg(all(feature = "std", any(test, debug_assertions)))]
|
||||
mod debug_helper {
|
||||
use std::cell::RefCell;
|
||||
|
||||
thread_local! {
|
||||
static TRANSACTION_LEVEL: RefCell<u32> = RefCell::new(0);
|
||||
}
|
||||
|
||||
pub fn require_transaction() {
|
||||
let level = TRANSACTION_LEVEL.with(|v| *v.borrow());
|
||||
if level == 0 {
|
||||
panic!("Require transaction not called within with_transaction");
|
||||
}
|
||||
}
|
||||
|
||||
pub struct TransactionLevelGuard;
|
||||
|
||||
impl Drop for TransactionLevelGuard {
|
||||
fn drop(&mut self) {
|
||||
TRANSACTION_LEVEL.with(|v| *v.borrow_mut() -= 1);
|
||||
}
|
||||
}
|
||||
|
||||
/// Increments the transaction level.
|
||||
///
|
||||
/// Returns a guard that when dropped decrements the transaction level automatically.
|
||||
pub fn inc_transaction_level() -> TransactionLevelGuard {
|
||||
TRANSACTION_LEVEL.with(|v| {
|
||||
let mut val = v.borrow_mut();
|
||||
*val += 1;
|
||||
if *val > 10 {
|
||||
crate::debug::warn!(
|
||||
"Detected with_transaction with nest level {}. Nested usage of with_transaction is not recommended.",
|
||||
*val
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
TransactionLevelGuard
|
||||
}
|
||||
}
|
||||
|
||||
/// Assert this method is called within a storage transaction.
|
||||
/// This will **panic** if is not called within a storage transaction.
|
||||
///
|
||||
/// This assertion is enabled for native execution and when `debug_assertions` are enabled.
|
||||
pub fn require_transaction() {
|
||||
#[cfg(all(feature = "std", any(test, debug_assertions)))]
|
||||
debug_helper::require_transaction();
|
||||
}
|
||||
|
||||
/// Execute the supplied function in a new storage transaction.
|
||||
///
|
||||
/// All changes to storage performed by the supplied function are discarded if the returned
|
||||
@@ -43,6 +94,10 @@ pub fn with_transaction<R>(f: impl FnOnce() -> TransactionOutcome<R>) -> R {
|
||||
use TransactionOutcome::*;
|
||||
|
||||
start_transaction();
|
||||
|
||||
#[cfg(all(feature = "std", any(test, debug_assertions)))]
|
||||
let _guard = debug_helper::inc_transaction_level();
|
||||
|
||||
match f() {
|
||||
Commit(res) => { commit_transaction(); res },
|
||||
Rollback(res) => { rollback_transaction(); res },
|
||||
@@ -732,4 +787,27 @@ mod test {
|
||||
assert_eq!(Digest::decode(&mut &value[..]).unwrap(), expected);
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic(expected = "Require transaction not called within with_transaction")]
|
||||
fn require_transaction_should_panic() {
|
||||
TestExternalities::default().execute_with(|| {
|
||||
require_transaction();
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn require_transaction_should_not_panic_in_with_transaction() {
|
||||
TestExternalities::default().execute_with(|| {
|
||||
with_transaction(|| {
|
||||
require_transaction();
|
||||
TransactionOutcome::Commit(())
|
||||
});
|
||||
|
||||
with_transaction(|| {
|
||||
require_transaction();
|
||||
TransactionOutcome::Rollback(())
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user