diff --git a/substrate/Cargo.lock b/substrate/Cargo.lock index 7c79f2aede..6fcc146b70 100644 --- a/substrate/Cargo.lock +++ b/substrate/Cargo.lock @@ -3124,8 +3124,10 @@ dependencies = [ "sr-sandbox 0.1.0", "sr-std 0.1.0", "srml-balances 0.1.0", + "srml-consensus 0.1.0", "srml-support 0.1.0", "srml-system 0.1.0", + "srml-timestamp 0.1.0", "substrate-primitives 0.1.0", "wabt 0.7.4 (registry+https://github.com/rust-lang/crates.io-index)", ] diff --git a/substrate/core/test-runtime/wasm/target/wasm32-unknown-unknown/release/substrate_test_runtime.compact.wasm b/substrate/core/test-runtime/wasm/target/wasm32-unknown-unknown/release/substrate_test_runtime.compact.wasm index 73202e9ccc..62bf57f859 100644 Binary files a/substrate/core/test-runtime/wasm/target/wasm32-unknown-unknown/release/substrate_test_runtime.compact.wasm and b/substrate/core/test-runtime/wasm/target/wasm32-unknown-unknown/release/substrate_test_runtime.compact.wasm differ diff --git a/substrate/node/runtime/src/lib.rs b/substrate/node/runtime/src/lib.rs index f86fa58206..fd250ec6b6 100644 --- a/substrate/node/runtime/src/lib.rs +++ b/substrate/node/runtime/src/lib.rs @@ -65,8 +65,8 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { spec_name: create_runtime_str!("node"), impl_name: create_runtime_str!("substrate-node"), authoring_version: 10, - spec_version: 22, - impl_version: 22, + spec_version: 23, + impl_version: 23, apis: RUNTIME_API_VERSIONS, }; diff --git a/substrate/node/runtime/wasm/Cargo.lock b/substrate/node/runtime/wasm/Cargo.lock index ce335fe24d..3b235e73cd 100644 --- a/substrate/node/runtime/wasm/Cargo.lock +++ b/substrate/node/runtime/wasm/Cargo.lock @@ -1201,6 +1201,7 @@ dependencies = [ "srml-balances 0.1.0", "srml-support 0.1.0", "srml-system 0.1.0", + "srml-timestamp 0.1.0", "substrate-primitives 0.1.0", ] diff --git a/substrate/node/runtime/wasm/target/wasm32-unknown-unknown/release/node_runtime.compact.wasm b/substrate/node/runtime/wasm/target/wasm32-unknown-unknown/release/node_runtime.compact.wasm index 1f7fa1bbf9..f101bf77d8 100644 Binary files a/substrate/node/runtime/wasm/target/wasm32-unknown-unknown/release/node_runtime.compact.wasm and b/substrate/node/runtime/wasm/target/wasm32-unknown-unknown/release/node_runtime.compact.wasm differ diff --git a/substrate/srml/contract/COMPLEXITY.md b/substrate/srml/contract/COMPLEXITY.md index 511f4e258f..219d9244dd 100644 --- a/substrate/srml/contract/COMPLEXITY.md +++ b/substrate/srml/contract/COMPLEXITY.md @@ -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. +## 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 **complexity**: This function is of constant complexity. diff --git a/substrate/srml/contract/Cargo.toml b/substrate/srml/contract/Cargo.toml index a154a9648a..17d58752f3 100644 --- a/substrate/srml/contract/Cargo.toml +++ b/substrate/srml/contract/Cargo.toml @@ -18,11 +18,13 @@ sandbox = { package = "sr-sandbox", path = "../../core/sr-sandbox", default-feat srml-support = { path = "../support", default-features = false } system = { package = "srml-system", path = "../system", default-features = false } balances = { package = "srml-balances", path = "../balances", default-features = false } +timestamp = { package = "srml-timestamp", path = "../timestamp", default-features = false } [dev-dependencies] wabt = "~0.7.4" assert_matches = "1.1" hex-literal = "0.1.0" +consensus = { package = "srml-consensus", path = "../consensus", default-features = false } [features] default = ["std"] @@ -38,6 +40,7 @@ std = [ "sandbox/std", "srml-support/std", "system/std", + "timestamp/std", "parity-wasm/std", "pwasm-utils/std", ] diff --git a/substrate/srml/contract/src/exec.rs b/substrate/srml/contract/src/exec.rs index a4024f439a..67ba3b99de 100644 --- a/substrate/srml/contract/src/exec.rs +++ b/substrate/srml/contract/src/exec.rs @@ -21,10 +21,13 @@ use crate::gas::{GasMeter, Token, approx_gas_for_balance}; use balances::{self, EnsureAccountLiquid}; use rstd::prelude::*; use runtime_primitives::traits::{CheckedAdd, CheckedSub, Zero}; +use timestamp; pub type BalanceOf = ::Balance; pub type AccountIdOf = ::AccountId; pub type CallOf = ::Call; +pub type MomentOf = ::Moment; +pub type SeedOf = ::Hash; #[cfg_attr(test, derive(Debug))] pub struct InstantiateReceipt { @@ -95,6 +98,12 @@ pub trait Ext { /// Returns the value transfered along with this call or as endowment. fn value_transferred(&self) -> BalanceOf; + + /// Returns a reference to the timestamp of the current block + fn now(&self) -> &MomentOf; + + /// Returns a reference to the random seed for the current block + fn random_seed(&self) -> &SeedOf; } /// Loader is a companion of the `Vm` trait. It loads an appropriate abstract @@ -311,6 +320,8 @@ where ctx: &mut nested, caller: self.self_account.clone(), value_transferred: value, + timestamp: timestamp::Module::::now(), + random_seed: system::Module::::random_seed(), }, input_data, empty_output_buf, @@ -382,6 +393,8 @@ where ctx: &mut nested, caller: self.self_account.clone(), value_transferred: endowment, + timestamp: timestamp::Module::::now(), + random_seed: system::Module::::random_seed(), }, input_data, EmptyOutputBuf::new(), @@ -528,6 +541,8 @@ struct CallContext<'a, 'b: 'a, T: Trait + 'b, V: Vm + 'b, L: Loader> { ctx: &'a mut ExecutionContext<'b, T, V, L>, caller: T::AccountId, 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> @@ -592,6 +607,14 @@ where fn value_transferred(&self) -> T::Balance { 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. diff --git a/substrate/srml/contract/src/lib.rs b/substrate/srml/contract/src/lib.rs index 2f278b2a2c..d0dd6a1770 100644 --- a/substrate/srml/contract/src/lib.rs +++ b/substrate/srml/contract/src/lib.rs @@ -81,6 +81,7 @@ use runtime_support::dispatch::{Result, Dispatchable}; use runtime_support::{Parameter, StorageMap, StorageValue, StorageDoubleMap}; use system::{ensure_signed, RawOrigin}; use runtime_io::{blake2_256, twox_128}; +use timestamp; pub type CodeHash = ::Hash; @@ -94,7 +95,7 @@ pub trait ComputeDispatchFee { fn compute_dispatch_fee(call: &Call) -> Balance; } -pub trait Trait: balances::Trait { +pub trait Trait: balances::Trait + timestamp::Trait { /// The outer call dispatch type. type Call: Parameter + Dispatchable::Origin>; diff --git a/substrate/srml/contract/src/tests.rs b/substrate/srml/contract/src/tests.rs index eee12b0ac1..339dd26e4f 100644 --- a/substrate/srml/contract/src/tests.rs +++ b/substrate/srml/contract/src/tests.rs @@ -20,14 +20,14 @@ #![allow(unused)] 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::BuildStorage; use runtime_io; use runtime_support::{StorageMap, StorageDoubleMap}; use substrate_primitives::{Blake2Hasher}; use system::{self, Phase, EventRecord}; -use {wabt, balances}; +use {wabt, balances, consensus}; use hex_literal::*; use assert_matches::assert_matches; use crate::{ @@ -78,6 +78,15 @@ impl balances::Trait for Test { type EnsureAccountLiquid = (); 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 { type Call = Call; type Gas = u64; diff --git a/substrate/srml/contract/src/wasm/mod.rs b/substrate/srml/contract/src/wasm/mod.rs index 079cb4aac6..bec50dac07 100644 --- a/substrate/srml/contract/src/wasm/mod.rs +++ b/substrate/srml/contract/src/wasm/mod.rs @@ -203,6 +203,7 @@ mod tests { transfers: Vec, dispatches: Vec, next_account_id: u64, + random_seed: H256, } impl Ext for MockExt { type T = Test; @@ -266,6 +267,14 @@ mod tests { fn value_transferred(&self) -> u64 { 1337 } + + fn now(&self) -> &u64 { + &1111 + } + + fn random_seed(&self) -> &H256{ + &self.random_seed + } } fn execute( @@ -1011,7 +1020,6 @@ mod tests { ) "#; - #[test] fn return_from_start_fn() { let mut mock_ext = MockExt::default(); @@ -1027,4 +1035,134 @@ mod tests { 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(); + } + } diff --git a/substrate/srml/contract/src/wasm/runtime.rs b/substrate/srml/contract/src/wasm/runtime.rs index 03f56cbc3d..fc13211f95 100644 --- a/substrate/srml/contract/src/wasm/runtime.rs +++ b/substrate/srml/contract/src/wasm/runtime.rs @@ -482,6 +482,19 @@ define_env!(Env, , 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 // of to-be-dispatched calls. //