Allow for customisation of chain selection systems (#2240)

* move SelectChain trait out of client

* Extend SelectChain, move longest chain implementation into it

* Bring SelectChain into service

* implement LongestChain SelectChain

* implement longest chain for node

* update Cargo.lock's

* in between erroring tests

* deprecate ::backend and ::import_lock

* Remove unneded space

Co-Authored-By: gnunicorn <ben.kampmann@googlemail.com>

* Remove unneded space

Co-Authored-By: gnunicorn <ben.kampmann@googlemail.com>

* Fixes test compilation

* remove todo

* re-enable client test

* add doc

* fixing tests

* Clarify SelectChain Interface, intended implementation and usage

* minor components cleanups

* minor cleanups

* Update lock files

* Implement cleaner interface for SelectChain

* addressing comments

* Updating tests

* bump node runtime impl version

* address grumbles
This commit is contained in:
Benjamin Kampmann
2019-05-10 14:08:12 +02:00
committed by Gavin Wood
parent 32fdeed21c
commit 18ca0170c3
22 changed files with 717 additions and 339 deletions
+58 -17
View File
@@ -16,14 +16,14 @@
//! Substrate service components.
use std::{sync::Arc, net::SocketAddr, marker::PhantomData, ops::Deref, ops::DerefMut};
use std::{sync::Arc, net::SocketAddr, ops::Deref, ops::DerefMut};
use serde::{Serialize, de::DeserializeOwned};
use tokio::runtime::TaskExecutor;
use crate::chain_spec::ChainSpec;
use client_db;
use client::{self, Client, runtime_api};
use crate::{error, Service, maybe_start_server};
use consensus_common::import_queue::ImportQueue;
use consensus_common::{import_queue::ImportQueue, SelectChain};
use network::{self, OnDemand};
use substrate_executor::{NativeExecutor, NativeExecutionDispatch};
use transaction_pool::txpool::{self, Options as TransactionPoolOptions, Pool as TransactionPool};
@@ -304,9 +304,11 @@ pub trait ServiceFactory: 'static + Sized {
/// Extended light service type.
type LightService: ServiceTrait<LightComponents<Self>>;
/// ImportQueue for full client
type FullImportQueue: consensus_common::import_queue::ImportQueue<Self::Block> + 'static;
type FullImportQueue: ImportQueue<Self::Block> + 'static;
/// ImportQueue for light clients
type LightImportQueue: consensus_common::import_queue::ImportQueue<Self::Block> + 'static;
type LightImportQueue: ImportQueue<Self::Block> + 'static;
/// The Fork Choice Strategy for the chain
type SelectChain: SelectChain<Self::Block> + 'static;
//TODO: replace these with a constructor trait. that TransactionPool implements. (#1242)
/// Extrinsic pool constructor for the full client.
@@ -320,6 +322,12 @@ pub trait ServiceFactory: 'static + Sized {
fn build_network_protocol(config: &FactoryFullConfiguration<Self>)
-> Result<Self::NetworkProtocol, error::Error>;
/// Build the Fork Choice algorithm for full client
fn build_select_chain(
config: &mut FactoryFullConfiguration<Self>,
client: Arc<FullClient<Self>>,
) -> Result<Self::SelectChain, error::Error>;
/// Build full service.
fn new_full(config: FactoryFullConfiguration<Self>, executor: TaskExecutor)
-> Result<Self::FullService, error::Error>;
@@ -330,7 +338,8 @@ pub trait ServiceFactory: 'static + Sized {
/// ImportQueue for a full client
fn build_full_import_queue(
config: &mut FactoryFullConfiguration<Self>,
_client: Arc<FullClient<Self>>
_client: Arc<FullClient<Self>>,
_select_chain: Self::SelectChain
) -> Result<Self::FullImportQueue, error::Error> {
if let Some(name) = config.chain_spec.consensus_engine() {
match name {
@@ -378,6 +387,8 @@ pub trait Components: Sized + 'static {
>;
/// Our Import Queue
type ImportQueue: ImportQueue<FactoryBlock<Self::Factory>> + 'static;
/// The Fork Choice Strategy for the chain
type SelectChain: SelectChain<FactoryBlock<Self::Factory>>;
/// Create client.
fn build_client(
@@ -398,13 +409,20 @@ pub trait Components: Sized + 'static {
/// instance of import queue for clients
fn build_import_queue(
config: &mut FactoryFullConfiguration<Self::Factory>,
client: Arc<ComponentClient<Self>>
client: Arc<ComponentClient<Self>>,
select_chain: Self::SelectChain,
) -> Result<Self::ImportQueue, error::Error>;
/// Build fork choice selector
fn build_select_chain(
config: &mut FactoryFullConfiguration<Self::Factory>,
client: Arc<ComponentClient<Self>>
) -> Result<Self::SelectChain, error::Error>;
}
/// A struct that implement `Components` for the full client.
pub struct FullComponents<Factory: ServiceFactory> {
_factory: PhantomData<Factory>,
service: Service<FullComponents<Factory>>,
}
@@ -416,7 +434,6 @@ impl<Factory: ServiceFactory> FullComponents<Factory> {
) -> Result<Self, error::Error> {
Ok(
Self {
_factory: Default::default(),
service: Service::new(config, task_executor)?,
}
)
@@ -445,6 +462,7 @@ impl<Factory: ServiceFactory> Components for FullComponents<Factory> {
type ImportQueue = Factory::FullImportQueue;
type RuntimeApi = Factory::RuntimeApi;
type RuntimeServices = Factory::FullService;
type SelectChain = Factory::SelectChain;
fn build_client(
config: &FactoryFullConfiguration<Factory>,
@@ -469,23 +487,32 @@ impl<Factory: ServiceFactory> Components for FullComponents<Factory> {
)?), None))
}
fn build_transaction_pool(config: TransactionPoolOptions, client: Arc<ComponentClient<Self>>)
-> Result<TransactionPool<Self::TransactionPoolApi>, error::Error>
{
fn build_transaction_pool(
config: TransactionPoolOptions,
client: Arc<ComponentClient<Self>>
) -> Result<TransactionPool<Self::TransactionPoolApi>, error::Error> {
Factory::build_full_transaction_pool(config, client)
}
fn build_import_queue(
config: &mut FactoryFullConfiguration<Self::Factory>,
client: Arc<ComponentClient<Self>>
client: Arc<ComponentClient<Self>>,
select_chain: Self::SelectChain,
) -> Result<Self::ImportQueue, error::Error> {
Factory::build_full_import_queue(config, client)
Factory::build_full_import_queue(config, client, select_chain)
}
fn build_select_chain(
config: &mut FactoryFullConfiguration<Self::Factory>,
client: Arc<ComponentClient<Self>>
) -> Result<Self::SelectChain, error::Error> {
Self::Factory::build_select_chain(config, client)
}
}
/// A struct that implement `Components` for the light client.
pub struct LightComponents<Factory: ServiceFactory> {
_factory: PhantomData<Factory>,
service: Service<LightComponents<Factory>>,
}
@@ -497,7 +524,6 @@ impl<Factory: ServiceFactory> LightComponents<Factory> {
) -> Result<Self, error::Error> {
Ok(
Self {
_factory: Default::default(),
service: Service::new(config, task_executor)?,
}
)
@@ -520,6 +546,7 @@ impl<Factory: ServiceFactory> Components for LightComponents<Factory> {
type ImportQueue = <Factory as ServiceFactory>::LightImportQueue;
type RuntimeApi = Factory::RuntimeApi;
type RuntimeServices = Factory::LightService;
type SelectChain = Factory::SelectChain;
fn build_client(
config: &FactoryFullConfiguration<Factory>,
@@ -554,16 +581,27 @@ impl<Factory: ServiceFactory> Components for LightComponents<Factory> {
fn build_import_queue(
config: &mut FactoryFullConfiguration<Self::Factory>,
client: Arc<ComponentClient<Self>>
client: Arc<ComponentClient<Self>>,
_select_chain: Self::SelectChain,
) -> Result<Self::ImportQueue, error::Error> {
Factory::build_light_import_queue(config, client)
}
/// Build fork choice selector
fn build_select_chain(
_config: &mut FactoryFullConfiguration<Self::Factory>,
_client: Arc<ComponentClient<Self>>
) -> Result<Self::SelectChain, error::Error> {
Err("Fork choice doesn't happen on light clients.".into())
}
}
#[cfg(test)]
mod tests {
use super::*;
use consensus_common::BlockOrigin;
use client::LongestChain;
use substrate_test_client::{self, TestClient, AccountKeyring, runtime::Transfer};
#[test]
@@ -576,8 +614,11 @@ mod tests {
from: AccountKeyring::Alice.into(),
to: Default::default(),
}.into_signed_tx();
let best = LongestChain::new(client.backend().clone(), client.import_lock())
.best_chain().unwrap();
// store the transaction in the pool
pool.submit_one(&BlockId::hash(client.best_block_header().unwrap().hash()), transaction.clone()).unwrap();
pool.submit_one(&BlockId::hash(best.hash()), transaction.clone()).unwrap();
// import the block
let mut builder = client.new_block().unwrap();