Skip to content
This repository has been archived by the owner on Nov 15, 2023. It is now read-only.

Make substrate generic #169

Merged
merged 63 commits into from
Jun 6, 2018
Merged
Show file tree
Hide file tree
Changes from 8 commits
Commits
Show all changes
63 commits
Select commit Hold shift + click to select a range
7fa1b17
Some initial work on RPC and client
gavofyork May 17, 2018
a43c5e7
Rephrase as params
gavofyork May 17, 2018
5348d4e
More work on traitifying substrate.
gavofyork May 18, 2018
0679ac6
Traitify in_mem.rs
gavofyork May 23, 2018
8b9b4ac
traitify client.rs
gavofyork May 24, 2018
047b294
Make new primitives (mainly traits) build again.
gavofyork May 24, 2018
f94f63e
Many (superficial) build fixes throughout.
gavofyork May 24, 2018
0fe8997
Fix remaining build issues up to bft interface.
gavofyork May 24, 2018
9f0113b
Make bft primitives be generic.
gavofyork May 24, 2018
967e478
Switch out MisBehaviorReport for generic version.
gavofyork May 24, 2018
0e1aa2e
Merge Hashing into Header.
gavofyork May 25, 2018
e508b8e
Update runtime for new generics (with Hashing).
gavofyork May 25, 2018
3ad0410
Update demo runtime.
gavofyork May 25, 2018
d2b8a35
Make runtime compile.
gavofyork May 25, 2018
5a88df4
Build fixes for runtime
gavofyork May 25, 2018
2f8bdd7
Remove old modules.
gavofyork May 25, 2018
d268ca0
port substrate-bft to use generic substrate types
rphmeier May 25, 2018
647aa7e
port client
rphmeier May 25, 2018
fedbaba
port substrate-test-runtime
rphmeier May 29, 2018
089367d
mostly port test-runtime to get compiling for std
rphmeier May 29, 2018
2a02f53
Ensure `AccountId` has a `Default`.
gavofyork May 29, 2018
33bc80f
Fix type deps.
gavofyork May 29, 2018
096150a
finish porting
rphmeier May 29, 2018
4e49ef7
initialize test_runtime from genesis correctly
rphmeier May 29, 2018
85a818f
remove commented code
rphmeier May 29, 2018
baf292e
Merge branch 'master' into gav-make-substrate-generic
rphmeier May 30, 2018
bf11a29
maybe unsigned signatures
rphmeier May 30, 2018
b1379de
runtimes compile
rphmeier May 30, 2018
65c84dd
port over most of network
rphmeier May 31, 2018
ea361d2
serialization for generic types
rphmeier May 31, 2018
e35a8d0
fix comment
rphmeier May 31, 2018
c8f064e
remove some unnecessary trait bounds
rphmeier May 31, 2018
34b4e0e
network compiles
rphmeier May 31, 2018
5ad3877
tests compile for sync
rphmeier Jun 1, 2018
b3cbe4f
fix deserialization
rphmeier Jun 1, 2018
1b7901b
Merge branch 'master' into gav-make-substrate-generic
rphmeier Jun 1, 2018
a36f328
temporarily remove deserialize derives
rphmeier Jun 1, 2018
d3ee03e
workarounds for serde issues for deriving deserialization
rphmeier Jun 1, 2018
c158c16
get demo-runtime compiling on std
rphmeier Jun 1, 2018
91409b6
port extrinsic-pool
rphmeier Jun 2, 2018
88629b3
primitives reshuffling
rphmeier Jun 2, 2018
defce82
get network compiling again
rphmeier Jun 2, 2018
4ec3670
remove debugging file
rphmeier Jun 2, 2018
d6bb4ea
runtime tests now passing
rphmeier Jun 2, 2018
f14b975
port client-db
rphmeier Jun 2, 2018
d01da87
start to port over substrate-rpc
rphmeier Jun 2, 2018
354de81
mostly port over PolkadotApi
rphmeier Jun 4, 2018
64accdd
test_runtime follows normal conventions
rphmeier Jun 4, 2018
0cf5f15
substrate runtime tests pass
rphmeier Jun 4, 2018
7d8272f
deal with inherent extrinsics correctly in polkadot-api
rphmeier Jun 4, 2018
13532f7
port transaction-pool
rphmeier Jun 5, 2018
ff852c8
port polkadot-consensus
rphmeier Jun 5, 2018
ddf5a5d
port substrate-rpc
rphmeier Jun 5, 2018
36c0b8e
everything compiles
rphmeier Jun 5, 2018
621be34
tests compile
rphmeier Jun 5, 2018
3bc9390
Merge branch 'master' into gav-make-substrate-generic
rphmeier Jun 5, 2018
a10bc64
fix grumbles
rphmeier Jun 6, 2018
5204fe4
test-runtime uses its own transfer type
rphmeier Jun 6, 2018
d9a87f9
switch to master branch of jsonrpc
rphmeier Jun 6, 2018
cb35573
fix network tests and some warnings
rphmeier Jun 6, 2018
ef3ec86
all tests pass locally
rphmeier Jun 6, 2018
40531bb
[ci-skip] add another comment about issue
rphmeier Jun 6, 2018
ccc65f7
remove some curlies
rphmeier Jun 6, 2018
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
176 changes: 72 additions & 104 deletions Cargo.lock

