diff --git a/substrate/srml/contracts/src/exec.rs b/substrate/srml/contracts/src/exec.rs index c726d93e13..d3c428061b 100644 --- a/substrate/srml/contracts/src/exec.rs +++ b/substrate/srml/contracts/src/exec.rs @@ -29,6 +29,7 @@ pub type AccountIdOf = ::AccountId; pub type CallOf = ::Call; pub type MomentOf = ::Moment; pub type SeedOf = ::Hash; +pub type BlockNumberOf = ::BlockNumber; /// A type that represents a topic of an event. At the moment a hash is used. pub type TopicOf = ::Hash; @@ -120,6 +121,9 @@ pub trait Ext { /// Rent allowance of the contract fn rent_allowance(&self) -> BalanceOf; + + /// Returns the current block number. + fn block_number(&self) -> BlockNumberOf; } /// Loader is a companion of the `Vm` trait. It loads an appropriate abstract @@ -363,6 +367,7 @@ where caller: self.self_account.clone(), value_transferred: value, timestamp: timestamp::Module::::now(), + block_number: >::block_number(), }, input_data, empty_output_buf, @@ -433,6 +438,7 @@ where caller: self.self_account.clone(), value_transferred: endowment, timestamp: timestamp::Module::::now(), + block_number: >::block_number(), }, input_data, EmptyOutputBuf::new(), @@ -585,6 +591,7 @@ struct CallContext<'a, 'b: 'a, T: Trait + 'b, V: Vm + 'b, L: Loader> { caller: T::AccountId, value_transferred: BalanceOf, timestamp: T::Moment, + block_number: T::BlockNumber, } impl<'a, 'b: 'a, T, E, V, L> Ext for CallContext<'a, 'b, T, V, L> @@ -673,6 +680,8 @@ where self.ctx.overlay.get_rent_allowance(&self.ctx.self_account) .unwrap_or(>::max_value()) // Must never be triggered actually } + + fn block_number(&self) -> T::BlockNumber { self.block_number } } /// These tests exercise the executive layer. diff --git a/substrate/srml/contracts/src/wasm/mod.rs b/substrate/srml/contracts/src/wasm/mod.rs index 71c1a1d3f4..1f63b5d9df 100644 --- a/substrate/srml/contracts/src/wasm/mod.rs +++ b/substrate/srml/contracts/src/wasm/mod.rs @@ -291,6 +291,8 @@ mod tests { fn rent_allowance(&self) -> u64 { self.rent_allowance } + + fn block_number(&self) -> u64 { 121 } } fn execute( @@ -1342,4 +1344,70 @@ mod tests { Err("during execution"), ); } + + /// calls `ext_block_number`, loads the current block number from the scratch buffer and + /// compares it with the constant 121. + const CODE_BLOCK_NUMBER: &str = r#" +(module + (import "env" "ext_block_number" (func $ext_block_number)) + (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 height in the scratch buffer + (call $ext_block_number) + + ;; 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 121. + (call $assert + (i64.eq + (i64.load + (i32.const 8) + ) + (i64.const 121) + ) + ) + ) + + (func (export "deploy")) +) +"#; + + #[test] + fn block_number() { + let mut mock_ext = MockExt::default(); + execute( + CODE_BLOCK_NUMBER, + &[], + &mut Vec::new(), + &mut mock_ext, + &mut GasMeter::with_limit(50_000, 1), + ) + .unwrap(); + } + } diff --git a/substrate/srml/contracts/src/wasm/runtime.rs b/substrate/srml/contracts/src/wasm/runtime.rs index d05b716478..29965c9676 100644 --- a/substrate/srml/contracts/src/wasm/runtime.rs +++ b/substrate/srml/contracts/src/wasm/runtime.rs @@ -701,6 +701,13 @@ define_env!(Env, , } Ok(()) }, + + // Stores the current block number of the current contract into the scratch buffer. + ext_block_number(ctx) => { + ctx.scratch_buf.clear(); + ctx.ext.block_number().encode_to(&mut ctx.scratch_buf); + Ok(()) + }, ); /// Finds duplicates in a given vector.