Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
72 commits
Select commit Hold shift + click to select a range
e7cb51b
Contracts pallet: Bump Runtime API (#12677)
jasl Nov 10, 2022
112468e
Fix typo (#12680)
sorpaas Nov 10, 2022
7763a32
Move `WeightCounter` to `sp-weights` (#12603)
ggwpez Nov 11, 2022
b042ebd
Allow other pallets to check asset ids. (#12666)
gilescope Nov 11, 2022
67e3f9b
derive type info for some grandpa types (#12683)
yjhmelody Nov 11, 2022
e6768a3
Safe TreeRoute constructor (#12691)
davxy Nov 11, 2022
3e71d60
New `root_testing` pallet (#12451)
Szegoo Nov 13, 2022
59da38b
[ci] Add DAG for build-rustdoc and check-dependent-project (#12687)
alvicsam Nov 14, 2022
940a458
Collective: Benchmark with greater `MaxProposals` (#12454)
Szegoo Nov 14, 2022
65a8990
[ci] fix buildah for publishing docker (#12703)
alvicsam Nov 15, 2022
c067438
Make public is_passing and ReferendumStatus (#12667)
amarsinghcodes Nov 15, 2022
a0ab42a
Asset Pallet: Support repeated destroys to safely destroy large asset…
tonyalaribe Nov 15, 2022
cd30493
`seal_reentrant_count` returns contract reentrant count (#12695)
Artemka374 Nov 15, 2022
eb1a2a8
Assets Pallet: reintroduce fungibles::Destroy trait (#12708)
tonyalaribe Nov 15, 2022
108d8ee
release `sp-core 7.0.0` and `sp-runtime 7.0.0` (#12599)
niklasad1 Nov 15, 2022
38f473b
Release `sp-keyring` and `pallet-contracts-primitives` `7.0.0` (#12716)
ascjones Nov 16, 2022
b8ba481
Fix `cargo check` for `pallet-contracts-proc-macro` (#12706)
joao-paulo-parity Nov 16, 2022
0699880
[ci] Improve pipeline stopper (#12717)
alvicsam Nov 16, 2022
a7ba55d
sc-chainspec: Switch to `assimilate_storage` (#12720)
bkchr Nov 16, 2022
35170c5
[Cleanup] Remove obsolete event from fast-unstake (#12725)
ruseinov Nov 17, 2022
4baabe4
[Fix] Deposit for fast-unstake has to be define as pallet::constant (…
ruseinov Nov 17, 2022
0dc5358
Add event testing example to pallet template (#12722)
elv-nate Nov 17, 2022
a73a35e
Remove the `wasmtime` feature flag (#12684)
koute Nov 18, 2022
7cfaa03
Fix the light client protocol protobuf schema (#12732)
tomaka Nov 18, 2022
c290950
Update template to remove clippy warnings (#12670)
simonsso Nov 18, 2022
f80c370
Check all crates (#12709)
joao-paulo-parity Nov 21, 2022
ee9ddf1
client/beefy: persist voter state (#12712)
acatangiu Nov 21, 2022
69662c4
[Fix] Get target count from TargetList instead of storage (#12748)
ruseinov Nov 21, 2022
6cb4b67
Move block/state/warpc sync requests/responses to `ChainSync` (#12739)
altonen Nov 22, 2022
06d7a23
perf: generate_initial_session_keys: load runtime only if its relevan…
librelois Nov 22, 2022
431429f
Prevent epochs pruning while finalizing blocks on epoch 0 (#12758)
davxy Nov 23, 2022
269c799
return error instead of expect in `feasibility_check` (#12745)
kianenigma Nov 23, 2022
08d1b2c
BEEFY: optimize voter event loop for fewer 'active' wakeups (#12760)
acatangiu Nov 23, 2022
4e3a12b
Sort crates before splitting them into groups (+ some improvements) (…
joao-paulo-parity Nov 24, 2022
f465fee
contracts: Replace `sp-sandbox` and `wasmi-validation` by newest wasm…
athei Nov 24, 2022
d122169
update DefaultNoBound derive macro (#12723)
benluelo Nov 25, 2022
ab6142f
Fix rustdoc (#12777)
ggwpez Nov 25, 2022
3e91823
Allow Alliance Fellows to Give Up Voting Rights (#12730)
joepetrowski Nov 25, 2022
a1dc9d8
Add total nb to trie migration rpc (#12770)
cheme Nov 25, 2022
d11846b
add EnsureWithSuccess (#12775)
xlc Nov 25, 2022
39ef178
Explicitly unset RUSTC_WRAPPER=sccache environment variable (#12771)
rcny Nov 25, 2022
2eb5128
contracts: Don't put unstable functions in special module (#12781)
athei Nov 27, 2022
a92005a
ed25519_verify: Support using dalek for historical blocks (#12661)
bkchr Nov 27, 2022
d833e15
client/beefy: fix on-demand justifications sync for old blocks (#12767)
acatangiu Nov 28, 2022
a0e00dc
Remove Default, HasCompact, and TypeInfo trait bounds on AssetId (#12…
joepetrowski Nov 28, 2022
9ce75af
pallet-mmr: move offchain logic to client-side gadget (#12753)
serban300 Nov 29, 2022
59ca8df
Require rust-features check (#12796)
ggwpez Nov 29, 2022
5c8aa7e
MMR: move RPC code from frame/ to client/ (#12805)
acatangiu Nov 30, 2022
357c363
chore: remove unused traits for wasm interface (#12792)
yjhmelody Nov 30, 2022
cc36931
sc-transaction-handler: Fix potential crashes on exit (#12807)
bkchr Nov 30, 2022
2ed4058
Don't announce blocks in `sync_to_tip_when_we_sync_together_with_mult…
altonen Nov 30, 2022
982f599
contracts: Replace cargo feature `unstable-interface` with config (#1…
athei Nov 30, 2022
009c872
Bounties use SpendOrigin (#12808)
gavofyork Dec 1, 2022
5ae8a3b
Reduce provisioner work (#12749)
Dec 1, 2022
c17c7d8
Fix quantization in referenda alarm (#12815)
gavofyork Dec 2, 2022
34900ca
Add `Weightless` benchmark bailing (#12829)
ggwpez Dec 2, 2022
9812205
API for registering inactive funds (#12813)
gavofyork Dec 3, 2022
1a0af36
Tweak to active total migrations (#12832)
gavofyork Dec 3, 2022
cb3eaf2
frame-executive: Reject invalid inherents in the executive (#12365)
bkchr Dec 4, 2022
2bde8c1
Upgrade tokio to 1.22.0 and replace async-std with tokio (#12646)
dmitry-markin Dec 5, 2022
62a85fb
make threshold pub instead of pub crate (#12814)
amarsinghcodes Dec 5, 2022
0ab43bc
Non-Interactive Staking (#12610)
gavofyork Dec 5, 2022
2704ab3
pallet-balances: Fix inactive funds migration (#12840)
bkchr Dec 5, 2022
05ebde1
client/beefy: add some bounds on enqueued votes (#12562)
dharjeezy Dec 5, 2022
404b8c9
OpenGov: Abstentions (#12842)
gavofyork Dec 5, 2022
b1396f7
Add `with_weight` extrinsic (#12848)
shawntabrizi Dec 5, 2022
fa42631
[contracts] Add per local weight for function call (#12806)
agryaznov Dec 6, 2022
234749e
contracts: Add `instantiation_nonce` API (#12800)
athei Dec 6, 2022
1cc97dd
Rename some crates for publishing to crates.io (#12837)
joao-paulo-parity Dec 6, 2022
90eb84a
Merge remote-tracking branch 'upstream/polkadot-v0.9.34' into update-…
kacperzuk-neti Jan 23, 2023
b2bbeb8
Merge remote-tracking branch 'origin/develop' into update-to-polkadot…
kacperzuk-neti Jan 24, 2023
89ebc92
Fix CitizenshipMinimum value
kacperzuk-neti Jan 24, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
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>
  • Loading branch information
Artemka374 and yarikbratashchuk authored Nov 15, 2022
commit cd30493bc93279bf4b18d6505cc5bdc8d592cbe2
37 changes: 37 additions & 0 deletions frame/contracts/fixtures/account_reentrance_count_call.wat
Original file line number Diff line number Diff line change
@@ -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"))

)
76 changes: 76 additions & 0 deletions frame/contracts/fixtures/reentrant_count_call.wat
Original file line number Diff line number Diff line change
@@ -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"))
)
71 changes: 71 additions & 0 deletions frame/contracts/fixtures/reentrant_count_delegated_call.wat
Original file line number Diff line number Diff line change
@@ -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"))
)
53 changes: 53 additions & 0 deletions frame/contracts/src/benchmarking/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
20 changes: 20 additions & 0 deletions frame/contracts/src/exec.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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`].
Expand Down Expand Up @@ -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 {
Expand Down
8 changes: 8 additions & 0 deletions frame/contracts/src/schedule.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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>,
Expand Down Expand Up @@ -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,
}
}
Expand Down
Loading