mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-06-13 19:51:05 +00:00
Expose block random seed and timestamp to contract ABI (#1630)
* Expose block random seed and timestamp to contract ABI * Add tests * Bump spec version
This commit is contained in:
committed by
Sergei Pepyakin
parent
eb6dc0394e
commit
fb0f4dfb03
Generated
+2
@@ -3124,8 +3124,10 @@ dependencies = [
|
|||||||
"sr-sandbox 0.1.0",
|
"sr-sandbox 0.1.0",
|
||||||
"sr-std 0.1.0",
|
"sr-std 0.1.0",
|
||||||
"srml-balances 0.1.0",
|
"srml-balances 0.1.0",
|
||||||
|
"srml-consensus 0.1.0",
|
||||||
"srml-support 0.1.0",
|
"srml-support 0.1.0",
|
||||||
"srml-system 0.1.0",
|
"srml-system 0.1.0",
|
||||||
|
"srml-timestamp 0.1.0",
|
||||||
"substrate-primitives 0.1.0",
|
"substrate-primitives 0.1.0",
|
||||||
"wabt 0.7.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
"wabt 0.7.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|||||||
BIN
Binary file not shown.
@@ -65,8 +65,8 @@ pub const VERSION: RuntimeVersion = RuntimeVersion {
|
|||||||
spec_name: create_runtime_str!("node"),
|
spec_name: create_runtime_str!("node"),
|
||||||
impl_name: create_runtime_str!("substrate-node"),
|
impl_name: create_runtime_str!("substrate-node"),
|
||||||
authoring_version: 10,
|
authoring_version: 10,
|
||||||
spec_version: 22,
|
spec_version: 23,
|
||||||
impl_version: 22,
|
impl_version: 23,
|
||||||
apis: RUNTIME_API_VERSIONS,
|
apis: RUNTIME_API_VERSIONS,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
Generated
+1
@@ -1201,6 +1201,7 @@ dependencies = [
|
|||||||
"srml-balances 0.1.0",
|
"srml-balances 0.1.0",
|
||||||
"srml-support 0.1.0",
|
"srml-support 0.1.0",
|
||||||
"srml-system 0.1.0",
|
"srml-system 0.1.0",
|
||||||
|
"srml-timestamp 0.1.0",
|
||||||
"substrate-primitives 0.1.0",
|
"substrate-primitives 0.1.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|||||||
BIN
Binary file not shown.
@@ -281,6 +281,18 @@ This function serializes the address of the caller into the scratch buffer.
|
|||||||
|
|
||||||
**complexity**: Assuming that the address is of constant size, this function has constant complexity.
|
**complexity**: Assuming that the address is of constant size, this function has constant complexity.
|
||||||
|
|
||||||
|
## ext_random_seed
|
||||||
|
|
||||||
|
This function serializes the current block's random seed into the scratch buffer.
|
||||||
|
|
||||||
|
**complexity**: Assuming that the random seed is of constant size, this function has constant complexity.
|
||||||
|
|
||||||
|
## ext_now
|
||||||
|
|
||||||
|
This function serializes the current block's timestamp into the scratch buffer.
|
||||||
|
|
||||||
|
**complexity**: Assuming that the timestamp is of constant size, this function has constant complexity.
|
||||||
|
|
||||||
## ext_input_size
|
## ext_input_size
|
||||||
|
|
||||||
**complexity**: This function is of constant complexity.
|
**complexity**: This function is of constant complexity.
|
||||||
|
|||||||
@@ -18,11 +18,13 @@ sandbox = { package = "sr-sandbox", path = "../../core/sr-sandbox", default-feat
|
|||||||
srml-support = { path = "../support", default-features = false }
|
srml-support = { path = "../support", default-features = false }
|
||||||
system = { package = "srml-system", path = "../system", default-features = false }
|
system = { package = "srml-system", path = "../system", default-features = false }
|
||||||
balances = { package = "srml-balances", path = "../balances", default-features = false }
|
balances = { package = "srml-balances", path = "../balances", default-features = false }
|
||||||
|
timestamp = { package = "srml-timestamp", path = "../timestamp", default-features = false }
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
wabt = "~0.7.4"
|
wabt = "~0.7.4"
|
||||||
assert_matches = "1.1"
|
assert_matches = "1.1"
|
||||||
hex-literal = "0.1.0"
|
hex-literal = "0.1.0"
|
||||||
|
consensus = { package = "srml-consensus", path = "../consensus", default-features = false }
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
default = ["std"]
|
default = ["std"]
|
||||||
@@ -38,6 +40,7 @@ std = [
|
|||||||
"sandbox/std",
|
"sandbox/std",
|
||||||
"srml-support/std",
|
"srml-support/std",
|
||||||
"system/std",
|
"system/std",
|
||||||
|
"timestamp/std",
|
||||||
"parity-wasm/std",
|
"parity-wasm/std",
|
||||||
"pwasm-utils/std",
|
"pwasm-utils/std",
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -21,10 +21,13 @@ use crate::gas::{GasMeter, Token, approx_gas_for_balance};
|
|||||||
use balances::{self, EnsureAccountLiquid};
|
use balances::{self, EnsureAccountLiquid};
|
||||||
use rstd::prelude::*;
|
use rstd::prelude::*;
|
||||||
use runtime_primitives::traits::{CheckedAdd, CheckedSub, Zero};
|
use runtime_primitives::traits::{CheckedAdd, CheckedSub, Zero};
|
||||||
|
use timestamp;
|
||||||
|
|
||||||
pub type BalanceOf<T> = <T as balances::Trait>::Balance;
|
pub type BalanceOf<T> = <T as balances::Trait>::Balance;
|
||||||
pub type AccountIdOf<T> = <T as system::Trait>::AccountId;
|
pub type AccountIdOf<T> = <T as system::Trait>::AccountId;
|
||||||
pub type CallOf<T> = <T as Trait>::Call;
|
pub type CallOf<T> = <T as Trait>::Call;
|
||||||
|
pub type MomentOf<T> = <T as timestamp::Trait>::Moment;
|
||||||
|
pub type SeedOf<T> = <T as system::Trait>::Hash;
|
||||||
|
|
||||||
#[cfg_attr(test, derive(Debug))]
|
#[cfg_attr(test, derive(Debug))]
|
||||||
pub struct InstantiateReceipt<AccountId> {
|
pub struct InstantiateReceipt<AccountId> {
|
||||||
@@ -95,6 +98,12 @@ pub trait Ext {
|
|||||||
|
|
||||||
/// Returns the value transfered along with this call or as endowment.
|
/// Returns the value transfered along with this call or as endowment.
|
||||||
fn value_transferred(&self) -> BalanceOf<Self::T>;
|
fn value_transferred(&self) -> BalanceOf<Self::T>;
|
||||||
|
|
||||||
|
/// Returns a reference to the timestamp of the current block
|
||||||
|
fn now(&self) -> &MomentOf<Self::T>;
|
||||||
|
|
||||||
|
/// Returns a reference to the random seed for the current block
|
||||||
|
fn random_seed(&self) -> &SeedOf<Self::T>;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Loader is a companion of the `Vm` trait. It loads an appropriate abstract
|
/// Loader is a companion of the `Vm` trait. It loads an appropriate abstract
|
||||||
@@ -311,6 +320,8 @@ where
|
|||||||
ctx: &mut nested,
|
ctx: &mut nested,
|
||||||
caller: self.self_account.clone(),
|
caller: self.self_account.clone(),
|
||||||
value_transferred: value,
|
value_transferred: value,
|
||||||
|
timestamp: timestamp::Module::<T>::now(),
|
||||||
|
random_seed: system::Module::<T>::random_seed(),
|
||||||
},
|
},
|
||||||
input_data,
|
input_data,
|
||||||
empty_output_buf,
|
empty_output_buf,
|
||||||
@@ -382,6 +393,8 @@ where
|
|||||||
ctx: &mut nested,
|
ctx: &mut nested,
|
||||||
caller: self.self_account.clone(),
|
caller: self.self_account.clone(),
|
||||||
value_transferred: endowment,
|
value_transferred: endowment,
|
||||||
|
timestamp: timestamp::Module::<T>::now(),
|
||||||
|
random_seed: system::Module::<T>::random_seed(),
|
||||||
},
|
},
|
||||||
input_data,
|
input_data,
|
||||||
EmptyOutputBuf::new(),
|
EmptyOutputBuf::new(),
|
||||||
@@ -528,6 +541,8 @@ struct CallContext<'a, 'b: 'a, T: Trait + 'b, V: Vm<T> + 'b, L: Loader<T>> {
|
|||||||
ctx: &'a mut ExecutionContext<'b, T, V, L>,
|
ctx: &'a mut ExecutionContext<'b, T, V, L>,
|
||||||
caller: T::AccountId,
|
caller: T::AccountId,
|
||||||
value_transferred: T::Balance,
|
value_transferred: T::Balance,
|
||||||
|
timestamp: T::Moment,
|
||||||
|
random_seed: T::Hash,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, 'b: 'a, T, E, V, L> Ext for CallContext<'a, 'b, T, V, L>
|
impl<'a, 'b: 'a, T, E, V, L> Ext for CallContext<'a, 'b, T, V, L>
|
||||||
@@ -592,6 +607,14 @@ where
|
|||||||
fn value_transferred(&self) -> T::Balance {
|
fn value_transferred(&self) -> T::Balance {
|
||||||
self.value_transferred
|
self.value_transferred
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn random_seed(&self) -> &T::Hash {
|
||||||
|
&self.random_seed
|
||||||
|
}
|
||||||
|
|
||||||
|
fn now(&self) -> &T::Moment {
|
||||||
|
&self.timestamp
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// These tests exercise the executive layer.
|
/// These tests exercise the executive layer.
|
||||||
|
|||||||
@@ -81,6 +81,7 @@ use runtime_support::dispatch::{Result, Dispatchable};
|
|||||||
use runtime_support::{Parameter, StorageMap, StorageValue, StorageDoubleMap};
|
use runtime_support::{Parameter, StorageMap, StorageValue, StorageDoubleMap};
|
||||||
use system::{ensure_signed, RawOrigin};
|
use system::{ensure_signed, RawOrigin};
|
||||||
use runtime_io::{blake2_256, twox_128};
|
use runtime_io::{blake2_256, twox_128};
|
||||||
|
use timestamp;
|
||||||
|
|
||||||
pub type CodeHash<T> = <T as system::Trait>::Hash;
|
pub type CodeHash<T> = <T as system::Trait>::Hash;
|
||||||
|
|
||||||
@@ -94,7 +95,7 @@ pub trait ComputeDispatchFee<Call, Balance> {
|
|||||||
fn compute_dispatch_fee(call: &Call) -> Balance;
|
fn compute_dispatch_fee(call: &Call) -> Balance;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait Trait: balances::Trait {
|
pub trait Trait: balances::Trait + timestamp::Trait {
|
||||||
/// The outer call dispatch type.
|
/// The outer call dispatch type.
|
||||||
type Call: Parameter + Dispatchable<Origin=<Self as system::Trait>::Origin>;
|
type Call: Parameter + Dispatchable<Origin=<Self as system::Trait>::Origin>;
|
||||||
|
|
||||||
|
|||||||
@@ -20,14 +20,14 @@
|
|||||||
#![allow(unused)]
|
#![allow(unused)]
|
||||||
|
|
||||||
use runtime_io::with_externalities;
|
use runtime_io::with_externalities;
|
||||||
use runtime_primitives::testing::{Digest, DigestItem, H256, Header};
|
use runtime_primitives::testing::{Digest, DigestItem, H256, Header, UintAuthorityId};
|
||||||
use runtime_primitives::traits::{BlakeTwo256, IdentityLookup};
|
use runtime_primitives::traits::{BlakeTwo256, IdentityLookup};
|
||||||
use runtime_primitives::BuildStorage;
|
use runtime_primitives::BuildStorage;
|
||||||
use runtime_io;
|
use runtime_io;
|
||||||
use runtime_support::{StorageMap, StorageDoubleMap};
|
use runtime_support::{StorageMap, StorageDoubleMap};
|
||||||
use substrate_primitives::{Blake2Hasher};
|
use substrate_primitives::{Blake2Hasher};
|
||||||
use system::{self, Phase, EventRecord};
|
use system::{self, Phase, EventRecord};
|
||||||
use {wabt, balances};
|
use {wabt, balances, consensus};
|
||||||
use hex_literal::*;
|
use hex_literal::*;
|
||||||
use assert_matches::assert_matches;
|
use assert_matches::assert_matches;
|
||||||
use crate::{
|
use crate::{
|
||||||
@@ -78,6 +78,15 @@ impl balances::Trait for Test {
|
|||||||
type EnsureAccountLiquid = ();
|
type EnsureAccountLiquid = ();
|
||||||
type Event = MetaEvent;
|
type Event = MetaEvent;
|
||||||
}
|
}
|
||||||
|
impl timestamp::Trait for Test {
|
||||||
|
type Moment = u64;
|
||||||
|
type OnTimestampSet = ();
|
||||||
|
}
|
||||||
|
impl consensus::Trait for Test {
|
||||||
|
type Log = DigestItem;
|
||||||
|
type SessionKey = UintAuthorityId;
|
||||||
|
type InherentOfflineReport = ();
|
||||||
|
}
|
||||||
impl Trait for Test {
|
impl Trait for Test {
|
||||||
type Call = Call;
|
type Call = Call;
|
||||||
type Gas = u64;
|
type Gas = u64;
|
||||||
|
|||||||
@@ -203,6 +203,7 @@ mod tests {
|
|||||||
transfers: Vec<TransferEntry>,
|
transfers: Vec<TransferEntry>,
|
||||||
dispatches: Vec<DispatchEntry>,
|
dispatches: Vec<DispatchEntry>,
|
||||||
next_account_id: u64,
|
next_account_id: u64,
|
||||||
|
random_seed: H256,
|
||||||
}
|
}
|
||||||
impl Ext for MockExt {
|
impl Ext for MockExt {
|
||||||
type T = Test;
|
type T = Test;
|
||||||
@@ -266,6 +267,14 @@ mod tests {
|
|||||||
fn value_transferred(&self) -> u64 {
|
fn value_transferred(&self) -> u64 {
|
||||||
1337
|
1337
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn now(&self) -> &u64 {
|
||||||
|
&1111
|
||||||
|
}
|
||||||
|
|
||||||
|
fn random_seed(&self) -> &H256{
|
||||||
|
&self.random_seed
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn execute<E: Ext>(
|
fn execute<E: Ext>(
|
||||||
@@ -1011,7 +1020,6 @@ mod tests {
|
|||||||
)
|
)
|
||||||
"#;
|
"#;
|
||||||
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn return_from_start_fn() {
|
fn return_from_start_fn() {
|
||||||
let mut mock_ext = MockExt::default();
|
let mut mock_ext = MockExt::default();
|
||||||
@@ -1027,4 +1035,134 @@ mod tests {
|
|||||||
|
|
||||||
assert_eq!(output_data, vec![1, 2, 3, 4]);
|
assert_eq!(output_data, vec![1, 2, 3, 4]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const CODE_TIMESTAMP_NOW: &str = r#"
|
||||||
|
(module
|
||||||
|
(import "env" "ext_now" (func $ext_now))
|
||||||
|
(import "env" "ext_scratch_size" (func $ext_scratch_size (result i32)))
|
||||||
|
(import "env" "ext_scratch_copy" (func $ext_scratch_copy (param i32 i32 i32)))
|
||||||
|
(import "env" "memory" (memory 1 1))
|
||||||
|
|
||||||
|
(func $assert (param i32)
|
||||||
|
(block $ok
|
||||||
|
(br_if $ok
|
||||||
|
(get_local 0)
|
||||||
|
)
|
||||||
|
(unreachable)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
(func (export "call")
|
||||||
|
;; This stores the block timestamp in the scratch buffer
|
||||||
|
(call $ext_now)
|
||||||
|
|
||||||
|
;; assert $ext_scratch_size == 8
|
||||||
|
(call $assert
|
||||||
|
(i32.eq
|
||||||
|
(call $ext_scratch_size)
|
||||||
|
(i32.const 8)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
;; copy contents of the scratch buffer into the contract's memory.
|
||||||
|
(call $ext_scratch_copy
|
||||||
|
(i32.const 8) ;; Pointer in memory to the place where to copy.
|
||||||
|
(i32.const 0) ;; Offset from the start of the scratch buffer.
|
||||||
|
(i32.const 8) ;; Count of bytes to copy.
|
||||||
|
)
|
||||||
|
|
||||||
|
;; assert that contents of the buffer is equal to the i64 value of 1111.
|
||||||
|
(call $assert
|
||||||
|
(i64.eq
|
||||||
|
(i64.load
|
||||||
|
(i32.const 8)
|
||||||
|
)
|
||||||
|
(i64.const 1111)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
(func (export "deploy"))
|
||||||
|
)
|
||||||
|
"#;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn now() {
|
||||||
|
let mut mock_ext = MockExt::default();
|
||||||
|
let mut gas_meter = GasMeter::with_limit(50_000, 1);
|
||||||
|
execute(
|
||||||
|
CODE_TIMESTAMP_NOW,
|
||||||
|
&[],
|
||||||
|
&mut Vec::new(),
|
||||||
|
&mut mock_ext,
|
||||||
|
&mut gas_meter,
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
const CODE_RANDOM_SEED: &str = r#"
|
||||||
|
(module
|
||||||
|
(import "env" "ext_random_seed" (func $ext_random_seed))
|
||||||
|
(import "env" "ext_scratch_size" (func $ext_scratch_size (result i32)))
|
||||||
|
(import "env" "ext_scratch_copy" (func $ext_scratch_copy (param i32 i32 i32)))
|
||||||
|
(import "env" "memory" (memory 1 1))
|
||||||
|
|
||||||
|
(func $assert (param i32)
|
||||||
|
(block $ok
|
||||||
|
(br_if $ok
|
||||||
|
(get_local 0)
|
||||||
|
)
|
||||||
|
(unreachable)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
(func (export "call")
|
||||||
|
;; This stores the block random seed in the scratch buffer
|
||||||
|
(call $ext_random_seed)
|
||||||
|
|
||||||
|
;; assert $ext_scratch_size == 32
|
||||||
|
(call $assert
|
||||||
|
(i32.eq
|
||||||
|
(call $ext_scratch_size)
|
||||||
|
(i32.const 32)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
;; copy contents of the scratch buffer into the contract's memory.
|
||||||
|
(call $ext_scratch_copy
|
||||||
|
(i32.const 8) ;; Pointer in memory to the place where to copy.
|
||||||
|
(i32.const 0) ;; Offset from the start of the scratch buffer.
|
||||||
|
(i32.const 32) ;; Count of bytes to copy.
|
||||||
|
)
|
||||||
|
|
||||||
|
;; assert the contents of the buffer in 4 x i64 parts matches 1,2,3,4.
|
||||||
|
(call $assert (i64.eq (i64.load (i32.const 8)) (i64.const 1)))
|
||||||
|
(call $assert (i64.eq (i64.load (i32.const 16)) (i64.const 2)))
|
||||||
|
(call $assert (i64.eq (i64.load (i32.const 24)) (i64.const 3)))
|
||||||
|
(call $assert (i64.eq (i64.load (i32.const 32)) (i64.const 4)))
|
||||||
|
)
|
||||||
|
(func (export "deploy"))
|
||||||
|
)
|
||||||
|
"#;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn random_seed() {
|
||||||
|
let mut mock_ext = MockExt::default();
|
||||||
|
let seed: [u8; 32] = [
|
||||||
|
1,0,0,0,0,0,0,0,
|
||||||
|
2,0,0,0,0,0,0,0,
|
||||||
|
3,0,0,0,0,0,0,0,
|
||||||
|
4,0,0,0,0,0,0,0,
|
||||||
|
];
|
||||||
|
mock_ext.random_seed = H256::from_slice(&seed);
|
||||||
|
let mut gas_meter = GasMeter::with_limit(50_000, 1);
|
||||||
|
execute(
|
||||||
|
CODE_RANDOM_SEED,
|
||||||
|
&[],
|
||||||
|
&mut Vec::new(),
|
||||||
|
&mut mock_ext,
|
||||||
|
&mut gas_meter,
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -482,6 +482,19 @@ define_env!(Env, <E: Ext>,
|
|||||||
Ok(())
|
Ok(())
|
||||||
},
|
},
|
||||||
|
|
||||||
|
// Load the latest block RNG seed into the scratch buffer
|
||||||
|
ext_random_seed(ctx) => {
|
||||||
|
ctx.scratch_buf = ctx.ext.random_seed().encode();
|
||||||
|
Ok(())
|
||||||
|
},
|
||||||
|
|
||||||
|
// Load the latest block timestamp into the scratch buffer
|
||||||
|
ext_now(ctx) => {
|
||||||
|
let now: u64 = As::as_(ctx.ext.now().clone());
|
||||||
|
ctx.scratch_buf = now.encode();
|
||||||
|
Ok(())
|
||||||
|
},
|
||||||
|
|
||||||
// Decodes the given buffer as a `T::Call` and adds it to the list
|
// Decodes the given buffer as a `T::Call` and adds it to the list
|
||||||
// of to-be-dispatched calls.
|
// of to-be-dispatched calls.
|
||||||
//
|
//
|
||||||
|
|||||||
Reference in New Issue
Block a user