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

Commit

Permalink
seal_delegate_call api function (support for library contracts) (#1…
Browse files Browse the repository at this point in the history
…0617)

* seal_call_code implementation

- tests
- benchmark

* Addressing @xgreenx's comments

* Fix test-linux-stable-int

* Rename seal_call_code to seal_delegate_call

* Pass value unchanged into lib contract

* Address @athei's comments

- whitespace .wat issues
- wrong/missing .wat comments
- redundant .wat calls/declarations

- change order of functions (seal_delegate_call right after seal_call)
  in decls, tests, benchmark
- fix comments, move doc comments to enum variants
- remove unnecessary empty lines

- rename runtime cost DelegateCall to DelegateCallBase
- do not set CallFlags::ALLOW_REENTRY for delegate_call

* Do not pass CallFlags::ALLOWS_REENTRY for delegate_call

* Update comment for seal_delegate_call and CallFlags

* Addressing @athei's comments (minor)

* Allow reentry for a new frame after delegate_call (revert)

* Same seal_caller and seal_value_transferred for lib contract

- test
- refactor frame args due to review
- logic for seal_caller (please review)

* Put caller on frame for delegate_call, minor fixes

* Update comment for delegate_call

* Addressing @athei's comments

* Update weights generated by benchmark

* Improve comments

* Address @HCastano's comments

* Update weights, thanks @joao-paulo-parity

* Improve InvalidCallFlags error comment
  • Loading branch information
yarikbratashchuk authored Feb 8, 2022
1 parent c8bef76 commit aa7a756
Show file tree
Hide file tree
Showing 10 changed files with 576 additions and 51 deletions.
111 changes: 111 additions & 0 deletions frame/contracts/fixtures/delegate_call.wat
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
(module
(import "seal0" "seal_input" (func $seal_input (param i32 i32)))
(import "seal0" "seal_get_storage" (func $seal_get_storage (param i32 i32 i32) (result i32)))
(import "seal0" "seal_set_storage" (func $seal_set_storage (param i32 i32 i32)))
(import "__unstable__" "seal_delegate_call" (func $seal_delegate_call (param i32 i32 i32 i32 i32 i32) (result i32)))
(import "env" "memory" (memory 3 3))

;; [0, 32) storage key
(data (i32.const 0) "\01")

;; [32, 64) storage key
(data (i32.const 32) "\02")

;; [64, 96) buffer where input is copied

;; [96, 100) size of the input buffer
(data (i32.const 96) "\20")

;; [100, 104) size of buffer for seal_get_storage
(data (i32.const 100) "\20")

;; [104, 136) seal_get_storage buffer

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

(func (export "call")
(local $exit_code i32)

;; Reading "callee" code_hash
(call $seal_input (i32.const 64) (i32.const 96))

;; assert input size == 32
(call $assert
(i32.eq
(i32.load (i32.const 96))
(i32.const 32)
)
)

;; place a value in storage, the size of which is specified by the call input.
(call $seal_set_storage
(i32.const 0) ;; Pointer to storage key
(i32.const 32) ;; Pointer to initial value
(i32.load (i32.const 100)) ;; Size of value
)

(call $assert
(i32.eq
(call $seal_get_storage
(i32.const 0) ;; Pointer to storage key
(i32.const 104) ;; buffer where to copy result
(i32.const 100) ;; pointer to size of buffer
)
(i32.const 0) ;; ReturnCode::Success
)
)

(call $assert
(i32.eq
(i32.load (i32.const 104)) ;; value received from storage
(i32.load (i32.const 32)) ;; initial value
)
)

;; Call deployed library contract code.
(set_local $exit_code
(call $seal_delegate_call
(i32.const 0) ;; Set no call flags
(i32.const 64) ;; 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
)
)

;; Check for success exit status.
(call $assert
(i32.eq (get_local $exit_code) (i32.const 0)) ;; ReturnCode::Success
)

(call $assert
(i32.eq
(call $seal_get_storage
(i32.const 0) ;; Pointer to storage key
(i32.const 104) ;; buffer where to copy result
(i32.const 100) ;; pointer to size of buffer
)
(i32.const 0) ;; ReturnCode::Success
)
)

;; Make sure that 'callee' code changed the value
(call $assert
(i32.eq
(i32.load (i32.const 104))
(i32.const 1)
)
)
)

(func (export "deploy"))

)
79 changes: 79 additions & 0 deletions frame/contracts/fixtures/delegate_call_lib.wat
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
(module
(import "seal0" "seal_set_storage" (func $seal_set_storage (param i32 i32 i32)))
(import "seal0" "seal_caller" (func $seal_caller (param i32 i32)))
(import "seal0" "seal_value_transferred" (func $seal_value_transferred (param i32 i32)))
(import "env" "memory" (memory 1 1))

;; [0, 32) storage key
(data (i32.const 0) "\01")

;; [32, 64) buffer for transferred value

;; [64, 96) size of the buffer for transferred value
(data (i32.const 64) "\20")

;; [96, 128) buffer for the caller

;; [128, 160) size of the buffer for caller
(data (i32.const 128) "\20")

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

(func (export "call")
;; place a value in storage
(call $seal_set_storage
(i32.const 0) ;; Pointer to storage key
(i32.const 0) ;; Pointer to value
(i32.const 32) ;; Size of value
)

;; This stores the value transferred in the buffer
(call $seal_value_transferred (i32.const 32) (i32.const 64))

;; assert len == 8
(call $assert
(i32.eq
(i32.load (i32.const 64))
(i32.const 8)
)
)

;; assert that contents of the buffer is equal to the value
;; passed to the `caller` contract: 1337
(call $assert
(i64.eq
(i64.load (i32.const 32))
(i64.const 1337)
)
)

;; fill the buffer with the caller.
(call $seal_caller (i32.const 96) (i32.const 128))

;; assert len == 32
(call $assert
(i32.eq
(i32.load (i32.const 128))
(i32.const 32)
)
)

;; assert that the first 64 byte are the beginning of "ALICE",
;; who is the caller of the `caller` contract
(call $assert
(i64.eq
(i64.load (i32.const 96))
(i64.const 0x0101010101010101)
)
)
)

(func (export "deploy"))
)
52 changes: 52 additions & 0 deletions frame/contracts/src/benchmarking/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1474,6 +1474,58 @@ benchmarks! {
let origin = RawOrigin::Signed(instance.caller.clone());
}: call(origin, instance.addr, 0u32.into(), Weight::MAX, None, vec![])

