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

seal_delegate_call api function (support for library contracts) #10617

Merged
merged 24 commits into from
Feb 8, 2022
Merged
Show file tree
Hide file tree
Changes from 23 commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
6ba6b7d
seal_call_code implementation
yarikbratashchuk Dec 30, 2021
99bb2bc
Merge branch 'master' into delegatecall
yarikbratashchuk Jan 8, 2022
81977ff
Addressing @xgreenx's comments
yarikbratashchuk Jan 10, 2022
55fe55a
Fix test-linux-stable-int
yarikbratashchuk Jan 10, 2022
7406645
Rename seal_call_code to seal_delegate_call
yarikbratashchuk Jan 18, 2022
48a8550
Pass value unchanged into lib contract
yarikbratashchuk Jan 18, 2022
1bd4b76
Address @athei's comments
yarikbratashchuk Jan 18, 2022
e14c194
Do not pass CallFlags::ALLOWS_REENTRY for delegate_call
yarikbratashchuk Jan 18, 2022
d3e442c
Update comment for seal_delegate_call and CallFlags
yarikbratashchuk Jan 18, 2022
39d3865
Addressing @athei's comments (minor)
yarikbratashchuk Jan 18, 2022
dcbce24
Allow reentry for a new frame after delegate_call (revert)
yarikbratashchuk Jan 18, 2022
2f0981e
Same seal_caller and seal_value_transferred for lib contract
yarikbratashchuk Jan 19, 2022
a41fbd9
Put caller on frame for delegate_call, minor fixes
yarikbratashchuk Jan 20, 2022
0a467a5
Update comment for delegate_call
yarikbratashchuk Jan 20, 2022
c21d0f3
Addressing @athei's comments
yarikbratashchuk Jan 20, 2022
304a235
Merge pull request #4 from Supercolony-net/delegatecall
yarikbratashchuk Jan 21, 2022
9947774
Update weights generated by benchmark
yarikbratashchuk Jan 24, 2022
675f093
Merge branch 'master' into delegatecall
yarikbratashchuk Jan 24, 2022
49ea4b8
Improve comments
yarikbratashchuk Jan 30, 2022
b6e7948
Address @HCastano's comments
yarikbratashchuk Feb 1, 2022
c690766
Merge branch 'master' into delegatecall
yarikbratashchuk Feb 2, 2022
5d08b3d
Update weights, thanks @joao-paulo-parity
yarikbratashchuk Feb 3, 2022
a0a1dbf
Improve InvalidCallFlags error comment
yarikbratashchuk Feb 3, 2022
3732d82
Merge branch 'master' into delegatecall
yarikbratashchuk Feb 8, 2022
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
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 @@ -1417,6 +1417,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