diff --git a/substrate/executor/src/native_executor.rs b/substrate/executor/src/native_executor.rs index d9426be1cb3e0d9505b67566b33d8df34ec976ca..94c5dd51ac6c31b6ae0d06e50b8de8cba1469d19 100644 --- a/substrate/executor/src/native_executor.rs +++ b/substrate/executor/src/native_executor.rs @@ -50,7 +50,7 @@ mod tests { const BLOATY_CODE: &[u8] = include_bytes!("../../wasm-runtime/target/wasm32-unknown-unknown/release/runtime_polkadot.wasm"); const COMPACT_CODE: &[u8] = include_bytes!("../../wasm-runtime/target/wasm32-unknown-unknown/release/runtime_polkadot.compact.wasm"); - fn tx() -> Vec<u8> { + fn tx() -> UncheckedTransaction { let transaction = Transaction { signed: one(), nonce: 0, @@ -60,7 +60,7 @@ mod tests { let signature = secret_for(&transaction.signed).unwrap() .sign(&transaction.to_vec()) .inner(); - UncheckedTransaction { transaction, signature }.to_vec() + UncheckedTransaction { transaction, signature } } #[test] @@ -70,7 +70,7 @@ mod tests { twox_128(&one.to_keyed_vec(b"sta:bal:")).to_vec() => vec![68u8, 0, 0, 0, 0, 0, 0, 0] ], }; - let r = NativeExecutor.call(&mut t, BLOATY_CODE, "execute_transaction", &CallData(tx())); + let r = NativeExecutor.call(&mut t, BLOATY_CODE, "execute_transaction", &CallData(vec![].join(&1u64).join(&tx()))); assert!(r.is_err()); } @@ -81,7 +81,7 @@ mod tests { twox_128(&one.to_keyed_vec(b"sta:bal:")).to_vec() => vec![68u8, 0, 0, 0, 0, 0, 0, 0] ], }; - let r = NativeExecutor.call(&mut t, COMPACT_CODE, "execute_transaction", &CallData(tx())); + let r = NativeExecutor.call(&mut t, COMPACT_CODE, "execute_transaction", &CallData(vec![].join(&1u64).join(&tx()))); assert!(r.is_err()); } @@ -94,7 +94,7 @@ mod tests { twox_128(&one.to_keyed_vec(b"sta:bal:")).to_vec() => vec![111u8, 0, 0, 0, 0, 0, 0, 0] ], }; - let r = NativeExecutor.call(&mut t, COMPACT_CODE, "execute_transaction", &CallData(tx())); + let r = NativeExecutor.call(&mut t, COMPACT_CODE, "execute_transaction", &CallData(vec![].join(&1u64).join(&tx()))); assert!(r.is_ok()); runtime_std::with_externalities(&mut t, || { @@ -112,7 +112,7 @@ mod tests { twox_128(&one.to_keyed_vec(b"sta:bal:")).to_vec() => vec![111u8, 0, 0, 0, 0, 0, 0, 0] ], }; - let r = NativeExecutor.call(&mut t, BLOATY_CODE, "execute_transaction", &CallData(tx())); + let r = NativeExecutor.call(&mut t, BLOATY_CODE, "execute_transaction", &CallData(vec![].join(&1u64).join(&tx()))); assert!(r.is_ok()); runtime_std::with_externalities(&mut t, || { diff --git a/substrate/executor/src/wasm_executor.rs b/substrate/executor/src/wasm_executor.rs index 5b87270724ef7891432109a699b49c5564057ce0..a9e8a856476699b53becbbacadd9515eeff52755 100644 --- a/substrate/executor/src/wasm_executor.rs +++ b/substrate/executor/src/wasm_executor.rs @@ -292,9 +292,9 @@ mod tests { use rustc_hex::FromHex; use primitives::{blake2_256, twox_128}; use runtime_std::{self, TestExternalities}; - use native_runtime::support::{one, two, StaticHexInto}; - use native_runtime::primitives::AccountID; - use native_runtime::codec::KeyedVec; + use native_runtime::support::{one, two}; + use native_runtime::primitives::{UncheckedTransaction, AccountID}; + use native_runtime::codec::{Joiner, KeyedVec}; use native_runtime::runtime::staking::balance; #[test] @@ -412,7 +412,7 @@ mod tests { } } - fn tx() -> Vec<u8> { + fn tx() -> UncheckedTransaction { use native_runtime::codec::{Joiner, Slicable}; use native_runtime::support::{one, two}; use native_runtime::primitives::*; @@ -425,7 +425,7 @@ mod tests { let signature = secret_for(&transaction.signed).unwrap() .sign(&transaction.to_vec()) .inner(); - UncheckedTransaction { transaction, signature }.to_vec() + UncheckedTransaction { transaction, signature } } #[test] @@ -436,7 +436,7 @@ mod tests { ], }; let foreign_code = include_bytes!("../../wasm-runtime/target/wasm32-unknown-unknown/release/runtime_polkadot.wasm"); - let r = WasmExecutor.call(&mut t, &foreign_code[..], "execute_transaction", &CallData(tx())); + let r = WasmExecutor.call(&mut t, &foreign_code[..], "execute_transaction", &CallData(vec![].join(&1u64).join(&tx()))); assert!(r.is_err()); } @@ -450,7 +450,7 @@ mod tests { ], }; let foreign_code = include_bytes!("../../wasm-runtime/target/wasm32-unknown-unknown/release/runtime_polkadot.compact.wasm"); - let r = WasmExecutor.call(&mut t, &foreign_code[..], "execute_transaction", &CallData(tx())); + let r = WasmExecutor.call(&mut t, &foreign_code[..], "execute_transaction", &CallData(vec![].join(&1u64).join(&tx()))); assert!(r.is_ok()); runtime_std::with_externalities(&mut t, || { diff --git a/substrate/wasm-runtime/polkadot/src/lib.rs b/substrate/wasm-runtime/polkadot/src/lib.rs index 33bf5546766e8ad019b4b98757d44cb4c57d5640..32d026e42f4643956aa3201e10809ae1fa0479ba 100644 --- a/substrate/wasm-runtime/polkadot/src/lib.rs +++ b/substrate/wasm-runtime/polkadot/src/lib.rs @@ -38,7 +38,7 @@ pub mod runtime; use runtime_std::prelude::*; use codec::Slicable; use runtime_std::print; -use primitives::{Block, UncheckedTransaction}; +use primitives::{Block, Header, BlockNumber, UncheckedTransaction}; /// Execute a block, with `input` being the canonical serialisation of the block. Returns the /// empty vector. @@ -49,8 +49,9 @@ pub fn execute_block(input: &[u8]) -> Vec<u8> { /// Execute a given, serialised, transaction. Returns the empty vector. pub fn execute_transaction(input: &[u8]) -> Vec<u8> { - let utx = UncheckedTransaction::from_slice(input).unwrap(); - runtime::system::internal::execute_transaction(&utx); + let number = BlockNumber::from_slice(&input[0..8]).unwrap(); + let utx = UncheckedTransaction::from_slice(&input[8..]).unwrap(); + runtime::system::internal::execute_transaction(&utx, Header::from_block_number(number)); Vec::new() } diff --git a/substrate/wasm-runtime/polkadot/src/primitives/header.rs b/substrate/wasm-runtime/polkadot/src/primitives/header.rs index c97d5ebf29743dcb560c554afc860a8f27214fa8..c37634cff58ced3d376aaa0cdc100a291d4af459 100644 --- a/substrate/wasm-runtime/polkadot/src/primitives/header.rs +++ b/substrate/wasm-runtime/polkadot/src/primitives/header.rs @@ -37,6 +37,18 @@ pub struct Header { pub digest: Digest, } +impl Header { + pub fn from_block_number(number: BlockNumber) -> Self { + Header { + parent_hash: Default::default(), + number, + state_root: Default::default(), + transaction_root: Default::default(), + digest: Default::default(), + } + } +} + impl Slicable for Header { fn from_slice(value: &[u8]) -> Option<Self> { let mut reader = StreamReader::new(value); diff --git a/substrate/wasm-runtime/polkadot/src/runtime/session.rs b/substrate/wasm-runtime/polkadot/src/runtime/session.rs index 495c60701a619530a226e4041a3f3ae3efc65248..2c195dbb72d3c21bc10e15918e6ec489aefc5d95 100644 --- a/substrate/wasm-runtime/polkadot/src/runtime/session.rs +++ b/substrate/wasm-runtime/polkadot/src/runtime/session.rs @@ -151,9 +151,9 @@ mod tests { twox_128(&0u32.to_keyed_vec(ValidatorStorageVec::PREFIX)).to_vec() => vec![10; 32], twox_128(&1u32.to_keyed_vec(ValidatorStorageVec::PREFIX)).to_vec() => vec![20; 32], // initial session keys (11, 21, ...) - twox_128(b"con:aut:len").to_vec() => vec![].join(&2u32), - twox_128(&0u32.to_keyed_vec(b"con:aut:")).to_vec() => vec![11; 32], - twox_128(&1u32.to_keyed_vec(b"con:aut:")).to_vec() => vec![21; 32] + b"con:aut:len".to_vec() => vec![].join(&2u32), + 0u32.to_keyed_vec(b"con:aut:") => vec![11; 32], + 1u32.to_keyed_vec(b"con:aut:") => vec![21; 32] ], } } diff --git a/substrate/wasm-runtime/polkadot/src/runtime/system.rs b/substrate/wasm-runtime/polkadot/src/runtime/system.rs index 3bad5413621f7ae64caaf2074986daf87bd80007..e6d93e94923297e3ca0a83dc386b466ea7189356 100644 --- a/substrate/wasm-runtime/polkadot/src/runtime/system.rs +++ b/substrate/wasm-runtime/polkadot/src/runtime/system.rs @@ -21,7 +21,7 @@ use runtime_std::prelude::*; use runtime_std::{mem, storage_root, enumerated_trie_root}; use codec::{KeyedVec, Slicable}; use support::{Hashable, storage, with_env}; -use primitives::{Block, BlockNumber, Hash, UncheckedTransaction, TxOrder}; +use primitives::{Block, BlockNumber, Header, Hash, UncheckedTransaction, TxOrder}; use runtime::{staking, session}; const NONCE_OF: &[u8] = b"sys:non:"; @@ -84,7 +84,7 @@ pub mod internal { // execute transactions for tx in &block.transactions { - execute_transaction(tx); + super::execute_transaction(tx); } staking::internal::check_new_era(); @@ -98,29 +98,34 @@ pub mod internal { debug_assert_hash(&header.state_root, &storage_root); assert!(header.state_root == storage_root, "Storage root must match that calculated."); - // store the header hash in storage; we can't do it before otherwise there would be a - // cyclic dependency. - let header_hash_key = header.number.to_keyed_vec(BLOCK_HASH_AT); - storage::put(&header_hash_key, &header.blake2_256()); + // any stuff that we do after taking the storage root. + post_finalise(header); } - /// Execute a given transaction. - pub fn execute_transaction(utx: &UncheckedTransaction) { - // Verify the signature is good. - assert!(utx.ed25519_verify(), "All transactions should be properly signed"); + /// Execute a transaction outside of the block execution function. + /// This doesn't attempt to validate anything regarding the block. + pub fn execute_transaction(utx: &UncheckedTransaction, mut header: Header) { + // populate environment from header. + with_env(|e| { + e.block_number = header.number; + mem::swap(&mut e.digest, &mut header.digest); + e.next_log_index = 0; + }); - let ref tx = utx.transaction; + super::execute_transaction(utx); + } + + /// Finalise the block - it is up the caller to ensure that all header fields are valid + /// except state-root. + pub fn finalise_block(mut header: Header) -> Header { + staking::internal::check_new_era(); + session::internal::check_rotate_session(); - // check nonce - let nonce_key = tx.signed.to_keyed_vec(NONCE_OF); - let expected_nonce: TxOrder = storage::get_or(&nonce_key, 0); - assert!(tx.nonce == expected_nonce, "All transactions should have the correct nonce"); + header.state_root = storage_root(); - // increment nonce in storage - storage::put(&nonce_key, &(expected_nonce + 1)); + post_finalise(&header); - // decode parameters and dispatch - tx.function.dispatch(&tx.signed, &tx.input_data); + header } #[cfg(feature = "with-std")] @@ -135,12 +140,36 @@ pub mod internal { fn debug_assert_hash(_given: &Hash, _expected: &Hash) {} } +fn execute_transaction(utx: &UncheckedTransaction) { + // Verify the signature is good. + assert!(utx.ed25519_verify(), "All transactions should be properly signed"); + + let ref tx = utx.transaction; + + // check nonce + let nonce_key = tx.signed.to_keyed_vec(NONCE_OF); + let expected_nonce: TxOrder = storage::get_or(&nonce_key, 0); + assert!(tx.nonce == expected_nonce, "All transactions should have the correct nonce"); + + // increment nonce in storage + storage::put(&nonce_key, &(expected_nonce + 1)); + + // decode parameters and dispatch + tx.function.dispatch(&tx.signed, &tx.input_data); +} + fn final_checks(_block: &Block) { with_env(|e| { assert_eq!(e.next_log_index, e.digest.logs.len()); }); } +fn post_finalise(header: &Header) { + // store the header hash in storage; we can't do it before otherwise there would be a + // cyclic dependency. + storage::put(&header.number.to_keyed_vec(BLOCK_HASH_AT), &header.blake2_256()); +} + #[cfg(test)] mod tests { use super::*; @@ -174,7 +203,7 @@ mod tests { println!("tx is {}", HexDisplay::from(&tx.transaction.to_vec())); with_externalities(&mut t, || { - execute_transaction(&tx); + internal::execute_transaction(&tx, Header::from_block_number(1)); assert_eq!(staking::balance(&one), 42); assert_eq!(staking::balance(&two), 69); });