seal_delegate_call {
let r in 0 .. API_BENCHMARK_BATCHES;
let hashes = (0..r * API_BENCHMARK_BATCH_SIZE)
.map(|i| {
let code = WasmModule::<T>::dummy_with_bytes(i);
Contracts::<T>::store_code_raw(code.code, whitelisted_caller())?;
Ok(code.hash)
})
.collect::<Result<Vec<_>, &'static str>>()?;
let hash_len = hashes.get(0).map(|x| x.encode().len()).unwrap_or(0);
let hashes_bytes = hashes.iter().flat_map(|x| x.encode()).collect::<Vec<_>>();
let hashes_len = hashes_bytes.len();
let hashes_offset = 0;

let code = WasmModule::<T>::from(ModuleDefinition {
memory: Some(ImportedMemory::max::<T>()),
imported_functions: vec![ImportedFunction {
module: "__unstable__",
name: "seal_delegate_call",
params: vec![
ValueType::I32,
ValueType::I32,
ValueType::I32,
ValueType::I32,
ValueType::I32,
ValueType::I32,
],
return_type: Some(ValueType::I32),
}],
data_segments: vec![
DataSegment {
offset: hashes_offset as u32,
value: hashes_bytes,
},
],
call_body: Some(body::repeated_dyn(r * API_BENCHMARK_BATCH_SIZE, vec![
Regular(Instruction::I32Const(0)), // flags
Counter(hashes_offset as u32, hash_len as u32), // code_hash_ptr
Regular(Instruction::I32Const(0)), // input_data_ptr
Regular(Instruction::I32Const(0)), // input_data_len
Regular(Instruction::I32Const(u32::max_value() as i32)), // output_ptr
Regular(Instruction::I32Const(0)), // output_len_ptr
Regular(Instruction::Call(0)),
Regular(Instruction::Drop),
])),
.. Default::default()
});
let instance = Contract::<T>::new(code, vec![])?;
let callee = instance.addr.clone();
let origin = RawOrigin::Signed(instance.caller.clone());
}: call(origin, callee, 0u32.into(), Weight::MAX, None, vec![])

seal_call_per_transfer_input_output_kb {
let t in 0 .. 1;
let i in 0 .. code::max_pages::<T>() * 64;
Expand Down
Loading

0 comments on commit aa7a756

Please sign in to comment.