Make node-template in sync with node. (#3422)

* Make node-template in sync with node.

* Update service.rs

* Updated babe constants.

* Added SignedExtra for CheckVersion in node-template and subkey.

* Added CheckVersion SignedExtra for node.

* Fixed tests.

* Try fix integration test.

* Attempt 2 at fixing integration test.

* Update node-template/runtime/src/lib.rs
This commit is contained in:
Gautam Dhameja
2019-08-19 09:17:33 +02:00
committed by Gavin Wood
parent 8eacdb54de
commit 0bb44f5024
15 changed files with 456 additions and 181 deletions
+3 -2
View File
@@ -27,8 +27,9 @@ substrate-service = { path = "../core/service" }
inherents = { package = "substrate-inherents", path = "../core/inherents" }
transaction-pool = { package = "substrate-transaction-pool", path = "../core/transaction-pool" }
network = { package = "substrate-network", path = "../core/network" }
consensus = { package = "substrate-consensus-aura", path = "../core/consensus/aura" }
aura-primitives = { package = "substrate-consensus-aura-primitives", path = "../core/consensus/aura/primitives" }
babe = { package = "substrate-consensus-babe", path = "../core/consensus/babe" }
babe-primitives = { package = "substrate-consensus-babe-primitives", path = "../core/consensus/babe/primitives" }
grandpa = { package = "substrate-finality-grandpa", path = "../core/finality-grandpa" }
grandpa-primitives = { package = "substrate-finality-grandpa-primitives", path = "../core/finality-grandpa/primitives" }
substrate-client = { path = "../core/client" }
basic-authorship = { package = "substrate-basic-authorship", path = "../core/basic-authorship" }
+13 -5
View File
@@ -1,8 +1,8 @@
# Template Node
# Substrate Node Template
A new SRML-based Substrate node, ready for hacking.
# Building
## Build
Install Rust:
@@ -16,13 +16,15 @@ Install required tools:
./scripts/init.sh
```
Build all native code:
Build Wasm and native code:
```bash
cargo build
```
# Run
## Run
### Single node development chain
You can start a development chain with:
@@ -32,7 +34,13 @@ cargo run -- --dev
Detailed logs may be shown by running the node with the following environment variables set: `RUST_LOG=debug RUST_BACKTRACE=1 cargo run -- --dev`.
If you want to see the multi-node consensus algorithm in action locally, then you can create a local testnet with two validator nodes for Alice and Bob, who are the initial authorities of the genesis chain that have been endowed with testnet units. Give each node a name and expose them so they are listed on the Polkadot [telemetry site](https://telemetry.polkadot.io/#/Local%20Testnet). You'll need two terminal windows open.
### Multi-node local testnet
If you want to see the multi-node consensus algorithm in action locally, then you can create a local testnet with two validator nodes for Alice and Bob, who are the initial authorities of the genesis chain that have been endowed with testnet units.
Optionally, give each node a name and expose them so they are listed on the Polkadot [telemetry site](https://telemetry.polkadot.io/#/Local%20Testnet).
You'll need two terminal windows open.
We'll start Alice's substrate node first on default TCP port 30333 with her chain database stored locally at `/tmp/alice`. The bootnode ID of her node is `QmRpheLN4JWdAnY7HGJfWFNbfkQCb6tFf4vvA6hgjMZKrR`, which is generated from the `--node-key` value that we specify below:
+8 -5
View File
@@ -5,7 +5,6 @@ authors = ["Anonymous"]
edition = "2018"
[dependencies]
serde = { version = "1.0", optional = true, features = ["derive"] }
safe-mix = { version = "1.0", default-features = false }
codec = { package = "parity-scale-codec", version = "1.0.0", default-features = false, features = ["derive"] }
@@ -16,15 +15,17 @@ support = { package = "srml-support", path = "../../srml/support", default_featu
primitives = { package = "substrate-primitives", path = "../../core/primitives", default_features = false }
substrate-session = { path = "../../core/session", default-features = false }
balances = { package = "srml-balances", path = "../../srml/balances", default_features = false }
aura = { package = "srml-aura", path = "../../srml/aura", default_features = false }
babe = { package = "srml-babe", path = "../../srml/babe", default-features = false }
babe-primitives = { package = "substrate-consensus-babe-primitives", path = "../../core/consensus/babe/primitives", default-features = false }
executive = { package = "srml-executive", path = "../../srml/executive", default_features = false }
indices = { package = "srml-indices", path = "../../srml/indices", default_features = false }
grandpa = { package = "srml-grandpa", path = "../../srml/grandpa", default-features = false }
system = { package = "srml-system", path = "../../srml/system", default_features = false }
timestamp = { package = "srml-timestamp", path = "../../srml/timestamp", default_features = false }
sudo = { package = "srml-sudo", path = "../../srml/sudo", default_features = false }
sr-primitives = { path = "../../core/sr-primitives", default_features = false }
client = { package = "substrate-client", path = "../../core/client", default_features = false }
consensus-aura = { package = "substrate-consensus-aura-primitives", path = "../../core/consensus/aura/primitives", default_features = false }
consensus-primitives = { package = "substrate-consensus-common-primitives", path = "../../core/consensus/common/primitives", default-features = false }
offchain-primitives = { package = "substrate-offchain-primitives", path = "../../core/offchain/primitives", default-features = false }
[build-dependencies]
@@ -39,9 +40,11 @@ std = [
"runtime-io/std",
"support/std",
"balances/std",
"babe/std",
"babe-primitives/std",
"executive/std",
"aura/std",
"indices/std",
"grandpa/std",
"primitives/std",
"sr-primitives/std",
"system/std",
@@ -50,7 +53,7 @@ std = [
"version/std",
"serde",
"safe-mix/std",
"consensus-aura/std",
"consensus-primitives/std",
"offchain-primitives/std",
"substrate-session/std",
]
+141 -47
View File
@@ -9,16 +9,19 @@
include!(concat!(env!("OUT_DIR"), "/wasm_binary.rs"));
use rstd::prelude::*;
use primitives::{sr25519, OpaqueMetadata, crypto::key_types};
use primitives::{OpaqueMetadata, crypto::key_types};
use sr_primitives::{
ApplyResult, transaction_validity::TransactionValidity, generic, create_runtime_str,
impl_opaque_keys,
impl_opaque_keys, AnySignature
};
use sr_primitives::traits::{NumberFor, BlakeTwo256, Block as BlockT, StaticLookup, Verify, ConvertInto};
use sr_primitives::traits::{NumberFor, BlakeTwo256, Block as BlockT, DigestFor, StaticLookup, Verify, ConvertInto};
use sr_primitives::weights::Weight;
use babe::{AuthorityId as BabeId};
use grandpa::{AuthorityId as GrandpaId, AuthorityWeight as GrandpaWeight};
use grandpa::fg_primitives::{self, ScheduledChange};
use client::{
block_builder::api::{CheckInherentsResult, InherentData, self as block_builder_api},
runtime_api, impl_runtime_apis
runtime_api as client_api, impl_runtime_apis
};
use version::RuntimeVersion;
#[cfg(feature = "std")]
@@ -32,29 +35,31 @@ pub use balances::Call as BalancesCall;
pub use sr_primitives::{Permill, Perbill};
pub use support::{StorageValue, construct_runtime, parameter_types};
/// Alias to the signature scheme used for Aura authority signatures.
pub type AuraSignature = consensus_aura::sr25519::AuthoritySignature;
/// An index to a block.
pub type BlockNumber = u32;
/// The Ed25519 pub key of an session that belongs to an Aura authority of the chain.
pub type AuraId = consensus_aura::sr25519::AuthorityId;
/// Alias to 512-bit hash when used in the context of a transaction signature on the chain.
pub type Signature = AnySignature;
/// Alias to pubkey that identifies an account on the chain.
pub type AccountId = <AccountSignature as Verify>::Signer;
/// Some way of identifying an account on the chain. We intentionally make it equivalent
/// to the public key of our transaction signing scheme.
pub type AccountId = <Signature as Verify>::Signer;
/// The type used by authorities to prove their ID.
pub type AccountSignature = sr25519::Signature;
/// The type for looking up accounts. We don't expect more than 4 billion of them, but you
/// never know...
pub type AccountIndex = u32;
/// Balance of an account.
pub type Balance = u128;
/// Index of a transaction in the chain.
pub type Index = u32;
/// A hash of some data used by the chain.
pub type Hash = primitives::H256;
/// Index of a block number in the chain.
pub type BlockNumber = u32;
/// Index of an account's extrinsic in the chain.
pub type Nonce = u32;
/// Balance type for the node.
pub type Balance = u128;
/// Digest item type.
pub type DigestItem = generic::DigestItem<Hash>;
/// Used for the module template in `./template.rs`
mod template;
@@ -75,10 +80,14 @@ pub mod opaque {
/// Opaque block identifier type.
pub type BlockId = generic::BlockId<Block>;
pub type SessionHandlers = (Grandpa, Babe);
impl_opaque_keys! {
pub struct SessionKeys {
#[id(key_types::AURA)]
pub aura: AuraId,
#[id(key_types::GRANDPA)]
pub grandpa: GrandpaId,
#[id(key_types::BABE)]
pub babe: BabeId,
}
}
}
@@ -93,6 +102,34 @@ pub const VERSION: RuntimeVersion = RuntimeVersion {
apis: RUNTIME_API_VERSIONS,
};
/// Constants for Babe.
/// Since BABE is probabilistic this is the average expected block time that
/// we are targetting. Blocks will be produced at a minimum duration defined
/// by `SLOT_DURATION`, but some slots will not be allocated to any
/// authority and hence no block will be produced. We expect to have this
/// block time on average following the defined slot duration and the value
/// of `c` configured for BABE (where `1 - c` represents the probability of
/// a slot being empty).
/// This value is only used indirectly to define the unit constants below
/// that are expressed in blocks. The rest of the code should use
/// `SLOT_DURATION` instead (like the timestamp module for calculating the
/// minimum period).
/// <https://research.web3.foundation/en/latest/polkadot/BABE/Babe/#6-practical-results>
pub const MILLISECS_PER_BLOCK: u64 = 6000;
pub const SLOT_DURATION: u64 = MILLISECS_PER_BLOCK;
pub const EPOCH_DURATION_IN_BLOCKS: u32 = 10 * MINUTES;
// These time units are defined in number of blocks.
pub const MINUTES: BlockNumber = 60_000 / (MILLISECS_PER_BLOCK as BlockNumber);
pub const HOURS: BlockNumber = MINUTES * 60;
pub const DAYS: BlockNumber = HOURS * 24;
// 1 in 4 blocks (on average, not counting collisions) will be primary babe blocks.
pub const PRIMARY_PROBABILITY: (u64, u64) = (1, 4);
/// The version infromation used to identify this runtime when compiled natively.
#[cfg(feature = "std")]
pub fn native_version() -> NativeVersion {
@@ -118,7 +155,7 @@ impl system::Trait for Runtime {
/// The lookup mechanism to get account ID from whatever is passed in dispatchers.
type Lookup = Indices;
/// The index type for storing how many extrinsics an account has signed.
type Index = Nonce;
type Index = Index;
/// The index type for blocks.
type BlockNumber = BlockNumber;
/// The type for hashing blocks and tries.
@@ -144,8 +181,18 @@ impl system::Trait for Runtime {
type Version = Version;
}
impl aura::Trait for Runtime {
type AuthorityId = AuraId;
parameter_types! {
pub const EpochDuration: u64 = EPOCH_DURATION_IN_BLOCKS as u64;
pub const ExpectedBlockTime: u64 = MILLISECS_PER_BLOCK;
}
impl babe::Trait for Runtime {
type EpochDuration = EpochDuration;
type ExpectedBlockTime = ExpectedBlockTime;
}
impl grandpa::Trait for Runtime {
type Event = Event;
}
impl indices::Trait for Runtime {
@@ -167,7 +214,7 @@ parameter_types! {
impl timestamp::Trait for Runtime {
/// A timestamp: milliseconds since the unix epoch.
type Moment = u64;
type OnTimestampSet = Aura;
type OnTimestampSet = Babe;
type MinimumPeriod = MinimumPeriod;
}
@@ -201,7 +248,6 @@ impl balances::Trait for Runtime {
}
impl sudo::Trait for Runtime {
/// The ubiquitous event type.
type Event = Event;
type Proposal = Call;
}
@@ -219,7 +265,8 @@ construct_runtime!(
{
System: system::{Module, Call, Storage, Config, Event},
Timestamp: timestamp::{Module, Call, Storage, Inherent},
Aura: aura::{Module, Config<T>, Inherent(Timestamp)},
Babe: babe::{Module, Call, Storage, Config, Inherent(Timestamp)},
Grandpa: grandpa::{Module, Call, Storage, Config, Event},
Indices: indices::{default, Config<T>},
Balances: balances,
Sudo: sudo,
@@ -228,28 +275,34 @@ construct_runtime!(
}
);
/// The type used as a helper for interpreting the sender of transactions.
type Context = system::ChainContext<Runtime>;
/// The address format for describing accounts.
type Address = <Indices as StaticLookup>::Source;
pub type Address = <Indices as StaticLookup>::Source;
/// Block header type as expected by this runtime.
pub type Header = generic::Header<BlockNumber, BlakeTwo256>;
/// Block type as expected by this runtime.
pub type Block = generic::Block<Header, UncheckedExtrinsic>;
/// A Block signed with a Justification
pub type SignedBlock = generic::SignedBlock<Block>;
/// BlockId type as expected by this runtime.
pub type BlockId = generic::BlockId<Block>;
/// The SignedExtension to the basic transaction logic.
pub type SignedExtra = (system::CheckNonce<Runtime>, system::CheckWeight<Runtime>, balances::TakeFees<Runtime>);
pub type SignedExtra = (
system::CheckVersion<Runtime>,
system::CheckGenesis<Runtime>,
system::CheckEra<Runtime>,
system::CheckNonce<Runtime>,
system::CheckWeight<Runtime>,
balances::TakeFees<Runtime>
);
/// Unchecked extrinsic type as expected by this runtime.
pub type UncheckedExtrinsic = generic::UncheckedExtrinsic<Address, Call, AccountSignature, SignedExtra>;
pub type UncheckedExtrinsic = generic::UncheckedExtrinsic<Address, Call, Signature, SignedExtra>;
/// Extrinsic type that has already been checked.
pub type CheckedExtrinsic = generic::CheckedExtrinsic<AccountId, Call, SignedExtra>;
/// Executive: handles dispatch to the various modules.
pub type Executive = executive::Executive<Runtime, Block, Context, Runtime, AllModules>;
pub type Executive = executive::Executive<Runtime, Block, system::ChainContext<Runtime>, Runtime, AllModules>;
// Implement our runtime API endpoints. This is just a bunch of proxying.
impl_runtime_apis! {
impl runtime_api::Core<Block> for Runtime {
impl client_api::Core<Block> for Runtime {
fn version() -> RuntimeVersion {
VERSION
}
@@ -263,7 +316,7 @@ impl_runtime_apis! {
}
}
impl runtime_api::Metadata<Block> for Runtime {
impl client_api::Metadata<Block> for Runtime {
fn metadata() -> OpaqueMetadata {
Runtime::metadata().into()
}
@@ -291,24 +344,65 @@ impl_runtime_apis! {
}
}
impl runtime_api::TaggedTransactionQueue<Block> for Runtime {
impl client_api::TaggedTransactionQueue<Block> for Runtime {
fn validate_transaction(tx: <Block as BlockT>::Extrinsic) -> TransactionValidity {
Executive::validate_transaction(tx)
}
}
impl consensus_aura::AuraApi<Block, AuraId> for Runtime {
fn slot_duration() -> u64 {
Aura::slot_duration()
}
fn authorities() -> Vec<AuraId> {
Aura::authorities()
impl offchain_primitives::OffchainWorkerApi<Block> for Runtime {
fn offchain_worker(number: NumberFor<Block>) {
Executive::offchain_worker(number)
}
}
impl offchain_primitives::OffchainWorkerApi<Block> for Runtime {
fn offchain_worker(n: NumberFor<Block>) {
Executive::offchain_worker(n)
impl fg_primitives::GrandpaApi<Block> for Runtime {
fn grandpa_pending_change(digest: &DigestFor<Block>)
-> Option<ScheduledChange<NumberFor<Block>>>
{
Grandpa::pending_change(digest)
}
fn grandpa_forced_change(digest: &DigestFor<Block>)
-> Option<(NumberFor<Block>, ScheduledChange<NumberFor<Block>>)>
{
Grandpa::forced_change(digest)
}
fn grandpa_authorities() -> Vec<(GrandpaId, GrandpaWeight)> {
Grandpa::grandpa_authorities()
}
}
impl babe_primitives::BabeApi<Block> for Runtime {
fn startup_data() -> babe_primitives::BabeConfiguration {
// The choice of `c` parameter (where `1 - c` represents the
// probability of a slot being empty), is done in accordance to the
// slot duration and expected target block time, for safely
// resisting network delays of maximum two seconds.
// <https://research.web3.foundation/en/latest/polkadot/BABE/Babe/#6-practical-results>
babe_primitives::BabeConfiguration {
median_required_blocks: 1000,
slot_duration: Babe::slot_duration(),
c: PRIMARY_PROBABILITY,
}
}
fn epoch() -> babe_primitives::Epoch {
babe_primitives::Epoch {
start_slot: Babe::epoch_start_slot(),
authorities: Babe::authorities(),
epoch_index: Babe::epoch_index(),
randomness: Babe::randomness(),
duration: EpochDuration::get(),
secondary_slots: Babe::secondary_slots().0,
}
}
}
impl consensus_primitives::ConsensusApi<Block, babe_primitives::AuthorityId> for Runtime {
fn authorities() -> Vec<babe_primitives::AuthorityId> {
Babe::authorities().into_iter().map(|(a, _)| a).collect()
}
}
+53 -30
View File
@@ -1,9 +1,10 @@
use primitives::{sr25519, Pair};
use primitives::{Pair, Public};
use node_template_runtime::{
AccountId, GenesisConfig, AuraConfig, BalancesConfig,
SudoConfig, IndicesConfig, SystemConfig, WASM_BINARY, AuraId
AccountId, BabeConfig, BalancesConfig, GenesisConfig, GrandpaConfig,
SudoConfig, IndicesConfig, SystemConfig, WASM_BINARY,
};
use aura_primitives::sr25519::AuthorityPair as AuraPair;
use babe_primitives::{AuthorityId as BabeId};
use grandpa_primitives::{AuthorityId as GrandpaId};
use substrate_service;
// Note this is the URL for the telemetry server
@@ -23,16 +24,21 @@ pub enum Alternative {
LocalTestnet,
}
fn authority_key(s: &str) -> AuraId {
AuraPair::from_string(&format!("//{}", s), None)
/// Helper function to generate a crypto pair from seed
pub fn get_from_seed<TPublic: Public>(seed: &str) -> <TPublic::Pair as Pair>::Public {
TPublic::Pair::from_string(&format!("//{}", seed), None)
.expect("static values are valid; qed")
.public()
}
fn account_key(s: &str) -> AccountId {
sr25519::Pair::from_string(&format!("//{}", s), None)
.expect("static values are valid; qed")
.public()
/// Helper function to generate stash, controller and session key from seed
pub fn get_authority_keys_from_seed(seed: &str) -> (AccountId, AccountId, GrandpaId, BabeId) {
(
get_from_seed::<AccountId>(&format!("{}//stash", seed)),
get_from_seed::<AccountId>(seed),
get_from_seed::<GrandpaId>(seed),
get_from_seed::<BabeId>(seed),
)
}
impl Alternative {
@@ -43,12 +49,16 @@ impl Alternative {
"Development",
"dev",
|| testnet_genesis(vec![
authority_key("Alice")
], vec![
account_key("Alice")
get_authority_keys_from_seed("Alice"),
],
account_key("Alice")
),
get_from_seed::<AccountId>("Alice"),
vec![
get_from_seed::<AccountId>("Alice"),
get_from_seed::<AccountId>("Bob"),
get_from_seed::<AccountId>("Alice//stash"),
get_from_seed::<AccountId>("Bob//stash"),
],
true),
vec![],
None,
None,
@@ -59,18 +69,25 @@ impl Alternative {
"Local Testnet",
"local_testnet",
|| testnet_genesis(vec![
authority_key("Alice"),
authority_key("Bob"),
], vec![
account_key("Alice"),
account_key("Bob"),
account_key("Charlie"),
account_key("Dave"),
account_key("Eve"),
account_key("Ferdie"),
get_authority_keys_from_seed("Alice"),
get_authority_keys_from_seed("Bob"),
],
get_from_seed::<AccountId>("Alice"),
vec![
get_from_seed::<AccountId>("Alice"),
get_from_seed::<AccountId>("Bob"),
get_from_seed::<AccountId>("Charlie"),
get_from_seed::<AccountId>("Dave"),
get_from_seed::<AccountId>("Eve"),
get_from_seed::<AccountId>("Ferdie"),
get_from_seed::<AccountId>("Alice//stash"),
get_from_seed::<AccountId>("Bob//stash"),
get_from_seed::<AccountId>("Charlie//stash"),
get_from_seed::<AccountId>("Dave//stash"),
get_from_seed::<AccountId>("Eve//stash"),
get_from_seed::<AccountId>("Ferdie//stash"),
],
account_key("Alice"),
),
true),
vec![],
None,
None,
@@ -89,15 +106,15 @@ impl Alternative {
}
}
fn testnet_genesis(initial_authorities: Vec<AuraId>, endowed_accounts: Vec<AccountId>, root_key: AccountId) -> GenesisConfig {
fn testnet_genesis(initial_authorities: Vec<(AccountId, AccountId, GrandpaId, BabeId)>,
root_key: AccountId,
endowed_accounts: Vec<AccountId>,
_enable_println: bool) -> GenesisConfig {
GenesisConfig {
system: Some(SystemConfig {
code: WASM_BINARY.to_vec(),
changes_trie_config: Default::default(),
}),
aura: Some(AuraConfig {
authorities: initial_authorities.clone(),
}),
indices: Some(IndicesConfig {
ids: endowed_accounts.clone(),
}),
@@ -108,5 +125,11 @@ fn testnet_genesis(initial_authorities: Vec<AuraId>, endowed_accounts: Vec<Accou
sudo: Some(SudoConfig {
key: root_key,
}),
babe: Some(BabeConfig {
authorities: initial_authorities.iter().map(|x| (x.3.clone(), 1)).collect(),
}),
grandpa: Some(GrandpaConfig {
authorities: initial_authorities.iter().map(|x| (x.2.clone(), 1)).collect(),
}),
}
}
+207 -81
View File
@@ -1,26 +1,26 @@
//! Service and ServiceFactory implementation. Specialized wrapper over Substrate service.
#![warn(unused_extern_crates)]
//! Service and ServiceFactory implementation. Specialized wrapper over substrate service.
use std::sync::Arc;
use transaction_pool::{self, txpool::{Pool as TransactionPool}};
use std::time::Duration;
use substrate_client::{self as client, LongestChain};
use babe::{import_queue, start_babe, BabeImportQueue, Config};
use grandpa::{self, FinalityProofProvider as GrandpaFinalityProofProvider};
use futures::prelude::*;
use node_template_runtime::{self, GenesisConfig, opaque::Block, RuntimeApi, WASM_BINARY};
use substrate_service::{
FactoryFullConfiguration, LightComponents, FullComponents, FullBackend,
FullClient, LightClient, LightBackend, FullExecutor, LightExecutor,
error::{Error as ServiceError},
};
use basic_authorship::ProposerFactory;
use consensus::{import_queue, start_aura, AuraImportQueue, SlotDuration};
use futures::prelude::*;
use substrate_client::{self as client, LongestChain};
use transaction_pool::{self, txpool::{Pool as TransactionPool}};
use inherents::InherentDataProviders;
use network::{config::DummyFinalityProofRequestBuilder, construct_simple_protocol};
use network::construct_simple_protocol;
use substrate_executor::native_executor_instance;
use substrate_service::construct_service_factory;
use aura_primitives::sr25519::AuthorityPair as AuraAuthorityPair;
use substrate_service::{ServiceFactory, construct_service_factory, TelemetryOnConnect};
pub use substrate_executor::NativeExecutor;
// Our native executor instance.
native_executor_instance!(
pub Executor,
@@ -29,62 +29,168 @@ native_executor_instance!(
WASM_BINARY
);
#[derive(Default)]
pub struct NodeConfig {
inherent_data_providers: InherentDataProviders,
}
construct_simple_protocol! {
/// Demo protocol attachment for substrate.
pub struct NodeProtocol where Block = Block { }
}
type BabeBlockImportForService<F> = babe::BabeBlockImport<
FullBackend<F>,
FullExecutor<F>,
<F as ServiceFactory>::Block,
grandpa::BlockImportForService<F>,
<F as ServiceFactory>::RuntimeApi,
client::Client<
FullBackend<F>,
FullExecutor<F>,
<F as ServiceFactory>::Block,
<F as ServiceFactory>::RuntimeApi
>,
>;
pub struct NodeConfig<F: ServiceFactory> {
/// GRANDPA and BABE connection to import block.
// FIXME #1134 rather than putting this on the config, let's have an actual intermediate setup state
pub import_setup: Option<(
BabeBlockImportForService<F>,
grandpa::LinkHalfForService<F>,
babe::BabeLink,
)>,
/// Tasks that were created by previous setup steps and should be spawned.
pub tasks_to_spawn: Option<Vec<Box<dyn Future<Item = (), Error = ()> + Send>>>,
inherent_data_providers: InherentDataProviders,
}
impl<F> Default for NodeConfig<F> where F: ServiceFactory {
fn default() -> NodeConfig<F> {
NodeConfig {
import_setup: None,
inherent_data_providers: InherentDataProviders::new(),
tasks_to_spawn: None,
}
}
}
construct_service_factory! {
struct Factory {
Block = Block,
RuntimeApi = RuntimeApi,
NetworkProtocol = NodeProtocol { |config| Ok(NodeProtocol::new()) },
RuntimeDispatch = Executor,
FullTransactionPoolApi = transaction_pool::ChainApi<
client::Client<FullBackend<Self>, FullExecutor<Self>, Block, RuntimeApi>,
Block
> {
|config, client| Ok(TransactionPool::new(config, transaction_pool::ChainApi::new(client)))
},
LightTransactionPoolApi = transaction_pool::ChainApi<
client::Client<LightBackend<Self>, LightExecutor<Self>, Block, RuntimeApi>,
Block
> {
|config, client| Ok(TransactionPool::new(config, transaction_pool::ChainApi::new(client)))
},
Genesis = GenesisConfig,
Configuration = NodeConfig,
FullService = FullComponents<Self>
{ |config: FactoryFullConfiguration<Self>|
FullComponents::<Factory>::new(config)
FullTransactionPoolApi =
transaction_pool::ChainApi<
client::Client<FullBackend<Self>, FullExecutor<Self>, Block, RuntimeApi>,
Block
> {
|config, client|
Ok(TransactionPool::new(config, transaction_pool::ChainApi::new(client)))
},
LightTransactionPoolApi =
transaction_pool::ChainApi<
client::Client<LightBackend<Self>, LightExecutor<Self>, Block, RuntimeApi>,
Block
> {
|config, client|
Ok(TransactionPool::new(config, transaction_pool::ChainApi::new(client)))
},
Genesis = GenesisConfig,
Configuration = NodeConfig<Self>,
FullService = FullComponents<Self> {
|config: FactoryFullConfiguration<Self>| FullComponents::<Factory>::new(config)
},
AuthoritySetup = {
|service: Self::FullService| {
|mut service: Self::FullService| {
let (block_import, link_half, babe_link) =
service.config_mut().custom.import_setup.take()
.expect("Link Half and Block Import are present for Full Services or setup failed before. qed");
// spawn any futures that were created in the previous setup steps
if let Some(tasks) = service.config_mut().custom.tasks_to_spawn.take() {
for task in tasks {
service.spawn_task(
task.select(service.on_exit())
.map(|_| ())
.map_err(|_| ())
);
}
}
if service.config().roles.is_authority() {
let proposer = ProposerFactory {
let proposer = basic_authorship::ProposerFactory {
client: service.client(),
transaction_pool: service.transaction_pool(),
};
let client = service.client();
let select_chain = service.select_chain()
.ok_or_else(|| ServiceError::SelectChainRequired)?;
let aura = start_aura::<_, _, _, _, _, AuraAuthorityPair, _, _, _>(
SlotDuration::get_or_compute(&*client)?,
client.clone(),
select_chain,
.ok_or(ServiceError::SelectChainRequired)?;
let babe_config = babe::BabeParams {
config: Config::get_or_compute(&*client)?,
keystore: service.keystore(),
client,
proposer,
service.network(),
service.config().custom.inherent_data_providers.clone(),
service.config().force_authoring,
Some(service.keystore()),
)?;
service.spawn_task(Box::new(aura.select(service.on_exit()).then(|_| Ok(()))));
select_chain,
block_import,
env: proposer,
sync_oracle: service.network(),
inherent_data_providers: service.config()
.custom.inherent_data_providers.clone(),
force_authoring: service.config().force_authoring,
time_source: babe_link,
};
let babe = start_babe(babe_config)?;
let select = babe.select(service.on_exit()).then(|_| Ok(()));
// the BABE authoring task is considered infallible, i.e. if it
// fails we take down the service with it.
service.spawn_essential_task(select);
}
let config = grandpa::Config {
// FIXME #1578 make this available through chainspec
gossip_duration: Duration::from_millis(333),
justification_period: 4096,
name: Some(service.config().name.clone()),
keystore: Some(service.keystore()),
};
match (service.config().roles.is_authority(), service.config().disable_grandpa) {
(false, false) => {
// start the lightweight GRANDPA observer
service.spawn_task(Box::new(grandpa::run_grandpa_observer(
config,
link_half,
service.network(),
service.on_exit(),
)?));
},
(true, false) => {
// start the full GRANDPA voter
let telemetry_on_connect = TelemetryOnConnect {
telemetry_connection_sinks: service.telemetry_on_connect_stream(),
};
let grandpa_config = grandpa::GrandpaParams {
config: config,
link: link_half,
network: service.network(),
inherent_data_providers:
service.config().custom.inherent_data_providers.clone(),
on_exit: service.on_exit(),
telemetry_on_connect: Some(telemetry_on_connect),
};
// the GRANDPA voter task is considered infallible, i.e.
// if it fails we take down the service with it.
service.spawn_essential_task(grandpa::run_grandpa_voter(grandpa_config)?);
},
(_, true) => {
grandpa::setup_disabled_grandpa(
service.client(),
&service.config().custom.inherent_data_providers,
service.network(),
)?;
},
}
Ok(service)
@@ -92,50 +198,70 @@ construct_service_factory! {
},
LightService = LightComponents<Self>
{ |config| <LightComponents<Factory>>::new(config) },
FullImportQueue = AuraImportQueue<
Self::Block,
>
{ |
FullImportQueue = BabeImportQueue<Self::Block> {
|
config: &mut FactoryFullConfiguration<Self>,
client: Arc<FullClient<Self>>,
_select_chain: Self::SelectChain,
select_chain: Self::SelectChain,
transaction_pool: Option<Arc<TransactionPool<Self::FullTransactionPoolApi>>>,
| {
import_queue::<_, _, aura_primitives::sr25519::AuthorityPair, _>(
SlotDuration::get_or_compute(&*client)?,
Box::new(client.clone()),
None,
None,
client,
config.custom.inherent_data_providers.clone(),
transaction_pool,
).map_err(Into::into)
}
},
LightImportQueue = AuraImportQueue<
Self::Block,
>
{ |config: &mut FactoryFullConfiguration<Self>, client: Arc<LightClient<Self>>| {
let fprb = Box::new(DummyFinalityProofRequestBuilder::default()) as Box<_>;
import_queue::<_, _, AuraAuthorityPair, TransactionPool<Self::FullTransactionPoolApi>>(
SlotDuration::get_or_compute(&*client)?,
Box::new(client.clone()),
None,
None,
client,
config.custom.inherent_data_providers.clone(),
None,
).map(|q| (q, fprb)).map_err(Into::into)
}
},
let (block_import, link_half) =
grandpa::block_import::<_, _, _, RuntimeApi, FullClient<Self>, _>(
client.clone(), client.clone(), select_chain
)?;
let justification_import = block_import.clone();
let (import_queue, babe_link, babe_block_import, pruning_task) = import_queue(
Config::get_or_compute(&*client)?,
block_import,
Some(Box::new(justification_import)),
None,
client.clone(),
client,
config.custom.inherent_data_providers.clone(),
transaction_pool,
)?;
config.custom.import_setup = Some((babe_block_import.clone(), link_half, babe_link));
config.custom.tasks_to_spawn = Some(vec![Box::new(pruning_task)]);
Ok(import_queue)
}
},
LightImportQueue = BabeImportQueue<Self::Block>
{ |config: &FactoryFullConfiguration<Self>, client: Arc<LightClient<Self>>| {
#[allow(deprecated)]
let fetch_checker = client.backend().blockchain().fetcher()
.upgrade()
.map(|fetcher| fetcher.checker().clone())
.ok_or_else(|| "Trying to start light import queue without active fetch checker")?;
let block_import = grandpa::light_block_import::<_, _, _, RuntimeApi, LightClient<Self>>(
client.clone(), Arc::new(fetch_checker), client.clone()
)?;
let finality_proof_import = block_import.clone();
let finality_proof_request_builder =
finality_proof_import.create_finality_proof_request_builder();
// FIXME: pruning task isn't started since light client doesn't do `AuthoritySetup`.
let (import_queue, ..) = import_queue::<_, _, _, _, _, _, TransactionPool<Self::FullTransactionPoolApi>>(
Config::get_or_compute(&*client)?,
block_import,
None,
Some(Box::new(finality_proof_import)),
client.clone(),
client,
config.custom.inherent_data_providers.clone(),
None,
)?;
Ok((import_queue, finality_proof_request_builder))
}},
SelectChain = LongestChain<FullBackend<Self>, Self::Block>
{ |config: &FactoryFullConfiguration<Self>, client: Arc<FullClient<Self>>| {
#[allow(deprecated)]
Ok(LongestChain::new(client.backend().clone()))
}
},
FinalityProofProvider = { |_client: Arc<FullClient<Self>>| {
Ok(None)
FinalityProofProvider = { |client: Arc<FullClient<Self>>| {
Ok(Some(Arc::new(GrandpaFinalityProofProvider::new(client.clone(), client)) as _))
}},
}
}