mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-05-30 22:11:02 +00:00
Expose block number in seal_random (#8329)
* Allow contract callable functions to specify the module * Add new version of `seal_random` * Fix overlong lines * Fix benchmarking code * Update README.md * Replace Module by Pallet
This commit is contained in:
committed by
GitHub
parent
f9b6c869a3
commit
1f911ddb61
@@ -20,7 +20,11 @@ In other words: Upgrading this pallet will not break pre-existing contracts.
|
|||||||
|
|
||||||
### Added
|
### Added
|
||||||
|
|
||||||
|
- Add new version of `seal_random` which exposes additional information.
|
||||||
|
[1](https://github.com/paritytech/substrate/pull/8329)
|
||||||
|
|
||||||
- Add `seal_rent_params` contract callable function.
|
- Add `seal_rent_params` contract callable function.
|
||||||
|
[1](https://github.com/paritytech/substrate/pull/8231)
|
||||||
|
|
||||||
## [v3.0.0] 2021-02-25
|
## [v3.0.0] 2021-02-25
|
||||||
|
|
||||||
|
|||||||
@@ -243,7 +243,7 @@ pub trait Ext: sealing::Sealed {
|
|||||||
fn tombstone_deposit(&self) -> BalanceOf<Self::T>;
|
fn tombstone_deposit(&self) -> BalanceOf<Self::T>;
|
||||||
|
|
||||||
/// Returns a random number for the current block with the given subject.
|
/// Returns a random number for the current block with the given subject.
|
||||||
fn random(&self, subject: &[u8]) -> SeedOf<Self::T>;
|
fn random(&self, subject: &[u8]) -> (SeedOf<Self::T>, BlockNumberOf<Self::T>);
|
||||||
|
|
||||||
/// Deposit an event with the given topics.
|
/// Deposit an event with the given topics.
|
||||||
///
|
///
|
||||||
@@ -845,10 +845,8 @@ where
|
|||||||
self.value_transferred
|
self.value_transferred
|
||||||
}
|
}
|
||||||
|
|
||||||
fn random(&self, subject: &[u8]) -> SeedOf<T> {
|
fn random(&self, subject: &[u8]) -> (SeedOf<T>, BlockNumberOf<T>) {
|
||||||
// TODO: change API to expose randomness freshness
|
T::Randomness::random(subject)
|
||||||
// https://github.com/paritytech/substrate/issues/8297
|
|
||||||
T::Randomness::random(subject).0
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn now(&self) -> &MomentOf<T> {
|
fn now(&self) -> &MomentOf<T> {
|
||||||
|
|||||||
@@ -43,21 +43,23 @@ macro_rules! gen_signature {
|
|||||||
|
|
||||||
macro_rules! gen_signature_dispatch {
|
macro_rules! gen_signature_dispatch {
|
||||||
(
|
(
|
||||||
|
$needle_module:ident,
|
||||||
$needle_name:ident,
|
$needle_name:ident,
|
||||||
$needle_sig:ident ;
|
$needle_sig:ident ;
|
||||||
|
$module:ident,
|
||||||
$name:ident
|
$name:ident
|
||||||
( $ctx:ident $( , $names:ident : $params:ty )* ) $( -> $returns:ty )* , $($rest:tt)* ) => {
|
( $ctx:ident $( , $names:ident : $params:ty )* ) $( -> $returns:ty )* , $($rest:tt)*
|
||||||
if stringify!($name).as_bytes() == $needle_name {
|
) => {
|
||||||
|
if stringify!($module).as_bytes() == $needle_module && stringify!($name).as_bytes() == $needle_name {
|
||||||
let signature = gen_signature!( ( $( $params ),* ) $( -> $returns )* );
|
let signature = gen_signature!( ( $( $params ),* ) $( -> $returns )* );
|
||||||
if $needle_sig == &signature {
|
if $needle_sig == &signature {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
gen_signature_dispatch!($needle_name, $needle_sig ; $($rest)*);
|
gen_signature_dispatch!($needle_module, $needle_name, $needle_sig ; $($rest)*);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
( $needle_name:ident, $needle_sig:ident ; ) => {
|
( $needle_module:ident, $needle_name:ident, $needle_sig:ident ; ) => {};
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Unmarshall arguments and then execute `body` expression and return its result.
|
/// Unmarshall arguments and then execute `body` expression and return its result.
|
||||||
@@ -151,10 +153,11 @@ macro_rules! register_func {
|
|||||||
( $reg_cb:ident, < E: $seal_ty:tt > ; ) => {};
|
( $reg_cb:ident, < E: $seal_ty:tt > ; ) => {};
|
||||||
|
|
||||||
( $reg_cb:ident, < E: $seal_ty:tt > ;
|
( $reg_cb:ident, < E: $seal_ty:tt > ;
|
||||||
$name:ident ( $ctx:ident $( , $names:ident : $params:ty )* )
|
$module:ident $name:ident ( $ctx:ident $( , $names:ident : $params:ty )* )
|
||||||
$( -> $returns:ty )* => $body:tt $($rest:tt)*
|
$( -> $returns:ty )* => $body:tt $($rest:tt)*
|
||||||
) => {
|
) => {
|
||||||
$reg_cb(
|
$reg_cb(
|
||||||
|
stringify!($module).as_bytes(),
|
||||||
stringify!($name).as_bytes(),
|
stringify!($name).as_bytes(),
|
||||||
{
|
{
|
||||||
define_func!(
|
define_func!(
|
||||||
@@ -176,14 +179,17 @@ macro_rules! register_func {
|
|||||||
/// and reject the code if any imported function has a mismatched signature.
|
/// and reject the code if any imported function has a mismatched signature.
|
||||||
macro_rules! define_env {
|
macro_rules! define_env {
|
||||||
( $init_name:ident , < E: $seal_ty:tt > ,
|
( $init_name:ident , < E: $seal_ty:tt > ,
|
||||||
$( $name:ident ( $ctx:ident $( , $names:ident : $params:ty )* )
|
$( [$module:ident] $name:ident ( $ctx:ident $( , $names:ident : $params:ty )* )
|
||||||
$( -> $returns:ty )* => $body:tt , )*
|
$( -> $returns:ty )* => $body:tt , )*
|
||||||
) => {
|
) => {
|
||||||
pub struct $init_name;
|
pub struct $init_name;
|
||||||
|
|
||||||
impl $crate::wasm::env_def::ImportSatisfyCheck for $init_name {
|
impl $crate::wasm::env_def::ImportSatisfyCheck for $init_name {
|
||||||
fn can_satisfy(name: &[u8], func_type: &parity_wasm::elements::FunctionType) -> bool {
|
fn can_satisfy(module: &[u8], name: &[u8], func_type: &parity_wasm::elements::FunctionType) -> bool {
|
||||||
gen_signature_dispatch!( name, func_type ; $( $name ( $ctx $(, $names : $params )* ) $( -> $returns )* , )* );
|
gen_signature_dispatch!(
|
||||||
|
module, name, func_type ;
|
||||||
|
$( $module, $name ( $ctx $(, $names : $params )* ) $( -> $returns )* , )*
|
||||||
|
);
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -195,8 +201,12 @@ macro_rules! define_env {
|
|||||||
sp_core::crypto::UncheckedFrom<<E::T as frame_system::Config>::Hash> +
|
sp_core::crypto::UncheckedFrom<<E::T as frame_system::Config>::Hash> +
|
||||||
AsRef<[u8]>
|
AsRef<[u8]>
|
||||||
{
|
{
|
||||||
fn impls<F: FnMut(&[u8], $crate::wasm::env_def::HostFunc<E>)>(f: &mut F) {
|
fn impls<F: FnMut(&[u8], &[u8], $crate::wasm::env_def::HostFunc<E>)>(f: &mut F) {
|
||||||
register_func!(f, < E: $seal_ty > ; $( $name ( $ctx $( , $names : $params )* ) $( -> $returns)* => $body )* );
|
register_func!(
|
||||||
|
f,
|
||||||
|
< E: $seal_ty > ;
|
||||||
|
$( $module $name ( $ctx $( , $names : $params )* ) $( -> $returns)* => $body )*
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -327,7 +337,7 @@ mod tests {
|
|||||||
use crate::wasm::env_def::ImportSatisfyCheck;
|
use crate::wasm::env_def::ImportSatisfyCheck;
|
||||||
|
|
||||||
define_env!(Env, <E: Ext>,
|
define_env!(Env, <E: Ext>,
|
||||||
seal_gas( _ctx, amount: u32 ) => {
|
[seal0] seal_gas( _ctx, amount: u32 ) => {
|
||||||
let amount = Weight::from(amount);
|
let amount = Weight::from(amount);
|
||||||
if !amount.is_zero() {
|
if !amount.is_zero() {
|
||||||
Ok(())
|
Ok(())
|
||||||
@@ -337,7 +347,11 @@ mod tests {
|
|||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
assert!(Env::can_satisfy(b"seal_gas", &FunctionType::new(vec![ValueType::I32], None)));
|
assert!(
|
||||||
assert!(!Env::can_satisfy(b"not_exists", &FunctionType::new(vec![], None)));
|
Env::can_satisfy(b"seal0", b"seal_gas",&FunctionType::new(vec![ValueType::I32], None))
|
||||||
|
);
|
||||||
|
assert!(
|
||||||
|
!Env::can_satisfy(b"seal0", b"not_exists", &FunctionType::new(vec![], None))
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -74,7 +74,7 @@ pub type HostFunc<E> =
|
|||||||
) -> Result<sp_sandbox::ReturnValue, sp_sandbox::HostError>;
|
) -> Result<sp_sandbox::ReturnValue, sp_sandbox::HostError>;
|
||||||
|
|
||||||
pub trait FunctionImplProvider<E: Ext> {
|
pub trait FunctionImplProvider<E: Ext> {
|
||||||
fn impls<F: FnMut(&[u8], HostFunc<E>)>(f: &mut F);
|
fn impls<F: FnMut(&[u8], &[u8], HostFunc<E>)>(f: &mut F);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// This trait can be used to check whether the host environment can satisfy
|
/// This trait can be used to check whether the host environment can satisfy
|
||||||
@@ -83,5 +83,5 @@ pub trait ImportSatisfyCheck {
|
|||||||
/// Returns `true` if the host environment contains a function with
|
/// Returns `true` if the host environment contains a function with
|
||||||
/// the specified name and its type matches to the given type, or `false`
|
/// the specified name and its type matches to the given type, or `false`
|
||||||
/// otherwise.
|
/// otherwise.
|
||||||
fn can_satisfy(name: &[u8], func_type: &FunctionType) -> bool;
|
fn can_satisfy(module: &[u8], name: &[u8], func_type: &FunctionType) -> bool;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -192,8 +192,8 @@ where
|
|||||||
|
|
||||||
let mut imports = sp_sandbox::EnvironmentDefinitionBuilder::new();
|
let mut imports = sp_sandbox::EnvironmentDefinitionBuilder::new();
|
||||||
imports.add_memory(self::prepare::IMPORT_MODULE_MEMORY, "memory", memory.clone());
|
imports.add_memory(self::prepare::IMPORT_MODULE_MEMORY, "memory", memory.clone());
|
||||||
runtime::Env::impls(&mut |name, func_ptr| {
|
runtime::Env::impls(&mut |module, name, func_ptr| {
|
||||||
imports.add_host_func(self::prepare::IMPORT_MODULE_FN, name, func_ptr);
|
imports.add_host_func(module, name, func_ptr);
|
||||||
});
|
});
|
||||||
|
|
||||||
let mut runtime = Runtime::new(
|
let mut runtime = Runtime::new(
|
||||||
@@ -246,7 +246,7 @@ mod tests {
|
|||||||
use super::*;
|
use super::*;
|
||||||
use crate::{
|
use crate::{
|
||||||
CodeHash, BalanceOf, Error, Pallet as Contracts,
|
CodeHash, BalanceOf, Error, Pallet as Contracts,
|
||||||
exec::{Ext, StorageKey, AccountIdOf, Executable, RentParams},
|
exec::{Ext, StorageKey, AccountIdOf, Executable, SeedOf, BlockNumberOf, RentParams},
|
||||||
gas::GasMeter,
|
gas::GasMeter,
|
||||||
tests::{Test, Call, ALICE, BOB},
|
tests::{Test, Call, ALICE, BOB},
|
||||||
};
|
};
|
||||||
@@ -414,8 +414,8 @@ mod tests {
|
|||||||
fn tombstone_deposit(&self) -> u64 {
|
fn tombstone_deposit(&self) -> u64 {
|
||||||
16
|
16
|
||||||
}
|
}
|
||||||
fn random(&self, subject: &[u8]) -> H256 {
|
fn random(&self, subject: &[u8]) -> (SeedOf<Self::T>, BlockNumberOf<Self::T>) {
|
||||||
H256::from_slice(subject)
|
(H256::from_slice(subject), 42)
|
||||||
}
|
}
|
||||||
fn deposit_event(&mut self, topics: Vec<H256>, data: Vec<u8>) {
|
fn deposit_event(&mut self, topics: Vec<H256>, data: Vec<u8>) {
|
||||||
self.events.push((topics, data))
|
self.events.push((topics, data))
|
||||||
@@ -515,7 +515,7 @@ mod tests {
|
|||||||
fn tombstone_deposit(&self) -> u64 {
|
fn tombstone_deposit(&self) -> u64 {
|
||||||
(**self).tombstone_deposit()
|
(**self).tombstone_deposit()
|
||||||
}
|
}
|
||||||
fn random(&self, subject: &[u8]) -> H256 {
|
fn random(&self, subject: &[u8]) -> (SeedOf<Self::T>, BlockNumberOf<Self::T>) {
|
||||||
(**self).random(subject)
|
(**self).random(subject)
|
||||||
}
|
}
|
||||||
fn deposit_event(&mut self, topics: Vec<H256>, data: Vec<u8>) {
|
fn deposit_event(&mut self, topics: Vec<H256>, data: Vec<u8>) {
|
||||||
@@ -1531,6 +1531,85 @@ mod tests {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const CODE_RANDOM_V1: &str = r#"
|
||||||
|
(module
|
||||||
|
(import "seal1" "seal_random" (func $seal_random (param i32 i32 i32 i32)))
|
||||||
|
(import "seal0" "seal_return" (func $seal_return (param i32 i32 i32)))
|
||||||
|
(import "env" "memory" (memory 1 1))
|
||||||
|
|
||||||
|
;; [0,128) is reserved for the result of PRNG.
|
||||||
|
|
||||||
|
;; the subject used for the PRNG. [128,160)
|
||||||
|
(data (i32.const 128)
|
||||||
|
"\00\01\02\03\04\05\06\07\08\09\0A\0B\0C\0D\0E\0F"
|
||||||
|
"\00\01\02\03\04\05\06\07\08\09\0A\0B\0C\0D\0E\0F"
|
||||||
|
)
|
||||||
|
|
||||||
|
;; size of our buffer is 128 bytes
|
||||||
|
(data (i32.const 160) "\80")
|
||||||
|
|
||||||
|
(func $assert (param i32)
|
||||||
|
(block $ok
|
||||||
|
(br_if $ok
|
||||||
|
(get_local 0)
|
||||||
|
)
|
||||||
|
(unreachable)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
(func (export "call")
|
||||||
|
;; This stores the block random seed in the buffer
|
||||||
|
(call $seal_random
|
||||||
|
(i32.const 128) ;; Pointer in memory to the start of the subject buffer
|
||||||
|
(i32.const 32) ;; The subject buffer's length
|
||||||
|
(i32.const 0) ;; Pointer to the output buffer
|
||||||
|
(i32.const 160) ;; Pointer to the output buffer length
|
||||||
|
)
|
||||||
|
|
||||||
|
;; assert len == 32
|
||||||
|
(call $assert
|
||||||
|
(i32.eq
|
||||||
|
(i32.load (i32.const 160))
|
||||||
|
(i32.const 40)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
;; return the random data
|
||||||
|
(call $seal_return
|
||||||
|
(i32.const 0)
|
||||||
|
(i32.const 0)
|
||||||
|
(i32.const 40)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
(func (export "deploy"))
|
||||||
|
)
|
||||||
|
"#;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn random_v1() {
|
||||||
|
let mut gas_meter = GasMeter::new(GAS_LIMIT);
|
||||||
|
|
||||||
|
let output = execute(
|
||||||
|
CODE_RANDOM_V1,
|
||||||
|
vec![],
|
||||||
|
MockExt::default(),
|
||||||
|
&mut gas_meter,
|
||||||
|
).unwrap();
|
||||||
|
|
||||||
|
// The mock ext just returns the same data that was passed as the subject.
|
||||||
|
assert_eq!(
|
||||||
|
output,
|
||||||
|
ExecReturnValue {
|
||||||
|
flags: ReturnFlags::empty(),
|
||||||
|
data: (
|
||||||
|
hex!("000102030405060708090A0B0C0D0E0F000102030405060708090A0B0C0D0E0F"),
|
||||||
|
42u64,
|
||||||
|
).encode(),
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
const CODE_DEPOSIT_EVENT: &str = r#"
|
const CODE_DEPOSIT_EVENT: &str = r#"
|
||||||
(module
|
(module
|
||||||
(import "seal0" "seal_deposit_event" (func $seal_deposit_event (param i32 i32 i32 i32)))
|
(import "seal0" "seal_deposit_event" (func $seal_deposit_event (param i32 i32 i32 i32)))
|
||||||
|
|||||||
@@ -28,11 +28,7 @@ use parity_wasm::elements::{self, Internal, External, MemoryType, Type, ValueTyp
|
|||||||
use sp_runtime::traits::Hash;
|
use sp_runtime::traits::Hash;
|
||||||
use sp_std::prelude::*;
|
use sp_std::prelude::*;
|
||||||
|
|
||||||
/// Currently, all imported functions must be located inside this module. We might support
|
/// Imported memory must be located inside this module. The reason for hardcoding is that current
|
||||||
/// additional modules for versioning later.
|
|
||||||
pub const IMPORT_MODULE_FN: &str = "seal0";
|
|
||||||
|
|
||||||
/// Imported memory must be located inside this module. The reason for that is that current
|
|
||||||
/// compiler toolchains might not support specifying other modules than "env" for memory imports.
|
/// compiler toolchains might not support specifying other modules than "env" for memory imports.
|
||||||
pub const IMPORT_MODULE_MEMORY: &str = "env";
|
pub const IMPORT_MODULE_MEMORY: &str = "env";
|
||||||
|
|
||||||
@@ -194,7 +190,7 @@ impl<'a, T: Config> ContractModule<'a, T> {
|
|||||||
let contract_module = pwasm_utils::inject_gas_counter(
|
let contract_module = pwasm_utils::inject_gas_counter(
|
||||||
self.module,
|
self.module,
|
||||||
&gas_rules,
|
&gas_rules,
|
||||||
IMPORT_MODULE_FN
|
"seal0",
|
||||||
).map_err(|_| "gas instrumentation failed")?;
|
).map_err(|_| "gas instrumentation failed")?;
|
||||||
Ok(ContractModule {
|
Ok(ContractModule {
|
||||||
module: contract_module,
|
module: contract_module,
|
||||||
@@ -325,12 +321,7 @@ impl<'a, T: Config> ContractModule<'a, T> {
|
|||||||
let type_idx = match import.external() {
|
let type_idx = match import.external() {
|
||||||
&External::Table(_) => return Err("Cannot import tables"),
|
&External::Table(_) => return Err("Cannot import tables"),
|
||||||
&External::Global(_) => return Err("Cannot import globals"),
|
&External::Global(_) => return Err("Cannot import globals"),
|
||||||
&External::Function(ref type_idx) => {
|
&External::Function(ref type_idx) => type_idx,
|
||||||
if import.module() != IMPORT_MODULE_FN {
|
|
||||||
return Err("Invalid module for imported function");
|
|
||||||
}
|
|
||||||
type_idx
|
|
||||||
},
|
|
||||||
&External::Memory(ref memory_type) => {
|
&External::Memory(ref memory_type) => {
|
||||||
if import.module() != IMPORT_MODULE_MEMORY {
|
if import.module() != IMPORT_MODULE_MEMORY {
|
||||||
return Err("Invalid module for imported memory");
|
return Err("Invalid module for imported memory");
|
||||||
@@ -363,7 +354,9 @@ impl<'a, T: Config> ContractModule<'a, T> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if import_fn_banlist.iter().any(|f| import.field().as_bytes() == *f)
|
if import_fn_banlist.iter().any(|f| import.field().as_bytes() == *f)
|
||||||
|| !C::can_satisfy(import.field().as_bytes(), func_ty)
|
|| !C::can_satisfy(
|
||||||
|
import.module().as_bytes(), import.field().as_bytes(), func_ty,
|
||||||
|
)
|
||||||
{
|
{
|
||||||
return Err("module imports a non-existent function");
|
return Err("module imports a non-existent function");
|
||||||
}
|
}
|
||||||
@@ -498,7 +491,7 @@ pub mod benchmarking {
|
|||||||
use parity_wasm::elements::FunctionType;
|
use parity_wasm::elements::FunctionType;
|
||||||
|
|
||||||
impl ImportSatisfyCheck for () {
|
impl ImportSatisfyCheck for () {
|
||||||
fn can_satisfy(_name: &[u8], _func_type: &FunctionType) -> bool {
|
fn can_satisfy(_module: &[u8], _name: &[u8], _func_type: &FunctionType) -> bool {
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -543,14 +536,17 @@ mod tests {
|
|||||||
// Define test environment for tests. We need ImportSatisfyCheck
|
// Define test environment for tests. We need ImportSatisfyCheck
|
||||||
// implementation from it. So actual implementations doesn't matter.
|
// implementation from it. So actual implementations doesn't matter.
|
||||||
define_env!(Test, <E: Ext>,
|
define_env!(Test, <E: Ext>,
|
||||||
panic(_ctx) => { unreachable!(); },
|
[seal0] panic(_ctx) => { unreachable!(); },
|
||||||
|
|
||||||
// gas is an implementation defined function and a contract can't import it.
|
// gas is an implementation defined function and a contract can't import it.
|
||||||
gas(_ctx, _amount: u32) => { unreachable!(); },
|
[seal0] gas(_ctx, _amount: u32) => { unreachable!(); },
|
||||||
|
|
||||||
nop(_ctx, _unused: u64) => { unreachable!(); },
|
[seal0] nop(_ctx, _unused: u64) => { unreachable!(); },
|
||||||
|
|
||||||
seal_println(_ctx, _ptr: u32, _len: u32) => { unreachable!(); },
|
// new version of nop with other data type for argumebt
|
||||||
|
[seal1] nop(_ctx, _unused: i32) => { unreachable!(); },
|
||||||
|
|
||||||
|
[seal0] seal_println(_ctx, _ptr: u32, _len: u32) => { unreachable!(); },
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -904,30 +900,16 @@ mod tests {
|
|||||||
Err("Invalid module for imported memory")
|
Err("Invalid module for imported memory")
|
||||||
);
|
);
|
||||||
|
|
||||||
// functions are in "env" and not in "seal0"
|
prepare_test!(function_in_other_module_works,
|
||||||
prepare_test!(function_not_in_env,
|
|
||||||
r#"
|
r#"
|
||||||
(module
|
(module
|
||||||
(import "env" "nop" (func (param i64)))
|
(import "seal1" "nop" (func (param i32)))
|
||||||
|
|
||||||
(func (export "call"))
|
(func (export "call"))
|
||||||
(func (export "deploy"))
|
(func (export "deploy"))
|
||||||
)
|
)
|
||||||
"#,
|
"#,
|
||||||
Err("Invalid module for imported function")
|
Ok(_)
|
||||||
);
|
|
||||||
|
|
||||||
// functions are in "seal0" and not in in some arbitrary module
|
|
||||||
prepare_test!(function_not_arbitrary_module,
|
|
||||||
r#"
|
|
||||||
(module
|
|
||||||
(import "any_module" "nop" (func (param i64)))
|
|
||||||
|
|
||||||
(func (export "call"))
|
|
||||||
(func (export "deploy"))
|
|
||||||
)
|
|
||||||
"#,
|
|
||||||
Err("Invalid module for imported function")
|
|
||||||
);
|
);
|
||||||
|
|
||||||
// wrong signature
|
// wrong signature
|
||||||
|
|||||||
@@ -629,7 +629,7 @@ define_env!(Env, <E: Ext>,
|
|||||||
// This call is supposed to be called only by instrumentation injected code.
|
// This call is supposed to be called only by instrumentation injected code.
|
||||||
//
|
//
|
||||||
// - amount: How much gas is used.
|
// - amount: How much gas is used.
|
||||||
gas(ctx, amount: u32) => {
|
[seal0] gas(ctx, amount: u32) => {
|
||||||
ctx.charge_gas(RuntimeToken::MeteringBlock(amount))?;
|
ctx.charge_gas(RuntimeToken::MeteringBlock(amount))?;
|
||||||
Ok(())
|
Ok(())
|
||||||
},
|
},
|
||||||
@@ -649,7 +649,7 @@ define_env!(Env, <E: Ext>,
|
|||||||
//
|
//
|
||||||
// - If value length exceeds the configured maximum value length of a storage entry.
|
// - If value length exceeds the configured maximum value length of a storage entry.
|
||||||
// - Upon trying to set an empty storage entry (value length is 0).
|
// - Upon trying to set an empty storage entry (value length is 0).
|
||||||
seal_set_storage(ctx, key_ptr: u32, value_ptr: u32, value_len: u32) => {
|
[seal0] seal_set_storage(ctx, key_ptr: u32, value_ptr: u32, value_len: u32) => {
|
||||||
ctx.charge_gas(RuntimeToken::SetStorage(value_len))?;
|
ctx.charge_gas(RuntimeToken::SetStorage(value_len))?;
|
||||||
if value_len > ctx.ext.max_value_size() {
|
if value_len > ctx.ext.max_value_size() {
|
||||||
Err(Error::<E::T>::ValueTooLarge)?;
|
Err(Error::<E::T>::ValueTooLarge)?;
|
||||||
@@ -665,7 +665,7 @@ define_env!(Env, <E: Ext>,
|
|||||||
// # Parameters
|
// # Parameters
|
||||||
//
|
//
|
||||||
// - `key_ptr`: pointer into the linear memory where the location to clear the value is placed.
|
// - `key_ptr`: pointer into the linear memory where the location to clear the value is placed.
|
||||||
seal_clear_storage(ctx, key_ptr: u32) => {
|
[seal0] seal_clear_storage(ctx, key_ptr: u32) => {
|
||||||
ctx.charge_gas(RuntimeToken::ClearStorage)?;
|
ctx.charge_gas(RuntimeToken::ClearStorage)?;
|
||||||
let mut key: StorageKey = [0; 32];
|
let mut key: StorageKey = [0; 32];
|
||||||
ctx.read_sandbox_memory_into_buf(key_ptr, &mut key)?;
|
ctx.read_sandbox_memory_into_buf(key_ptr, &mut key)?;
|
||||||
@@ -684,7 +684,7 @@ define_env!(Env, <E: Ext>,
|
|||||||
// # Errors
|
// # Errors
|
||||||
//
|
//
|
||||||
// `ReturnCode::KeyNotFound`
|
// `ReturnCode::KeyNotFound`
|
||||||
seal_get_storage(ctx, key_ptr: u32, out_ptr: u32, out_len_ptr: u32) -> ReturnCode => {
|
[seal0] seal_get_storage(ctx, key_ptr: u32, out_ptr: u32, out_len_ptr: u32) -> ReturnCode => {
|
||||||
ctx.charge_gas(RuntimeToken::GetStorageBase)?;
|
ctx.charge_gas(RuntimeToken::GetStorageBase)?;
|
||||||
let mut key: StorageKey = [0; 32];
|
let mut key: StorageKey = [0; 32];
|
||||||
ctx.read_sandbox_memory_into_buf(key_ptr, &mut key)?;
|
ctx.read_sandbox_memory_into_buf(key_ptr, &mut key)?;
|
||||||
@@ -713,7 +713,7 @@ define_env!(Env, <E: Ext>,
|
|||||||
//
|
//
|
||||||
// `ReturnCode::BelowSubsistenceThreshold`
|
// `ReturnCode::BelowSubsistenceThreshold`
|
||||||
// `ReturnCode::TransferFailed`
|
// `ReturnCode::TransferFailed`
|
||||||
seal_transfer(
|
[seal0] seal_transfer(
|
||||||
ctx,
|
ctx,
|
||||||
account_ptr: u32,
|
account_ptr: u32,
|
||||||
account_len: u32,
|
account_len: u32,
|
||||||
@@ -767,7 +767,7 @@ define_env!(Env, <E: Ext>,
|
|||||||
// `ReturnCode::BelowSubsistenceThreshold`
|
// `ReturnCode::BelowSubsistenceThreshold`
|
||||||
// `ReturnCode::TransferFailed`
|
// `ReturnCode::TransferFailed`
|
||||||
// `ReturnCode::NotCallable`
|
// `ReturnCode::NotCallable`
|
||||||
seal_call(
|
[seal0] seal_call(
|
||||||
ctx,
|
ctx,
|
||||||
callee_ptr: u32,
|
callee_ptr: u32,
|
||||||
callee_len: u32,
|
callee_len: u32,
|
||||||
@@ -868,7 +868,7 @@ define_env!(Env, <E: Ext>,
|
|||||||
// `ReturnCode::TransferFailed`
|
// `ReturnCode::TransferFailed`
|
||||||
// `ReturnCode::NewContractNotFunded`
|
// `ReturnCode::NewContractNotFunded`
|
||||||
// `ReturnCode::CodeNotFound`
|
// `ReturnCode::CodeNotFound`
|
||||||
seal_instantiate(
|
[seal0] seal_instantiate(
|
||||||
ctx,
|
ctx,
|
||||||
code_hash_ptr: u32,
|
code_hash_ptr: u32,
|
||||||
code_hash_len: u32,
|
code_hash_len: u32,
|
||||||
@@ -950,7 +950,7 @@ define_env!(Env, <E: Ext>,
|
|||||||
// - The contract is live i.e is already on the call stack.
|
// - The contract is live i.e is already on the call stack.
|
||||||
// - Failed to send the balance to the beneficiary.
|
// - Failed to send the balance to the beneficiary.
|
||||||
// - The deletion queue is full.
|
// - The deletion queue is full.
|
||||||
seal_terminate(
|
[seal0] seal_terminate(
|
||||||
ctx,
|
ctx,
|
||||||
beneficiary_ptr: u32,
|
beneficiary_ptr: u32,
|
||||||
beneficiary_len: u32
|
beneficiary_len: u32
|
||||||
@@ -981,7 +981,7 @@ define_env!(Env, <E: Ext>,
|
|||||||
// # Note
|
// # Note
|
||||||
//
|
//
|
||||||
// This function can only be called once. Calling it multiple times will trigger a trap.
|
// This function can only be called once. Calling it multiple times will trigger a trap.
|
||||||
seal_input(ctx, out_ptr: u32, out_len_ptr: u32) => {
|
[seal0] seal_input(ctx, out_ptr: u32, out_len_ptr: u32) => {
|
||||||
ctx.charge_gas(RuntimeToken::InputBase)?;
|
ctx.charge_gas(RuntimeToken::InputBase)?;
|
||||||
if let Some(input) = ctx.input_data.take() {
|
if let Some(input) = ctx.input_data.take() {
|
||||||
ctx.write_sandbox_output(out_ptr, out_len_ptr, &input, false, |len| {
|
ctx.write_sandbox_output(out_ptr, out_len_ptr, &input, false, |len| {
|
||||||
@@ -1010,7 +1010,7 @@ define_env!(Env, <E: Ext>,
|
|||||||
// --- msb ---
|
// --- msb ---
|
||||||
//
|
//
|
||||||
// Using a reserved bit triggers a trap.
|
// Using a reserved bit triggers a trap.
|
||||||
seal_return(ctx, flags: u32, data_ptr: u32, data_len: u32) => {
|
[seal0] seal_return(ctx, flags: u32, data_ptr: u32, data_len: u32) => {
|
||||||
ctx.charge_gas(RuntimeToken::Return(data_len))?;
|
ctx.charge_gas(RuntimeToken::Return(data_len))?;
|
||||||
Err(TrapReason::Return(ReturnData {
|
Err(TrapReason::Return(ReturnData {
|
||||||
flags,
|
flags,
|
||||||
@@ -1028,7 +1028,7 @@ define_env!(Env, <E: Ext>,
|
|||||||
// If this is a top-level call (i.e. initiated by an extrinsic) the origin address of the
|
// If this is a top-level call (i.e. initiated by an extrinsic) the origin address of the
|
||||||
// extrinsic will be returned. Otherwise, if this call is initiated by another contract then the
|
// extrinsic will be returned. Otherwise, if this call is initiated by another contract then the
|
||||||
// address of the contract will be returned. The value is encoded as T::AccountId.
|
// address of the contract will be returned. The value is encoded as T::AccountId.
|
||||||
seal_caller(ctx, out_ptr: u32, out_len_ptr: u32) => {
|
[seal0] seal_caller(ctx, out_ptr: u32, out_len_ptr: u32) => {
|
||||||
ctx.charge_gas(RuntimeToken::Caller)?;
|
ctx.charge_gas(RuntimeToken::Caller)?;
|
||||||
Ok(ctx.write_sandbox_output(
|
Ok(ctx.write_sandbox_output(
|
||||||
out_ptr, out_len_ptr, &ctx.ext.caller().encode(), false, already_charged
|
out_ptr, out_len_ptr, &ctx.ext.caller().encode(), false, already_charged
|
||||||
@@ -1041,7 +1041,7 @@ define_env!(Env, <E: Ext>,
|
|||||||
// `out_len_ptr` must point to a u32 value that describes the available space at
|
// `out_len_ptr` must point to a u32 value that describes the available space at
|
||||||
// `out_ptr`. This call overwrites it with the size of the value. If the available
|
// `out_ptr`. This call overwrites it with the size of the value. If the available
|
||||||
// space at `out_ptr` is less than the size of the value a trap is triggered.
|
// space at `out_ptr` is less than the size of the value a trap is triggered.
|
||||||
seal_address(ctx, out_ptr: u32, out_len_ptr: u32) => {
|
[seal0] seal_address(ctx, out_ptr: u32, out_len_ptr: u32) => {
|
||||||
ctx.charge_gas(RuntimeToken::Address)?;
|
ctx.charge_gas(RuntimeToken::Address)?;
|
||||||
Ok(ctx.write_sandbox_output(
|
Ok(ctx.write_sandbox_output(
|
||||||
out_ptr, out_len_ptr, &ctx.ext.address().encode(), false, already_charged
|
out_ptr, out_len_ptr, &ctx.ext.address().encode(), false, already_charged
|
||||||
@@ -1061,7 +1061,7 @@ define_env!(Env, <E: Ext>,
|
|||||||
//
|
//
|
||||||
// It is recommended to avoid specifying very small values for `gas` as the prices for a single
|
// It is recommended to avoid specifying very small values for `gas` as the prices for a single
|
||||||
// gas can be smaller than one.
|
// gas can be smaller than one.
|
||||||
seal_weight_to_fee(ctx, gas: u64, out_ptr: u32, out_len_ptr: u32) => {
|
[seal0] seal_weight_to_fee(ctx, gas: u64, out_ptr: u32, out_len_ptr: u32) => {
|
||||||
ctx.charge_gas(RuntimeToken::WeightToFee)?;
|
ctx.charge_gas(RuntimeToken::WeightToFee)?;
|
||||||
Ok(ctx.write_sandbox_output(
|
Ok(ctx.write_sandbox_output(
|
||||||
out_ptr, out_len_ptr, &ctx.ext.get_weight_price(gas).encode(), false, already_charged
|
out_ptr, out_len_ptr, &ctx.ext.get_weight_price(gas).encode(), false, already_charged
|
||||||
@@ -1076,7 +1076,7 @@ define_env!(Env, <E: Ext>,
|
|||||||
// space at `out_ptr` is less than the size of the value a trap is triggered.
|
// space at `out_ptr` is less than the size of the value a trap is triggered.
|
||||||
//
|
//
|
||||||
// The data is encoded as Gas.
|
// The data is encoded as Gas.
|
||||||
seal_gas_left(ctx, out_ptr: u32, out_len_ptr: u32) => {
|
[seal0] seal_gas_left(ctx, out_ptr: u32, out_len_ptr: u32) => {
|
||||||
ctx.charge_gas(RuntimeToken::GasLeft)?;
|
ctx.charge_gas(RuntimeToken::GasLeft)?;
|
||||||
Ok(ctx.write_sandbox_output(
|
Ok(ctx.write_sandbox_output(
|
||||||
out_ptr, out_len_ptr, &ctx.gas_meter.gas_left().encode(), false, already_charged
|
out_ptr, out_len_ptr, &ctx.gas_meter.gas_left().encode(), false, already_charged
|
||||||
@@ -1091,7 +1091,7 @@ define_env!(Env, <E: Ext>,
|
|||||||
// space at `out_ptr` is less than the size of the value a trap is triggered.
|
// space at `out_ptr` is less than the size of the value a trap is triggered.
|
||||||
//
|
//
|
||||||
// The data is encoded as T::Balance.
|
// The data is encoded as T::Balance.
|
||||||
seal_balance(ctx, out_ptr: u32, out_len_ptr: u32) => {
|
[seal0] seal_balance(ctx, out_ptr: u32, out_len_ptr: u32) => {
|
||||||
ctx.charge_gas(RuntimeToken::Balance)?;
|
ctx.charge_gas(RuntimeToken::Balance)?;
|
||||||
Ok(ctx.write_sandbox_output(
|
Ok(ctx.write_sandbox_output(
|
||||||
out_ptr, out_len_ptr, &ctx.ext.balance().encode(), false, already_charged
|
out_ptr, out_len_ptr, &ctx.ext.balance().encode(), false, already_charged
|
||||||
@@ -1106,7 +1106,7 @@ define_env!(Env, <E: Ext>,
|
|||||||
// space at `out_ptr` is less than the size of the value a trap is triggered.
|
// space at `out_ptr` is less than the size of the value a trap is triggered.
|
||||||
//
|
//
|
||||||
// The data is encoded as T::Balance.
|
// The data is encoded as T::Balance.
|
||||||
seal_value_transferred(ctx, out_ptr: u32, out_len_ptr: u32) => {
|
[seal0] seal_value_transferred(ctx, out_ptr: u32, out_len_ptr: u32) => {
|
||||||
ctx.charge_gas(RuntimeToken::ValueTransferred)?;
|
ctx.charge_gas(RuntimeToken::ValueTransferred)?;
|
||||||
Ok(ctx.write_sandbox_output(
|
Ok(ctx.write_sandbox_output(
|
||||||
out_ptr, out_len_ptr, &ctx.ext.value_transferred().encode(), false, already_charged
|
out_ptr, out_len_ptr, &ctx.ext.value_transferred().encode(), false, already_charged
|
||||||
@@ -1121,7 +1121,43 @@ define_env!(Env, <E: Ext>,
|
|||||||
// space at `out_ptr` is less than the size of the value a trap is triggered.
|
// space at `out_ptr` is less than the size of the value a trap is triggered.
|
||||||
//
|
//
|
||||||
// The data is encoded as T::Hash.
|
// The data is encoded as T::Hash.
|
||||||
seal_random(ctx, subject_ptr: u32, subject_len: u32, out_ptr: u32, out_len_ptr: u32) => {
|
//
|
||||||
|
// # Deprecation
|
||||||
|
//
|
||||||
|
// This function is deprecated. Users should migrate to the version in the "seal1" module.
|
||||||
|
[seal0] seal_random(ctx, subject_ptr: u32, subject_len: u32, out_ptr: u32, out_len_ptr: u32) => {
|
||||||
|
ctx.charge_gas(RuntimeToken::Random)?;
|
||||||
|
if subject_len > ctx.ext.schedule().limits.subject_len {
|
||||||
|
Err(Error::<E::T>::RandomSubjectTooLong)?;
|
||||||
|
}
|
||||||
|
let subject_buf = ctx.read_sandbox_memory(subject_ptr, subject_len)?;
|
||||||
|
Ok(ctx.write_sandbox_output(
|
||||||
|
out_ptr, out_len_ptr, &ctx.ext.random(&subject_buf).0.encode(), false, already_charged
|
||||||
|
)?)
|
||||||
|
},
|
||||||
|
|
||||||
|
// Stores a random number for the current block and the given subject into the supplied buffer.
|
||||||
|
//
|
||||||
|
// The value is stored to linear memory at the address pointed to by `out_ptr`.
|
||||||
|
// `out_len_ptr` must point to a u32 value that describes the available space at
|
||||||
|
// `out_ptr`. This call overwrites it with the size of the value. If the available
|
||||||
|
// space at `out_ptr` is less than the size of the value a trap is triggered.
|
||||||
|
//
|
||||||
|
// The data is encoded as (T::Hash, T::BlockNumber).
|
||||||
|
//
|
||||||
|
// # Changes from v0
|
||||||
|
//
|
||||||
|
// In addition to the seed it returns the block number since which it was determinable
|
||||||
|
// by chain observers.
|
||||||
|
//
|
||||||
|
// # Note
|
||||||
|
//
|
||||||
|
// The returned seed should only be used to distinguish commitments made before
|
||||||
|
// the returned block number. If the block number is too early (i.e. commitments were
|
||||||
|
// made afterwards), then ensure no further commitments may be made and repeatedly
|
||||||
|
// call this on later blocks until the block number returned is later than the latest
|
||||||
|
// commitment.
|
||||||
|
[seal1] seal_random(ctx, subject_ptr: u32, subject_len: u32, out_ptr: u32, out_len_ptr: u32) => {
|
||||||
ctx.charge_gas(RuntimeToken::Random)?;
|
ctx.charge_gas(RuntimeToken::Random)?;
|
||||||
if subject_len > ctx.ext.schedule().limits.subject_len {
|
if subject_len > ctx.ext.schedule().limits.subject_len {
|
||||||
Err(Error::<E::T>::RandomSubjectTooLong)?;
|
Err(Error::<E::T>::RandomSubjectTooLong)?;
|
||||||
@@ -1138,7 +1174,7 @@ define_env!(Env, <E: Ext>,
|
|||||||
// `out_len_ptr` must point to a u32 value that describes the available space at
|
// `out_len_ptr` must point to a u32 value that describes the available space at
|
||||||
// `out_ptr`. This call overwrites it with the size of the value. If the available
|
// `out_ptr`. This call overwrites it with the size of the value. If the available
|
||||||
// space at `out_ptr` is less than the size of the value a trap is triggered.
|
// space at `out_ptr` is less than the size of the value a trap is triggered.
|
||||||
seal_now(ctx, out_ptr: u32, out_len_ptr: u32) => {
|
[seal0] seal_now(ctx, out_ptr: u32, out_len_ptr: u32) => {
|
||||||
ctx.charge_gas(RuntimeToken::Now)?;
|
ctx.charge_gas(RuntimeToken::Now)?;
|
||||||
Ok(ctx.write_sandbox_output(
|
Ok(ctx.write_sandbox_output(
|
||||||
out_ptr, out_len_ptr, &ctx.ext.now().encode(), false, already_charged
|
out_ptr, out_len_ptr, &ctx.ext.now().encode(), false, already_charged
|
||||||
@@ -1148,7 +1184,7 @@ define_env!(Env, <E: Ext>,
|
|||||||
// Stores the minimum balance (a.k.a. existential deposit) into the supplied buffer.
|
// Stores the minimum balance (a.k.a. existential deposit) into the supplied buffer.
|
||||||
//
|
//
|
||||||
// The data is encoded as T::Balance.
|
// The data is encoded as T::Balance.
|
||||||
seal_minimum_balance(ctx, out_ptr: u32, out_len_ptr: u32) => {
|
[seal0] seal_minimum_balance(ctx, out_ptr: u32, out_len_ptr: u32) => {
|
||||||
ctx.charge_gas(RuntimeToken::MinimumBalance)?;
|
ctx.charge_gas(RuntimeToken::MinimumBalance)?;
|
||||||
Ok(ctx.write_sandbox_output(
|
Ok(ctx.write_sandbox_output(
|
||||||
out_ptr, out_len_ptr, &ctx.ext.minimum_balance().encode(), false, already_charged
|
out_ptr, out_len_ptr, &ctx.ext.minimum_balance().encode(), false, already_charged
|
||||||
@@ -1170,7 +1206,7 @@ define_env!(Env, <E: Ext>,
|
|||||||
// a contract to leave a tombstone the balance of the contract must not go
|
// a contract to leave a tombstone the balance of the contract must not go
|
||||||
// below the sum of existential deposit and the tombstone deposit. The sum
|
// below the sum of existential deposit and the tombstone deposit. The sum
|
||||||
// is commonly referred as subsistence threshold in code.
|
// is commonly referred as subsistence threshold in code.
|
||||||
seal_tombstone_deposit(ctx, out_ptr: u32, out_len_ptr: u32) => {
|
[seal0] seal_tombstone_deposit(ctx, out_ptr: u32, out_len_ptr: u32) => {
|
||||||
ctx.charge_gas(RuntimeToken::TombstoneDeposit)?;
|
ctx.charge_gas(RuntimeToken::TombstoneDeposit)?;
|
||||||
Ok(ctx.write_sandbox_output(
|
Ok(ctx.write_sandbox_output(
|
||||||
out_ptr, out_len_ptr, &ctx.ext.tombstone_deposit().encode(), false, already_charged
|
out_ptr, out_len_ptr, &ctx.ext.tombstone_deposit().encode(), false, already_charged
|
||||||
@@ -1208,7 +1244,7 @@ define_env!(Env, <E: Ext>,
|
|||||||
// - Tombstone hashes do not match.
|
// - Tombstone hashes do not match.
|
||||||
// - The calling contract is already present on the call stack.
|
// - The calling contract is already present on the call stack.
|
||||||
// - The supplied code_hash does not exist on-chain.
|
// - The supplied code_hash does not exist on-chain.
|
||||||
seal_restore_to(
|
[seal0] seal_restore_to(
|
||||||
ctx,
|
ctx,
|
||||||
dest_ptr: u32,
|
dest_ptr: u32,
|
||||||
dest_len: u32,
|
dest_len: u32,
|
||||||
@@ -1279,8 +1315,13 @@ define_env!(Env, <E: Ext>,
|
|||||||
// - topics_len - the length of the topics buffer. Pass 0 if you want to pass an empty vector.
|
// - topics_len - the length of the topics buffer. Pass 0 if you want to pass an empty vector.
|
||||||
// - data_ptr - a pointer to a raw data buffer which will saved along the event.
|
// - data_ptr - a pointer to a raw data buffer which will saved along the event.
|
||||||
// - data_len - the length of the data buffer.
|
// - data_len - the length of the data buffer.
|
||||||
seal_deposit_event(ctx, topics_ptr: u32, topics_len: u32, data_ptr: u32, data_len: u32) => {
|
[seal0] seal_deposit_event(
|
||||||
|
ctx,
|
||||||
|
topics_ptr: u32,
|
||||||
|
topics_len: u32,
|
||||||
|
data_ptr: u32,
|
||||||
|
data_len: u32
|
||||||
|
) => {
|
||||||
fn has_duplicates<T: Ord>(items: &mut Vec<T>) -> bool {
|
fn has_duplicates<T: Ord>(items: &mut Vec<T>) -> bool {
|
||||||
// # Warning
|
// # Warning
|
||||||
//
|
//
|
||||||
@@ -1336,7 +1377,7 @@ define_env!(Env, <E: Ext>,
|
|||||||
// - value_ptr: a pointer to the buffer with value, how much to allow for rent
|
// - value_ptr: a pointer to the buffer with value, how much to allow for rent
|
||||||
// Should be decodable as a `T::Balance`. Traps otherwise.
|
// Should be decodable as a `T::Balance`. Traps otherwise.
|
||||||
// - value_len: length of the value buffer.
|
// - value_len: length of the value buffer.
|
||||||
seal_set_rent_allowance(ctx, value_ptr: u32, value_len: u32) => {
|
[seal0] seal_set_rent_allowance(ctx, value_ptr: u32, value_len: u32) => {
|
||||||
ctx.charge_gas(RuntimeToken::SetRentAllowance)?;
|
ctx.charge_gas(RuntimeToken::SetRentAllowance)?;
|
||||||
let value: BalanceOf<<E as Ext>::T> =
|
let value: BalanceOf<<E as Ext>::T> =
|
||||||
ctx.read_sandbox_memory_as(value_ptr, value_len)?;
|
ctx.read_sandbox_memory_as(value_ptr, value_len)?;
|
||||||
@@ -1353,7 +1394,7 @@ define_env!(Env, <E: Ext>,
|
|||||||
// space at `out_ptr` is less than the size of the value a trap is triggered.
|
// space at `out_ptr` is less than the size of the value a trap is triggered.
|
||||||
//
|
//
|
||||||
// The data is encoded as T::Balance.
|
// The data is encoded as T::Balance.
|
||||||
seal_rent_allowance(ctx, out_ptr: u32, out_len_ptr: u32) => {
|
[seal0] seal_rent_allowance(ctx, out_ptr: u32, out_len_ptr: u32) => {
|
||||||
ctx.charge_gas(RuntimeToken::RentAllowance)?;
|
ctx.charge_gas(RuntimeToken::RentAllowance)?;
|
||||||
Ok(ctx.write_sandbox_output(
|
Ok(ctx.write_sandbox_output(
|
||||||
out_ptr, out_len_ptr, &ctx.ext.rent_allowance().encode(), false, already_charged
|
out_ptr, out_len_ptr, &ctx.ext.rent_allowance().encode(), false, already_charged
|
||||||
@@ -1363,7 +1404,7 @@ define_env!(Env, <E: Ext>,
|
|||||||
// Prints utf8 encoded string from the data buffer.
|
// Prints utf8 encoded string from the data buffer.
|
||||||
// Only available on `--dev` chains.
|
// Only available on `--dev` chains.
|
||||||
// This function may be removed at any time, superseded by a more general contract debugging feature.
|
// This function may be removed at any time, superseded by a more general contract debugging feature.
|
||||||
seal_println(ctx, str_ptr: u32, str_len: u32) => {
|
[seal0] seal_println(ctx, str_ptr: u32, str_len: u32) => {
|
||||||
let data = ctx.read_sandbox_memory(str_ptr, str_len)?;
|
let data = ctx.read_sandbox_memory(str_ptr, str_len)?;
|
||||||
if let Ok(utf8) = core::str::from_utf8(&data) {
|
if let Ok(utf8) = core::str::from_utf8(&data) {
|
||||||
log::info!(target: "runtime::contracts", "seal_println: {}", utf8);
|
log::info!(target: "runtime::contracts", "seal_println: {}", utf8);
|
||||||
@@ -1377,7 +1418,7 @@ define_env!(Env, <E: Ext>,
|
|||||||
// `out_len_ptr` must point to a u32 value that describes the available space at
|
// `out_len_ptr` must point to a u32 value that describes the available space at
|
||||||
// `out_ptr`. This call overwrites it with the size of the value. If the available
|
// `out_ptr`. This call overwrites it with the size of the value. If the available
|
||||||
// space at `out_ptr` is less than the size of the value a trap is triggered.
|
// space at `out_ptr` is less than the size of the value a trap is triggered.
|
||||||
seal_block_number(ctx, out_ptr: u32, out_len_ptr: u32) => {
|
[seal0] seal_block_number(ctx, out_ptr: u32, out_len_ptr: u32) => {
|
||||||
ctx.charge_gas(RuntimeToken::BlockNumber)?;
|
ctx.charge_gas(RuntimeToken::BlockNumber)?;
|
||||||
Ok(ctx.write_sandbox_output(
|
Ok(ctx.write_sandbox_output(
|
||||||
out_ptr, out_len_ptr, &ctx.ext.block_number().encode(), false, already_charged
|
out_ptr, out_len_ptr, &ctx.ext.block_number().encode(), false, already_charged
|
||||||
@@ -1404,7 +1445,7 @@ define_env!(Env, <E: Ext>,
|
|||||||
// - `output_ptr`: the pointer into the linear memory where the output
|
// - `output_ptr`: the pointer into the linear memory where the output
|
||||||
// data is placed. The function will write the result
|
// data is placed. The function will write the result
|
||||||
// directly into this buffer.
|
// directly into this buffer.
|
||||||
seal_hash_sha2_256(ctx, input_ptr: u32, input_len: u32, output_ptr: u32) => {
|
[seal0] seal_hash_sha2_256(ctx, input_ptr: u32, input_len: u32, output_ptr: u32) => {
|
||||||
ctx.charge_gas(RuntimeToken::HashSha256(input_len))?;
|
ctx.charge_gas(RuntimeToken::HashSha256(input_len))?;
|
||||||
Ok(ctx.compute_hash_on_intermediate_buffer(sha2_256, input_ptr, input_len, output_ptr)?)
|
Ok(ctx.compute_hash_on_intermediate_buffer(sha2_256, input_ptr, input_len, output_ptr)?)
|
||||||
},
|
},
|
||||||
@@ -1429,7 +1470,7 @@ define_env!(Env, <E: Ext>,
|
|||||||
// - `output_ptr`: the pointer into the linear memory where the output
|
// - `output_ptr`: the pointer into the linear memory where the output
|
||||||
// data is placed. The function will write the result
|
// data is placed. The function will write the result
|
||||||
// directly into this buffer.
|
// directly into this buffer.
|
||||||
seal_hash_keccak_256(ctx, input_ptr: u32, input_len: u32, output_ptr: u32) => {
|
[seal0] seal_hash_keccak_256(ctx, input_ptr: u32, input_len: u32, output_ptr: u32) => {
|
||||||
ctx.charge_gas(RuntimeToken::HashKeccak256(input_len))?;
|
ctx.charge_gas(RuntimeToken::HashKeccak256(input_len))?;
|
||||||
Ok(ctx.compute_hash_on_intermediate_buffer(keccak_256, input_ptr, input_len, output_ptr)?)
|
Ok(ctx.compute_hash_on_intermediate_buffer(keccak_256, input_ptr, input_len, output_ptr)?)
|
||||||
},
|
},
|
||||||
@@ -1454,7 +1495,7 @@ define_env!(Env, <E: Ext>,
|
|||||||
// - `output_ptr`: the pointer into the linear memory where the output
|
// - `output_ptr`: the pointer into the linear memory where the output
|
||||||
// data is placed. The function will write the result
|
// data is placed. The function will write the result
|
||||||
// directly into this buffer.
|
// directly into this buffer.
|
||||||
seal_hash_blake2_256(ctx, input_ptr: u32, input_len: u32, output_ptr: u32) => {
|
[seal0] seal_hash_blake2_256(ctx, input_ptr: u32, input_len: u32, output_ptr: u32) => {
|
||||||
ctx.charge_gas(RuntimeToken::HashBlake256(input_len))?;
|
ctx.charge_gas(RuntimeToken::HashBlake256(input_len))?;
|
||||||
Ok(ctx.compute_hash_on_intermediate_buffer(blake2_256, input_ptr, input_len, output_ptr)?)
|
Ok(ctx.compute_hash_on_intermediate_buffer(blake2_256, input_ptr, input_len, output_ptr)?)
|
||||||
},
|
},
|
||||||
@@ -1479,7 +1520,7 @@ define_env!(Env, <E: Ext>,
|
|||||||
// - `output_ptr`: the pointer into the linear memory where the output
|
// - `output_ptr`: the pointer into the linear memory where the output
|
||||||
// data is placed. The function will write the result
|
// data is placed. The function will write the result
|
||||||
// directly into this buffer.
|
// directly into this buffer.
|
||||||
seal_hash_blake2_128(ctx, input_ptr: u32, input_len: u32, output_ptr: u32) => {
|
[seal0] seal_hash_blake2_128(ctx, input_ptr: u32, input_len: u32, output_ptr: u32) => {
|
||||||
ctx.charge_gas(RuntimeToken::HashBlake128(input_len))?;
|
ctx.charge_gas(RuntimeToken::HashBlake128(input_len))?;
|
||||||
Ok(ctx.compute_hash_on_intermediate_buffer(blake2_128, input_ptr, input_len, output_ptr)?)
|
Ok(ctx.compute_hash_on_intermediate_buffer(blake2_128, input_ptr, input_len, output_ptr)?)
|
||||||
},
|
},
|
||||||
@@ -1495,7 +1536,7 @@ define_env!(Env, <E: Ext>,
|
|||||||
//
|
//
|
||||||
// If no chain extension exists the contract will trap with the `NoChainExtension`
|
// If no chain extension exists the contract will trap with the `NoChainExtension`
|
||||||
// module error.
|
// module error.
|
||||||
seal_call_chain_extension(
|
[seal0] seal_call_chain_extension(
|
||||||
ctx,
|
ctx,
|
||||||
func_id: u32,
|
func_id: u32,
|
||||||
input_ptr: u32,
|
input_ptr: u32,
|
||||||
@@ -1531,7 +1572,7 @@ define_env!(Env, <E: Ext>,
|
|||||||
// The returned information was collected and cached when the current contract call
|
// The returned information was collected and cached when the current contract call
|
||||||
// started execution. Any change to those values that happens due to actions of the
|
// started execution. Any change to those values that happens due to actions of the
|
||||||
// current call or contracts that are called by this contract are not considered.
|
// current call or contracts that are called by this contract are not considered.
|
||||||
seal_rent_params(ctx, out_ptr: u32, out_len_ptr: u32) => {
|
[seal0] seal_rent_params(ctx, out_ptr: u32, out_len_ptr: u32) => {
|
||||||
ctx.charge_gas(RuntimeToken::RentParams)?;
|
ctx.charge_gas(RuntimeToken::RentParams)?;
|
||||||
Ok(ctx.write_sandbox_output(
|
Ok(ctx.write_sandbox_output(
|
||||||
out_ptr, out_len_ptr, &ctx.ext.rent_params().encode(), false, already_charged
|
out_ptr, out_len_ptr, &ctx.ext.rent_params().encode(), false, already_charged
|
||||||
|
|||||||
Reference in New Issue
Block a user