Skip to content
This repository was archived by the owner on Nov 15, 2023. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Next Next commit
Block builder (substrate)
  • Loading branch information
gavofyork committed Feb 12, 2018
commit acab9a333fb61b05fced8fb61b6d39bdab2eb57a
89 changes: 89 additions & 0 deletions substrate/client/src/block_builder.rs
Original file line number Diff line number Diff line change
@@ -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 <http://www.gnu.org/licenses/>.

//! 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<B, E> where
B: backend::Backend,
E: CodeExecutor + Clone,
error::Error: From<<<B as backend::Backend>::State as state_machine::backend::Backend>::Error>,
{
header: Header,
transactions: Vec<Transaction>,
executor: E,
state: B::State,
changes: state_machine::OverlayedChanges,
}

impl<B, E> BlockBuilder<B, E> where
B: backend::Backend,
E: CodeExecutor + Clone,
error::Error: From<<<B as backend::Backend>::State as state_machine::backend::Backend>::Error>,
{
/// Create a new instance of builder from the given client.
pub fn new(client: &Client<B, E>) -> error::Result<Self> {
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");
Copy link
Contributor

@rphmeier rphmeier Feb 16, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

typo fix reverted

self.transactions.push(tx);
Ok(())
}

/// Consume the builder to return a valid `Block` containing all pushed transactions.
pub fn bake(mut self) -> error::Result<Block> {
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");
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

and here

Ok(Block {
header: self.header,
transactions: self.transactions,
})
}
}
17 changes: 14 additions & 3 deletions substrate/client/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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};
Expand All @@ -59,6 +61,7 @@ pub struct Client<B, E> 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.
Expand Down Expand Up @@ -167,6 +170,11 @@ impl<B, E> Client<B, E> 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<Vec<AuthorityId>> {
let state = self.state_at(id)?;
Expand All @@ -183,10 +191,8 @@ impl<B, E> Client<B, E> where
/// No changes are made.
pub fn call(&self, id: &BlockId, method: &str, call_data: &[u8]) -> error::Result<CallResult> {
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,
Expand All @@ -195,6 +201,11 @@ impl<B, E> Client<B, E> where
Ok(CallResult { return_data, changes })
}

/// Create a new block, built on the head of the chain.
pub fn new_block(&self) -> error::Result<BlockBuilder<B, E>> where E: Clone {
BlockBuilder::new(self)
}

/// Queue a block for import.
pub fn import_block(&self, header: block::Header, body: Option<block::Body>) -> error::Result<ImportResult> {
// TODO: import lock
Expand Down
11 changes: 5 additions & 6 deletions substrate/primitives/src/block.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)]
Expand Down Expand Up @@ -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,
}
Expand Down
4 changes: 3 additions & 1 deletion substrate/primitives/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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];