mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-06-11 14:11:09 +00:00
seal_reentrant_count returns contract reentrant count (#12695)
* Add logic, test, broken benchmark * account_entrance_count * Addressing comments * Address @agryaznov's comments * Add test for account_entrance_count, fix ci * Cargo fmt * Fix tests * Fix tests * Remove delegated call from test, address comments * Minor fixes and indentation in wat files * Update test for account_entrance_count * Update reentrant_count_call test * Delegate call test * Cargo +nightly fmt * Address comments * Update reentrant_count_works test * Apply weights diff * Add fixture descriptions * Update comments as suggested * Update reentrant_count_call test to use seal_address * add missing code * cargo fmt * account_entrance_count -> account_reentrance_count * fix tests * fmt * normalize signatures Co-authored-by: yarikbratashchuk <yarik.bratashchuk@gmail.com>
This commit is contained in:
@@ -0,0 +1,37 @@
|
||||
;; This fixture tests if account_reentrance_count works as expected
|
||||
;; testing it with 2 different addresses
|
||||
(module
|
||||
(import "seal0" "seal_input" (func $seal_input (param i32 i32)))
|
||||
(import "seal0" "seal_caller" (func $seal_caller (param i32 i32)))
|
||||
(import "seal0" "seal_return" (func $seal_return (param i32 i32 i32)))
|
||||
(import "__unstable__" "account_reentrance_count" (func $account_reentrance_count (param i32) (result i32)))
|
||||
(import "env" "memory" (memory 1 1))
|
||||
|
||||
;; [0, 32) buffer where input is copied
|
||||
;; [32, 36) size of the input buffer
|
||||
(data (i32.const 32) "\20")
|
||||
|
||||
(func $assert (param i32)
|
||||
(block $ok
|
||||
(br_if $ok
|
||||
(get_local 0)
|
||||
)
|
||||
(unreachable)
|
||||
)
|
||||
)
|
||||
|
||||
(func (export "call")
|
||||
;; Reading "callee" input address
|
||||
(call $seal_input (i32.const 0) (i32.const 32))
|
||||
|
||||
(i32.store
|
||||
(i32.const 36)
|
||||
(call $account_reentrance_count (i32.const 0))
|
||||
)
|
||||
|
||||
(call $seal_return (i32.const 0) (i32.const 36) (i32.const 4))
|
||||
)
|
||||
|
||||
(func (export "deploy"))
|
||||
|
||||
)
|
||||
@@ -0,0 +1,76 @@
|
||||
;; This fixture recursively tests if reentrant_count returns correct reentrant count value when
|
||||
;; using seal_call to make caller contract call to itself
|
||||
(module
|
||||
(import "seal0" "seal_input" (func $seal_input (param i32 i32)))
|
||||
(import "seal0" "seal_address" (func $seal_address (param i32 i32)))
|
||||
(import "seal1" "seal_call" (func $seal_call (param i32 i32 i64 i32 i32 i32 i32 i32) (result i32)))
|
||||
(import "__unstable__" "reentrant_count" (func $reentrant_count (result i32)))
|
||||
(import "env" "memory" (memory 1 1))
|
||||
|
||||
;; [0, 32) reserved for $seal_address output
|
||||
|
||||
;; [32, 36) buffer for the call stack height
|
||||
|
||||
;; [36, 40) size of the input buffer
|
||||
(data (i32.const 36) "\04")
|
||||
|
||||
;; [40, 44) length of the buffer for $seal_address
|
||||
(data (i32.const 40) "\20")
|
||||
|
||||
(func $assert (param i32)
|
||||
(block $ok
|
||||
(br_if $ok
|
||||
(get_local 0)
|
||||
)
|
||||
(unreachable)
|
||||
)
|
||||
)
|
||||
(func (export "call")
|
||||
(local $expected_reentrant_count i32)
|
||||
(local $seal_call_exit_code i32)
|
||||
|
||||
;; reading current contract address
|
||||
(call $seal_address (i32.const 0) (i32.const 40))
|
||||
|
||||
;; reading passed input
|
||||
(call $seal_input (i32.const 32) (i32.const 36))
|
||||
|
||||
;; reading manually passed reentrant count
|
||||
(set_local $expected_reentrant_count (i32.load (i32.const 32)))
|
||||
|
||||
;; reentrance count is calculated correctly
|
||||
(call $assert
|
||||
(i32.eq (call $reentrant_count) (get_local $expected_reentrant_count))
|
||||
)
|
||||
|
||||
;; re-enter 5 times in a row and assert that the reentrant counter works as expected
|
||||
(i32.eq (call $reentrant_count) (i32.const 5))
|
||||
(if
|
||||
(then) ;; recursion exit case
|
||||
(else
|
||||
;; incrementing $expected_reentrant_count passed to the contract
|
||||
(i32.store (i32.const 32) (i32.add (i32.load (i32.const 32)) (i32.const 1)))
|
||||
|
||||
;; Call to itself
|
||||
(set_local $seal_call_exit_code
|
||||
(call $seal_call
|
||||
(i32.const 8) ;; Allow reentrancy flag set
|
||||
(i32.const 0) ;; Pointer to "callee" address
|
||||
(i64.const 0) ;; How much gas to devote for the execution. 0 = all.
|
||||
(i32.const 0) ;; Pointer to the buffer with value to transfer
|
||||
(i32.const 32) ;; Pointer to input data buffer address
|
||||
(i32.const 4) ;; Length of input data buffer
|
||||
(i32.const 0xffffffff) ;; u32 max sentinel value: do not copy output
|
||||
(i32.const 0) ;; Ptr to output buffer len
|
||||
)
|
||||
)
|
||||
|
||||
(call $assert
|
||||
(i32.eq (get_local $seal_call_exit_code) (i32.const 0))
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
(func (export "deploy"))
|
||||
)
|
||||
@@ -0,0 +1,71 @@
|
||||
;; This fixture recursively tests if reentrant_count returns correct reentrant count value when
|
||||
;; using seal_delegate_call to make caller contract delegate call to itself
|
||||
(module
|
||||
(import "seal0" "seal_input" (func $seal_input (param i32 i32)))
|
||||
(import "seal0" "seal_set_storage" (func $seal_set_storage (param i32 i32 i32)))
|
||||
(import "seal0" "seal_delegate_call" (func $seal_delegate_call (param i32 i32 i32 i32 i32 i32) (result i32)))
|
||||
(import "__unstable__" "reentrant_count" (func $reentrant_count (result i32)))
|
||||
(import "env" "memory" (memory 1 1))
|
||||
|
||||
;; [0, 32) buffer where code hash is copied
|
||||
|
||||
;; [32, 36) buffer for the call stack height
|
||||
|
||||
;; [36, 40) size of the input buffer
|
||||
(data (i32.const 36) "\24")
|
||||
|
||||
(func $assert (param i32)
|
||||
(block $ok
|
||||
(br_if $ok
|
||||
(get_local 0)
|
||||
)
|
||||
(unreachable)
|
||||
)
|
||||
)
|
||||
(func (export "call")
|
||||
(local $callstack_height i32)
|
||||
(local $delegate_call_exit_code i32)
|
||||
|
||||
;; Reading input
|
||||
(call $seal_input (i32.const 0) (i32.const 36))
|
||||
|
||||
;; reading passed callstack height
|
||||
(set_local $callstack_height (i32.load (i32.const 32)))
|
||||
|
||||
;; incrementing callstack height
|
||||
(i32.store (i32.const 32) (i32.add (i32.load (i32.const 32)) (i32.const 1)))
|
||||
|
||||
;; reentrance count stays 0
|
||||
(call $assert
|
||||
(i32.eq (call $reentrant_count) (i32.const 0))
|
||||
)
|
||||
|
||||
(i32.eq (get_local $callstack_height) (i32.const 5))
|
||||
(if
|
||||
(then) ;; exit recursion case
|
||||
(else
|
||||
;; Call to itself
|
||||
(set_local $delegate_call_exit_code
|
||||
(call $seal_delegate_call
|
||||
(i32.const 0) ;; Set no call flags
|
||||
(i32.const 0) ;; Pointer to "callee" code_hash.
|
||||
(i32.const 0) ;; Pointer to the input data
|
||||
(i32.const 36) ;; Length of the input
|
||||
(i32.const 4294967295) ;; u32 max sentinel value: do not copy output
|
||||
(i32.const 0) ;; Length is ignored in this case
|
||||
)
|
||||
)
|
||||
|
||||
(call $assert
|
||||
(i32.eq (get_local $delegate_call_exit_code) (i32.const 0))
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
(call $assert
|
||||
(i32.le_s (get_local $callstack_height) (i32.const 5))
|
||||
)
|
||||
)
|
||||
|
||||
(func (export "deploy"))
|
||||
)
|
||||
@@ -2086,6 +2086,59 @@ benchmarks! {
|
||||
let origin = RawOrigin::Signed(instance.caller.clone());
|
||||
}: call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![])
|
||||
|
||||
reentrant_count {
|
||||
let r in 0 .. API_BENCHMARK_BATCHES;
|
||||
let code = WasmModule::<T>::from(ModuleDefinition {
|
||||
memory: Some(ImportedMemory::max::<T>()),
|
||||
imported_functions: vec![ImportedFunction {
|
||||
module: "__unstable__",
|
||||
name: "reentrant_count",
|
||||
params: vec![],
|
||||
return_type: Some(ValueType::I32),
|
||||
}],
|
||||
call_body: Some(body::repeated(r * API_BENCHMARK_BATCH_SIZE, &[
|
||||
Instruction::Call(0),
|
||||
Instruction::Drop,
|
||||
])),
|
||||
.. Default::default()
|
||||
});
|
||||
let instance = Contract::<T>::new(code, vec![])?;
|
||||
let origin = RawOrigin::Signed(instance.caller.clone());
|
||||
}: call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![])
|
||||
|
||||
account_reentrance_count {
|
||||
let r in 0 .. API_BENCHMARK_BATCHES;
|
||||
let dummy_code = WasmModule::<T>::dummy_with_bytes(0);
|
||||
let accounts = (0..r * API_BENCHMARK_BATCH_SIZE)
|
||||
.map(|i| Contract::with_index(i + 1, dummy_code.clone(), vec![]))
|
||||
.collect::<Result<Vec<_>, _>>()?;
|
||||
let account_id_len = accounts.get(0).map(|i| i.account_id.encode().len()).unwrap_or(0);
|
||||
let account_id_bytes = accounts.iter().flat_map(|x| x.account_id.encode()).collect();
|
||||
let code = WasmModule::<T>::from(ModuleDefinition {
|
||||
memory: Some(ImportedMemory::max::<T>()),
|
||||
imported_functions: vec![ImportedFunction {
|
||||
module: "__unstable__",
|
||||
name: "account_reentrance_count",
|
||||
params: vec![ValueType::I32],
|
||||
return_type: Some(ValueType::I32),
|
||||
}],
|
||||
data_segments: vec![
|
||||
DataSegment {
|
||||
offset: 0,
|
||||
value: account_id_bytes,
|
||||
},
|
||||
],
|
||||
call_body: Some(body::repeated_dyn(r * API_BENCHMARK_BATCH_SIZE, vec![
|
||||
Counter(0, account_id_len as u32), // account_ptr
|
||||
Regular(Instruction::Call(0)),
|
||||
Regular(Instruction::Drop),
|
||||
])),
|
||||
.. Default::default()
|
||||
});
|
||||
let instance = Contract::<T>::new(code, vec![])?;
|
||||
let origin = RawOrigin::Signed(instance.caller.clone());
|
||||
}: call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![])
|
||||
|
||||
// We make the assumption that pushing a constant and dropping a value takes roughly
|
||||
// the same amount of time. We follow that `t.load` and `drop` both have the weight
|
||||
// of this benchmark / 2. We need to make this assumption because there is no way
|
||||
|
||||
@@ -296,6 +296,15 @@ pub trait Ext: sealing::Sealed {
|
||||
|
||||
/// Sets new code hash for existing contract.
|
||||
fn set_code_hash(&mut self, hash: CodeHash<Self::T>) -> Result<(), DispatchError>;
|
||||
|
||||
/// Returns the number of times the currently executing contract exists on the call stack in
|
||||
/// addition to the calling instance. A value of 0 means no reentrancy.
|
||||
fn reentrant_count(&self) -> u32;
|
||||
|
||||
/// Returns the number of times the specified contract exists on the call stack. Delegated calls
|
||||
/// are not calculated as separate entrance.
|
||||
/// A value of 0 means it does not exist on the call stack.
|
||||
fn account_reentrance_count(&self, account_id: &AccountIdOf<Self::T>) -> u32;
|
||||
}
|
||||
|
||||
/// Describes the different functions that can be exported by an [`Executable`].
|
||||
@@ -1374,6 +1383,17 @@ where
|
||||
);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn reentrant_count(&self) -> u32 {
|
||||
let id: &AccountIdOf<Self::T> = &self.top_frame().account_id;
|
||||
self.account_reentrance_count(id).saturating_sub(1)
|
||||
}
|
||||
|
||||
fn account_reentrance_count(&self, account_id: &AccountIdOf<Self::T>) -> u32 {
|
||||
self.frames()
|
||||
.filter(|f| f.delegate_caller.is_none() && &f.account_id == account_id)
|
||||
.count() as u32
|
||||
}
|
||||
}
|
||||
|
||||
mod sealing {
|
||||
|
||||
@@ -423,6 +423,12 @@ pub struct HostFnWeights<T: Config> {
|
||||
/// Weight of calling `seal_ecdsa_to_eth_address`.
|
||||
pub ecdsa_to_eth_address: u64,
|
||||
|
||||
/// Weight of calling `seal_reentrant_count`.
|
||||
pub reentrant_count: u64,
|
||||
|
||||
/// Weight of calling `seal_account_reentrance_count`.
|
||||
pub account_reentrance_count: u64,
|
||||
|
||||
/// The type parameter is used in the default implementation.
|
||||
#[codec(skip)]
|
||||
pub _phantom: PhantomData<T>,
|
||||
@@ -659,6 +665,8 @@ impl<T: Config> Default for HostFnWeights<T> {
|
||||
hash_blake2_128_per_byte: cost_byte_batched!(seal_hash_blake2_128_per_kb),
|
||||
ecdsa_recover: cost_batched!(seal_ecdsa_recover),
|
||||
ecdsa_to_eth_address: cost_batched!(seal_ecdsa_to_eth_address),
|
||||
reentrant_count: cost_batched!(seal_reentrant_count),
|
||||
account_reentrance_count: cost_batched!(seal_account_reentrance_count),
|
||||
_phantom: PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4383,3 +4383,142 @@ fn delegate_call_indeterministic_code() {
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(feature = "unstable-interface")]
|
||||
fn reentrant_count_works_with_call() {
|
||||
let (wasm, code_hash) = compile_module::<Test>("reentrant_count_call").unwrap();
|
||||
let contract_addr = Contracts::contract_address(&ALICE, &code_hash, &[]);
|
||||
|
||||
ExtBuilder::default().existential_deposit(100).build().execute_with(|| {
|
||||
let _ = Balances::deposit_creating(&ALICE, 1_000_000);
|
||||
|
||||
assert_ok!(Contracts::instantiate_with_code(
|
||||
RuntimeOrigin::signed(ALICE),
|
||||
300_000,
|
||||
GAS_LIMIT,
|
||||
None,
|
||||
wasm,
|
||||
vec![],
|
||||
vec![],
|
||||
));
|
||||
|
||||
// passing reentrant count to the input
|
||||
let input = 0.encode();
|
||||
|
||||
Contracts::bare_call(
|
||||
ALICE,
|
||||
contract_addr,
|
||||
0,
|
||||
GAS_LIMIT,
|
||||
None,
|
||||
input,
|
||||
true,
|
||||
Determinism::Deterministic,
|
||||
)
|
||||
.result
|
||||
.unwrap();
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(feature = "unstable-interface")]
|
||||
fn reentrant_count_works_with_delegated_call() {
|
||||
let (wasm, code_hash) = compile_module::<Test>("reentrant_count_delegated_call").unwrap();
|
||||
let contract_addr = Contracts::contract_address(&ALICE, &code_hash, &[]);
|
||||
|
||||
ExtBuilder::default().existential_deposit(100).build().execute_with(|| {
|
||||
let _ = Balances::deposit_creating(&ALICE, 1_000_000);
|
||||
|
||||
assert_ok!(Contracts::instantiate_with_code(
|
||||
RuntimeOrigin::signed(ALICE),
|
||||
300_000,
|
||||
GAS_LIMIT,
|
||||
None,
|
||||
wasm,
|
||||
vec![],
|
||||
vec![],
|
||||
));
|
||||
|
||||
// adding a callstack height to the input
|
||||
let input = (code_hash, 1).encode();
|
||||
|
||||
Contracts::bare_call(
|
||||
ALICE,
|
||||
contract_addr.clone(),
|
||||
0,
|
||||
GAS_LIMIT,
|
||||
None,
|
||||
input,
|
||||
true,
|
||||
Determinism::Deterministic,
|
||||
)
|
||||
.result
|
||||
.unwrap();
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(feature = "unstable-interface")]
|
||||
fn account_reentrance_count_works() {
|
||||
let (wasm, code_hash) = compile_module::<Test>("account_reentrance_count_call").unwrap();
|
||||
let (wasm_reentrant_count, code_hash_reentrant_count) =
|
||||
compile_module::<Test>("reentrant_count_call").unwrap();
|
||||
|
||||
ExtBuilder::default().existential_deposit(100).build().execute_with(|| {
|
||||
let _ = Balances::deposit_creating(&ALICE, 1_000_000);
|
||||
|
||||
assert_ok!(Contracts::instantiate_with_code(
|
||||
RuntimeOrigin::signed(ALICE),
|
||||
300_000,
|
||||
GAS_LIMIT,
|
||||
None,
|
||||
wasm,
|
||||
vec![],
|
||||
vec![],
|
||||
));
|
||||
|
||||
assert_ok!(Contracts::instantiate_with_code(
|
||||
RuntimeOrigin::signed(ALICE),
|
||||
300_000,
|
||||
GAS_LIMIT,
|
||||
None,
|
||||
wasm_reentrant_count,
|
||||
vec![],
|
||||
vec![]
|
||||
));
|
||||
|
||||
let contract_addr = Contracts::contract_address(&ALICE, &code_hash, &[]);
|
||||
let another_contract_addr =
|
||||
Contracts::contract_address(&ALICE, &code_hash_reentrant_count, &[]);
|
||||
|
||||
let result1 = Contracts::bare_call(
|
||||
ALICE,
|
||||
contract_addr.clone(),
|
||||
0,
|
||||
GAS_LIMIT,
|
||||
None,
|
||||
contract_addr.encode(),
|
||||
true,
|
||||
Determinism::Deterministic,
|
||||
)
|
||||
.result
|
||||
.unwrap();
|
||||
|
||||
let result2 = Contracts::bare_call(
|
||||
ALICE,
|
||||
contract_addr.clone(),
|
||||
0,
|
||||
GAS_LIMIT,
|
||||
None,
|
||||
another_contract_addr.encode(),
|
||||
true,
|
||||
Determinism::Deterministic,
|
||||
)
|
||||
.result
|
||||
.unwrap();
|
||||
|
||||
assert_eq!(result1.data, 1.encode());
|
||||
assert_eq!(result2.data, 0.encode());
|
||||
});
|
||||
}
|
||||
|
||||
@@ -578,6 +578,12 @@ mod tests {
|
||||
fn ecdsa_to_eth_address(&self, _pk: &[u8; 33]) -> Result<[u8; 20], ()> {
|
||||
Ok([2u8; 20])
|
||||
}
|
||||
fn reentrant_count(&self) -> u32 {
|
||||
12
|
||||
}
|
||||
fn account_reentrance_count(&self, _account_id: &AccountIdOf<Self::T>) -> u32 {
|
||||
12
|
||||
}
|
||||
}
|
||||
|
||||
fn execute<E: BorrowMut<MockExt>>(wat: &str, input_data: Vec<u8>, mut ext: E) -> ExecResult {
|
||||
@@ -2850,4 +2856,70 @@ mod tests {
|
||||
|
||||
assert_eq!(mock_ext.code_hashes.pop().unwrap(), H256::from_slice(&[17u8; 32]));
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(feature = "unstable-interface")]
|
||||
fn reentrant_count_works() {
|
||||
const CODE: &str = r#"
|
||||
(module
|
||||
(import "__unstable__" "reentrant_count" (func $reentrant_count (result i32)))
|
||||
(import "env" "memory" (memory 1 1))
|
||||
(func $assert (param i32)
|
||||
(block $ok
|
||||
(br_if $ok
|
||||
(get_local 0)
|
||||
)
|
||||
(unreachable)
|
||||
)
|
||||
)
|
||||
(func (export "call")
|
||||
(local $return_val i32)
|
||||
(set_local $return_val
|
||||
(call $reentrant_count)
|
||||
)
|
||||
(call $assert
|
||||
(i32.eq (get_local $return_val) (i32.const 12))
|
||||
)
|
||||
)
|
||||
|
||||
(func (export "deploy"))
|
||||
)
|
||||
"#;
|
||||
|
||||
let mut mock_ext = MockExt::default();
|
||||
execute(CODE, vec![], &mut mock_ext).unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(feature = "unstable-interface")]
|
||||
fn account_reentrance_count_works() {
|
||||
const CODE: &str = r#"
|
||||
(module
|
||||
(import "__unstable__" "account_reentrance_count" (func $account_reentrance_count (param i32) (result i32)))
|
||||
(import "env" "memory" (memory 1 1))
|
||||
(func $assert (param i32)
|
||||
(block $ok
|
||||
(br_if $ok
|
||||
(get_local 0)
|
||||
)
|
||||
(unreachable)
|
||||
)
|
||||
)
|
||||
(func (export "call")
|
||||
(local $return_val i32)
|
||||
(set_local $return_val
|
||||
(call $account_reentrance_count (i32.const 0))
|
||||
)
|
||||
(call $assert
|
||||
(i32.eq (get_local $return_val) (i32.const 12))
|
||||
)
|
||||
)
|
||||
|
||||
(func (export "deploy"))
|
||||
)
|
||||
"#;
|
||||
|
||||
let mut mock_ext = MockExt::default();
|
||||
execute(CODE, vec![], &mut mock_ext).unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -251,6 +251,12 @@ pub enum RuntimeCosts {
|
||||
SetCodeHash,
|
||||
/// Weight of calling `ecdsa_to_eth_address`
|
||||
EcdsaToEthAddress,
|
||||
/// Weight of calling `seal_reentrant_count`
|
||||
#[cfg(feature = "unstable-interface")]
|
||||
ReentrantCount,
|
||||
/// Weight of calling `seal_account_reentrance_count`
|
||||
#[cfg(feature = "unstable-interface")]
|
||||
AccountEntranceCount,
|
||||
}
|
||||
|
||||
impl RuntimeCosts {
|
||||
@@ -330,6 +336,10 @@ impl RuntimeCosts {
|
||||
CallRuntime(weight) => weight.ref_time(),
|
||||
SetCodeHash => s.set_code_hash,
|
||||
EcdsaToEthAddress => s.ecdsa_to_eth_address,
|
||||
#[cfg(feature = "unstable-interface")]
|
||||
ReentrantCount => s.reentrant_count,
|
||||
#[cfg(feature = "unstable-interface")]
|
||||
AccountEntranceCount => s.account_reentrance_count,
|
||||
};
|
||||
RuntimeToken {
|
||||
#[cfg(test)]
|
||||
@@ -1188,6 +1198,7 @@ pub mod env {
|
||||
Ok(ReturnCode::KeyNotFound)
|
||||
}
|
||||
}
|
||||
|
||||
/// Transfer some value to another account.
|
||||
///
|
||||
/// # Parameters
|
||||
@@ -1354,6 +1365,7 @@ pub mod env {
|
||||
output_len_ptr,
|
||||
)
|
||||
}
|
||||
|
||||
/// Instantiate a contract with the specified code hash.
|
||||
///
|
||||
/// # Deprecation
|
||||
@@ -2444,4 +2456,34 @@ pub mod env {
|
||||
Err(_) => Ok(ReturnCode::EcdsaRecoverFailed),
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the number of times the currently executing contract exists on the call stack in
|
||||
/// addition to the calling instance.
|
||||
///
|
||||
/// # Return Value
|
||||
///
|
||||
/// Returns 0 when there is no reentrancy.
|
||||
#[unstable]
|
||||
fn reentrant_count(ctx: Runtime<E>) -> Result<u32, TrapReason> {
|
||||
ctx.charge_gas(RuntimeCosts::ReentrantCount)?;
|
||||
Ok(ctx.ext.reentrant_count())
|
||||
}
|
||||
|
||||
/// Returns the number of times specified contract exists on the call stack. Delegated calls are
|
||||
/// not counted as separate calls.
|
||||
///
|
||||
/// # Parameters
|
||||
///
|
||||
/// - `account_ptr`: a pointer to the contract address.
|
||||
///
|
||||
/// # Return Value
|
||||
///
|
||||
/// Returns 0 when the contract does not exist on the call stack.
|
||||
#[unstable]
|
||||
fn account_reentrance_count(ctx: Runtime<E>, account_ptr: u32) -> Result<u32, TrapReason> {
|
||||
ctx.charge_gas(RuntimeCosts::AccountEntranceCount)?;
|
||||
let account_id: <<E as Ext>::T as frame_system::Config>::AccountId =
|
||||
ctx.read_sandbox_memory_as(account_ptr)?;
|
||||
Ok(ctx.ext.account_reentrance_count(&account_id))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -109,6 +109,8 @@ pub trait WeightInfo {
|
||||
fn seal_ecdsa_recover(r: u32, ) -> Weight;
|
||||
fn seal_ecdsa_to_eth_address(r: u32, ) -> Weight;
|
||||
fn seal_set_code_hash(r: u32, ) -> Weight;
|
||||
fn seal_reentrant_count(r: u32, ) -> Weight;
|
||||
fn seal_account_reentrance_count(r: u32, ) -> Weight;
|
||||
fn instr_i64const(r: u32, ) -> Weight;
|
||||
fn instr_i64load(r: u32, ) -> Weight;
|
||||
fn instr_i64store(r: u32, ) -> Weight;
|
||||
@@ -1020,6 +1022,30 @@ impl<T: frame_system::Config> WeightInfo for SubstrateWeight<T> {
|
||||
.saturating_add(T::DbWeight::get().writes(3 as u64))
|
||||
.saturating_add(T::DbWeight::get().writes((150 as u64).saturating_mul(r as u64)))
|
||||
}
|
||||
// Storage: System Account (r:1 w:0)
|
||||
// Storage: Contracts ContractInfoOf (r:1 w:1)
|
||||
// Storage: Contracts CodeStorage (r:1 w:0)
|
||||
// Storage: Timestamp Now (r:1 w:0)
|
||||
/// The range of component `r` is `[0, 20]`.
|
||||
fn seal_reentrant_count(r: u32, ) -> Weight {
|
||||
Weight::from_ref_time(304_709_000 as u64)
|
||||
// Standard Error: 67_000
|
||||
.saturating_add(Weight::from_ref_time(15_411_000 as u64).saturating_mul(r as u64))
|
||||
.saturating_add(T::DbWeight::get().reads(4 as u64))
|
||||
.saturating_add(T::DbWeight::get().writes(1 as u64))
|
||||
}
|
||||
// Storage: System Account (r:1 w:0)
|
||||
// Storage: Contracts ContractInfoOf (r:1 w:1)
|
||||
// Storage: Contracts CodeStorage (r:1 w:0)
|
||||
// Storage: Timestamp Now (r:1 w:0)
|
||||
/// The range of component `r` is `[0, 20]`.
|
||||
fn seal_account_reentrance_count(r: u32, ) -> Weight {
|
||||
Weight::from_ref_time(328_378_000 as u64)
|
||||
// Standard Error: 137_000
|
||||
.saturating_add(Weight::from_ref_time(37_448_000 as u64).saturating_mul(r as u64))
|
||||
.saturating_add(T::DbWeight::get().reads(4 as u64))
|
||||
.saturating_add(T::DbWeight::get().writes(1 as u64))
|
||||
}
|
||||
/// The range of component `r` is `[0, 50]`.
|
||||
fn instr_i64const(r: u32, ) -> Weight {
|
||||
// Minimum execution time: 69_022 nanoseconds.
|
||||
@@ -2236,6 +2262,30 @@ impl WeightInfo for () {
|
||||
.saturating_add(RocksDbWeight::get().writes(3 as u64))
|
||||
.saturating_add(RocksDbWeight::get().writes((150 as u64).saturating_mul(r as u64)))
|
||||
}
|
||||
// Storage: System Account (r:1 w:0)
|
||||
// Storage: Contracts ContractInfoOf (r:1 w:1)
|
||||
// Storage: Contracts CodeStorage (r:1 w:0)
|
||||
// Storage: Timestamp Now (r:1 w:0)
|
||||
/// The range of component `r` is `[0, 20]`.
|
||||
fn seal_reentrant_count(r: u32, ) -> Weight {
|
||||
Weight::from_ref_time(304_709_000 as u64)
|
||||
// Standard Error: 67_000
|
||||
.saturating_add(Weight::from_ref_time(15_411_000 as u64).saturating_mul(r as u64))
|
||||
.saturating_add(RocksDbWeight::get().reads(4 as u64))
|
||||
.saturating_add(RocksDbWeight::get().writes(1 as u64))
|
||||
}
|
||||
// Storage: System Account (r:1 w:0)
|
||||
// Storage: Contracts ContractInfoOf (r:1 w:1)
|
||||
// Storage: Contracts CodeStorage (r:1 w:0)
|
||||
// Storage: Timestamp Now (r:1 w:0)
|
||||
/// The range of component `r` is `[0, 20]`.
|
||||
fn seal_account_reentrance_count(r: u32, ) -> Weight {
|
||||
Weight::from_ref_time(328_378_000 as u64)
|
||||
// Standard Error: 137_000
|
||||
.saturating_add(Weight::from_ref_time(37_448_000 as u64).saturating_mul(r as u64))
|
||||
.saturating_add(RocksDbWeight::get().reads(4 as u64))
|
||||
.saturating_add(RocksDbWeight::get().writes(1 as u64))
|
||||
}
|
||||
/// The range of component `r` is `[0, 50]`.
|
||||
fn instr_i64const(r: u32, ) -> Weight {
|
||||
// Minimum execution time: 69_022 nanoseconds.
|
||||
@@ -2593,4 +2643,4 @@ impl WeightInfo for () {
|
||||
// Standard Error: 986
|
||||
.saturating_add(Weight::from_ref_time(1_867_001 as u64).saturating_mul(r as u64))
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user