Large diffs are not rendered by default.

76 changes: 22 additions & 54 deletions polkadot/service/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,16 +28,14 @@ extern crate polkadot_api;
extern crate polkadot_consensus as consensus;
extern crate polkadot_transaction_pool as transaction_pool;
extern crate polkadot_keystore as keystore;
extern crate substrate_client as client;
extern crate substrate_runtime_io as runtime_io;
extern crate substrate_primitives as primitives;
extern crate substrate_network as network;
extern crate substrate_codec as codec;
extern crate substrate_client_db as client_db;
extern crate substrate_executor;

extern crate exit_future;
extern crate tokio_core;
extern crate substrate_client as client;

#[macro_use]
extern crate error_chain;
Expand Down Expand Up @@ -65,21 +63,20 @@ use polkadot_api::PolkadotApi;
use polkadot_runtime::{GenesisConfig, ConsensusConfig, CouncilConfig, DemocracyConfig,
SessionConfig, StakingConfig, BuildExternalities};
use client::{genesis, BlockchainEvents};
use client::in_mem::Backend as InMemory;
use network::ManageNetwork;
use exit_future::Signal;

pub use self::error::{ErrorKind, Error};
pub use config::{Configuration, Role, ChainSpec};

type Client = client::Client<client_db::Backend, NativeExecutor<LocalDispatch>>;
type Client = client::Client<InMemory, NativeExecutor<LocalDispatch>>;

/// Polkadot service.
pub struct Service {
thread: Option<thread::JoinHandle<()>>,
client: Arc<Client>,
network: Arc<network::Service>,
transaction_pool: Arc<Mutex<TransactionPool>>,
signal: Option<Signal>,
_consensus: Option<consensus::Service>,
}

