From 92d8712b2b76bd2d30232029e17f18aba36bd251 Mon Sep 17 00:00:00 2001 From: Gav Date: Thu, 18 Jan 2018 15:14:01 +0100 Subject: [PATCH] Introduce UncheckedTransaction & test. --- .../polkadot/src/codec/endiansensitive.rs | 4 +- substrate/wasm-runtime/polkadot/src/lib.rs | 7 +- .../polkadot/src/runtime/consensus.rs | 7 +- .../polkadot/src/runtime/staking.rs | 10 +- .../polkadot/src/runtime/system.rs | 21 +-- .../polkadot/src/runtime/timestamp.rs | 7 +- .../polkadot/src/support/primitives.rs | 152 +++++++++++++----- .../polkadot/src/support/storage.rs | 6 +- 8 files changed, 143 insertions(+), 71 deletions(-) diff --git a/substrate/wasm-runtime/polkadot/src/codec/endiansensitive.rs b/substrate/wasm-runtime/polkadot/src/codec/endiansensitive.rs index c13a96f23d..f1e042d886 100644 --- a/substrate/wasm-runtime/polkadot/src/codec/endiansensitive.rs +++ b/substrate/wasm-runtime/polkadot/src/codec/endiansensitive.rs @@ -26,4 +26,6 @@ macro_rules! impl_non_endians { } impl_endians!(u16, u32, u64, usize, i16, i32, i64, isize); -impl_non_endians!(u8, i8, [u8; 20], [u8; 32]); +impl_non_endians!(u8, i8, [u8; 1], [u8; 2], [u8; 3], [u8; 4], [u8; 5], [u8; 6], [u8; 7], [u8; 8], + [u8; 10], [u8; 12], [u8; 14], [u8; 16], [u8; 20], [u8; 24], [u8; 28], [u8; 32], [u8; 40], + [u8; 48], [u8; 56], [u8; 64], [u8; 80], [u8; 96], [u8; 112], [u8; 128]); diff --git a/substrate/wasm-runtime/polkadot/src/lib.rs b/substrate/wasm-runtime/polkadot/src/lib.rs index 52b29b05cf..18ce4059a8 100644 --- a/substrate/wasm-runtime/polkadot/src/lib.rs +++ b/substrate/wasm-runtime/polkadot/src/lib.rs @@ -11,11 +11,12 @@ pub use codec::{endiansensitive, streamreader, joiner, slicable, keyedvec}; pub use support::{primitives, function, environment, storage}; #[cfg(test)] pub use support::testing; -#[allow(unused_imports)] // TODO: remove in due course + +#[allow(unused_imports)] // TODO: remove in due course use runtime_support::Vec; use slicable::Slicable; -use primitives::{Block, Transaction}; +use primitives::{Block, UncheckedTransaction}; // TODO: add externals for: // - keccak256 (or some better hashing scheme) @@ -27,7 +28,7 @@ pub fn execute_block(input: Vec) -> Vec { } pub fn execute_transaction(input: Vec) -> Vec { - runtime::system::execute_transaction(&Transaction::from_slice(&input).unwrap()) + runtime::system::execute_transaction(&UncheckedTransaction::from_slice(&input).unwrap()) } impl_stubs!(execute_block, execute_transaction); diff --git a/substrate/wasm-runtime/polkadot/src/runtime/consensus.rs b/substrate/wasm-runtime/polkadot/src/runtime/consensus.rs index add87a1808..0d2531cea4 100644 --- a/substrate/wasm-runtime/polkadot/src/runtime/consensus.rs +++ b/substrate/wasm-runtime/polkadot/src/runtime/consensus.rs @@ -2,14 +2,13 @@ use runtime_support::Vec; use keyedvec::KeyedVec; use storage::Storage; use primitives::{AccountID, SessionKey, BlockNumber}; -use storage::storage_into; pub fn set_authority(index: u32, authority: AccountID) { authority.store(&index.to_keyed_vec(b"con\0aut\0")); } fn authority(index: u32) -> AccountID { - storage_into(&index.to_keyed_vec(b"con\0aut\0")) + Storage::into(&index.to_keyed_vec(b"con\0aut\0")) } pub fn set_authority_count(count: u32) { @@ -18,7 +17,7 @@ pub fn set_authority_count(count: u32) { } fn authority_count() -> u32 { - storage_into(b"con\0aut\0len") + Storage::into(b"con\0aut\0len") } /// Get the current set of authorities. These are the session keys. @@ -49,7 +48,7 @@ pub fn set_validators(_new: &[AccountID]) { /// The number of blocks in each session. pub fn session_length() -> BlockNumber { - storage_into(b"con\0bps") + Storage::into(b"con\0bps") } /// Sets the session key of `_transactor` to `_session`. This doesn't take effect until the next diff --git a/substrate/wasm-runtime/polkadot/src/runtime/staking.rs b/substrate/wasm-runtime/polkadot/src/runtime/staking.rs index ca37e7f6fe..6e22cfcd5f 100644 --- a/substrate/wasm-runtime/polkadot/src/runtime/staking.rs +++ b/substrate/wasm-runtime/polkadot/src/runtime/staking.rs @@ -1,5 +1,5 @@ use keyedvec::KeyedVec; -use storage::{Storage, storage_into}; +use storage::Storage; use primitives::{BlockNumber, Balance, AccountID}; use runtime::consensus; @@ -10,7 +10,7 @@ pub fn era_length() -> BlockNumber { /// The length of a staking era in sessions. pub fn sessions_per_era() -> BlockNumber { - storage_into(b"sta\0spe") + Storage::into(b"sta\0spe") } /// The era has changed - enact new staking set. @@ -22,16 +22,16 @@ pub fn next_era() { /// The balance of a given account. pub fn balance(who: &AccountID) -> Balance { - storage_into(&who.to_keyed_vec(b"sta\0bal\0")) + Storage::into(&who.to_keyed_vec(b"sta\0bal\0")) } /// Transfer some unlocked staking balance to another staker. pub fn transfer_stake(transactor: &AccountID, dest: &AccountID, value: Balance) { let from_key = transactor.to_keyed_vec(b"sta\0bal\0"); - let from_balance: Balance = storage_into(&from_key); + let from_balance: Balance = Storage::into(&from_key); assert!(from_balance >= value); let to_key = dest.to_keyed_vec(b"sta\0bal\0"); - let to_balance: Balance = storage_into(&to_key); + let to_balance: Balance = Storage::into(&to_key); assert!(to_balance + value > to_balance); // no overflow (from_balance - value).store(&from_key); (to_balance + value).store(&to_key); diff --git a/substrate/wasm-runtime/polkadot/src/runtime/system.rs b/substrate/wasm-runtime/polkadot/src/runtime/system.rs index 27c5eb4fd9..3c4d020dee 100644 --- a/substrate/wasm-runtime/polkadot/src/runtime/system.rs +++ b/substrate/wasm-runtime/polkadot/src/runtime/system.rs @@ -1,4 +1,4 @@ -use primitives::{Block, BlockNumber, Hash, Transaction}; +use primitives::{Block, BlockNumber, Hash, UncheckedTransaction}; use runtime_support::{Vec, swap}; use environment::with_env; use runtime_support; @@ -53,7 +53,7 @@ fn final_checks(_block: &Block) { } /// Execute a given transaction. -pub fn execute_transaction(_tx: &Transaction) -> Vec { +pub fn execute_transaction(_tx: &UncheckedTransaction) -> Vec { // TODO: decode data and ensure valid // TODO: ensure signature valid and recover id (use authentication::authenticate) // TODO: check nonce @@ -61,7 +61,7 @@ pub fn execute_transaction(_tx: &Transaction) -> Vec { // TODO: ensure target_function valid // TODO: decode parameters - _tx.function.dispatch(&_tx.signed, &_tx.input_data); + _tx.transaction.function.dispatch(&_tx.transaction.signed, &_tx.transaction.input_data); // TODO: encode any return Vec::new() @@ -78,7 +78,7 @@ mod tests { use function::Function; use std::collections::HashMap; use runtime_support::{NoError, with_externalities, Externalities}; - use primitives::{AccountID, Transaction}; + use primitives::{AccountID, UncheckedTransaction, Transaction}; use runtime::{system, staking}; #[derive(Debug, Default)] @@ -114,11 +114,14 @@ mod tests { { let mut r = b"sta\0bal\0".to_vec(); r.extend_from_slice(&one); r } => vec![111u8, 0, 0, 0, 0, 0, 0, 0] ], }; - let tx = Transaction { - signed: one.clone(), - function: Function::StakingTransferStake, - input_data: vec![].join(&two).join(&69u64), - nonce: 0, + let tx = UncheckedTransaction { + transaction: Transaction { + signed: one.clone(), + nonce: 0, + function: Function::StakingTransferStake, + input_data: vec![].join(&two).join(&69u64), + }, + signature: [1u8; 64], }; with_externalities(&mut t, || { diff --git a/substrate/wasm-runtime/polkadot/src/runtime/timestamp.rs b/substrate/wasm-runtime/polkadot/src/runtime/timestamp.rs index 6a4043651d..6d694c88ae 100644 --- a/substrate/wasm-runtime/polkadot/src/runtime/timestamp.rs +++ b/substrate/wasm-runtime/polkadot/src/runtime/timestamp.rs @@ -1,9 +1,10 @@ use primitives::Timestamp; +use storage::Storage; pub fn timestamp() -> Timestamp { - unimplemented!() + Storage::into(b"tim\0val") } -pub fn set_timestamp(_now: Timestamp) { - unimplemented!() +pub fn set_timestamp(now: Timestamp) { + now.store(b"tim\0val") } diff --git a/substrate/wasm-runtime/polkadot/src/support/primitives.rs b/substrate/wasm-runtime/polkadot/src/support/primitives.rs index f1bd31cc66..bb82da8f3b 100644 --- a/substrate/wasm-runtime/polkadot/src/support/primitives.rs +++ b/substrate/wasm-runtime/polkadot/src/support/primitives.rs @@ -5,10 +5,13 @@ use slicable::{Slicable, NonTrivialSlicable}; use function::Function; use runtime_support::size_of; -/// The hash of an ECDSA pub key which is used to identify an external transactor. +#[cfg(test)] +use std::fmt; + +/// The Ed25519 pubkey that identifies an account. pub type AccountID = [u8; 32]; -/// The ECDSA pub key of an authority. This is what the external environment/consensus algorithm -/// refers to as a "authority". +/// The Ed25519 pub key of an session that belongs to an authority. This is used as what the +/// external environment/consensus algorithm calls an "authority". pub type SessionKey = AccountID; pub type Balance = u64; pub type ChainID = u64; @@ -36,15 +39,9 @@ pub struct Header { #[cfg_attr(test, derive(PartialEq, Debug))] pub struct Transaction { pub signed: AccountID, + pub nonce: TxOrder, pub function: Function, pub input_data: Vec, - pub nonce: TxOrder, -} - -#[cfg_attr(test, derive(PartialEq, Debug))] -pub struct Block { - pub header: Header, - pub transactions: Vec, } impl Slicable for Transaction { @@ -52,8 +49,8 @@ impl Slicable for Transaction { let mut reader = StreamReader::new(value); Some(Transaction { signed: reader.read()?, - function: Function::from_u8(reader.read()?)?, nonce: reader.read()?, + function: Function::from_u8(reader.read()?)?, input_data: reader.read()?, }) } @@ -65,13 +62,13 @@ impl Slicable for Transaction { fn to_vec(&self) -> Vec { Vec::new() .join(&self.signed) - .join(&(self.function as u8)) .join(&self.nonce) + .join(&(self.function as u8)) .join(&self.input_data) } fn size_of(data: &[u8]) -> Option { - let first_part = size_of::() + size_of::() + size_of::(); + let first_part = size_of::() + size_of::() + size_of::(); let second_part = >::size_of(&data[first_part..])?; Some(first_part + second_part) } @@ -79,6 +76,59 @@ impl Slicable for Transaction { impl NonTrivialSlicable for Transaction {} +pub struct UncheckedTransaction { + pub transaction: Transaction, + pub signature: [u8; 64], +} + +#[cfg(test)] +impl PartialEq for UncheckedTransaction { + fn eq(&self, other: &Self) -> bool { + self.signature.iter().eq(other.signature.iter()) && self.transaction == other.transaction + } +} + +#[cfg(test)] +impl fmt::Debug for UncheckedTransaction { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "UncheckedTransaction({:?})", self.transaction) + } +} + +impl Slicable for UncheckedTransaction { + fn from_slice(value: &[u8]) -> Option { + let mut reader = StreamReader::new(value); + Some(UncheckedTransaction { + signature: reader.read()?, + transaction: reader.read()?, + }) + } + + fn set_as_slice bool>(_fill_slice: F) -> Option { + unimplemented!(); + } + + fn to_vec(&self) -> Vec { + Vec::new() + .join(&self.signature) + .join(&self.transaction) + } + + fn size_of(data: &[u8]) -> Option { + let first_part = size_of::<[u8; 64]>(); + let second_part = ::size_of(&data[first_part..])?; + Some(first_part + second_part) + } +} + +impl NonTrivialSlicable for UncheckedTransaction {} + +#[cfg_attr(test, derive(PartialEq, Debug))] +pub struct Block { + pub header: Header, + pub transactions: Vec, +} + impl NonTrivialSlicable for Vec where Vec: Slicable {} impl Slicable for Vec { @@ -181,15 +231,15 @@ mod tests { let two: AccountID = [2u8; 32]; let tx = Transaction { signed: one.clone(), + nonce: 69, function: Function::StakingTransferStake, input_data: Vec::new().join(&two).join(&69u64), - nonce: 69, }; let serialised = tx.to_vec(); assert_eq!(serialised, vec![ 1u8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 2, 69, 0, 0, 0, 0, 0, 0, 0, + 2, 40, 0, 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 69, 0, 0, 0, 0, 0, 0, 0 @@ -202,14 +252,14 @@ mod tests { let two: AccountID = [2u8; 32]; let tx = Transaction { signed: one.clone(), + nonce: 69, function: Function::StakingTransferStake, input_data: Vec::new().join(&two).join(&69u64), - nonce: 69, }; let data = [ 1u8, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 2, 69, 0, 0, 0, 0, 0, 0, 0, + 2, 40, 0, 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 69, 0, 0, 0, 0, 0, 0, 0 @@ -269,17 +319,23 @@ mod tests { fn serialise_block_works() { let one: AccountID = [1u8; 32]; let two: AccountID = [2u8; 32]; - let tx1 = Transaction { - signed: one.clone(), - function: Function::StakingTransferStake, - input_data: Vec::new().join(&two).join(&69u64), - nonce: 69, + let tx1 = UncheckedTransaction { + transaction: Transaction { + signed: one.clone(), + nonce: 69, + function: Function::StakingTransferStake, + input_data: Vec::new().join(&two).join(&69u64), + }, + signature: [1u8; 64], }; - let tx2 = Transaction { - signed: two.clone(), - function: Function::StakingStake, - input_data: Vec::new(), - nonce: 42, + let tx2 = UncheckedTransaction { + transaction: Transaction { + signed: two.clone(), + nonce: 42, + function: Function::StakingStake, + input_data: Vec::new(), + }, + signature: [2u8; 64], }; let h = Header { parent_hash: [4u8; 32], @@ -305,18 +361,20 @@ mod tests { 11, 0, 0, 0, 97, 110, 111, 116, 104, 101, 114, 32, 108, 111, 103, // transactions - 130, 0, 0, 0, + 2, 1, 0, 0, // tx1 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 2, 69, 0, 0, 0, 0, 0, 0, 0, + 2, 40, 0, 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 69, 0, 0, 0, 0, 0, 0, 0, // tx2 + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 0, 42, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0 ]); } @@ -325,17 +383,23 @@ mod tests { fn deserialise_block_works() { let one: AccountID = [1u8; 32]; let two: AccountID = [2u8; 32]; - let tx1 = Transaction { - signed: one.clone(), - function: Function::StakingTransferStake, - input_data: Vec::new().join(&two).join(&69u64), - nonce: 69, + let tx1 = UncheckedTransaction { + transaction: Transaction { + signed: one.clone(), + nonce: 69, + function: Function::StakingTransferStake, + input_data: Vec::new().join(&two).join(&69u64), + }, + signature: [1u8; 64], }; - let tx2 = Transaction { - signed: two.clone(), - function: Function::StakingStake, - input_data: Vec::new(), - nonce: 42, + let tx2 = UncheckedTransaction { + transaction: Transaction { + signed: two.clone(), + nonce: 42, + function: Function::StakingStake, + input_data: Vec::new(), + }, + signature: [2u8; 64], }; let h = Header { parent_hash: [4u8; 32], @@ -360,18 +424,20 @@ mod tests { 11, 0, 0, 0, 97, 110, 111, 116, 104, 101, 114, 32, 108, 111, 103, // transactions - 130, 0, 0, 0, + 2, 1, 0, 0, // tx1 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 2, 69, 0, 0, 0, 0, 0, 0, 0, + 2, 40, 0, 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 69, 0, 0, 0, 0, 0, 0, 0, // tx2 + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 0, 42, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0 ]; let deserialised = Block::from_slice(&data).unwrap(); diff --git a/substrate/wasm-runtime/polkadot/src/support/storage.rs b/substrate/wasm-runtime/polkadot/src/support/storage.rs index 13a9074d95..99c8bab880 100644 --- a/substrate/wasm-runtime/polkadot/src/support/storage.rs +++ b/substrate/wasm-runtime/polkadot/src/support/storage.rs @@ -3,12 +3,12 @@ use endiansensitive::EndianSensitive; use runtime_support; pub trait Storage { - fn storage_into(key: &[u8]) -> Self; + fn into(key: &[u8]) -> Self; fn store(&self, key: &[u8]); } impl Storage for T { - fn storage_into(key: &[u8]) -> Self { + fn into(key: &[u8]) -> Self { Slicable::set_as_slice(|out| runtime_support::read_storage(key, out) == out.len()) .unwrap_or_else(Default::default) } @@ -19,5 +19,5 @@ impl Storage for T { } pub fn storage_into(key: &[u8]) -> T { - T::storage_into(key) + T::into(key) }