seal_delegate_call api function (support for library contracts) (#10617)

* 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
This commit is contained in:
Yarik Bratashchuk
2022-02-08 13:43:32 +02:00
committed by GitHub
parent 1d62516fad
commit d14e1c641e
10 changed files with 574 additions and 49 deletions
+63
View File
@@ -302,11 +302,18 @@ mod tests {
allows_reentry: bool,
}
#[derive(Debug, PartialEq, Eq)]
struct CallCodeEntry {
code_hash: H256,
data: Vec<u8>,
}
pub struct MockExt {
storage: HashMap<StorageKey, Vec<u8>>,
instantiates: Vec<InstantiateEntry>,
terminations: Vec<TerminationEntry>,
calls: Vec<CallEntry>,
code_calls: Vec<CallCodeEntry>,
transfers: Vec<TransferEntry>,
// (topics, data)
events: Vec<(Vec<H256>, Vec<u8>)>,
@@ -329,6 +336,7 @@ mod tests {
instantiates: Default::default(),
terminations: Default::default(),
calls: Default::default(),
code_calls: Default::default(),
transfers: Default::default(),
events: Default::default(),
runtime_calls: Default::default(),
@@ -354,6 +362,14 @@ mod tests {
self.calls.push(CallEntry { to, value, data, allows_reentry });
Ok(ExecReturnValue { flags: ReturnFlags::empty(), data: call_return_data() })
}
fn delegate_call(
&mut self,
code_hash: CodeHash<Self::T>,
data: Vec<u8>,
) -> Result<ExecReturnValue, ExecError> {
self.code_calls.push(CallCodeEntry { code_hash, data });
Ok(ExecReturnValue { flags: ReturnFlags::empty(), data: call_return_data() })
}
fn instantiate(
&mut self,
gas_limit: Weight,
@@ -579,6 +595,53 @@ mod tests {
);
}
#[test]
#[cfg(feature = "unstable-interface")]
fn contract_delegate_call() {
const CODE: &str = r#"
(module
;; seal_delegate_call(
;; flags: u32,
;; code_hash_ptr: u32,
;; input_data_ptr: u32,
;; input_data_len: u32,
;; output_ptr: u32,
;; output_len_ptr: u32
;;) -> u32
(import "__unstable__" "seal_delegate_call" (func $seal_delegate_call (param i32 i32 i32 i32 i32 i32) (result i32)))
(import "env" "memory" (memory 1 1))
(func (export "call")
(drop
(call $seal_delegate_call
(i32.const 0) ;; No flags are set
(i32.const 4) ;; Pointer to "callee" code_hash.
(i32.const 36) ;; Pointer to input data buffer address
(i32.const 4) ;; Length of input data buffer
(i32.const 4294967295) ;; u32 max value is the sentinel value: do not copy output
(i32.const 0) ;; Length is ignored in this case
)
)
)
(func (export "deploy"))
;; Callee code_hash
(data (i32.const 4)
"\11\11\11\11\11\11\11\11\11\11\11\11\11\11\11\11"
"\11\11\11\11\11\11\11\11\11\11\11\11\11\11\11\11"
)
(data (i32.const 36) "\01\02\03\04")
)
"#;
let mut mock_ext = MockExt::default();
assert_ok!(execute(CODE, vec![], &mut mock_ext));
assert_eq!(
&mock_ext.code_calls,
&[CallCodeEntry { code_hash: [0x11; 32].into(), data: vec![1, 2, 3, 4] }]
);
}
#[test]
fn contract_call_forward_input() {
const CODE: &str = r#"