mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-06-20 10:31:03 +00:00
contracts: add seal_code_hash and seal_own_code_hash to API (#10933)
* `seal_origin` + tests added * `seal_origin` benchmark added * `seal_code_hash` + tests added * `seal_code_hash` benchmark added * `seal_own_code_hash` + tests added * `seal_own_code_hash` benchmark added * fmt lil fix * akward accident bug fix * Apply suggestions from code review Co-authored-by: Alexander Theißen <alex.theissen@me.com> * Apply suggestions from code review Co-authored-by: Alexander Theißen <alex.theissen@me.com> * benchmark fix * `WasmModule::getter()` to take `module_name` arg * test enhanced * fixes based on review feedback * Apply suggestions from code review Co-authored-by: Alexander Theißen <alex.theissen@me.com> * Hash left as const to return a ref to it from mock * HASH test val to local const in mock * Apply suggestions from code review Co-authored-by: Alexander Theißen <alex.theissen@me.com> * fixes to benchmarks according to review feedback * cargo run --quiet --profile=production --features=runtime-benchmarks --manifest-path=bin/node/cli/Cargo.toml -- benchmark --chain=dev --steps=50 --repeat=20 --pallet=pallet_contracts --extrinsic=* --execution=wasm --wasm-execution=compiled --heap-pages=4096 --output=./frame/contracts/src/weights.rs --template=./.maintain/frame-weight-template.hbs * removed `seal_origin` from API Co-authored-by: Alexander Theißen <alex.theissen@me.com> Co-authored-by: Parity Bot <admin@parity.io>
This commit is contained in:
committed by
GitHub
parent
83d4be6151
commit
e4caf7388a
@@ -438,6 +438,13 @@ mod tests {
|
||||
fn is_contract(&self, _address: &AccountIdOf<Self::T>) -> bool {
|
||||
true
|
||||
}
|
||||
fn code_hash(&self, _address: &AccountIdOf<Self::T>) -> Option<CodeHash<Self::T>> {
|
||||
Some(H256::from_slice(&[0x11; 32]))
|
||||
}
|
||||
fn own_code_hash(&mut self) -> &CodeHash<Self::T> {
|
||||
const HASH: H256 = H256::repeat_byte(0x10);
|
||||
&HASH
|
||||
}
|
||||
fn caller_is_origin(&self) -> bool {
|
||||
false
|
||||
}
|
||||
@@ -1155,7 +1162,7 @@ mod tests {
|
||||
);
|
||||
}
|
||||
|
||||
/// calls `seal_caller` and compares the result with the constant 42.
|
||||
/// calls `seal_caller` and compares the result with the constant (ALICE's address part).
|
||||
const CODE_CALLER: &str = r#"
|
||||
(module
|
||||
(import "seal0" "seal_caller" (func $seal_caller (param i32 i32)))
|
||||
@@ -1185,7 +1192,7 @@ mod tests {
|
||||
)
|
||||
)
|
||||
|
||||
;; assert that the first 64 byte are the beginning of "ALICE"
|
||||
;; assert that the first 8 bytes are the beginning of "ALICE"
|
||||
(call $assert
|
||||
(i64.eq
|
||||
(i64.load (i32.const 0))
|
||||
@@ -1203,7 +1210,7 @@ mod tests {
|
||||
assert_ok!(execute(CODE_CALLER, vec![], MockExt::default()));
|
||||
}
|
||||
|
||||
/// calls `seal_address` and compares the result with the constant 69.
|
||||
/// calls `seal_address` and compares the result with the constant (BOB's address part).
|
||||
const CODE_ADDRESS: &str = r#"
|
||||
(module
|
||||
(import "seal0" "seal_address" (func $seal_address (param i32 i32)))
|
||||
@@ -1233,7 +1240,7 @@ mod tests {
|
||||
)
|
||||
)
|
||||
|
||||
;; assert that the first 64 byte are the beginning of "BOB"
|
||||
;; assert that the first 8 bytes are the beginning of "BOB"
|
||||
(call $assert
|
||||
(i64.eq
|
||||
(i64.load (i32.const 0))
|
||||
@@ -2361,6 +2368,111 @@ mod tests {
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(feature = "unstable-interface")]
|
||||
fn code_hash_works() {
|
||||
/// calls `seal_code_hash` and compares the result with the constant.
|
||||
const CODE_CODE_HASH: &str = r#"
|
||||
(module
|
||||
(import "__unstable__" "seal_code_hash" (func $seal_code_hash (param i32 i32 i32) (result i32)))
|
||||
(import "env" "memory" (memory 1 1))
|
||||
|
||||
;; size of our buffer is 32 bytes
|
||||
(data (i32.const 32) "\20")
|
||||
|
||||
(func $assert (param i32)
|
||||
(block $ok
|
||||
(br_if $ok
|
||||
(get_local 0)
|
||||
)
|
||||
(unreachable)
|
||||
)
|
||||
)
|
||||
|
||||
(func (export "call")
|
||||
;; fill the buffer with the code hash.
|
||||
(call $seal_code_hash
|
||||
(i32.const 0) ;; input: address_ptr (before call)
|
||||
(i32.const 0) ;; output: code_hash_ptr (after call)
|
||||
(i32.const 32) ;; same 32 bytes length for input and output
|
||||
)
|
||||
|
||||
;; assert size == 32
|
||||
(call $assert
|
||||
(i32.eq
|
||||
(i32.load (i32.const 32))
|
||||
(i32.const 32)
|
||||
)
|
||||
)
|
||||
|
||||
;; assert that the first 8 bytes are "1111111111111111"
|
||||
(call $assert
|
||||
(i64.eq
|
||||
(i64.load (i32.const 0))
|
||||
(i64.const 0x1111111111111111)
|
||||
)
|
||||
)
|
||||
drop
|
||||
)
|
||||
|
||||
(func (export "deploy"))
|
||||
)
|
||||
"#;
|
||||
assert_ok!(execute(CODE_CODE_HASH, vec![], MockExt::default()));
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(feature = "unstable-interface")]
|
||||
fn own_code_hash_works() {
|
||||
/// calls `seal_own_code_hash` and compares the result with the constant.
|
||||
const CODE_OWN_CODE_HASH: &str = r#"
|
||||
(module
|
||||
(import "__unstable__" "seal_own_code_hash" (func $seal_own_code_hash (param i32 i32)))
|
||||
(import "env" "memory" (memory 1 1))
|
||||
|
||||
;; size of our buffer is 32 bytes
|
||||
(data (i32.const 32) "\20")
|
||||
|
||||
(func $assert (param i32)
|
||||
(block $ok
|
||||
(br_if $ok
|
||||
(get_local 0)
|
||||
)
|
||||
(unreachable)
|
||||
)
|
||||
)
|
||||
|
||||
(func (export "call")
|
||||
;; fill the buffer with the code hash
|
||||
(call $seal_own_code_hash
|
||||
(i32.const 0) ;; output: code_hash_ptr
|
||||
(i32.const 32) ;; 32 bytes length of code_hash output
|
||||
)
|
||||
|
||||
;; assert size == 32
|
||||
(call $assert
|
||||
(i32.eq
|
||||
(i32.load (i32.const 32))
|
||||
(i32.const 32)
|
||||
)
|
||||
)
|
||||
|
||||
;; assert that the first 8 bytes are "1010101010101010"
|
||||
(call $assert
|
||||
(i64.eq
|
||||
(i64.load (i32.const 0))
|
||||
(i64.const 0x1010101010101010)
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
(func (export "deploy"))
|
||||
)
|
||||
"#;
|
||||
assert_ok!(execute(CODE_OWN_CODE_HASH, vec![], MockExt::default()));
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(feature = "unstable-interface")]
|
||||
fn caller_is_origin_works() {
|
||||
const CODE_CALLER_IS_ORIGIN: &str = r#"
|
||||
;; This runs `caller_is_origin` check on zero account address
|
||||
|
||||
@@ -144,6 +144,12 @@ pub enum RuntimeCosts {
|
||||
Caller,
|
||||
/// Weight of calling `seal_is_contract`.
|
||||
IsContract,
|
||||
/// Weight of calling `seal_code_hash`.
|
||||
#[cfg(feature = "unstable-interface")]
|
||||
CodeHash,
|
||||
/// Weight of calling `seal_own_code_hash`.
|
||||
#[cfg(feature = "unstable-interface")]
|
||||
OwnCodeHash,
|
||||
/// Weight of calling `seal_caller_is_origin`.
|
||||
CallerIsOrigin,
|
||||
/// Weight of calling `seal_address`.
|
||||
@@ -234,6 +240,10 @@ impl RuntimeCosts {
|
||||
CopyToContract(len) => s.input_per_byte.saturating_mul(len.into()),
|
||||
Caller => s.caller,
|
||||
IsContract => s.is_contract,
|
||||
#[cfg(feature = "unstable-interface")]
|
||||
CodeHash => s.code_hash,
|
||||
#[cfg(feature = "unstable-interface")]
|
||||
OwnCodeHash => s.own_code_hash,
|
||||
CallerIsOrigin => s.caller_is_origin,
|
||||
Address => s.address,
|
||||
GasLeft => s.gas_left,
|
||||
@@ -1371,6 +1381,44 @@ define_env!(Env, <E: Ext>,
|
||||
Ok(ctx.ext.is_contract(&address) as u32)
|
||||
},
|
||||
|
||||
// Retrieve the code hash for a specified contract address.
|
||||
//
|
||||
// # Parameters
|
||||
//
|
||||
// - `account_ptr`: a pointer to the address in question.
|
||||
// Should be decodable as an `T::AccountId`. Traps otherwise.
|
||||
// - `out_ptr`: pointer to the linear memory where the returning value is written to.
|
||||
// - `out_len_ptr`: in-out pointer into linear memory where the buffer length
|
||||
// is read from and the value length is written to.
|
||||
//
|
||||
// # Errors
|
||||
//
|
||||
// `ReturnCode::KeyNotFound`
|
||||
[__unstable__] seal_code_hash(ctx, account_ptr: u32, out_ptr: u32, out_len_ptr: u32) -> ReturnCode => {
|
||||
ctx.charge_gas(RuntimeCosts::CodeHash)?;
|
||||
let address: <<E as Ext>::T as frame_system::Config>::AccountId =
|
||||
ctx.read_sandbox_memory_as(account_ptr)?;
|
||||
if let Some(value) = ctx.ext.code_hash(&address) {
|
||||
ctx.write_sandbox_output(out_ptr, out_len_ptr, &value.encode(), false, already_charged)?;
|
||||
Ok(ReturnCode::Success)
|
||||
} else {
|
||||
Ok(ReturnCode::KeyNotFound)
|
||||
}
|
||||
},
|
||||
|
||||
// Retrieve the code hash of the currently executing contract.
|
||||
//
|
||||
// # Parameters
|
||||
//
|
||||
// - `out_ptr`: pointer to the linear memory where the returning value is written to.
|
||||
// - `out_len_ptr`: in-out pointer into linear memory where the buffer length
|
||||
// is read from and the value length is written to.
|
||||
[__unstable__] seal_own_code_hash(ctx, out_ptr: u32, out_len_ptr: u32) => {
|
||||
ctx.charge_gas(RuntimeCosts::OwnCodeHash)?;
|
||||
let code_hash_encoded = &ctx.ext.own_code_hash().encode();
|
||||
Ok(ctx.write_sandbox_output(out_ptr, out_len_ptr, code_hash_encoded, false, already_charged)?)
|
||||
},
|
||||
|
||||
// Checks whether the caller of the current contract is the origin of the whole call stack.
|
||||
//
|
||||
// Prefer this over `seal_is_contract` when checking whether your contract is being called by a contract
|
||||
|
||||
Reference in New Issue
Block a user