Proposal creation and evaluation to plug into BFT (#77)

* reshuffle consensus libraries

* polkadot-useful type definitions for statement table

* begin BftService

* primary selection logic

* bft service implementation without I/O

* extract out `BlockImport` trait

* allow bft primitives to compile on wasm

* Block builder (substrate)

* take polkadot-consensus down to the core.

* test for preemption

* fix test build

* Fix wasm build

* Bulid on any block

* Test for block builder.

* Block import tests for client.

* Tidy ups

* clean up block builder instantiation

* justification verification logic

* JustifiedHeader and import

* Propert block generation for tests

* network and tablerouter trait

* use statement import to drive creation of further statements

* Fixed rpc tests

* custom error type for consensus

* create proposer

* asynchronous proposal evaluation

* inherent transactions in polkadot runtime

* fix tests to match real polkadot block constraints

* implicitly generate inherent functions

* add inherent transaction functionality to block body

* block builder logic for polkadot

* some tests for the polkadot API
This commit is contained in:
Robert Habermeier
2018-02-25 10:58:17 +01:00
committed by Gav Wood
parent ec9060460c
commit 1f2d01566e
30 changed files with 1300 additions and 300 deletions
+194 -8
View File
@@ -21,7 +21,7 @@ use primitives::bytes;
use primitives::H256;
use rstd::vec::Vec;
use codec::{Input, Slicable};
use transaction::UncheckedTransaction;
use transaction::{UncheckedTransaction, Function, InherentFunction};
pub use primitives::block::Id;
@@ -69,8 +69,65 @@ impl Slicable for Digest {
}
}
/// The block "body": A bunch of transactions.
pub type Body = Vec<UncheckedTransaction>;
/// Iterator over all inherent transactions.
pub struct InherentTransactions<'a> {
number: u64,
body: &'a Body,
}
impl<'a> Iterator for InherentTransactions<'a> {
type Item = UncheckedTransaction;
fn next(&mut self) -> Option<UncheckedTransaction> {
if self.number == InherentFunction::count() {
return None
}
self.number += 1;
let function = match self.number {
1 => Some(InherentFunction::TimestampSet(self.body.timestamp)),
_ => None,
};
function.map(UncheckedTransaction::inherent)
}
}
/// Type alias for an iterator over all transactions in a block.
pub type AllTransactions<'a> = ::rstd::iter::Chain<
InherentTransactions<'a>,
::rstd::iter::Cloned<::rstd::slice::Iter<'a, UncheckedTransaction>>,
>;
/// The block body. Contains timestamp and transactions.
// TODO: add candidates update as well.
#[derive(PartialEq, Eq, Clone)]
#[cfg_attr(feature = "std", derive(Serialize, Deserialize, Debug))]
#[cfg_attr(feature = "std", serde(rename_all = "camelCase"))]
#[cfg_attr(feature = "std", serde(deny_unknown_fields))]
pub struct Body {
/// The timestamp of the block.
pub timestamp: u64,
/// The transactions in the block.
pub transactions: Vec<UncheckedTransaction>,
}
impl Body {
/// Get an iterator over all inherent transactions of the body.
pub fn inherent_transactions(&self) -> InherentTransactions {
InherentTransactions {
number: 0,
body: self,
}
}
/// Get an iterator over all transactions in a block.
pub fn all_transactions(&self) -> AllTransactions {
self.inherent_transactions().chain(self.transactions.iter().cloned())
}
}
/// A Polkadot relay chain block.
#[derive(PartialEq, Eq, Clone)]
@@ -78,21 +135,65 @@ pub type Body = Vec<UncheckedTransaction>;
pub struct Block {
/// The block header.
pub header: Header,
/// All relay-chain transactions.
pub transactions: Body,
/// The block body.
pub body: Body,
}
impl Block {
/// Get an iterator over all inherent transactions of the body.
pub fn inherent_transactions(&self) -> InherentTransactions {
self.body.inherent_transactions()
}
/// Get an iterator over all transactions in a block.
pub fn all_transactions(&self) -> AllTransactions {
self.body.all_transactions()
}
}
impl Slicable for Block {
fn decode<I: Input>(input: &mut I) -> Option<Self> {
let (header, transactions) = try_opt!(Slicable::decode(input));
Some(Block { header, transactions })
let header = try_opt!(Slicable::decode(input));
let transactions_len: u32 = try_opt!(Slicable::decode(input));
let regular_transactions_len = try_opt!(transactions_len.checked_sub(InherentFunction::count() as u32));
let timestamp_tx = try_opt!(UncheckedTransaction::decode(input));
let timestamp = match timestamp_tx.transaction.function {
Function::Inherent(InherentFunction::TimestampSet(ref t)) if timestamp_tx.is_well_formed() => { t.clone() }
_ => return None,
};
let transactions: Option<Vec<_>> = (0..regular_transactions_len)
.map(|_| UncheckedTransaction::decode(input))
.filter(|tx| tx.as_ref().map_or(true, |tx| tx.is_well_formed()))
.collect();
let body = Body {
timestamp,
transactions: try_opt!(transactions),
};
Some(Block { header, body })
}
fn encode(&self) -> Vec<u8> {
let mut v = Vec::new();
v.extend(self.header.encode());
v.extend(self.transactions.encode());
// encode inherent transactions before non-inherent.
let transactions_len = self.body.transactions.len() as u64 + InherentFunction::count();
(transactions_len as u32).using_encoded(|s| v.extend(s));
let timestamp_set_tx = UncheckedTransaction::inherent(
InherentFunction::TimestampSet(self.body.timestamp)
);
v.extend(timestamp_set_tx.encode());
for non_inherent_transaction in &self.body.transactions {
v.extend(non_inherent_transaction.encode());
}
v
}
@@ -186,4 +287,89 @@ mod tests {
let v = header.encode();
assert_eq!(Header::decode(&mut &v[..]).unwrap(), header);
}
#[test]
fn block_encoding_round_trip() {
let mut block = Block {
header: Header::from_block_number(1),
body: Body {
timestamp: 100_000_000,
transactions: Vec::new(),
}
};
let raw = block.encode();
let decoded = Block::decode(&mut &raw[..]).unwrap();
assert_eq!(block, decoded);
block.body.transactions.push(UncheckedTransaction {
transaction: ::transaction::Transaction {
function: Function::StakingStake,
signed: Default::default(),
nonce: 10101,
},
signature: Default::default(),
});
let raw = block.encode();
let decoded = Block::decode(&mut &raw[..]).unwrap();
assert_eq!(block, decoded);
}
#[test]
fn block_encoding_substrate_round_trip() {
let mut block = Block {
header: Header::from_block_number(1),
body: Body {
timestamp: 100_000_000,
transactions: Vec::new(),
}
};
block.body.transactions.push(UncheckedTransaction {
transaction: ::transaction::Transaction {
function: Function::StakingStake,
signed: Default::default(),
nonce: 10101,
},
signature: Default::default(),
});
let raw = block.encode();
let decoded_substrate = ::primitives::block::Block::decode(&mut &raw[..]).unwrap();
let encoded_substrate = decoded_substrate.encode();
let decoded = Block::decode(&mut &encoded_substrate[..]).unwrap();
assert_eq!(block, decoded);
}
#[test]
fn decode_body_without_inherents_fails() {
let substrate_blank = ::primitives::block::Block {
header: ::primitives::block::Header::from_block_number(1),
transactions: Vec::new(),
};
let encoded_substrate = substrate_blank.encode();
assert!(Block::decode(&mut &encoded_substrate[..]).is_none());
}
#[test]
fn inherent_transactions_iter_contains_all_inherent() {
let block = Block {
header: Header::from_block_number(1),
body: Body {
timestamp: 10101,
transactions: Vec::new(),
}
};
let mut iter = block.inherent_transactions();
assert_eq!(InherentFunction::count(), 1); // following depends on this assertion.
assert_eq!(iter.next().unwrap(), UncheckedTransaction::inherent(InherentFunction::TimestampSet(10101)));
assert!(iter.next().is_none());
}
}