Newer
Older
Gav
committed
#![cfg_attr(feature = "without-std", no_std)]
#![cfg_attr(feature = "strict", deny(warnings))]
#[macro_use]
extern crate runtime_support;
use runtime_support::{Vec, size_of, Rc, RefCell, transmute, swap, Box};
/// The hash of an ECDSA pub key which is used to identify an external transactor.
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".
pub type SessionKey = AccountID;
pub type Balance = u64;
pub type ChainID = u64;
pub type Hash = [u8; 32];
pub type BlockNumber = u64;
pub type Timestamp = u64;
pub type TxOrder = u64;
/// The functions that a transaction can call (and be dispatched to).
#[cfg_attr(test, derive(PartialEq, Debug))]
#[derive(Clone, Copy)]
impl Function {
fn from_u8(value: u8) -> Option<Function> {
match value {
x if x == Function::StakingStake as u8 => Some(Function::StakingStake),
x if x == Function::StakingUnstake as u8 => Some(Function::StakingUnstake),
x if x == Function::StakingTransferStake as u8 => Some(Function::StakingTransferStake),
x if x == Function::ConsensusSetSessionKey as u8 => Some(Function::ConsensusSetSessionKey),
_ => None,
}
}
}
struct StreamReader<'a> {
data: &'a[u8],
offset: usize,
}
impl<'a> StreamReader<'a> {
fn new(data: &'a[u8]) -> Self {
StreamReader {
data: data,
offset: 0,
}
}
fn read<T: Slicable>(&mut self) -> Option<T> {
let size = T::size_of(&self.data[self.offset..])?;
let new_offset = self.offset + size;
let slice = &self.data[self.offset..new_offset];
self.offset = new_offset;
Slicable::from_slice(slice)
}
}
/*
// Not in use yet
// TODO: introduce fn size_will_be(&self) -> usize; to Slicable trait and implement
struct StreamWriter<'a> {
data: &'a mut[u8],
offset: usize,
}
impl<'a> StreamWriter<'a> {
fn new(data: &'a mut[u8]) -> Self {
StreamWriter {
data: data,
offset: 0,
}
}
fn write<T: Slicable>(&mut self, value: &T) -> bool {
value.as_slice_then(|s| {
let new_offset = self.offset + s.len();
if self.data.len() <= new_offset {
self.offset = new_offset;
slice.copy_from_slice(s);
true
} else {
false
}
})
}
}
trait Joiner {
fn join<T: Slicable + Sized>(self, value: &T) -> Self;
}
impl Joiner for Vec<u8> {
fn join<T: Slicable + Sized>(mut self, value: &T) -> Vec<u8> {
value.as_slice_then(|s| self.extend_from_slice(s));
self
}
}
impl Function {
/// Dispatch the function.
pub fn dispatch(&self, transactor: &AccountID, data: &[u8]) {
let mut params = StreamReader::new(data);
match *self {
Function::StakingStake => {
staking::stake(transactor);
}
Function::StakingUnstake => {
staking::unstake(transactor);
}
let dest = params.read().unwrap();
let value = params.read().unwrap();
staking::transfer_stake(transactor, &dest, value);
}
let session = params.read().unwrap();
consensus::set_session_key(transactor, &session);
pub struct Digest {
pub logs: Vec<Vec<u8>>,
pub struct Header {
pub parent_hash: Hash,
pub number: BlockNumber,
pub state_root: Hash,
pub transaction_root: Hash,
pub digest: Digest,
pub function: Function,
pub input_data: Vec<u8>,
pub nonce: TxOrder,
pub struct Block {
pub header: Header,
pub transactions: Vec<Transaction>,
}
impl Header {
pub fn from_rlp(_rlp: &[u8]) -> Self {
unimplemented!()
}
}
impl Transaction {
pub fn from_rlp(_rlp: &[u8]) -> Self {
unimplemented!()
}
}
impl Block {
pub fn from_rlp(_rlp: &[u8]) -> Self {
unimplemented!()
}
}
#[derive(Default)]
struct Environment {
digest: Digest,
next_log_index: usize,
fn with_env<T, F: FnOnce(&mut Environment) -> T>(f: F) -> T {
let e = env();
let mut eb = e.borrow_mut();
f(&mut *eb)
}
static mut SINGLETON: *const Rc<RefCell<Environment>> = 0 as *const Rc<RefCell<Environment>>;
if SINGLETON == 0 as *const Rc<RefCell<Environment>> {
let singleton: Rc<RefCell<Environment>> = Rc::new(RefCell::new(Default::default()));
// Put it in the heap so it can outlive this call
// Now we give out a copy of the data that is safe to use concurrently.
(*SINGLETON).clone()
}
}
trait EndianSensitive: Sized {
fn to_le(self) -> Self { self }
fn to_be(self) -> Self { self }
fn from_le(self) -> Self { self }
fn from_be(self) -> Self { self }
fn as_be_then<T, F: FnOnce(&Self) -> T>(&self, f: F) -> T { f(&self) }
fn as_le_then<T, F: FnOnce(&Self) -> T>(&self, f: F) -> T { f(&self) }
}
macro_rules! impl_endians {
( $( $t:ty ),* ) => { $(
impl EndianSensitive for $t {
fn to_le(self) -> Self { <$t>::to_le(self) }
fn to_be(self) -> Self { <$t>::to_be(self) }
fn from_le(self) -> Self { <$t>::from_le(self) }
fn from_be(self) -> Self { <$t>::from_be(self) }
fn as_be_then<T, F: FnOnce(&Self) -> T>(&self, f: F) -> T { let d = self.to_be(); f(&d) }
fn as_le_then<T, F: FnOnce(&Self) -> T>(&self, f: F) -> T { let d = self.to_le(); f(&d) }
}
)* }
}
macro_rules! impl_non_endians {
( $( $t:ty ),* ) => { $(
impl EndianSensitive for $t {}
)* }
}
impl_endians!(u16, u32, u64, usize, i16, i32, i64, isize);
impl_non_endians!(u8, i8, [u8; 20], [u8; 32]);
trait Storage {
fn storage_into(key: &[u8]) -> Self;
impl<T: Default + Sized + EndianSensitive> Storage for T {
Slicable::set_as_slice(|out| runtime_support::read_storage(key, out) == out.len())
fn store(&self, key: &[u8]) {
self.as_slice_then(|slice| runtime_support::set_storage(key, slice));
}
}
fn storage_into<T: Storage>(key: &[u8]) -> T {
T::storage_into(key)
}
/// Trait that allows zero-copy read/write of value-references to/from slices in LE format.
trait Slicable: Sized {
fn from_slice(value: &[u8]) -> Option<Self> {
Self::set_as_slice(|out| if value.len() == out.len() {
out.copy_from_slice(&value);
true
} else {
false
})
}
fn to_vec(&self) -> Vec<u8> {
self.as_slice_then(|s| s.to_vec())
}
fn set_as_slice<F: FnOnce(&mut[u8]) -> bool>(set_slice: F) -> Option<Self>;
fn as_slice_then<R, F: FnOnce(&[u8]) -> R>(&self, f: F) -> R {
f(&self.to_vec())
}
impl<T: EndianSensitive> Slicable for T {
fn set_as_slice<F: FnOnce(&mut[u8]) -> bool>(fill_slice: F) -> Option<Self> {
let mut result: T = unsafe { std::mem::uninitialized() };
let result_slice = unsafe {
std::slice::from_raw_parts_mut(transmute::<*mut T, *mut u8>(&mut result), size)
};
if fill_slice(result_slice) {
Some(result.from_le())
fn as_slice_then<R, F: FnOnce(&[u8]) -> R>(&self, f: F) -> R {
let size = size_of::<Self>();
self.as_le_then(|le| {
let value_slice = unsafe {
std::slice::from_raw_parts(transmute::<*const Self, *const u8>(le), size)
};
f(value_slice)
})
}
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
fn size_of(_value: &[u8]) -> Option<usize> {
Some(size_of::<Self>())
}
}
impl Slicable for Vec<u8> {
fn from_slice(value: &[u8]) -> Option<Self> {
Some(value[4..].to_vec())
}
fn set_as_slice<F: FnOnce(&mut[u8]) -> bool>(_fill_slice: F) -> Option<Self> {
unimplemented!();
}
fn to_vec(&self) -> Vec<u8> {
let mut r = vec![].join(&(self.len() as u32));
r.extend_from_slice(&self);
r
}
fn size_of(data: &[u8]) -> Option<usize> {
u32::from_slice(&data[0..4]).map(|i| (i + 4) as usize)
}
}
impl Slicable for Transaction {
fn from_slice(value: &[u8]) -> Option<Self> {
let mut reader = StreamReader::new(value);
Some(Transaction {
signed: reader.read()?,
function: Function::from_u8(reader.read()?)?,
nonce: reader.read()?,
input_data: reader.read()?,
})
}
fn set_as_slice<F: FnOnce(&mut[u8]) -> bool>(_fill_slice: F) -> Option<Self> {
unimplemented!();
}
fn to_vec(&self) -> Vec<u8> {
vec![]
.join(&self.signed)
.join(&(self.function as u8))
.join(&self.nonce)
.join(&self.input_data)
}
fn size_of(data: &[u8]) -> Option<usize> {
let first_part = size_of::<AccountID>() + size_of::<u8>() + size_of::<TxOrder>();
let second_part = <Vec<u8>>::size_of(&data[first_part..])?;
Some(first_part + second_part)
}
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
impl NonTrivialSlicable for Transaction {}
impl<T: Slicable> NonTrivialSlicable for Vec<T> where Vec<T>: Slicable {}
impl<T: NonTrivialSlicable> Slicable for Vec<T> {
fn from_slice(value: &[u8]) -> Option<Self> {
let len = Self::size_of(&value[0..4])?;
let mut off = 4;
let mut r = vec![];
while off < len {
let element_len = T::size_of(&value[off..])?;
r.push(T::from_slice(&value[off..off + element_len])?);
off += element_len;
}
Some(r)
}
fn set_as_slice<F: FnOnce(&mut[u8]) -> bool>(_fill_slice: F) -> Option<Self> {
unimplemented!();
}
fn to_vec(&self) -> Vec<u8> {
let vecs = self.iter().map(Slicable::to_vec).collect::<Vec<_>>();
let len = vecs.iter().fold(0, |mut a, v| {a += v.len(); a});
let mut r = vec![].join(&(len as u32));
vecs.iter().for_each(|v| r.extend_from_slice(v));
r
}
fn size_of(data: &[u8]) -> Option<usize> {
u32::from_slice(&data[0..4]).map(|i| (i + 4) as usize)
}
}
impl Slicable for Header {
fn from_slice(value: &[u8]) -> Option<Self> {
let mut reader = StreamReader::new(value);
Some(Header {
parent_hash: reader.read()?,
number: reader.read()?,
state_root: reader.read()?,
transaction_root: reader.read()?,
digest: Digest { logs: reader.read()?, },
})
}
fn set_as_slice<F: FnOnce(&mut[u8]) -> bool>(_fill_slice: F) -> Option<Self> {
unimplemented!();
}
fn to_vec(&self) -> Vec<u8> {
vec![]
.join(&self.parent_hash)
.join(&self.number)
.join(&self.state_root)
.join(&self.transaction_root)
.join(&self.digest.logs)
}
fn size_of(data: &[u8]) -> Option<usize> {
let first_part = size_of::<Hash>() + size_of::<BlockNumber>() + size_of::<Hash>() + size_of::<Hash>();
let second_part = <Vec<Vec<u8>>>::size_of(&data[first_part..])?;
Some(first_part + second_part)
}
}
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
impl Slicable for Block {
fn from_slice(value: &[u8]) -> Option<Self> {
let mut reader = StreamReader::new(value);
Some(Block {
header: reader.read()?,
transactions: reader.read()?,
})
}
fn set_as_slice<F: FnOnce(&mut[u8]) -> bool>(_fill_slice: F) -> Option<Self> {
unimplemented!();
}
fn to_vec(&self) -> Vec<u8> {
vec![]
.join(&self.header)
.join(&self.transactions)
}
fn size_of(data: &[u8]) -> Option<usize> {
let first_part = Header::size_of(data)?;
let second_part = <Vec<Transaction>>::size_of(&data[first_part..])?;
Some(first_part + second_part)
}
}
trait KeyedVec {
fn to_keyed_vec(&self, prepend_key: &[u8]) -> Vec<u8>;
}
impl KeyedVec for AccountID {
fn to_keyed_vec(&self, prepend_key: &[u8]) -> Vec<u8> {
let mut r = prepend_key.to_vec();
r.extend_from_slice(self);
r
}
}
macro_rules! impl_endians {
( $( $t:ty ),* ) => { $(
impl KeyedVec for $t {
fn to_keyed_vec(&self, prepend_key: &[u8]) -> Vec<u8> {
self.as_slice_then(|slice| {
let mut r = prepend_key.to_vec();
r.extend_from_slice(slice);
r
})
}
}
)* }
}
impl_endians!(u16, u32, u64, usize, i16, i32, i64, isize);
// TODO: add keccak256 (or some better hashing scheme) & ECDSA-recover (or some better sig scheme)
pub fn execute_block(input: Vec<u8>) -> Vec<u8> {
environment::execute_block(Block::from_slice(&input).unwrap())
pub fn execute_transaction(input: Vec<u8>) -> Vec<u8> {
environment::execute_transaction(&Transaction::from_slice(&input).unwrap())
impl_stubs!(execute_block, execute_transaction);
/// The current relay chain identifier.
// TODO: retrieve from external
unimplemented!()
}
/// The current block number being processed. Set by `execute_block`.
pub fn block_number() -> BlockNumber {
with_env(|e| e.block_number)
}
/// Get the block hash of a given block (uses storage).
pub fn block_hash(_number: BlockNumber) -> Hash {
unimplemented!()
}
/// Deposits a log and ensures it matches the blocks log data.
pub fn deposit_log(log: &[u8]) {
with_env(|e| {
assert_eq!(log, &e.digest.logs[e.next_log_index][..]);
e.next_log_index += 1;
});
}
pub fn execute_block(mut block: Block) -> Vec<u8> {
with_env(|e| {
e.block_number = block.header.number;
swap(&mut e.digest, &mut block.header.digest);
e.next_log_index = 0;
});
// TODO: check transaction trie root represents the transactions.
// TODO: store the header hash in storage.
block.transactions.iter().for_each(|tx| { execute_transaction(tx); });
final_checks(&block);
// TODO: check state root somehow
fn final_checks(_block: &Block) {
with_env(|e| {
assert_eq!(e.next_log_index, e.digest.logs.len());
});
}
pub fn execute_transaction(_tx: &Transaction) -> Vec<u8> {
// TODO: decode data and ensure valid
// TODO: ensure signature valid and recover id (use authentication::authenticate)
// TODO: check nonce
// TODO: increment nonce in storage
// TODO: ensure target_function valid
// TODO: decode parameters
_tx.function.dispatch(&_tx.signed, &_tx.input_data);
// TODO: encode any return
Vec::new()
}
/// Set the new code.
pub fn set_code(new: &[u8]) {
pub fn set_authority(index: u32, authority: AccountID) {
authority.store(&index.to_keyed_vec(b"con\0aut\0"));
storage_into(&index.to_keyed_vec(b"con\0aut\0"))
(count..authority_count()).for_each(|i| set_authority(i, SessionKey::default()));
count.store(b"con\0aut\0len");
storage_into(b"con\0aut\0len")
}
/// Get the current set of authorities. These are the session keys.
pub fn authorities() -> Vec<AccountID> {
(0..authority_count()).into_iter().map(authority).collect()
/// Set the current set of authorities' session keys.
///
/// Called by `next_session` only.
pub fn set_authorities(authorities: &[AccountID]) {
set_authority_count(authorities.len() as u32);
authorities.iter().enumerate().for_each(|(v, &i)| set_authority(v as u32, i));
/// Get the current set of validators. These are the long-term identifiers for the validators
/// and will be mapped to a session key with the most recent `set_next_session_key`.
pub fn validators() -> Vec<AccountID> {
unimplemented!()
}
/// Set the current set of validators.
///
/// Called by staking::next_era() only.
pub fn set_validators(_new: &[AccountID]) {
unimplemented!()
}
Gav
committed
/// The number of blocks in each session.
pub fn session_length() -> BlockNumber {
Gav
committed
}
/// Sets the session key of `_transactor` to `_session`. This doesn't take effect until the next
pub fn set_session_key(_transactor: &AccountID, _session: &AccountID) {
unimplemented!()
}
/// Move onto next session: register the new authority set.
pub fn next_session() {
// TODO: Call set_authorities().
unimplemented!()
}
/// Hook to be called prior to transaction processing.
pub fn pre_transactions() {}
/// Hook to be called after to transaction processing.
pub fn post_transactions() {
// TODO: check block number and call next_session if necessary.
}
/// The length of a staking era in blocks.
pub fn era_length() -> BlockNumber {
sessions_per_era() * consensus::session_length()
}
Gav
committed
/// The length of a staking era in sessions.
/// The era has changed - enact new staking set.
///
Gav
committed
/// NOTE: This always happens on a session change.
/// The balance of a given account.
pub fn balance(who: &AccountID) -> Balance {
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);
assert!(from_balance >= value);
let to_key = dest.to_keyed_vec(b"sta\0bal\0");
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);
}
///
/// Effects will be felt at the beginning of the next era.
pub fn stake(_transactor: &AccountID) {
unimplemented!()
}
///
/// Effects will be felt at the beginning of the next era.
pub fn unstake(_transactor: &AccountID) {
unimplemented!()
}
/// Hook to be called prior to transaction processing.
pub fn pre_transactions() {
/// Hook to be called after to transaction processing.
pub fn post_transactions() {
// TODO: check block number and call next_era if necessary.
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
pub fn timestamp() -> Timestamp {
unimplemented!()
}
pub fn set_timestamp(_now: Timestamp) {
unimplemented!()
}
}
#[cfg(test)]
mod tests {
use super::*;
use std::collections::HashMap;
use runtime_support::{NoError, with_externalities, Externalities};
#[derive(Debug, Default)]
struct TestExternalities {
storage: HashMap<Vec<u8>, Vec<u8>>,
}
impl Externalities for TestExternalities {
type Error = NoError;
fn storage(&self, key: &[u8]) -> Result<&[u8], NoError> {
Ok(self.storage.get(&key.to_vec()).map_or(&[] as &[u8], Vec::as_slice))
}
fn set_storage(&mut self, key: Vec<u8>, value: Vec<u8>) {
self.storage.insert(key, value);
}
}
macro_rules! map {
($( $name:expr => $value:expr ),*) => (
vec![ $( ( $name, $value ) ),* ].into_iter().collect()
)
}
#[test]
fn staking_balance_works() {
let one: AccountID = [1u8; 32];
let two: AccountID = [2u8; 32];
let mut t = TestExternalities { storage: map![
{ let mut r = b"sta\0bal\0".to_vec(); r.extend_from_slice(&one); r } => vec![42u8, 0, 0, 0, 0, 0, 0, 0]
], };
with_externalities(&mut t, || {
assert_eq!(staking::balance(&one), 42);
assert_eq!(staking::balance(&two), 0);
});
}
#[test]
fn staking_balance_transfer_works() {
let one: AccountID = [1u8; 32];
let two: AccountID = [2u8; 32];
let mut t = TestExternalities { storage: map![
{ let mut r = b"sta\0bal\0".to_vec(); r.extend_from_slice(&one); r } => vec![111u8, 0, 0, 0, 0, 0, 0, 0]
], };
with_externalities(&mut t, || {
staking::transfer_stake(&one, &two, 69);
assert_eq!(staking::balance(&one), 42);
assert_eq!(staking::balance(&two), 69);
});
}
#[test]
fn staking_balance_transfer_dispatch_works() {
let one: AccountID = [1u8; 32];
let two: AccountID = [2u8; 32];
let mut t = TestExternalities { storage: map![
{ 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,
};
with_externalities(&mut t, || {
environment::execute_transaction(&tx);
assert_eq!(staking::balance(&one), 42);
assert_eq!(staking::balance(&two), 69);
});
}
#[test]
fn serialise_transaction_works() {
let one: AccountID = [1u8; 32];
let two: AccountID = [2u8; 32];
let tx = Transaction {
signed: one.clone(),
function: Function::StakingTransferStake,
input_data: vec![].join(&two).join(&69u64),
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,
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
]);
}
#[test]
fn deserialise_transaction_works() {
let one: AccountID = [1u8; 32];
let two: AccountID = [2u8; 32];
let tx = Transaction {
signed: one.clone(),
function: Function::StakingTransferStake,
input_data: vec![].join(&two).join(&69u64),
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,
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
];
let deserialised = Transaction::from_slice(&data).unwrap();
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
#[test]
fn serialise_header_works() {
let h = Header {
parent_hash: [4u8; 32],
number: 42,
state_root: [5u8; 32],
transaction_root: [6u8; 32],
digest: Digest { logs: vec![ b"one log".to_vec(), b"another log".to_vec() ], },
};
let serialised = h.to_vec();
assert_eq!(serialised, vec![
4u8, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
42, 0, 0, 0, 0, 0, 0, 0,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
26, 0, 0, 0,
7, 0, 0, 0,
111, 110, 101, 32, 108, 111, 103,
11, 0, 0, 0,
97, 110, 111, 116, 104, 101, 114, 32, 108, 111, 103
]);
}
#[test]
fn deserialise_header_works() {
let h = Header {
parent_hash: [4u8; 32],
number: 42,
state_root: [5u8; 32],
transaction_root: [6u8; 32],
digest: Digest { logs: vec![ b"one log".to_vec(), b"another log".to_vec() ], },
};
let data = [
4u8, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
42, 0, 0, 0, 0, 0, 0, 0,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
26, 0, 0, 0,
7, 0, 0, 0,
111, 110, 101, 32, 108, 111, 103,
11, 0, 0, 0,
97, 110, 111, 116, 104, 101, 114, 32, 108, 111, 103
];
let deserialised = Header::from_slice(&data).unwrap();
assert_eq!(deserialised, h);
}
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
#[test]
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![].join(&two).join(&69u64),
nonce: 69,
};
let tx2 = Transaction {
signed: two.clone(),
function: Function::StakingStake,
input_data: vec![],
nonce: 42,
};
let h = Header {
parent_hash: [4u8; 32],
number: 42,
state_root: [5u8; 32],
transaction_root: [6u8; 32],
digest: Digest { logs: vec![ b"one log".to_vec(), b"another log".to_vec() ], },
};
let b = Block {
header: h,
transactions: vec![tx1, tx2],
};
let serialised = b.to_vec();
assert_eq!(serialised, vec![
// header
4u8, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
42, 0, 0, 0, 0, 0, 0, 0,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
26, 0, 0, 0,
7, 0, 0, 0,
111, 110, 101, 32, 108, 111, 103,
11, 0, 0, 0,
97, 110, 111, 116, 104, 101, 114, 32, 108, 111, 103,
// transactions
130, 0, 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,
2,
69, 0, 0, 0, 0, 0, 0, 0,
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,
0,
42, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0
]);
}
#[test]
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![].join(&two).join(&69u64),
nonce: 69,
};
let tx2 = Transaction {
signed: two.clone(),
function: Function::StakingStake,
input_data: vec![],
nonce: 42,
};
let h = Header {
parent_hash: [4u8; 32],
number: 42,
state_root: [5u8; 32],
transaction_root: [6u8; 32],
digest: Digest { logs: vec![ b"one log".to_vec(), b"another log".to_vec() ], },
};
let b = Block {
header: h,
transactions: vec![tx1, tx2],
};
let data = [
// header
4u8, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
42, 0, 0, 0, 0, 0, 0, 0,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
26, 0, 0, 0,
7, 0, 0, 0,
111, 110, 101, 32, 108, 111, 103,
11, 0, 0, 0,
97, 110, 111, 116, 104, 101, 114, 32, 108, 111, 103,
// transactions
130, 0, 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,
2,
69, 0, 0, 0, 0, 0, 0, 0,
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,
0,
42, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0
];
let deserialised = Block::from_slice(&data).unwrap();
assert_eq!(deserialised, b);
}