Skip to content
This repository was archived by the owner on Nov 15, 2023. It is now read-only.

Commit 9780579

Browse files
pgherveouagryaznovatheijuangirini
authored
Contracts Add deposit for dependencies (#14079)
* wip * fixes * rm comment * join fns * clippy * Fix limits * reduce diff * fix * fix * fix typo * refactor store to use self * refactor run to take self by value * pass tests * rm comment * fixes * fix typo * rm * fix fmt * clippy * ".git/.scripts/commands/bench/bench.sh" pallet dev pallet_contracts * Update frame/contracts/src/lib.rs Co-authored-by: Sasha Gryaznov <[email protected]> * Update frame/contracts/src/wasm/mod.rs Co-authored-by: Sasha Gryaznov <[email protected]> * Update frame/contracts/src/wasm/mod.rs Co-authored-by: Sasha Gryaznov <[email protected]> * PR review, rm duplicate increment_refcount * PR review * Update frame/contracts/src/wasm/prepare.rs Co-authored-by: Sasha Gryaznov <[email protected]> * Add test for failing storage_deposit * fix lint * wip * Delegate update take 2 * update * fix migration * fix migration * doc * fix lint * update migration * fix warning * reformat comment * regenerate weightInfo trait * fix merge * PR review #14079 (comment) * PR review https://github.com/paritytech/substrate/pull/14079/files#r1257521373 * PR review remove optimisation https://github.com/paritytech/substrate/pull/14079/files#r1263312237 * PR review fix return type https://github.com/paritytech/substrate/pull/14079/files#r1263315804 * Apply suggestions from code review Co-authored-by: Alexander Theißen <[email protected]> * PR review pass CodeInfo and update docstring https://github.com/paritytech/substrate/pull/14079/files#r1257522327 * PR review add code_info to the executable https://github.com/paritytech/substrate/pull/14079/files#r1263309049 * rename info -> contract_info * Update frame/contracts/src/exec.rs Co-authored-by: Alexander Theißen <[email protected]> * Update frame/contracts/fixtures/add_remove_delegate_dependency.wat Co-authored-by: Alexander Theißen <[email protected]> * Update frame/contracts/src/migration/v13.rs * fix tests * Fmt & fix tests * Test Result<(), _> return type * Update frame/contracts/src/migration.rs Co-authored-by: Alexander Theißen <[email protected]> * Revert "Test Result<(), _> return type" This reverts commit a876168. * add / update doc comments * fix backticks * Revert "Revert "Test Result<(), _> return type"" This reverts commit 3cbb616. * fix bench * fix bench * fix * Update frame/contracts/src/storage/meter.rs Co-authored-by: Alexander Theißen <[email protected]> * rm stale comments * Apply suggestions from code review Co-authored-by: Sasha Gryaznov <[email protected]> * PR suggestion * Add missing doc * fx lint * ".git/.scripts/commands/bench/bench.sh" --subcommand=pallet --runtime=dev --target_dir=substrate --pallet=pallet_contracts * Update frame/contracts/src/lib.rs Co-authored-by: Juan <[email protected]> --------- Co-authored-by: command-bot <> Co-authored-by: Sasha Gryaznov <[email protected]> Co-authored-by: Alexander Theißen <[email protected]> Co-authored-by: Juan <[email protected]>
1 parent bb0af12 commit 9780579

File tree

14 files changed

+3973
-2815
lines changed

14 files changed

+3973
-2815
lines changed

bin/node/runtime/src/lib.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1223,6 +1223,7 @@ parameter_types! {
12231223
pub const DepositPerByte: Balance = deposit(0, 1);
12241224
pub const DefaultDepositLimit: Balance = deposit(1024, 1024 * 1024);
12251225
pub Schedule: pallet_contracts::Schedule<Runtime> = Default::default();
1226+
pub CodeHashLockupDepositPercent: Perbill = Perbill::from_percent(30);
12261227
}
12271228

12281229
impl pallet_contracts::Config for Runtime {
@@ -1255,6 +1256,8 @@ impl pallet_contracts::Config for Runtime {
12551256
type Migrations = ();
12561257
#[cfg(feature = "runtime-benchmarks")]
12571258
type Migrations = (NoopMigration<1>, NoopMigration<2>);
1259+
type MaxDelegateDependencies = ConstU32<32>;
1260+
type CodeHashLockupDepositPercent = CodeHashLockupDepositPercent;
12581261
}
12591262

12601263
impl pallet_sudo::Config for Runtime {
Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
;; This contract tests the behavior of adding / removing delegate_dependencies when delegate calling into a contract.
2+
(module
3+
(import "seal0" "add_delegate_dependency" (func $add_delegate_dependency (param i32)))
4+
(import "seal0" "remove_delegate_dependency" (func $remove_delegate_dependency (param i32)))
5+
(import "seal0" "input" (func $input (param i32 i32)))
6+
(import "seal1" "terminate" (func $terminate (param i32)))
7+
(import "seal0" "delegate_call" (func $delegate_call (param i32 i32 i32 i32 i32 i32) (result i32)))
8+
(import "env" "memory" (memory 1 1))
9+
10+
;; [100, 132) Address of Alice
11+
(data (i32.const 100)
12+
"\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01"
13+
"\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01"
14+
)
15+
16+
(func $assert (param i32)
17+
(block $ok
18+
(br_if $ok
19+
(get_local 0)
20+
)
21+
(unreachable)
22+
)
23+
)
24+
25+
;; This function loads input data and performs the action specified.
26+
;; The first 4 bytes of the input specify the action to perform.
27+
;; The next 32 bytes specify the code hash to use when calling add_delegate_dependency or remove_delegate_dependency.
28+
;; Actions are:
29+
;; 1: call add_delegate_dependency
30+
;; 2: call remove_delegate_dependency.
31+
;; 3: call terminate.
32+
;; Any other value is a no-op.
33+
(func $load_input
34+
(local $action i32)
35+
(local $code_hash_ptr i32)
36+
37+
;; Store available input size at offset 0.
38+
(i32.store (i32.const 0) (i32.const 512))
39+
40+
;; Read input data.
41+
(call $input (i32.const 4) (i32.const 0))
42+
43+
;; Input data layout.
44+
;; [0..4) - size of the call
45+
;; [4..8) - action to perform
46+
;; [8..42) - code hash of the callee
47+
(set_local $action (i32.load (i32.const 4)))
48+
(set_local $code_hash_ptr (i32.const 8))
49+
50+
;; Assert input size == 36 (4 for action + 32 for code_hash).
51+
(call $assert
52+
(i32.eq
53+
(i32.load (i32.const 0))
54+
(i32.const 36)
55+
)
56+
)
57+
58+
;; Call add_delegate_dependency when action == 1.
59+
(if (i32.eq (get_local $action) (i32.const 1))
60+
(then
61+
(call $add_delegate_dependency (get_local $code_hash_ptr))
62+
)
63+
(else)
64+
)
65+
66+
;; Call remove_delegate_dependency when action == 2.
67+
(if (i32.eq (get_local $action) (i32.const 2))
68+
(then
69+
(call $remove_delegate_dependency
70+
(get_local $code_hash_ptr)
71+
)
72+
)
73+
(else)
74+
)
75+
76+
;; Call terminate when action == 3.
77+
(if (i32.eq (get_local $action) (i32.const 3))
78+
(then
79+
(call $terminate
80+
(i32.const 100) ;; Pointer to beneficiary address
81+
)
82+
(unreachable) ;; terminate never returns
83+
)
84+
(else)
85+
)
86+
)
87+
88+
(func (export "deploy")
89+
(call $load_input)
90+
)
91+
92+
(func (export "call")
93+
(call $load_input)
94+
95+
;; Delegate call into passed code hash.
96+
(call $assert
97+
(i32.eq
98+
(call $delegate_call
99+
(i32.const 0) ;; Set no call flags.
100+
(i32.const 8) ;; Pointer to "callee" code_hash.
101+
(i32.const 0) ;; Input is ignored.
102+
(i32.const 0) ;; Length of the input.
103+
(i32.const 4294967295) ;; u32 max sentinel value: do not copy output.
104+
(i32.const 0) ;; Length is ignored in this case.
105+
)
106+
(i32.const 0)
107+
)
108+
)
109+
)
110+
111+
)

frame/contracts/src/benchmarking/mod.rs

Lines changed: 131 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ use self::{
3030
};
3131
use crate::{
3232
exec::{AccountIdOf, Key},
33-
migration::{v09, v10, v11, v12, MigrationStep},
33+
migration::{v09, v10, v11, v12, v13, MigrationStep},
3434
wasm::CallFlags,
3535
Pallet as Contracts, *,
3636
};
@@ -257,6 +257,19 @@ benchmarks! {
257257
m.step();
258258
}
259259

260+
// This benchmarks the v13 migration step (Add delegate_dependencies field).
261+
#[pov_mode = Measured]
262+
v13_migration_step {
263+
let contract = <Contract<T>>::with_caller(
264+
whitelisted_caller(), WasmModule::dummy(), vec![],
265+
)?;
266+
267+
v13::store_old_contract_info::<T>(contract.account_id.clone(), contract.info()?);
268+
let mut m = v13::Migration::<T>::default();
269+
}: {
270+
m.step();
271+
}
272+
260273
// This benchmarks the weight of executing Migration::migrate to execute a noop migration.
261274
#[pov_mode = Measured]
262275
migration_noop {
@@ -832,20 +845,48 @@ benchmarks! {
832845
let beneficiary = account::<T::AccountId>("beneficiary", 0, 0);
833846
let beneficiary_bytes = beneficiary.encode();
834847
let beneficiary_len = beneficiary_bytes.len();
848+
849+
// Maximize the delegate_dependencies to account for the worst-case scenario.
850+
let code_hashes = (0..T::MaxDelegateDependencies::get())
851+
.map(|i| {
852+
let new_code = WasmModule::<T>::dummy_with_bytes(65 + i);
853+
Contracts::<T>::store_code_raw(new_code.code, whitelisted_caller())?;
854+
Ok(new_code.hash)
855+
})
856+
.collect::<Result<Vec<_>, &'static str>>()?;
857+
let code_hash_len = code_hashes.get(0).map(|x| x.encode().len()).unwrap_or(0);
858+
let code_hashes_bytes = code_hashes.iter().flat_map(|x| x.encode()).collect::<Vec<_>>();
859+
835860
let code = WasmModule::<T>::from(ModuleDefinition {
836861
memory: Some(ImportedMemory::max::<T>()),
837-
imported_functions: vec![ImportedFunction {
838-
module: "seal0",
839-
name: "seal_terminate",
840-
params: vec![ValueType::I32, ValueType::I32],
841-
return_type: None,
842-
}],
862+
imported_functions: vec![
863+
ImportedFunction {
864+
module: "seal0",
865+
name: "seal_terminate",
866+
params: vec![ValueType::I32, ValueType::I32],
867+
return_type: None,
868+
},
869+
ImportedFunction {
870+
module: "seal0",
871+
name: "add_delegate_dependency",
872+
params: vec![ValueType::I32],
873+
return_type: None,
874+
}
875+
],
843876
data_segments: vec![
844877
DataSegment {
845878
offset: 0,
846879
value: beneficiary_bytes,
847880
},
881+
DataSegment {
882+
offset: beneficiary_len as u32,
883+
value: code_hashes_bytes,
884+
},
848885
],
886+
deploy_body: Some(body::repeated_dyn(r, vec![
887+
Counter(beneficiary_len as u32, code_hash_len as u32), // code_hash_ptr
888+
Regular(Instruction::Call(1)),
889+
])),
849890
call_body: Some(body::repeated(r, &[
850891
Instruction::I32Const(0), // beneficiary_ptr
851892
Instruction::I32Const(beneficiary_len as i32), // beneficiary_len
@@ -2327,6 +2368,89 @@ benchmarks! {
23272368
let origin = RawOrigin::Signed(instance.caller.clone());
23282369
}: call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![])
23292370

2371+
#[pov_mode = Measured]
2372+
add_delegate_dependency {
2373+
let r in 0 .. T::MaxDelegateDependencies::get();
2374+
let code_hashes = (0..r)
2375+
.map(|i| {
2376+
let new_code = WasmModule::<T>::dummy_with_bytes(65 + i);
2377+
Contracts::<T>::store_code_raw(new_code.code, whitelisted_caller())?;
2378+
Ok(new_code.hash)
2379+
})
2380+
.collect::<Result<Vec<_>, &'static str>>()?;
2381+
let code_hash_len = code_hashes.get(0).map(|x| x.encode().len()).unwrap_or(0);
2382+
let code_hashes_bytes = code_hashes.iter().flat_map(|x| x.encode()).collect::<Vec<_>>();
2383+
2384+
let code = WasmModule::<T>::from(ModuleDefinition {
2385+
memory: Some(ImportedMemory::max::<T>()),
2386+
imported_functions: vec![ImportedFunction {
2387+
module: "seal0",
2388+
name: "add_delegate_dependency",
2389+
params: vec![ValueType::I32],
2390+
return_type: None,
2391+
}],
2392+
data_segments: vec![
2393+
DataSegment {
2394+
offset: 0,
2395+
value: code_hashes_bytes,
2396+
},
2397+
],
2398+
call_body: Some(body::repeated_dyn(r, vec![
2399+
Counter(0, code_hash_len as u32), // code_hash_ptr
2400+
Regular(Instruction::Call(0)),
2401+
])),
2402+
.. Default::default()
2403+
});
2404+
let instance = Contract::<T>::new(code, vec![])?;
2405+
let origin = RawOrigin::Signed(instance.caller.clone());
2406+
}: call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![])
2407+
2408+
remove_delegate_dependency {
2409+
let r in 0 .. T::MaxDelegateDependencies::get();
2410+
let code_hashes = (0..r)
2411+
.map(|i| {
2412+
let new_code = WasmModule::<T>::dummy_with_bytes(65 + i);
2413+
Contracts::<T>::store_code_raw(new_code.code, whitelisted_caller())?;
2414+
Ok(new_code.hash)
2415+
})
2416+
.collect::<Result<Vec<_>, &'static str>>()?;
2417+
2418+
let code_hash_len = code_hashes.get(0).map(|x| x.encode().len()).unwrap_or(0);
2419+
let code_hashes_bytes = code_hashes.iter().flat_map(|x| x.encode()).collect::<Vec<_>>();
2420+
2421+
let code = WasmModule::<T>::from(ModuleDefinition {
2422+
memory: Some(ImportedMemory::max::<T>()),
2423+
imported_functions: vec![ImportedFunction {
2424+
module: "seal0",
2425+
name: "remove_delegate_dependency",
2426+
params: vec![ValueType::I32],
2427+
return_type: None,
2428+
}, ImportedFunction {
2429+
module: "seal0",
2430+
name: "add_delegate_dependency",
2431+
params: vec![ValueType::I32],
2432+
return_type: None
2433+
}],
2434+
data_segments: vec![
2435+
DataSegment {
2436+
offset: 0,
2437+
value: code_hashes_bytes,
2438+
},
2439+
],
2440+
deploy_body: Some(body::repeated_dyn(r, vec![
2441+
Counter(0, code_hash_len as u32), // code_hash_ptr
2442+
Regular(Instruction::Call(1)),
2443+
])),
2444+
call_body: Some(body::repeated_dyn(r, vec![
2445+
Counter(0, code_hash_len as u32), // code_hash_ptr
2446+
Regular(Instruction::Call(0)),
2447+
])),
2448+
.. Default::default()
2449+
});
2450+
let instance = Contract::<T>::new(code, vec![])?;
2451+
let origin = RawOrigin::Signed(instance.caller.clone());
2452+
}: call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![])
2453+
23302454
#[pov_mode = Measured]
23312455
seal_reentrance_count {
23322456
let r in 0 .. API_BENCHMARK_RUNS;

0 commit comments

Comments
 (0)