Expand Down Expand Up @@ -260,10 +257,6 @@ fn local_testnet_config() -> ChainConfig {
impl Service {
/// Creates and register protocol with the network service
pub fn new(mut config: Configuration) -> Result<Service, error::Error> {
use std::sync::Barrier;

let (signal, exit) = ::exit_future::signal();

// Create client
let executor = polkadot_executor::Executor::new();
let mut storage = Default::default();
Expand Down Expand Up @@ -291,12 +284,7 @@ impl Service {
(primitives::block::Header::decode(&mut block.header.encode().as_ref()).expect("to_vec() always gives a valid serialisation; qed"), storage.into_iter().collect())
};

let db_settings = client_db::DatabaseSettings {
cache_size: None,
path: config.database_path.into(),
};

let client = Arc::new(client_db::new_client(db_settings, executor, prepare_genesis)?);
let client = Arc::new(client::new_in_mem(executor, prepare_genesis)?);
let best_header = client.best_block_header()?;
info!("Starting Polkadot. Best block is #{}", best_header.number);
let transaction_pool = Arc::new(Mutex::new(TransactionPool::new(config.transaction_pool)));
Expand All @@ -312,39 +300,7 @@ impl Service {
chain: client.clone(),
transaction_pool: transaction_pool_adapter,
};

let network = network::Service::new(network_params)?;
let barrier = ::std::sync::Arc::new(Barrier::new(2));

let thread = {
let client = client.clone();
let network = network.clone();
let txpool = transaction_pool.clone();

let thread_barrier = barrier.clone();
thread::spawn(move || {
network.start_network();

thread_barrier.wait();
let mut core = Core::new().expect("tokio::Core could not be created");
let events = client.import_notification_stream().for_each(move |notification| {
network.on_block_imported(notification.hash, &notification.header);
prune_imported(&*client, &*txpool, notification.hash);

Ok(())
});

core.handle().spawn(events);
if let Err(e) = core.run(exit) {
debug!("Polkadot service event loop shutdown with {:?}", e);
}
debug!("Polkadot service shutdown");
})
};

// wait for the network to start up before starting the consensus
// service.
barrier.wait();

// Spin consensus service if configured
let consensus_service = if config.roles & Role::VALIDATOR == Role::VALIDATOR {
Expand All @@ -356,12 +312,28 @@ impl Service {
None
};

let thread_client = client.clone();
let thread_network = network.clone();
let thread_txpool = transaction_pool.clone();
let thread = thread::spawn(move || {
thread_network.start_network();
let mut core = Core::new().expect("tokio::Core could not be created");
let events = thread_client.import_notification_stream().for_each(|notification| {
thread_network.on_block_imported(notification.hash, &notification.header);
prune_imported(&*thread_client, &*thread_txpool, notification.hash);

Ok(())
});
if let Err(e) = core.run(events) {
debug!("Polkadot service event loop shutdown with {:?}", e);
}
debug!("Polkadot service shutdown");
});
Ok(Service {
thread: Some(thread),
client: client,
network: network,
transaction_pool: transaction_pool,
signal: Some(signal),
_consensus: consensus_service,
})
}
Expand Down Expand Up @@ -401,12 +373,8 @@ pub fn prune_imported(client: &Client, pool: &Mutex<TransactionPool>, hash: Head

impl Drop for Service {
fn drop(&mut self) {
self.client.stop_notifications();
self.network.stop_network();

if let Some(signal) = self.signal.take() {
signal.fire();
}

if let Some(thread) = self.thread.take() {
thread.join().expect("The service thread has panicked");
}
Expand Down
1 change: 1 addition & 0 deletions substrate/client/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ substrate-executor = { path = "../executor" }
substrate-primitives = { path = "../primitives" }
substrate-runtime-io = { path = "../runtime-io" }
substrate-runtime-support = { path = "../runtime-support" }
substrate-runtime-primitives = { path = "../runtime/primitives" }
substrate-state-machine = { path = "../state-machine" }
substrate-keyring = { path = "../../substrate/keyring" }

Expand Down
19 changes: 10 additions & 9 deletions substrate/client/src/backend.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,18 +18,19 @@

use state_machine::backend::Backend as StateBackend;
use error;
use primitives::block::{self, Id as BlockId};
use primitives;
use primitives::bft::Justification;
use runtime_primitives::traits::Block as BlockT;
use runtime_primitives::generic::BlockId;

/// Block insertion operation. Keeps hold if the inserted block state and data.
pub trait BlockImportOperation {
pub trait BlockImportOperation<Block: BlockT> {
/// Associated state backend type.
type State: StateBackend;

/// Returns pending state.
fn state(&self) -> error::Result<&Self::State>;
/// Append block data to the transaction.
fn set_block_data(&mut self, header: block::Header, body: Option<block::Body>, justification: Option<primitives::bft::Justification>, is_new_best: bool) -> error::Result<()>;
fn set_block_data(&mut self, header: Block::Header, body: Option<Vec<Block::Extrinsic>>, justification: Option<Justification>, is_new_best: bool) -> error::Result<()>;
/// Inject storage data into the database.
fn update_storage(&mut self, update: <Self::State as StateBackend>::Transaction) -> error::Result<()>;
/// Inject storage data into the database replacing any existing data.
Expand All @@ -44,21 +45,21 @@ pub trait BlockImportOperation {
///
/// The same applies for live `BlockImportOperation`s: while an import operation building on a parent `P`
/// is alive, the state for `P` should not be pruned.
pub trait Backend {
pub trait Backend<Block: BlockT> {
/// Associated block insertion operation type.
type BlockImportOperation: BlockImportOperation;
type BlockImportOperation: BlockImportOperation<Block>;
/// Associated blockchain backend type.
type Blockchain: ::blockchain::Backend;
type Blockchain: ::blockchain::Backend<Block>;
/// Associated state backend type.
type State: StateBackend;

/// Begin a new block insertion transaction with given parent block id.
/// When constructing the genesis, this is called with all-zero hash.
fn begin_operation(&self, block: BlockId) -> error::Result<Self::BlockImportOperation>;
fn begin_operation(&self, block: BlockId<Block>) -> error::Result<Self::BlockImportOperation>;
/// Commit block insertion.
fn commit_operation(&self, transaction: Self::BlockImportOperation) -> error::Result<()>;
/// Returns reference to blockchain backend.
fn blockchain(&self) -> &Self::Blockchain;
/// Returns state backend with post-state of given block.
fn state_at(&self, block: BlockId) -> error::Result<Self::State>;
fn state_at(&self, block: BlockId<Block>) -> error::Result<Self::State>;
}
73 changes: 38 additions & 35 deletions substrate/client/src/block_builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,74 +17,77 @@
//! Utility struct to build a block.

use std::vec::Vec;
use std::marker::PhantomData;
use codec::{Joiner, Slicable};
use state_machine::{self, CodeExecutor};
use primitives::{Header, Block};
use primitives::block::{Id as BlockId, Extrinsic};
use runtime_primitives::traits::{Header as HeaderT, Hashing as HashingT, Block as BlockT};
use runtime_primitives::generic::BlockId;
use {backend, error, 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,
/// Utility for building new (valid) blocks from a stream of extrinsics.
pub struct BlockBuilder<B, E, Block, Hashing> where
B: backend::Backend<Block>,
E: CodeExecutor + Clone,
error::Error: From<<<B as backend::Backend>::State as state_machine::backend::Backend>::Error>,
Block: BlockT,
Hashing: HashingT<Output = <<Block as BlockT>::Header as HeaderT>::Hash>,
error::Error: From<<<B as backend::Backend<Block>>::State as state_machine::backend::Backend>::Error>,
{
header: Header,
transactions: Vec<Extrinsic>,
header: <Block as BlockT>::Header,
extrinsics: Vec<<Block as BlockT>::Extrinsic>,
executor: E,
state: B::State,
changes: state_machine::OverlayedChanges,
dummy: PhantomData<Hashing>,
Copy link
Contributor

@rphmeier rphmeier May 24, 2018

Choose a reason for hiding this comment

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

The block (or even header) type ought to specify what hash algorithm it's using. Otherwise you need to specify Hashing everywhere you want to do a simple transformation from block header to hash.

}

impl<B, E> BlockBuilder<B, E> where
B: backend::Backend,
impl<B, E, Block, Hashing> BlockBuilder<B, E, Block, Hashing> where
B: backend::Backend<Block>,
E: CodeExecutor + Clone,
error::Error: From<<<B as backend::Backend>::State as state_machine::backend::Backend>::Error>,
Block: BlockT,
Hashing: HashingT<Output = <<Block as BlockT>::Header as HeaderT>::Hash>,
error::Error: From<<<B as backend::Backend<Block>>::State as state_machine::backend::Backend>::Error>,
{
/// Create a new instance of builder from the given client, building on the latest block.
pub fn new(client: &Client<B, E>) -> error::Result<Self> {
client.info().and_then(|i| Self::at_block(&BlockId::Hash(i.chain.best_hash), client))
pub fn new(client: &Client<B, E, Block, Hashing>) -> error::Result<Self> {
client.info().and_then(|i| Self::at_block(&BlockId::<Block>::Hash(i.chain.best_hash), client))
}

/// Create a new instance of builder from the given client using a particular block's ID to
/// build upon.
pub fn at_block(block_id: &BlockId, client: &Client<B, E>) -> error::Result<Self> {
pub fn at_block(block_id: &BlockId<Block>, client: &Client<B, E, Block, Hashing>) -> error::Result<Self> {
Ok(BlockBuilder {
header: Header {
number: client.block_number_from_id(block_id)?.ok_or(error::ErrorKind::UnknownBlock(*block_id))? + 1,
parent_hash: client.block_hash_from_id(block_id)?.ok_or(error::ErrorKind::UnknownBlock(*block_id))?,
state_root: Default::default(),
extrinsics_root: Default::default(),
digest: Default::default(),
},
transactions: Default::default(),
header: <<Block as BlockT>::Header as HeaderT>::new(
client.block_number_from_id(block_id)?.ok_or(error::ErrorKind::UnknownBlock(Box::new(block_id.clone())))? + 1,
Default::default(),
Default::default(),
client.block_hash_from_id(block_id)?.ok_or(error::ErrorKind::UnknownBlock(Box::new(block_id.clone())))?,
Default::default()
),
extrinsics: Default::default(),
executor: client.clone_executor(),
state: client.state_at(block_id)?,
changes: Default::default(),
dummy: Default::default(),
})
}

/// Push a transaction onto the block's list of transactions. This will ensure the transaction
/// Push a transaction onto the block's list of extrinsics. 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: Extrinsic) -> error::Result<()> {
pub fn push(&mut self, xt: <Block as BlockT>::Extrinsic) -> 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 so must be valid");
self.transactions.push(tx);
&vec![].and(&self.header).and(&xt))?;
self.header = <<Block as BlockT>::Header as Slicable>::decode(&mut &output[..]).expect("Header came straight out of runtime so must be valid");
self.extrinsics.push(xt);
Ok(())
}

/// Consume the builder to return a valid `Block` containing all pushed transactions.
/// Consume the builder to return a valid `Block` containing all pushed extrinsics.
pub fn bake(mut self) -> error::Result<Block> {
self.header.extrinsics_root = ordered_trie_root(self.transactions.iter().map(Slicable::encode)).0.into();
self.header.extrinsics_root = Hashing::ordered_trie_root(self.extrinsics.iter().map(Slicable::encode));
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 so must be valid");
Ok(Block {
header: self.header,
transactions: self.transactions,
})
self.header = <<Block as BlockT>::Header as Slicable>::decode(&mut &output[..]).expect("Header came straight out of runtime so must be valid");
Ok(<Block as BlockT>::new(self.header, self.extrinsics))
}
}
28 changes: 15 additions & 13 deletions substrate/client/src/blockchain.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,24 +16,26 @@

//! Polkadot blockchain trait

use primitives::block::{self, Id as BlockId};
use primitives;
use runtime_primitives::traits::{Block as BlockT, Header as HeaderT};
use runtime_primitives::generic::BlockId;
use primitives::bft::Justification;

use error::Result;

/// Blockchain database backend. Does not perform any validation.
pub trait Backend: Send + Sync {
pub trait Backend<Block: BlockT>: Send + Sync {
/// Get block header. Returns `None` if block is not found.
fn header(&self, id: BlockId) -> Result<Option<block::Header>>;
fn header(&self, id: BlockId<Block>) -> Result<Option<<Block as BlockT>::Header>>;
/// Get block body. Returns `None` if block is not found.
fn body(&self, id: BlockId) -> Result<Option<block::Body>>;
fn body(&self, id: BlockId<Block>) -> Result<Option<Vec<<Block as BlockT>::Extrinsic>>>;
/// Get block justification. Returns `None` if justification does not exist.
fn justification(&self, id: BlockId) -> Result<Option<primitives::bft::Justification>>;
fn justification(&self, id: BlockId<Block>) -> Result<Option<Justification>>;
/// Get blockchain info.
fn info(&self) -> Result<Info>;
fn info(&self) -> Result<Info<Block>>;
/// Get block status.
fn status(&self, id: BlockId) -> Result<BlockStatus>;
fn status(&self, id: BlockId<Block>) -> Result<BlockStatus>;
/// Get block hash by number. Returns `None` if the header is not in the chain.
fn hash(&self, number: block::Number) -> Result<Option<block::HeaderHash>>;
fn hash(&self, number: <<Block as BlockT>::Header as HeaderT>::Number) -> Result<Option<<<Block as BlockT>::Header as HeaderT>::Hash>>;
}

/// Block import outcome
Expand All @@ -50,13 +52,13 @@ pub enum ImportResult<E> {

/// Blockchain info
#[derive(Debug)]
pub struct Info {
pub struct Info<Block: BlockT> {
/// Best block hash.
pub best_hash: block::HeaderHash,
pub best_hash: <<Block as BlockT>::Header as HeaderT>::Hash,
/// Best block number.
pub best_number: block::Number,
pub best_number: <<Block as BlockT>::Header as HeaderT>::Number,
/// Genesis block hash.
pub genesis_hash: block::HeaderHash,
pub genesis_hash: <<Block as BlockT>::Header as HeaderT>::Hash,
}

/// Block status.
Expand Down
Loading