diff --git a/substrate/substrate/client/src/block_builder.rs b/substrate/substrate/client/src/block_builder.rs
new file mode 100644
index 0000000000..ebd8ec6c47
--- /dev/null
+++ b/substrate/substrate/client/src/block_builder.rs
@@ -0,0 +1,89 @@
+// Copyright 2017 Parity Technologies (UK) Ltd.
+// This file is part of Substrate.
+
+// Substrate 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.
+
+// Substrate 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 Substrate. If not, see .
+
+//! Utility struct to build a block.
+
+use std::vec::Vec;
+use codec::{Joiner, Slicable};
+use state_machine::{self, CodeExecutor};
+use primitives::{Header, Block};
+use primitives::block::Transaction;
+use {backend, error, BlockId, BlockStatus, Client};
+use triehash::ordered_trie_root;
+
+/// Utility for building new (valid) blocks from a stream of transactions.
+pub struct BlockBuilder where
+ B: backend::Backend,
+ E: CodeExecutor + Clone,
+ error::Error: From<<::State as state_machine::backend::Backend>::Error>,
+{
+ header: Header,
+ transactions: Vec,
+ executor: E,
+ state: B::State,
+ changes: state_machine::OverlayedChanges,
+}
+
+impl BlockBuilder where
+ B: backend::Backend,
+ E: CodeExecutor + Clone,
+ error::Error: From<<::State as state_machine::backend::Backend>::Error>,
+{
+ /// Create a new instance of builder from the given client.
+ pub fn new(client: &Client) -> error::Result {
+ let best = (client.info().map(|i| i.chain.best_number)?..1)
+ .find(|&n| if let Ok(BlockStatus::InChain) = client.block_status(&BlockId::Number(n))
+ { true } else { false })
+ .unwrap_or(0);
+
+ Ok(BlockBuilder {
+ header: Header {
+ number: best + 1,
+ parent_hash: client.block_hash(best)?.expect("We already ascertained this is InChain before; qed"),
+ state_root: Default::default(),
+ transaction_root: Default::default(),
+ digest: Default::default(),
+ },
+ transactions: Default::default(),
+ executor: client.clone_executor(),
+ state: client.state_at(&BlockId::Number(best))?,
+ changes: Default::default(),
+ })
+ }
+
+ /// Push a transaction onto the block's list of transactions. This will ensure the transaction
+ /// can be validly executed (by executing it); if it is invalid, it'll be returned along with
+ /// the error. Otherwise, it will return a mutable reference to self (in order to chain).
+ pub fn push(&mut self, tx: Transaction) -> error::Result<()> {
+ let output = state_machine::execute(&self.state, &mut self.changes, &self.executor, "execute_transaction",
+ &vec![].and(&self.header).and(&tx))?;
+ self.header = Header::decode(&mut &output[..]).expect("Header came straight out of runtime do must be valid");
+ self.transactions.push(tx);
+ Ok(())
+ }
+
+ /// Consume the builder to return a valid `Block` containing all pushed transactions.
+ pub fn bake(mut self) -> error::Result {
+ self.header.transaction_root = ordered_trie_root(self.transactions.iter().map(Slicable::encode)).0.into();
+ let output = state_machine::execute(&self.state, &mut self.changes, &self.executor, "finalise_block",
+ &self.header.encode())?;
+ self.header = Header::decode(&mut &output[..]).expect("Header came straight out of runtime do must be valid");
+ Ok(Block {
+ header: self.header,
+ transactions: self.transactions,
+ })
+ }
+}
diff --git a/substrate/substrate/client/src/lib.rs b/substrate/substrate/client/src/lib.rs
index 530288ca29..1a7d4ceb62 100644
--- a/substrate/substrate/client/src/lib.rs
+++ b/substrate/substrate/client/src/lib.rs
@@ -39,9 +39,11 @@ pub mod blockchain;
pub mod backend;
pub mod in_mem;
pub mod genesis;
+pub mod block_builder;
pub use blockchain::Info as ChainInfo;
pub use blockchain::BlockId;
+pub use block_builder::BlockBuilder;
use primitives::{block, AuthorityId};
use primitives::storage::{StorageKey, StorageData};
@@ -59,6 +61,7 @@ pub struct Client where B: backend::Backend {
}
/// Client info
+// TODO: split queue info from chain info and amalgamate into single struct.
#[derive(Debug)]
pub struct ClientInfo {
/// Best block hash.
@@ -167,6 +170,11 @@ impl Client where
self.storage(id, &StorageKey(b":code".to_vec())).map(|data| data.0)
}
+ /// Clone a new instance of Executor.
+ pub fn clone_executor(&self) -> E where E: Clone {
+ self.executor.clone()
+ }
+
/// Get the current set of authorities from storage.
pub fn authorities_at(&self, id: &BlockId) -> error::Result> {
let state = self.state_at(id)?;
@@ -183,10 +191,8 @@ impl Client where
/// No changes are made.
pub fn call(&self, id: &BlockId, method: &str, call_data: &[u8]) -> error::Result {
let mut changes = state_machine::OverlayedChanges::default();
- let state = self.state_at(id)?;
-
let return_data = state_machine::execute(
- &state,
+ &self.state_at(id)?,
&mut changes,
&self.executor,
method,
@@ -195,6 +201,11 @@ impl Client where
Ok(CallResult { return_data, changes })
}
+ /// Create a new block, built on the head of the chain.
+ pub fn new_block(&self) -> error::Result> where E: Clone {
+ BlockBuilder::new(self)
+ }
+
/// Queue a block for import.
pub fn import_block(&self, header: block::Header, body: Option) -> error::Result {
// TODO: import lock
diff --git a/substrate/substrate/primitives/src/block.rs b/substrate/substrate/primitives/src/block.rs
index ba34dd085f..90882f7fc3 100644
--- a/substrate/substrate/primitives/src/block.rs
+++ b/substrate/substrate/primitives/src/block.rs
@@ -17,19 +17,18 @@
//! Block and header type definitions.
#[cfg(feature = "std")]
-use bytes;
use rstd::vec::Vec;
+use {bytes, Hash};
use codec::{Input, Slicable};
-use hash::H256;
/// Used to refer to a block number.
pub type Number = u64;
/// Hash used to refer to a block hash.
-pub type HeaderHash = H256;
+pub type HeaderHash = Hash;
/// Hash used to refer to a transaction hash.
-pub type TransactionHash = H256;
+pub type TransactionHash = Hash;
/// Simple generic transaction type.
#[derive(PartialEq, Eq, Clone)]
@@ -127,9 +126,9 @@ pub struct Header {
/// Block number.
pub number: Number,
/// State root after this transition.
- pub state_root: H256,
+ pub state_root: Hash,
/// The root of the trie that represents this block's transactions, indexed by a 32-byte integer.
- pub transaction_root: H256,
+ pub transaction_root: Hash,
/// The digest of activity on the block.
pub digest: Digest,
}
diff --git a/substrate/substrate/primitives/src/lib.rs b/substrate/substrate/primitives/src/lib.rs
index 1c282fe42e..211bfce8f5 100644
--- a/substrate/substrate/primitives/src/lib.rs
+++ b/substrate/substrate/primitives/src/lib.rs
@@ -90,8 +90,10 @@ mod tests;
pub use self::hash::{H160, H256};
pub use self::uint::{U256, U512};
-
pub use block::{Block, Header};
+/// General hash type.
+pub type Hash = H256;
+
/// An identifier for an authority in the consensus algorithm. The same as ed25519::Public.
pub type AuthorityId = [u8; 32];