Introduce UncheckedTransaction & test.

This commit is contained in:
Gav
2018-01-18 15:14:01 +01:00
parent 712becb205
commit 92d8712b2b
8 changed files with 143 additions and 71 deletions
@@ -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]);
+4 -3
View File
@@ -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<u8>) -> Vec<u8> {
}
pub fn execute_transaction(input: Vec<u8>) -> Vec<u8> {
runtime::system::execute_transaction(&Transaction::from_slice(&input).unwrap())
runtime::system::execute_transaction(&UncheckedTransaction::from_slice(&input).unwrap())
}
impl_stubs!(execute_block, execute_transaction);
@@ -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
@@ -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);
@@ -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<u8> {
pub fn execute_transaction(_tx: &UncheckedTransaction) -> Vec<u8> {
// 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<u8> {
// 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, || {
@@ -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")
}
@@ -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<u8>,
pub nonce: TxOrder,
}
#[cfg_attr(test, derive(PartialEq, Debug))]
pub struct Block {
pub header: Header,
pub transactions: Vec<Transaction>,
}
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<u8> {
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<usize> {
let first_part = size_of::<AccountID>() + size_of::<u8>() + size_of::<TxOrder>();
let first_part = size_of::<AccountID>() + size_of::<TxOrder>() + size_of::<u8>();
let second_part = <Vec<u8>>::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<Self> {
let mut reader = StreamReader::new(value);
Some(UncheckedTransaction {
signature: reader.read()?,
transaction: reader.read()?,
})
}
fn set_as_slice<F: FnOnce(&mut[u8]) -> bool>(_fill_slice: F) -> Option<Self> {
unimplemented!();
}
fn to_vec(&self) -> Vec<u8> {
Vec::new()
.join(&self.signature)
.join(&self.transaction)
}
fn size_of(data: &[u8]) -> Option<usize> {
let first_part = size_of::<[u8; 64]>();
let second_part = <Transaction>::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<UncheckedTransaction>,
}
impl<T: Slicable> NonTrivialSlicable for Vec<T> where Vec<T>: Slicable {}
impl<T: NonTrivialSlicable> Slicable for Vec<T> {
@@ -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();
@@ -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<T: Default + Sized + EndianSensitive> 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<T: Default + Sized + EndianSensitive> Storage for T {
}
pub fn storage_into<T: Storage>(key: &[u8]) -> T {
T::storage_into(key)
T::into(key)
}