Introduce basic skeleton for Polkadot runtime. (#32)

* Introduce basic skeleton for Polkador runtime.

* Clean up the runtime skeleton.

* Make initial runtime skeleton compile.

* Compile polkadot-runtime both for Wasm ad native, allowing for testing and direct usage.

* More fleshing out on runtime.

* Update native support.

* Fix warning.

* Update gitignore

* Update path.

* Fix path.

* Remove accidentally committed files.

* Add wasm binaries.

* Fix test.

* Native storage support API.

* Add environmental module

* Add native environment to make native source-code compatible with wasm.

Also tests.

* Finish up & polish environment stuff.

* Avoid using reentrancy issues.

* Add some docs and a test.

* Remove unneeded function.

* Documentation

* Tweak docs

* Remove TODOs.

* Balance transfers + util methods.

* Rejig tests and ensure authorities are addressed consistently.

* Add marshaller for xfer function

* Transaction dispatch test.

* Minor fix.

* Add test for ser/de transaction.

* Add ser/de for header.

* Add tests for header ser/de

* Introduce basic block decoding/execution framework.

* Introduce block decoding/execution framework (p2)

* Big refactor.

* Split out joiner.

* Hide away support modules.

* Fix up wasm runtime.

* use externalities for chain_id

* Clean up (Test)Externalities.

* Repot and introduce keccak-256 external.

* Signing with crypto.

* fix unsafety hole in environmental using function

* Introduce Ed25519 crypto.

* Repotting.

* Add ed25519_verify external.

* Introduce Ed25519 verify as an external.

* fix unsafety hole around unwinding

* Compile fixes.

* use new environmental API

* Tests for ed25519 verify.

* Polish

* Introduce UncheckedTransaction & test.

* Implement basic block and tx processing

* Introduce static hex and valid signature for block test.

* Repot session.

* comments.

* Refactor and timestamp test

* Remove fluff

* Remove fluff.

* Staking eras and tests.

* Implement sessions.

* Polish

* Test sessions.

* Introduce better hashing.

- Blake2 for secure hashing
- XX for fast hashing

* Fix tests.

* Introduce staking.

* Tests for simple staking system.

* Build fix for wasm.

* Fix tests.

* Repotting and docs.

* Docs and licence.

* Documentation.

* Remove superfluous code.

* Remove dummy key.

* Remove other superfluous file.

* Optimise with swap_remove
This commit is contained in:
Gav Wood
2018-01-23 15:24:17 +01:00
committed by Arkadiy Paronyan
parent 28d84d8ac4
commit 3402f169a7
70 changed files with 3578 additions and 282 deletions
@@ -0,0 +1,78 @@
// Copyright 2017 Parity Technologies (UK) Ltd.
// This file is part of Polkadot.
// Polkadot is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// Polkadot is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with Polkadot. If not, see <http://www.gnu.org/licenses/>.
//! Environment API: Allows certain information to be accessed throughout the runtime.
use runtime_support::{Rc, RefCell, transmute, Box};
use primitives::{BlockNumber, Digest};
#[derive(Default)]
/// The information that can be accessed globally.
pub struct Environment {
/// The current block number.
pub block_number: BlockNumber,
/// The current block digest.
pub digest: Digest,
/// The number of log items in this block that have been accounted for so far.
pub next_log_index: usize,
}
/// Do something with the environment and return its value. Keep the function short.
pub fn with_env<T, F: FnOnce(&mut Environment) -> T>(f: F) -> T {
let e = env();
let mut eb = e.borrow_mut();
f(&mut *eb)
}
#[cfg(not(test))]
fn env() -> Rc<RefCell<Environment>> {
// Initialize it to a null value
static mut SINGLETON: *const Rc<RefCell<Environment>> = 0 as *const Rc<RefCell<Environment>>;
unsafe {
if SINGLETON == 0 as *const Rc<RefCell<Environment>> {
// Make it
let singleton: Rc<RefCell<Environment>> = Rc::new(RefCell::new(Default::default()));
// Put it in the heap so it can outlive this call
SINGLETON = transmute(Box::new(singleton));
}
// Now we give out a copy of the data that is safe to use concurrently.
(*SINGLETON).clone()
}
}
#[cfg(test)]
fn env() -> Rc<RefCell<Environment>> {
// Initialize it to a null value
thread_local!{
static SINGLETON: RefCell<*const Rc<RefCell<Environment>>> = RefCell::new(0 as *const Rc<RefCell<Environment>>);
}
SINGLETON.with(|s| unsafe {
if *s.borrow() == 0 as *const Rc<RefCell<Environment>> {
// Make it
let singleton: Rc<RefCell<Environment>> = Rc::new(RefCell::new(Default::default()));
// Put it in the heap so it can outlive this call
*s.borrow_mut() = transmute(Box::new(singleton));
}
// Now we give out a copy of the data that is safe to use concurrently.
(**s.borrow()).clone()
})
}
@@ -0,0 +1,74 @@
// Copyright 2017 Parity Technologies (UK) Ltd.
// This file is part of Polkadot.
// Polkadot is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// Polkadot is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with Polkadot. If not, see <http://www.gnu.org/licenses/>.
//! Function data: This describes a function that can be called from an external transaction.
use primitives::AccountID;
use streamreader::StreamReader;
use runtime::{staking, session, timestamp};
/// The functions that a transaction can call (and be dispatched to).
#[cfg_attr(test, derive(PartialEq, Debug))]
#[derive(Clone, Copy)]
pub enum Function {
StakingStake,
StakingUnstake,
StakingTransfer,
SessionSetKey,
TimestampSet,
}
impl Function {
/// Derive `Some` value from a `u8`, or `None` if it's invalid.
pub 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::StakingTransfer as u8 => Some(Function::StakingTransfer),
x if x == Function::SessionSetKey as u8 => Some(Function::SessionSetKey),
x if x == Function::TimestampSet as u8 => Some(Function::TimestampSet),
_ => None,
}
}
}
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);
}
Function::StakingTransfer => {
let dest = params.read().unwrap();
let value = params.read().unwrap();
staking::transfer(transactor, &dest, value);
}
Function::SessionSetKey => {
let session = params.read().unwrap();
session::set_key(transactor, &session);
}
Function::TimestampSet => {
let t = params.read().unwrap();
timestamp::set(t);
}
}
}
}
@@ -0,0 +1,28 @@
// Copyright 2017 Parity Technologies (UK) Ltd.
// This file is part of Polkadot.
// Polkadot is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// Polkadot is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with Polkadot. If not, see <http://www.gnu.org/licenses/>.
//! Support code for the runtime.
pub mod primitives;
pub mod function;
pub mod environment;
pub mod storable;
#[cfg(test)]
pub mod statichex;
#[cfg(test)]
#[macro_use]
pub mod testing;
@@ -0,0 +1,515 @@
// Copyright 2017 Parity Technologies (UK) Ltd.
// This file is part of Polkadot.
// Polkadot is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// Polkadot is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with Polkadot. If not, see <http://www.gnu.org/licenses/>.
//! Primitive types.
use runtime_support::Vec;
use streamreader::StreamReader;
use joiner::Joiner;
use slicable::{Slicable, NonTrivialSlicable};
use function::Function;
use runtime_support::{size_of, blake2_256, twox_128, twox_256, ed25519_verify};
#[cfg(test)]
use std::fmt;
/// The Ed25519 pubkey that identifies an account.
pub type AccountID = [u8; 32];
/// 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;
/// Indentifier for a chain.
pub type ChainID = u64;
/// Index of a block in the chain.
pub type BlockNumber = u64;
/// Index of a transaction.
pub type TxOrder = u64;
/// A hash of some data.
pub type Hash = [u8; 32];
#[derive(Clone, Default)]
#[cfg_attr(test, derive(PartialEq, Debug))]
/// The digest of a block, useful for light-clients.
pub struct Digest {
/// All logs that have happened in the block.
pub logs: Vec<Vec<u8>>,
}
#[derive(Clone)]
#[cfg_attr(test, derive(PartialEq, Debug))]
/// The header for a block.
pub struct Header {
/// The parent block's "hash" (actually the Blake2-256 hash of its serialised header).
pub parent_hash: Hash,
/// The block's number (how many ancestors does it have?).
pub number: BlockNumber,
/// The root of the trie that represents this block's final storage map.
pub state_root: Hash,
/// The root of the trie that represents this block's transactions, indexed by a 32-bit integer.
pub transaction_root: Hash,
/// The digest for this block.
pub digest: Digest,
}
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::new()
.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)
}
}
impl NonTrivialSlicable for Header {}
#[cfg_attr(test, derive(PartialEq, Debug))]
/// A vetted and verified transaction from the external world.
pub struct Transaction {
/// Who signed it (note this is not a signature).
pub signed: AccountID,
/// The number of transactions have come before from the same signer.
pub nonce: TxOrder,
/// The function that should be called.
pub function: Function,
/// Serialised input data to the function.
pub input_data: Vec<u8>,
}
impl Slicable for Transaction {
fn from_slice(value: &[u8]) -> Option<Self> {
let mut reader = StreamReader::new(value);
Some(Transaction {
signed: reader.read()?,
nonce: reader.read()?,
function: Function::from_u8(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::new()
.join(&self.signed)
.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::<TxOrder>() + size_of::<u8>();
let second_part = <Vec<u8>>::size_of(&data[first_part..])?;
Some(first_part + second_part)
}
}
pub trait Hashable: Sized {
fn blake2_256(&self) -> [u8; 32];
fn twox_128(&self) -> [u8; 16];
fn twox_256(&self) -> [u8; 32];
}
impl<T: Slicable> Hashable for T {
fn blake2_256(&self) -> [u8; 32] {
blake2_256(&self.to_vec())
}
fn twox_128(&self) -> [u8; 16] {
twox_128(&self.to_vec())
}
fn twox_256(&self) -> [u8; 32] {
twox_256(&self.to_vec())
}
}
impl NonTrivialSlicable for Transaction {}
/// A transactions right from the external world. Unchecked.
pub struct UncheckedTransaction {
/// The actual transaction information.
pub transaction: Transaction,
/// The signature; should be an Ed25519 signature applied to the serialised `transaction` field.
pub signature: [u8; 64],
}
impl UncheckedTransaction {
/// Verify the signature.
pub fn ed25519_verify(&self) -> bool {
let msg = self.transaction.to_vec();
ed25519_verify(&self.signature, &msg, &self.transaction.signed)
}
}
#[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))]
/// A Polkadot relay chain block.
pub struct Block {
/// The header of the block.
pub header: Header,
/// All transactions.
pub transactions: Vec<UncheckedTransaction>,
}
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::new()
.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)
}
}
impl NonTrivialSlicable for Block {}
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::new();
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::new().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)
}
}
#[cfg(test)]
mod tests {
use super::*;
use joiner::Joiner;
use function::Function;
#[test]
fn serialise_transaction_works() {
let one: AccountID = [1u8; 32];
let two: AccountID = [2u8; 32];
let tx = Transaction {
signed: one.clone(),
nonce: 69,
function: Function::StakingTransfer,
input_data: Vec::new().join(&two).join(&69u64),
};
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,
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
]);
}
#[test]
fn deserialise_transaction_works() {
let one: AccountID = [1u8; 32];
let two: AccountID = [2u8; 32];
let tx = Transaction {
signed: one.clone(),
nonce: 69,
function: Function::StakingTransfer,
input_data: Vec::new().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,
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
];
let deserialised = Transaction::from_slice(&data).unwrap();
assert_eq!(deserialised, tx);
}
#[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);
}
#[test]
fn serialise_block_works() {
let one: AccountID = [1u8; 32];
let two: AccountID = [2u8; 32];
let tx1 = UncheckedTransaction {
transaction: Transaction {
signed: one.clone(),
nonce: 69,
function: Function::StakingTransfer,
input_data: Vec::new().join(&two).join(&69u64),
},
signature: [1u8; 64],
};
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],
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
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,
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,
42, 0, 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 = UncheckedTransaction {
transaction: Transaction {
signed: one.clone(),
nonce: 69,
function: Function::StakingTransfer,
input_data: Vec::new().join(&two).join(&69u64),
},
signature: [1u8; 64],
};
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],
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
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,
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,
42, 0, 0, 0, 0, 0, 0, 0,
0,
0, 0, 0, 0
];
let deserialised = Block::from_slice(&data).unwrap();
assert_eq!(deserialised, b);
}
}
@@ -0,0 +1,52 @@
// Copyright 2017 Parity Technologies (UK) Ltd.
// This file is part of Polkadot.
// Polkadot is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// Polkadot is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with Polkadot. If not, see <http://www.gnu.org/licenses/>.
//! Interpret a static string of hex as a desired type.
use rustc_hex::FromHex;
/// Trait to allow conversion from a static hex string to an instance.
pub trait StaticHexConversion: Sized {
/// Convert the static str into Self. Use just like `From::from`.
fn from_static_hex(hex: &'static str) -> Self;
}
macro_rules! impl_sizes {
( $( $t:expr ),* ) => { $(
impl StaticHexConversion for [u8; $t] {
fn from_static_hex(hex: &'static str) -> Self {
let mut r = [0u8; $t];
r.copy_from_slice(&FromHex::from_hex(hex).unwrap());
r
}
}
)* }
}
impl_sizes!(1, 2, 3, 4, 5, 6, 7, 8, 10, 12, 14, 16, 20, 24, 28, 32, 40, 48, 56, 64, 80, 96, 112, 128);
/// Trait to allow converting from itself (only implemented for a static str) into some useful
/// type (which must implement `StaticHexConversion`).
pub trait StaticHexInto {
/// Convert self (i.e. a static str) into the appropriate type. Use just like `Into::into`.
fn convert<T: StaticHexConversion>(self) -> T;
}
impl StaticHexInto for &'static str {
fn convert<T: StaticHexConversion>(self) -> T {
T::from_static_hex(self)
}
}
@@ -0,0 +1,87 @@
// Copyright 2017 Parity Technologies (UK) Ltd.
// This file is part of Polkadot.
// Polkadot is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// Polkadot is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with Polkadot. If not, see <http://www.gnu.org/licenses/>.
//! Stuff to do with the runtime's storage.
use slicable::Slicable;
use endiansensitive::EndianSensitive;
use keyedvec::KeyedVec;
use runtime_support::{self, twox_128, Vec};
/// Trait for a value which may be stored in the storage DB.
pub trait Storable {
/// Lookup the value in storage and deserialise, giving a default value if not found.
fn lookup_default(key: &[u8]) -> Self where Self: Sized + Default { Self::lookup(key).unwrap_or_else(Default::default) }
/// Lookup `Some` value in storage and deserialise; `None` if it's not there.
fn lookup(_key: &[u8]) -> Option<Self> where Self: Sized { unimplemented!() }
/// Place the value in storage under `key`.
fn store(&self, key: &[u8]);
}
// TODO: consider using blake256 to avoid possible eclipse attack.
/// Remove `key` from storage.
pub fn kill(key: &[u8]) { runtime_support::set_storage(&twox_128(key)[..], b""); }
impl<T: Default + Sized + EndianSensitive> Storable for T {
fn lookup(key: &[u8]) -> Option<Self> {
Slicable::set_as_slice(|out| runtime_support::read_storage(&twox_128(key)[..], out) == out.len())
}
fn store(&self, key: &[u8]) {
self.as_slice_then(|slice| runtime_support::set_storage(&twox_128(key)[..], slice));
}
}
impl Storable for [u8] {
fn store(&self, key: &[u8]) {
runtime_support::set_storage(&twox_128(key)[..], self)
}
}
/// A trait to conveniently store a vector of storable data.
// TODO: add iterator support
pub trait StorageVec {
type Item: Default + Sized + Storable;
const PREFIX: &'static [u8];
/// Get the current set of items.
fn items() -> Vec<Self::Item> {
(0..Self::count()).into_iter().map(Self::item).collect()
}
/// Set the current set of items.
fn set_items(items: &[Self::Item]) {
Self::set_count(items.len() as u32);
items.iter().enumerate().for_each(|(v, ref i)| Self::set_item(v as u32, i));
}
fn set_item(index: u32, item: &Self::Item) {
item.store(&index.to_keyed_vec(Self::PREFIX));
}
fn item(index: u32) -> Self::Item {
Storable::lookup_default(&index.to_keyed_vec(Self::PREFIX))
}
fn set_count(count: u32) {
(count..Self::count()).for_each(|i| Self::set_item(i, &Self::Item::default()));
count.store(&b"len".to_keyed_vec(Self::PREFIX));
}
fn count() -> u32 {
Storable::lookup_default(&b"len".to_keyed_vec(Self::PREFIX))
}
}
@@ -0,0 +1,106 @@
// Copyright 2017 Parity Technologies (UK) Ltd.
// This file is part of Polkadot.
// Polkadot is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// Polkadot is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with Polkadot. If not, see <http://www.gnu.org/licenses/>.
//! Testing helpers.
use runtime_support::{NoError, Externalities};
use std::collections::HashMap;
use primitives::AccountID;
use statichex::StaticHexInto;
#[derive(Debug, Default)]
/// Simple externaties implementation.
pub struct TestExternalities {
/// The storage map.
pub 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);
}
fn chain_id(&self) -> u64 { 42 }
}
#[macro_export]
macro_rules! map {
($( $name:expr => $value:expr ),*) => (
vec![ $( ( $name, $value ) ),* ].into_iter().collect()
)
}
/// One account (to which we know the secret key).
pub fn one() -> AccountID {
"2f8c6129d816cf51c374bc7f08c3e63ed156cf78aefb4a6550d97b87997977ee".convert()
}
/// Another account (secret key known).
pub fn two() -> AccountID {
"d75a980182b10ab7d54bfed3c964073a0ee172f3daa62325af021a68f707511a".convert()
}
/// Hex display, this time for no_std. See main codebase for documentation.
pub struct HexDisplay<'a>(&'a [u8]);
impl<'a> HexDisplay<'a> {
/// See main codebase for documentation.
pub fn from(d: &'a AsBytesRef) -> Self { HexDisplay(d.as_bytes_ref()) }
}
impl<'a> ::std::fmt::Display for HexDisplay<'a> {
fn fmt(&self, fmtr: &mut ::std::fmt::Formatter) -> Result<(), ::std::fmt::Error> {
for byte in self.0 {
try!( fmtr.write_fmt(format_args!("{:02x}", byte)));
}
Ok(())
}
}
/// See main codebase for documentation.
pub trait AsBytesRef {
/// See main codebase for documentation.
fn as_bytes_ref(&self) -> &[u8];
}
impl AsBytesRef for [u8] {
fn as_bytes_ref(&self) -> &[u8] { &self }
}
impl<'a> AsBytesRef for &'a[u8] {
fn as_bytes_ref(&self) -> &[u8] { self }
}
impl AsBytesRef for Vec<u8> {
fn as_bytes_ref(&self) -> &[u8] { &self[..] }
}
macro_rules! impl_non_endians {
( $( $t:ty ),* ) => { $(
impl AsBytesRef for $t {
fn as_bytes_ref(&self) -> &[u8] { &self[..] }
}
)* }
}
impl_non_endians!([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]);