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

Commit

Permalink
Contracts Add deposit for dependencies (#14079)
Browse files Browse the repository at this point in the history
* 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 <hi@agryaznov.com>

* Update frame/contracts/src/wasm/mod.rs

Co-authored-by: Sasha Gryaznov <hi@agryaznov.com>

* Update frame/contracts/src/wasm/mod.rs

Co-authored-by: Sasha Gryaznov <hi@agryaznov.com>

* PR review, rm duplicate increment_refcount

* PR review

* Update frame/contracts/src/wasm/prepare.rs

Co-authored-by: Sasha Gryaznov <hi@agryaznov.com>

* 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 <alex.theissen@me.com>

* 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 <alex.theissen@me.com>

* Update frame/contracts/fixtures/add_remove_delegate_dependency.wat

Co-authored-by: Alexander Theißen <alex.theissen@me.com>

* 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 <alex.theissen@me.com>

* 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 <alex.theissen@me.com>

* rm stale comments

* Apply suggestions from code review

Co-authored-by: Sasha Gryaznov <hi@agryaznov.com>

* 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 <juangirini@gmail.com>

---------

Co-authored-by: command-bot <>
Co-authored-by: Sasha Gryaznov <hi@agryaznov.com>
Co-authored-by: Alexander Theißen <alex.theissen@me.com>
Co-authored-by: Juan <juangirini@gmail.com>
  • Loading branch information
4 people authored Jul 26, 2023
1 parent bb0af12 commit 9780579
Show file tree
Hide file tree
Showing 14 changed files with 3,973 additions and 2,815 deletions.
3 changes: 3 additions & 0 deletions bin/node/runtime/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1223,6 +1223,7 @@ parameter_types! {
pub const DepositPerByte: Balance = deposit(0, 1);
pub const DefaultDepositLimit: Balance = deposit(1024, 1024 * 1024);
pub Schedule: pallet_contracts::Schedule<Runtime> = Default::default();
pub CodeHashLockupDepositPercent: Perbill = Perbill::from_percent(30);
}

impl pallet_contracts::Config for Runtime {
Expand Down Expand Up @@ -1255,6 +1256,8 @@ impl pallet_contracts::Config for Runtime {
type Migrations = ();
#[cfg(feature = "runtime-benchmarks")]
type Migrations = (NoopMigration<1>, NoopMigration<2>);
type MaxDelegateDependencies = ConstU32<32>;
type CodeHashLockupDepositPercent = CodeHashLockupDepositPercent;
}

impl pallet_sudo::Config for Runtime {
Expand Down
111 changes: 111 additions & 0 deletions frame/contracts/fixtures/add_remove_delegate_dependency.wat
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
;; This contract tests the behavior of adding / removing delegate_dependencies when delegate calling into a contract.
(module
(import "seal0" "add_delegate_dependency" (func $add_delegate_dependency (param i32)))
(import "seal0" "remove_delegate_dependency" (func $remove_delegate_dependency (param i32)))
(import "seal0" "input" (func $input (param i32 i32)))
(import "seal1" "terminate" (func $terminate (param i32)))
(import "seal0" "delegate_call" (func $delegate_call (param i32 i32 i32 i32 i32 i32) (result i32)))
(import "env" "memory" (memory 1 1))

;; [100, 132) Address of Alice
(data (i32.const 100)
"\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01"
"\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01\01"
)

(func $assert (param i32)
(block $ok
(br_if $ok
(get_local 0)
)
(unreachable)
)
)

;; This function loads input data and performs the action specified.
;; The first 4 bytes of the input specify the action to perform.
;; The next 32 bytes specify the code hash to use when calling add_delegate_dependency or remove_delegate_dependency.
;; Actions are:
;; 1: call add_delegate_dependency
;; 2: call remove_delegate_dependency.
;; 3: call terminate.
;; Any other value is a no-op.
(func $load_input
(local $action i32)
(local $code_hash_ptr i32)

;; Store available input size at offset 0.
(i32.store (i32.const 0) (i32.const 512))

;; Read input data.
(call $input (i32.const 4) (i32.const 0))

;; Input data layout.
;; [0..4) - size of the call
;; [4..8) - action to perform
;; [8..42) - code hash of the callee
(set_local $action (i32.load (i32.const 4)))
(set_local $code_hash_ptr (i32.const 8))

;; Assert input size == 36 (4 for action + 32 for code_hash).
(call $assert
(i32.eq
(i32.load (i32.const 0))
(i32.const 36)
)
)

;; Call add_delegate_dependency when action == 1.
(if (i32.eq (get_local $action) (i32.const 1))
(then
(call $add_delegate_dependency (get_local $code_hash_ptr))
)
(else)
)

;; Call remove_delegate_dependency when action == 2.
(if (i32.eq (get_local $action) (i32.const 2))
(then
(call $remove_delegate_dependency
(get_local $code_hash_ptr)
)
)
(else)
)

;; Call terminate when action == 3.
(if (i32.eq (get_local $action) (i32.const 3))
(then
(call $terminate
(i32.const 100) ;; Pointer to beneficiary address
)
(unreachable) ;; terminate never returns
)
(else)
)
)

(func (export "deploy")
(call $load_input)
)

(func (export "call")
(call $load_input)

;; Delegate call into passed code hash.
(call $assert
(i32.eq
(call $delegate_call
(i32.const 0) ;; Set no call flags.
(i32.const 8) ;; Pointer to "callee" code_hash.
(i32.const 0) ;; Input is ignored.
(i32.const 0) ;; Length of the input.
(i32.const 4294967295) ;; u32 max sentinel value: do not copy output.
(i32.const 0) ;; Length is ignored in this case.
)
(i32.const 0)
)
)
)

)
138 changes: 131 additions & 7 deletions frame/contracts/src/benchmarking/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ use self::{
};
use crate::{
exec::{AccountIdOf, Key},
migration::{v09, v10, v11, v12, MigrationStep},
migration::{v09, v10, v11, v12, v13, MigrationStep},
wasm::CallFlags,
Pallet as Contracts, *,
};
Expand Down Expand Up @@ -257,6 +257,19 @@ benchmarks! {
m.step();
}

// This benchmarks the v13 migration step (Add delegate_dependencies field).
#[pov_mode = Measured]
v13_migration_step {
let contract = <Contract<T>>::with_caller(
whitelisted_caller(), WasmModule::dummy(), vec![],
)?;

v13::store_old_contract_info::<T>(contract.account_id.clone(), contract.info()?);
let mut m = v13::Migration::<T>::default();
}: {
m.step();
}

// This benchmarks the weight of executing Migration::migrate to execute a noop migration.
#[pov_mode = Measured]
migration_noop {
Expand Down Expand Up @@ -832,20 +845,48 @@ benchmarks! {
let beneficiary = account::<T::AccountId>("beneficiary", 0, 0);
let beneficiary_bytes = beneficiary.encode();
let beneficiary_len = beneficiary_bytes.len();

// Maximize the delegate_dependencies to account for the worst-case scenario.
let code_hashes = (0..T::MaxDelegateDependencies::get())
.map(|i| {
let new_code = WasmModule::<T>::dummy_with_bytes(65 + i);
Contracts::<T>::store_code_raw(new_code.code, whitelisted_caller())?;
Ok(new_code.hash)
})
.collect::<Result<Vec<_>, &'static str>>()?;
let code_hash_len = code_hashes.get(0).map(|x| x.encode().len()).unwrap_or(0);
let code_hashes_bytes = code_hashes.iter().flat_map(|x| x.encode()).collect::<Vec<_>>();

let code = WasmModule::<T>::from(ModuleDefinition {
memory: Some(ImportedMemory::max::<T>()),
imported_functions: vec![ImportedFunction {
module: "seal0",
name: "seal_terminate",
params: vec![ValueType::I32, ValueType::I32],
return_type: None,
}],
imported_functions: vec![
ImportedFunction {
module: "seal0",
name: "seal_terminate",
params: vec![ValueType::I32, ValueType::I32],
return_type: None,
},
ImportedFunction {
module: "seal0",
name: "add_delegate_dependency",
params: vec![ValueType::I32],
return_type: None,
}
],
data_segments: vec![
DataSegment {
offset: 0,
value: beneficiary_bytes,
},
DataSegment {
offset: beneficiary_len as u32,
value: code_hashes_bytes,
},
],
deploy_body: Some(body::repeated_dyn(r, vec![
Counter(beneficiary_len as u32, code_hash_len as u32), // code_hash_ptr
Regular(Instruction::Call(1)),
])),
call_body: Some(body::repeated(r, &[
Instruction::I32Const(0), // beneficiary_ptr
Instruction::I32Const(beneficiary_len as i32), // beneficiary_len
Expand Down Expand Up @@ -2327,6 +2368,89 @@ benchmarks! {
let origin = RawOrigin::Signed(instance.caller.clone());
}: call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![])

#[pov_mode = Measured]
add_delegate_dependency {
let r in 0 .. T::MaxDelegateDependencies::get();
let code_hashes = (0..r)
.map(|i| {
let new_code = WasmModule::<T>::dummy_with_bytes(65 + i);
Contracts::<T>::store_code_raw(new_code.code, whitelisted_caller())?;
Ok(new_code.hash)
})
.collect::<Result<Vec<_>, &'static str>>()?;
let code_hash_len = code_hashes.get(0).map(|x| x.encode().len()).unwrap_or(0);
let code_hashes_bytes = code_hashes.iter().flat_map(|x| x.encode()).collect::<Vec<_>>();

let code = WasmModule::<T>::from(ModuleDefinition {
memory: Some(ImportedMemory::max::<T>()),
imported_functions: vec![ImportedFunction {
module: "seal0",
name: "add_delegate_dependency",
params: vec![ValueType::I32],
return_type: None,
}],
data_segments: vec![
DataSegment {
offset: 0,
value: code_hashes_bytes,
},
],
call_body: Some(body::repeated_dyn(r, vec![
Counter(0, code_hash_len as u32), // code_hash_ptr
Regular(Instruction::Call(0)),
])),
.. 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![])

remove_delegate_dependency {
let r in 0 .. T::MaxDelegateDependencies::get();
let code_hashes = (0..r)
.map(|i| {
let new_code = WasmModule::<T>::dummy_with_bytes(65 + i);
Contracts::<T>::store_code_raw(new_code.code, whitelisted_caller())?;
Ok(new_code.hash)
})
.collect::<Result<Vec<_>, &'static str>>()?;

let code_hash_len = code_hashes.get(0).map(|x| x.encode().len()).unwrap_or(0);
let code_hashes_bytes = code_hashes.iter().flat_map(|x| x.encode()).collect::<Vec<_>>();

let code = WasmModule::<T>::from(ModuleDefinition {
memory: Some(ImportedMemory::max::<T>()),
imported_functions: vec![ImportedFunction {
module: "seal0",
name: "remove_delegate_dependency",
params: vec![ValueType::I32],
return_type: None,
}, ImportedFunction {
module: "seal0",
name: "add_delegate_dependency",
params: vec![ValueType::I32],
return_type: None
}],
data_segments: vec![
DataSegment {
offset: 0,
value: code_hashes_bytes,
},
],
deploy_body: Some(body::repeated_dyn(r, vec![
Counter(0, code_hash_len as u32), // code_hash_ptr
Regular(Instruction::Call(1)),
])),
call_body: Some(body::repeated_dyn(r, vec![
Counter(0, code_hash_len as u32), // code_hash_ptr
Regular(Instruction::Call(0)),
])),
.. 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![])

#[pov_mode = Measured]
seal_reentrance_count {
let r in 0 .. API_BENCHMARK_RUNS;
Expand Down
Loading

0 comments on commit 9780579

Please sign in to comment.