From 0bb44f5024600d6f0ae9d5336099e25e41c13e59 Mon Sep 17 00:00:00 2001 From: Gautam Dhameja <gautamdhameja@users.noreply.github.com> Date: Mon, 19 Aug 2019 09:17:33 +0200 Subject: [PATCH] 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 --- substrate/Cargo.lock | 11 +- substrate/node-template/Cargo.toml | 5 +- substrate/node-template/README.md | 18 +- substrate/node-template/runtime/Cargo.toml | 13 +- substrate/node-template/runtime/src/lib.rs | 186 ++++++++--- substrate/node-template/src/chain_spec.rs | 83 +++-- substrate/node-template/src/service.rs | 288 +++++++++++++----- substrate/node/cli/src/factory_impl.rs | 5 +- substrate/node/cli/src/service.rs | 7 +- substrate/node/executor/src/lib.rs | 9 +- substrate/node/runtime/src/lib.rs | 1 + substrate/subkey/src/main.rs | 1 + .../transaction-factory/src/complex_mode.rs | 2 + .../test-utils/transaction-factory/src/lib.rs | 4 + .../transaction-factory/src/simple_modes.rs | 2 + 15 files changed, 455 insertions(+), 180 deletions(-) diff --git a/substrate/Cargo.lock b/substrate/Cargo.lock index fc3be28b208..35afd37dbb3 100644 --- a/substrate/Cargo.lock +++ b/substrate/Cargo.lock @@ -2406,9 +2406,10 @@ dependencies = [ "substrate-basic-authorship 2.0.0", "substrate-cli 2.0.0", "substrate-client 2.0.0", - "substrate-consensus-aura 2.0.0", - "substrate-consensus-aura-primitives 2.0.0", + "substrate-consensus-babe 2.0.0", + "substrate-consensus-babe-primitives 2.0.0", "substrate-executor 2.0.0", + "substrate-finality-grandpa 2.0.0", "substrate-finality-grandpa-primitives 2.0.0", "substrate-inherents 2.0.0", "substrate-network 2.0.0", @@ -2431,16 +2432,18 @@ dependencies = [ "sr-primitives 2.0.0", "sr-std 2.0.0", "sr-version 2.0.0", - "srml-aura 2.0.0", + "srml-babe 2.0.0", "srml-balances 2.0.0", "srml-executive 2.0.0", + "srml-grandpa 2.0.0", "srml-indices 2.0.0", "srml-sudo 2.0.0", "srml-support 2.0.0", "srml-system 2.0.0", "srml-timestamp 2.0.0", "substrate-client 2.0.0", - "substrate-consensus-aura-primitives 2.0.0", + "substrate-consensus-babe-primitives 2.0.0", + "substrate-consensus-common-primitives 2.0.0", "substrate-offchain-primitives 2.0.0", "substrate-primitives 2.0.0", "substrate-session 2.0.0", diff --git a/substrate/node-template/Cargo.toml b/substrate/node-template/Cargo.toml index 4112452b272..73aefc3a282 100644 --- a/substrate/node-template/Cargo.toml +++ b/substrate/node-template/Cargo.toml @@ -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" } diff --git a/substrate/node-template/README.md b/substrate/node-template/README.md index 497ed84a52b..5a59652c1b3 100644 --- a/substrate/node-template/README.md +++ b/substrate/node-template/README.md @@ -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: diff --git a/substrate/node-template/runtime/Cargo.toml b/substrate/node-template/runtime/Cargo.toml index 2f41513048d..54aee700f8c 100644 --- a/substrate/node-template/runtime/Cargo.toml +++ b/substrate/node-template/runtime/Cargo.toml @@ -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", ] diff --git a/substrate/node-template/runtime/src/lib.rs b/substrate/node-template/runtime/src/lib.rs index 3f298f1032e..9f520971ad9 100644 --- a/substrate/node-template/runtime/src/lib.rs +++ b/substrate/node-template/runtime/src/lib.rs @@ -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; -/// A hash of some data used by the chain. -pub type Hash = primitives::H256; +/// Balance of an account. +pub type Balance = u128; -/// Index of a block number in the chain. -pub type BlockNumber = u32; +/// Index of a transaction in the chain. +pub type Index = u32; -/// Index of an account's extrinsic in the chain. -pub type Nonce = u32; +/// A hash of some data used by the chain. +pub type Hash = primitives::H256; -/// 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() + impl offchain_primitives::OffchainWorkerApi<Block> for Runtime { + fn offchain_worker(number: NumberFor<Block>) { + Executive::offchain_worker(number) + } + } + + impl fg_primitives::GrandpaApi<Block> for Runtime { + fn grandpa_pending_change(digest: &DigestFor<Block>) + -> Option<ScheduledChange<NumberFor<Block>>> + { + Grandpa::pending_change(digest) } - fn authorities() -> Vec<AuraId> { - Aura::authorities() + + 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 offchain_primitives::OffchainWorkerApi<Block> for Runtime { - fn offchain_worker(n: NumberFor<Block>) { - Executive::offchain_worker(n) + 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() } } diff --git a/substrate/node-template/src/chain_spec.rs b/substrate/node-template/src/chain_spec.rs index 65caab70dbe..9fdc6ee2ca6 100644 --- a/substrate/node-template/src/chain_spec.rs +++ b/substrate/node-template/src/chain_spec.rs @@ -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"), + ], + 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"), ], - account_key("Alice") - ), + 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(), + }), } } diff --git a/substrate/node-template/src/service.rs b/substrate/node-template/src/service.rs index 7f2c80c48b2..b4a1a96413c 100644 --- a/substrate/node-template/src/service.rs +++ b/substrate/node-template/src/service.rs @@ -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 _)) }}, } } diff --git a/substrate/node/cli/src/factory_impl.rs b/substrate/node/cli/src/factory_impl.rs index 6345a851f28..e371aef8e08 100644 --- a/substrate/node/cli/src/factory_impl.rs +++ b/substrate/node/cli/src/factory_impl.rs @@ -51,6 +51,7 @@ type Number = <<node_primitives::Block as BlockT>::Header as HeaderT>::Number; impl<Number> FactoryState<Number> { fn build_extra(index: node_primitives::Index, phase: u64) -> node_runtime::SignedExtra { ( + system::CheckVersion::new(), system::CheckGenesis::new(), system::CheckEra::from(Era::mortal(256, phase)), system::CheckNonce::from(index), @@ -132,12 +133,12 @@ impl RuntimeAdapter for FactoryState<Number> { key: &Self::Secret, destination: &Self::AccountId, amount: &Self::Balance, + version: u32, genesis_hash: &<Self::Block as BlockT>::Hash, prior_block_hash: &<Self::Block as BlockT>::Hash, ) -> <Self::Block as BlockT>::Extrinsic { let index = self.extract_index(&sender, prior_block_hash); let phase = self.extract_phase(*prior_block_hash); - sign::<Self>(CheckedExtrinsic { signed: Some((sender.clone(), Self::build_extra(index, phase))), function: Call::Balances( @@ -146,7 +147,7 @@ impl RuntimeAdapter for FactoryState<Number> { (*amount).into() ) ) - }, key, (genesis_hash.clone(), prior_block_hash.clone(), (), (), ())) + }, key, (version, genesis_hash.clone(), prior_block_hash.clone(), (), (), ())) } fn inherent_extrinsics(&self) -> InherentData { diff --git a/substrate/node/cli/src/service.rs b/substrate/node/cli/src/service.rs index ebd2f29fd51..b691b508fd4 100644 --- a/substrate/node/cli/src/service.rs +++ b/substrate/node/cli/src/service.rs @@ -454,18 +454,21 @@ mod tests { let to = AddressPublic::from_raw(bob.public().0); let from = AddressPublic::from_raw(charlie.public().0); let genesis_hash = service.get().client().block_hash(0).unwrap().unwrap(); + let best_block_id = BlockId::number(service.get().client().info().chain.best_number); + let version = service.get().client().runtime_version_at(&best_block_id).unwrap().spec_version; let signer = charlie.clone(); let function = Call::Balances(BalancesCall::transfer(to.into(), amount)); + let check_version = system::CheckVersion::new(); let check_genesis = system::CheckGenesis::new(); let check_era = system::CheckEra::from(Era::Immortal); let check_nonce = system::CheckNonce::from(index); let check_weight = system::CheckWeight::new(); let take_fees = balances::TakeFees::from(0); - let extra = (check_genesis, check_era, check_nonce, check_weight, take_fees); + let extra = (check_version, check_genesis, check_era, check_nonce, check_weight, take_fees); - let raw_payload = (function, extra.clone(), genesis_hash, genesis_hash); + let raw_payload = (function, extra.clone(), version, genesis_hash, genesis_hash); let signature = raw_payload.using_encoded(|payload| if payload.len() > 256 { signer.sign(&blake2_256(payload)[..]) } else { diff --git a/substrate/node/executor/src/lib.rs b/substrate/node/executor/src/lib.rs index eece362ea8d..448ab9d8b6f 100644 --- a/substrate/node/executor/src/lib.rs +++ b/substrate/node/executor/src/lib.rs @@ -44,7 +44,7 @@ mod tests { use keyring::{AccountKeyring, Ed25519Keyring, Sr25519Keyring}; use runtime_support::{Hashable, StorageValue, StorageMap, assert_eq_error_rate, traits::Currency}; use state_machine::{CodeExecutor, Externalities, TestExternalities as CoreTestExternalities}; - use primitives::{ twox_128, blake2_256, Blake2Hasher, ChangesTrieConfiguration, NeverNativeValue, NativeOrEncoded}; + use primitives::{twox_128, blake2_256, Blake2Hasher, ChangesTrieConfiguration, NeverNativeValue, NativeOrEncoded}; use node_primitives::{Hash, BlockNumber, AccountId, Balance, Index}; use sr_primitives::traits::{Header as HeaderT, Hash as HashT, Convert}; use sr_primitives::{generic::Era, ApplyOutcome, ApplyError, ApplyResult, Perbill}; @@ -55,7 +55,7 @@ mod tests { Header, Block, UncheckedExtrinsic, CheckedExtrinsic, Call, Runtime, Balances, BuildStorage, GenesisConfig, BalancesConfig, SessionConfig, StakingConfig, System, SystemConfig, GrandpaConfig, IndicesConfig, ContractsConfig, Event, SessionKeys, SignedExtra, - TransferFee, TransactionBaseFee, TransactionByteFee, + TransferFee, TransactionBaseFee, TransactionByteFee }; use node_runtime::constants::currency::*; use node_runtime::impls::WeightToFee; @@ -79,6 +79,8 @@ mod tests { const GENESIS_HASH: [u8; 32] = [69u8; 32]; + const VERSION: u32 = node_runtime::VERSION.spec_version; + type TestExternalities<H> = CoreTestExternalities<H, u64>; /// Default transfer fee @@ -122,7 +124,7 @@ mod tests { fn sign(xt: CheckedExtrinsic) -> UncheckedExtrinsic { match xt.signed { Some((signed, extra)) => { - let payload = (xt.function, extra.clone(), GENESIS_HASH, GENESIS_HASH); + let payload = (xt.function, extra.clone(), VERSION, GENESIS_HASH, GENESIS_HASH); let key = AccountKeyring::from_public(&signed).unwrap(); let signature = payload.using_encoded(|b| { if b.len() > 256 { @@ -145,6 +147,7 @@ mod tests { fn signed_extra(nonce: Index, extra_fee: Balance) -> SignedExtra { ( + system::CheckVersion::new(), system::CheckGenesis::new(), system::CheckEra::from(Era::mortal(256, 0)), system::CheckNonce::from(nonce), diff --git a/substrate/node/runtime/src/lib.rs b/substrate/node/runtime/src/lib.rs index c2cbe74194e..0a7016770d2 100644 --- a/substrate/node/runtime/src/lib.rs +++ b/substrate/node/runtime/src/lib.rs @@ -463,6 +463,7 @@ pub type SignedBlock = generic::SignedBlock<Block>; pub type BlockId = generic::BlockId<Block>; /// The SignedExtension to the basic transaction logic. pub type SignedExtra = ( + system::CheckVersion<Runtime>, system::CheckGenesis<Runtime>, system::CheckEra<Runtime>, system::CheckNonce<Runtime>, diff --git a/substrate/subkey/src/main.rs b/substrate/subkey/src/main.rs index 8f32ddb7d39..ba9d1a6cce0 100644 --- a/substrate/subkey/src/main.rs +++ b/substrate/subkey/src/main.rs @@ -97,6 +97,7 @@ fn execute<C: Crypto>(matches: clap::ArgMatches) where { let extra = |i: Index, f: Balance| { ( + system::CheckVersion::<Runtime>::new(), system::CheckGenesis::<Runtime>::new(), system::CheckEra::<Runtime>::from(Era::Immortal), system::CheckNonce::<Runtime>::from(i), diff --git a/substrate/test-utils/transaction-factory/src/complex_mode.rs b/substrate/test-utils/transaction-factory/src/complex_mode.rs index 25170f8c188..85b12248d80 100644 --- a/substrate/test-utils/transaction-factory/src/complex_mode.rs +++ b/substrate/test-utils/transaction-factory/src/complex_mode.rs @@ -54,6 +54,7 @@ use crate::{RuntimeAdapter, create_block}; pub fn next<F, RA>( factory_state: &mut RA, client: &Arc<ComponentClient<FullComponents<F>>>, + version: u32, genesis_hash: <RA::Block as BlockT>::Hash, prior_block_hash: <RA::Block as BlockT>::Hash, prior_block_id: BlockId<F::Block>, @@ -92,6 +93,7 @@ where &from.1, &to, &amount, + version, &genesis_hash, &prior_block_hash, ); diff --git a/substrate/test-utils/transaction-factory/src/lib.rs b/substrate/test-utils/transaction-factory/src/lib.rs index ab7dfb8ceab..16bb08a2b43 100644 --- a/substrate/test-utils/transaction-factory/src/lib.rs +++ b/substrate/test-utils/transaction-factory/src/lib.rs @@ -77,6 +77,7 @@ pub trait RuntimeAdapter { key: &Self::Secret, destination: &Self::AccountId, amount: &Self::Balance, + version: u32, genesis_hash: &<Self::Block as BlockT>::Hash, prior_block_hash: &<Self::Block as BlockT>::Hash, ) -> <Self::Block as BlockT>::Extrinsic; @@ -119,6 +120,7 @@ where select_chain.best_chain().map_err(|e| format!("{:?}", e).into()); let mut best_hash = best_header?.hash(); let best_block_id = BlockId::<F::Block>::hash(best_hash); + let version = client.runtime_version_at(&best_block_id)?.spec_version; let genesis_hash = client.block_hash(Zero::zero())? .expect("Genesis block always exists; qed").into(); @@ -126,6 +128,7 @@ where Mode::MasterToNToM => complex_mode::next::<F, RA>( &mut factory_state, &client, + version, genesis_hash, best_hash.into(), best_block_id, @@ -133,6 +136,7 @@ where _ => simple_modes::next::<F, RA>( &mut factory_state, &client, + version, genesis_hash, best_hash.into(), best_block_id, diff --git a/substrate/test-utils/transaction-factory/src/simple_modes.rs b/substrate/test-utils/transaction-factory/src/simple_modes.rs index 0554678fbbd..ec4f484fa98 100644 --- a/substrate/test-utils/transaction-factory/src/simple_modes.rs +++ b/substrate/test-utils/transaction-factory/src/simple_modes.rs @@ -49,6 +49,7 @@ use crate::{Mode, RuntimeAdapter, create_block}; pub fn next<F, RA>( factory_state: &mut RA, client: &Arc<ComponentClient<FullComponents<F>>>, + version: u32, genesis_hash: <RA::Block as BlockT>::Hash, prior_block_hash: <RA::Block as BlockT>::Hash, prior_block_id: BlockId<F::Block>, @@ -83,6 +84,7 @@ where &from.1, &to, &amount, + version, &genesis_hash, &prior_block_hash, ); -- GitLab