diff --git a/Cargo.lock b/Cargo.lock
index 2f44bc62a88c..b4525658eefd 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -4071,6 +4071,7 @@ dependencies = [
"nix 0.17.0",
"parity-util-mem",
"polkadot-cli",
+ "polkadot-collator",
"polkadot-service",
"tempfile",
]
@@ -4109,6 +4110,7 @@ dependencies = [
"futures 0.3.5",
"log 0.4.8",
"polkadot-service",
+ "polkadot-service-new",
"sc-cli",
"sc-client-api",
"sc-client-db",
@@ -4137,6 +4139,7 @@ dependencies = [
"polkadot-network",
"polkadot-primitives",
"polkadot-service",
+ "polkadot-service-new",
"polkadot-validation",
"sc-cli",
"sc-client-api",
@@ -4519,6 +4522,65 @@ dependencies = [
"westend-runtime",
]
+[[package]]
+name = "polkadot-service-new"
+version = "0.8.3"
+dependencies = [
+ "env_logger",
+ "frame-benchmarking",
+ "frame-system-rpc-runtime-api",
+ "futures 0.3.5",
+ "hex-literal",
+ "kusama-runtime",
+ "lazy_static",
+ "log 0.4.8",
+ "pallet-babe",
+ "pallet-im-online",
+ "pallet-staking",
+ "pallet-transaction-payment-rpc-runtime-api",
+ "parity-scale-codec",
+ "parking_lot 0.9.0",
+ "polkadot-network",
+ "polkadot-overseer",
+ "polkadot-primitives",
+ "polkadot-rpc",
+ "polkadot-runtime",
+ "polkadot-test-runtime-client",
+ "sc-authority-discovery",
+ "sc-basic-authorship",
+ "sc-block-builder",
+ "sc-chain-spec",
+ "sc-client-api",
+ "sc-client-db",
+ "sc-consensus",
+ "sc-consensus-babe",
+ "sc-executor",
+ "sc-finality-grandpa",
+ "sc-keystore",
+ "sc-network",
+ "sc-service",
+ "sc-telemetry",
+ "sc-transaction-pool",
+ "serde",
+ "slog",
+ "sp-api",
+ "sp-authority-discovery",
+ "sp-block-builder",
+ "sp-blockchain",
+ "sp-consensus",
+ "sp-consensus-babe",
+ "sp-core",
+ "sp-finality-grandpa",
+ "sp-inherents",
+ "sp-io",
+ "sp-offchain",
+ "sp-runtime",
+ "sp-session",
+ "sp-transaction-pool",
+ "substrate-prometheus-endpoint",
+ "westend-runtime",
+]
+
[[package]]
name = "polkadot-statement-table"
version = "0.8.7"
diff --git a/Cargo.toml b/Cargo.toml
index 7b6d6aed5502..2833abcceb7f 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -10,6 +10,8 @@ edition = "2018"
[dependencies]
cli = { package = "polkadot-cli", path = "cli" }
+# It looks like this is the only way to pass features to it
+collator = { package = "polkadot-collator", path = "collator" }
futures = "0.3.4"
service = { package = "polkadot-service", path = "service" }
parity-util-mem = { version = "*", default-features = false, features = ["jemalloc-global"] }
@@ -42,6 +44,7 @@ members = [
"node/messages",
"node/overseer",
+ "node/service",
"parachain/test-parachains",
"parachain/test-parachains/adder",
@@ -64,3 +67,7 @@ panic = "unwind"
[features]
runtime-benchmarks=["cli/runtime-benchmarks"]
+service-rewr= [
+ "cli/service-rewr",
+ "collator/service-rewr",
+]
diff --git a/cli/Cargo.toml b/cli/Cargo.toml
index ec4df900be11..b631dd1e7807 100644
--- a/cli/Cargo.toml
+++ b/cli/Cargo.toml
@@ -23,7 +23,8 @@ sp-runtime = { git = "https://github.com/paritytech/substrate", branch = "master
sc-client-api = { git = "https://github.com/paritytech/substrate", branch = "master" }
sc-client-db = { git = "https://github.com/paritytech/substrate", branch = "master" }
sc-executor = { git = "https://github.com/paritytech/substrate", branch = "master" }
-service = { package = "polkadot-service", path = "../service", default-features = false }
+service = { package = "polkadot-service", path = "../service", default-features = false, optional = true }
+service-new = { package = "polkadot-service-new", path = "../node/service", default-features = false, optional = true }
tokio = { version = "0.2.13", features = ["rt-threaded"], optional = true }
frame-benchmarking-cli = { git = "https://github.com/paritytech/substrate", branch = "master", optional = true }
@@ -38,7 +39,7 @@ browser-utils = { package = "substrate-browser-utils", git = "https://github.com
substrate-build-script-utils = { git = "https://github.com/paritytech/substrate", branch = "master" }
[features]
-default = [ "wasmtime", "db", "cli" ]
+default = [ "wasmtime", "db", "cli", "service-old" ]
wasmtime = [ "sc-cli/wasmtime" ]
db = [ "service/db" ]
cli = [
@@ -46,11 +47,13 @@ cli = [
"sc-cli",
"sc-service",
"frame-benchmarking-cli",
- "service/full-node",
]
+service-old = [ "service/full-node" ]
browser = [
"wasm-bindgen",
"wasm-bindgen-futures",
"browser-utils",
+ "service",
]
-runtime-benchmarks = ["service/runtime-benchmarks"]
+runtime-benchmarks = [ "service/runtime-benchmarks" ]
+service-rewr = [ "service-new/full-node" ]
diff --git a/cli/src/command.rs b/cli/src/command.rs
index 9890d39544aa..5e9d78382833 100644
--- a/cli/src/command.rs
+++ b/cli/src/command.rs
@@ -15,7 +15,10 @@
// along with Polkadot. If not, see .
use log::info;
+#[cfg(not(feature = "service-rewr"))]
use service::{IdentifyVariant, self};
+#[cfg(feature = "service-rewr")]
+use service_new::{IdentifyVariant, self as service};
use sc_executor::NativeExecutionDispatch;
use sc_cli::{SubstrateCli, Result};
use crate::cli::{Cli, Subcommand};
@@ -206,7 +209,7 @@ pub fn run() -> Result<()> {
if cfg!(feature = "browser") {
Err(sc_cli::Error::Input("Cannot run validation worker in browser".into()))
} else {
- #[cfg(not(feature = "browser"))]
+ #[cfg(all(not(feature = "browser"), not(feature = "service-rewr")))]
service::run_validation_worker(&cmd.mem_id)?;
Ok(())
}
diff --git a/cli/src/lib.rs b/cli/src/lib.rs
index 3e31fa0bb2ae..be2f3c6cd646 100644
--- a/cli/src/lib.rs
+++ b/cli/src/lib.rs
@@ -26,11 +26,19 @@ mod cli;
#[cfg(feature = "cli")]
mod command;
+#[cfg(not(feature = "service-rewr"))]
pub use service::{
AbstractService, ProvideRuntimeApi, CoreApi, ParachainHost, IdentifyVariant,
Block, self, RuntimeApiCollection, TFullClient
};
+#[cfg(feature = "service-rewr")]
+pub use service_new::{
+ self as service,
+ AbstractService, ProvideRuntimeApi, CoreApi, ParachainHost, IdentifyVariant,
+ Block, self, RuntimeApiCollection, TFullClient
+};
+
#[cfg(feature = "cli")]
pub use cli::*;
diff --git a/collator/Cargo.toml b/collator/Cargo.toml
index a2e8691e7a64..52d04fba10fe 100644
--- a/collator/Cargo.toml
+++ b/collator/Cargo.toml
@@ -21,7 +21,8 @@ polkadot-primitives = { path = "../primitives" }
polkadot-cli = { path = "../cli" }
polkadot-network = { path = "../network" }
polkadot-validation = { path = "../validation" }
-polkadot-service = { path = "../service" }
+polkadot-service = { path = "../service", optional = true}
+polkadot-service-new = { path = "../node/service", optional = true }
log = "0.4.8"
tokio = "0.2.13"
futures-timer = "2.0"
@@ -29,3 +30,8 @@ codec = { package = "parity-scale-codec", version = "1.3.0" }
[dev-dependencies]
keyring = { package = "sp-keyring", git = "https://github.com/paritytech/substrate", branch = "master" }
+
+[features]
+default = ["service-old"]
+service-old = [ "polkadot-service" ]
+service-rewr = [ "polkadot-service-new" ]
diff --git a/collator/src/lib.rs b/collator/src/lib.rs
index 08706a7cb090..932648f3e159 100644
--- a/collator/src/lib.rs
+++ b/collator/src/lib.rs
@@ -74,7 +74,13 @@ pub use sc_network::PeerId;
pub use service::RuntimeApiCollection;
pub use sc_cli::SubstrateCli;
use sp_api::{ConstructRuntimeApi, ApiExt, HashFor};
-use polkadot_service::PolkadotClient;
+#[cfg(not(feature = "service-rewr"))]
+use polkadot_service::{FullNodeHandles, PolkadotClient};
+#[cfg(feature = "service-rewr")]
+use polkadot_service_new::{
+ self as polkadot_service,
+ Error as ServiceError, FullNodeHandles, PolkadotClient,
+};
const COLLATION_TIMEOUT: Duration = Duration::from_secs(30);
@@ -201,9 +207,46 @@ pub async fn collate
(
Ok(collation)
}
+#[cfg(feature = "service-rewr")]
+fn build_collator_service(
+ _spawner: SP,
+ _handles: FullNodeHandles,
+ _client: Arc,
+ _para_id: ParaId,
+ _key: Arc,
+ _build_parachain_context: P,
+) -> Result, polkadot_service::Error>
+ where
+ C: PolkadotClient<
+ service::Block,
+ service::TFullBackend,
+ R
+ > + 'static,
+ R: ConstructRuntimeApi + Sync + Send,
+ >::RuntimeApi:
+ sp_api::ApiExt<
+ service::Block,
+ StateBackend = as service::Backend>::State,
+ >
+ + RuntimeApiCollection<
+ Extrinsic,
+ StateBackend = as service::Backend>::State,
+ >
+ + Sync + Send,
+ P: BuildParachainContext,
+ P::ParachainContext: Send + 'static,
+ ::ProduceCandidate: Send,
+ Extrinsic: service::Codec + Send + Sync + 'static,
+ SP: Spawn + Clone + Send + Sync + 'static,
+{
+ Err("Collator is not functional with the new service yet".into())
+}
+
+
+#[cfg(not(feature = "service-rewr"))]
fn build_collator_service(
spawner: SP,
- handles: polkadot_service::FullNodeHandles,
+ handles: FullNodeHandles,
client: Arc,
para_id: ParaId,
key: Arc,
@@ -408,6 +451,7 @@ where
Ok(())
}
+#[cfg(not(feature = "service-rewr"))]
fn compute_targets(para_id: ParaId, session_keys: &[ValidatorId], roster: DutyRoster) -> HashSet {
use polkadot_primitives::parachain::Chain;
diff --git a/node/overseer/src/lib.rs b/node/overseer/src/lib.rs
index abe648bfa194..56bf953f61de 100644
--- a/node/overseer/src/lib.rs
+++ b/node/overseer/src/lib.rs
@@ -56,6 +56,7 @@
use std::fmt::Debug;
use std::pin::Pin;
+use std::sync::Arc;
use std::task::Poll;
use std::time::Duration;
use std::collections::HashSet;
@@ -232,7 +233,7 @@ impl OverseerHandler {
/// [`Overseer`]: struct.Overseer.html
/// [`OverseerHandler`]: struct.OverseerHandler.html
pub async fn forward_events>(
- client: P,
+ client: Arc,
mut handler: OverseerHandler,
) -> SubsystemResult<()> {
let mut finality = client.finality_notification_stream();
diff --git a/node/service/Cargo.toml b/node/service/Cargo.toml
new file mode 100644
index 000000000000..74069f0233af
--- /dev/null
+++ b/node/service/Cargo.toml
@@ -0,0 +1,69 @@
+[package]
+name = "polkadot-service-new"
+version = "0.8.3"
+authors = ["Parity Technologies "]
+edition = "2018"
+
+[dependencies]
+parking_lot = "0.9.0"
+serde = { version = "1.0.102", features = ["derive"] }
+lazy_static = "1.4.0"
+log = "0.4.8"
+futures = "0.3.4"
+slog = "2.5.2"
+hex-literal = "0.2.1"
+polkadot-primitives = { path = "../../primitives" }
+polkadot-runtime = { path = "../../runtime/polkadot" }
+polkadot-overseer = { path = "../overseer" }
+kusama-runtime = { path = "../../runtime/kusama" }
+westend-runtime = { path = "../../runtime/westend" }
+polkadot-network = { path = "../../network", optional = true }
+polkadot-rpc = { path = "../../rpc" }
+sp-io = { git = "https://github.com/paritytech/substrate", branch = "master" }
+sp-api = { git = "https://github.com/paritytech/substrate", branch = "master" }
+sp-runtime = { git = "https://github.com/paritytech/substrate", branch = "master" }
+sp-blockchain = { git = "https://github.com/paritytech/substrate", branch = "master" }
+sp-core = { git = "https://github.com/paritytech/substrate", branch = "master" }
+sc-client-api = { git = "https://github.com/paritytech/substrate", branch = "master" }
+sc-client-db = { git = "https://github.com/paritytech/substrate", branch = "master" }
+sc-chain-spec = { git = "https://github.com/paritytech/substrate", branch = "master" }
+sc-executor = { git = "https://github.com/paritytech/substrate", branch = "master" }
+sc-consensus = { git = "https://github.com/paritytech/substrate", branch = "master" }
+sc-network = { git = "https://github.com/paritytech/substrate", branch = "master" }
+consensus_common = { package = "sp-consensus", git = "https://github.com/paritytech/substrate", branch = "master" }
+grandpa = { package = "sc-finality-grandpa", git = "https://github.com/paritytech/substrate", branch = "master" }
+grandpa_primitives = { package = "sp-finality-grandpa", git = "https://github.com/paritytech/substrate", branch = "master" }
+inherents = { package = "sp-inherents", git = "https://github.com/paritytech/substrate", branch = "master" }
+service = { package = "sc-service", git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
+telemetry = { package = "sc-telemetry", git = "https://github.com/paritytech/substrate", branch = "master" }
+sc-block-builder = { git = "https://github.com/paritytech/substrate", branch = "master" }
+sc-transaction-pool = { git = "https://github.com/paritytech/substrate", branch = "master" }
+sp-transaction-pool = { git = "https://github.com/paritytech/substrate", branch = "master" }
+sc-keystore = { git = "https://github.com/paritytech/substrate", branch = "master" }
+pallet-babe = { git = "https://github.com/paritytech/substrate", branch = "master" }
+pallet-staking = { git = "https://github.com/paritytech/substrate", branch = "master" }
+im-online = { package = "pallet-im-online", git = "https://github.com/paritytech/substrate", branch = "master" }
+authority-discovery = { package = "sc-authority-discovery", git = "https://github.com/paritytech/substrate", branch = "master" }
+authority-discovery-primitives = { package = "sp-authority-discovery", git = "https://github.com/paritytech/substrate", branch = "master" }
+babe = { package = "sc-consensus-babe", git = "https://github.com/paritytech/substrate", branch = "master" }
+babe-primitives = { package = "sp-consensus-babe", git = "https://github.com/paritytech/substrate", branch = "master" }
+sp-block-builder = { git = "https://github.com/paritytech/substrate", branch = "master" }
+pallet-transaction-payment-rpc-runtime-api = { git = "https://github.com/paritytech/substrate", branch = "master" }
+system_rpc_runtime_api = { package = "frame-system-rpc-runtime-api", git = "https://github.com/paritytech/substrate", branch = "master" }
+codec = { package = "parity-scale-codec", version = "1.3.0" }
+sp-session = { git = "https://github.com/paritytech/substrate", branch = "master" }
+sp-offchain = { package = "sp-offchain", git = "https://github.com/paritytech/substrate", branch = "master" }
+prometheus-endpoint = { package = "substrate-prometheus-endpoint", git = "https://github.com/paritytech/substrate", branch = "master" }
+frame-benchmarking = { git = "https://github.com/paritytech/substrate", branch = "master" }
+sc-basic-authorship = { git = "https://github.com/paritytech/substrate", branch = "master" }
+
+[dev-dependencies]
+polkadot-test-runtime-client = { path = "../../runtime/test-runtime/client" }
+sc-block-builder = { git = "https://github.com/paritytech/substrate", branch = "master" }
+env_logger = "0.7.0"
+
+[features]
+default = ["db", "full-node"]
+db = ["service/db"]
+runtime-benchmarks = ["polkadot-runtime/runtime-benchmarks", "kusama-runtime/runtime-benchmarks", "westend-runtime/runtime-benchmarks"]
+full-node = []
diff --git a/node/service/README.adoc b/node/service/README.adoc
new file mode 100644
index 000000000000..2196d5467806
--- /dev/null
+++ b/node/service/README.adoc
@@ -0,0 +1,5 @@
+
+= Polkadot Service
+
+placeholder
+//TODO Write content :) (https://github.com/paritytech/polkadot/issues/159)
diff --git a/node/service/src/chain_spec.rs b/node/service/src/chain_spec.rs
new file mode 100644
index 000000000000..0659d0808301
--- /dev/null
+++ b/node/service/src/chain_spec.rs
@@ -0,0 +1,963 @@
+// Copyright 2017-2020 Parity Technologies (UK) Ltd.
+// This file is part of Polkadot.
+
+// Polkadot is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// Polkadot is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with Polkadot. If not, see .
+
+//! Polkadot chain configurations.
+
+use sp_core::{Pair, Public, crypto::UncheckedInto, sr25519};
+use polkadot_primitives::{AccountId, AccountPublic, parachain::ValidatorId};
+use polkadot_runtime as polkadot;
+use kusama_runtime as kusama;
+use westend_runtime as westend;
+use polkadot::constants::currency::DOTS;
+use kusama::constants::currency::DOTS as KSM;
+use westend::constants::currency::DOTS as WND;
+use sc_chain_spec::{ChainSpecExtension, ChainType};
+use sp_runtime::{traits::IdentifyAccount, Perbill};
+use serde::{Serialize, Deserialize};
+use telemetry::TelemetryEndpoints;
+use hex_literal::hex;
+use babe_primitives::AuthorityId as BabeId;
+use grandpa::AuthorityId as GrandpaId;
+use im_online::sr25519::{AuthorityId as ImOnlineId};
+use authority_discovery_primitives::AuthorityId as AuthorityDiscoveryId;
+use pallet_staking::Forcing;
+
+const POLKADOT_STAGING_TELEMETRY_URL: &str = "wss://telemetry.polkadot.io/submit/";
+const KUSAMA_STAGING_TELEMETRY_URL: &str = "wss://telemetry.polkadot.io/submit/";
+const WESTEND_STAGING_TELEMETRY_URL: &str = "wss://telemetry.polkadot.io/submit/";
+const DEFAULT_PROTOCOL_ID: &str = "dot";
+
+/// Node `ChainSpec` extensions.
+///
+/// Additional parameters for some Substrate core modules,
+/// customizable from the chain spec.
+#[derive(Default, Clone, Serialize, Deserialize, ChainSpecExtension)]
+#[serde(rename_all = "camelCase")]
+pub struct Extensions {
+ /// Block numbers with known hashes.
+ pub fork_blocks: sc_client_api::ForkBlocks,
+ /// Known bad block hashes.
+ pub bad_blocks: sc_client_api::BadBlocks,
+}
+
+/// The `ChainSpec parametrised for polkadot runtime`.
+pub type PolkadotChainSpec = service::GenericChainSpec<
+ polkadot::GenesisConfig,
+ Extensions,
+>;
+
+/// The `ChainSpec parametrised for kusama runtime`.
+pub type KusamaChainSpec = service::GenericChainSpec<
+ kusama::GenesisConfig,
+ Extensions,
+>;
+
+/// The `ChainSpec parametrised for westend runtime`.
+pub type WestendChainSpec = service::GenericChainSpec<
+ westend::GenesisConfig,
+ Extensions,
+>;
+
+pub fn polkadot_config() -> Result {
+ PolkadotChainSpec::from_json_bytes(&include_bytes!("../../../service/res/polkadot.json")[..])
+}
+
+pub fn kusama_config() -> Result {
+ KusamaChainSpec::from_json_bytes(&include_bytes!("../../../service/res/kusama.json")[..])
+}
+
+pub fn westend_config() -> Result {
+ PolkadotChainSpec::from_json_bytes(&include_bytes!("../../../service/res/westend.json")[..])
+}
+
+fn polkadot_session_keys(
+ babe: BabeId,
+ grandpa: GrandpaId,
+ im_online: ImOnlineId,
+ parachain_validator: ValidatorId,
+ authority_discovery: AuthorityDiscoveryId
+) -> polkadot::SessionKeys {
+ polkadot::SessionKeys { babe, grandpa, im_online, parachain_validator, authority_discovery }
+}
+
+fn kusama_session_keys(
+ babe: BabeId,
+ grandpa: GrandpaId,
+ im_online: ImOnlineId,
+ parachain_validator: ValidatorId,
+ authority_discovery: AuthorityDiscoveryId
+) -> kusama::SessionKeys {
+ kusama::SessionKeys { babe, grandpa, im_online, parachain_validator, authority_discovery }
+}
+
+fn westend_session_keys(
+ babe: BabeId,
+ grandpa: GrandpaId,
+ im_online: ImOnlineId,
+ parachain_validator: ValidatorId,
+ authority_discovery: AuthorityDiscoveryId
+) -> westend::SessionKeys {
+ westend::SessionKeys { babe, grandpa, im_online, parachain_validator, authority_discovery }
+}
+
+fn polkadot_staging_testnet_config_genesis() -> polkadot::GenesisConfig {
+ // subkey inspect "$SECRET"
+ let endowed_accounts = vec![];
+
+ let initial_authorities: Vec<(
+ AccountId,
+ AccountId,
+ BabeId,
+ GrandpaId,
+ ImOnlineId,
+ ValidatorId,
+ AuthorityDiscoveryId
+ )> = vec![];
+
+ const ENDOWMENT: u128 = 1_000_000 * DOTS;
+ const STASH: u128 = 100 * DOTS;
+
+ polkadot::GenesisConfig {
+ system: Some(polkadot::SystemConfig {
+ code: polkadot::WASM_BINARY.to_vec(),
+ changes_trie_config: Default::default(),
+ }),
+ balances: Some(polkadot::BalancesConfig {
+ balances: endowed_accounts.iter()
+ .map(|k: &AccountId| (k.clone(), ENDOWMENT))
+ .chain(initial_authorities.iter().map(|x| (x.0.clone(), STASH)))
+ .collect(),
+ }),
+ indices: Some(polkadot::IndicesConfig {
+ indices: vec![],
+ }),
+ session: Some(polkadot::SessionConfig {
+ keys: initial_authorities.iter().map(|x| (
+ x.0.clone(),
+ x.0.clone(),
+ polkadot_session_keys(x.2.clone(), x.3.clone(), x.4.clone(), x.5.clone(), x.6.clone()),
+ )).collect::>(),
+ }),
+ staking: Some(polkadot::StakingConfig {
+ validator_count: 50,
+ minimum_validator_count: 4,
+ stakers: initial_authorities
+ .iter()
+ .map(|x| (x.0.clone(), x.1.clone(), STASH, polkadot::StakerStatus::Validator))
+ .collect(),
+ invulnerables: initial_authorities.iter().map(|x| x.0.clone()).collect(),
+ force_era: Forcing::ForceNone,
+ slash_reward_fraction: Perbill::from_percent(10),
+ .. Default::default()
+ }),
+ elections_phragmen: Some(Default::default()),
+ democracy: Some(Default::default()),
+ collective_Instance1: Some(polkadot::CouncilConfig {
+ members: vec![],
+ phantom: Default::default(),
+ }),
+ collective_Instance2: Some(polkadot::TechnicalCommitteeConfig {
+ members: vec![],
+ phantom: Default::default(),
+ }),
+ membership_Instance1: Some(Default::default()),
+ babe: Some(Default::default()),
+ grandpa: Some(Default::default()),
+ im_online: Some(Default::default()),
+ authority_discovery: Some(polkadot::AuthorityDiscoveryConfig {
+ keys: vec![],
+ }),
+ parachains: Some(polkadot::ParachainsConfig {
+ authorities: vec![],
+ }),
+ registrar: Some(polkadot::RegistrarConfig {
+ parachains: vec![],
+ _phdata: Default::default(),
+ }),
+ claims: Some(polkadot::ClaimsConfig {
+ claims: vec![],
+ vesting: vec![],
+ }),
+ vesting: Some(polkadot::VestingConfig {
+ vesting: vec![],
+ }),
+ sudo: Some(polkadot::SudoConfig {
+ key: endowed_accounts[0].clone(),
+ }),
+ }
+}
+
+fn westend_staging_testnet_config_genesis() -> westend::GenesisConfig {
+// subkey inspect "$SECRET"
+ let endowed_accounts = vec![
+ // 5ENpP27BrVdJTdUfY6djmcw3d3xEJ6NzSUU52CCPmGpMrdEY
+ hex!["6648d7f3382690650c681aba1b993cd11e54deb4df21a3a18c3e2177de9f7342"].into(),
+ ];
+
+ // for i in 1 2 3 4; do for j in stash controller; do subkey inspect "$SECRET//$i//$j"; done; done
+ // for i in 1 2 3 4; do for j in babe; do subkey --sr25519 inspect "$SECRET//$i//$j"; done; done
+ // for i in 1 2 3 4; do for j in grandpa; do subkey --ed25519 inspect "$SECRET//$i//$j"; done; done
+ // for i in 1 2 3 4; do for j in im_online; do subkey --sr25519 inspect "$SECRET//$i//$j"; done; done
+ // for i in 1 2 3 4; do for j in parachains; do subkey --sr25519 inspect "$SECRET//$i//$j"; done; done
+ let initial_authorities: Vec<(
+ AccountId,
+ AccountId,
+ BabeId,
+ GrandpaId,
+ ImOnlineId,
+ ValidatorId,
+ AuthorityDiscoveryId
+ )> = vec![(
+ // 5FZoQhgUCmqBxnkHX7jCqThScS2xQWiwiF61msg63CFL3Y8f
+ hex!["9ae581fef1fc06828723715731adcf810e42ce4dadad629b1b7fa5c3c144a81d"].into(),
+ // 5ExdKyXFhtrjiFhexnyQPDyGSP8xU9qHc4KDwVrtWxaP2RP6
+ hex!["8011fb3641f0641f5570ba8787a64a0ff7d9c9999481f333d7207c4abd7e981c"].into(),
+ // 5Ef8qY8LRV6RFd4bThrwxBhhWfLjzqmd4rK8nX3Xs7zJqqp7
+ hex!["72bae70a1398c0ba52f815cc5dfbc9ec5c013771e541ae28e05d1129243e3001"].unchecked_into(),
+ // 5FSscBiPfaPaEhFbAt2qRhcYjryKBKf714X76F5nFfwtdXLa
+ hex!["959cebf18fecb305b96fd998c95f850145f52cbbb64b3ef937c0575cc7ebd652"].unchecked_into(),
+ // 5Ef8qY8LRV6RFd4bThrwxBhhWfLjzqmd4rK8nX3Xs7zJqqp7
+ hex!["72bae70a1398c0ba52f815cc5dfbc9ec5c013771e541ae28e05d1129243e3001"].unchecked_into(),
+ // 5Ef8qY8LRV6RFd4bThrwxBhhWfLjzqmd4rK8nX3Xs7zJqqp7
+ hex!["72bae70a1398c0ba52f815cc5dfbc9ec5c013771e541ae28e05d1129243e3001"].unchecked_into(),
+ // 5Ef8qY8LRV6RFd4bThrwxBhhWfLjzqmd4rK8nX3Xs7zJqqp7
+ hex!["72bae70a1398c0ba52f815cc5dfbc9ec5c013771e541ae28e05d1129243e3001"].unchecked_into(),
+ ),(
+ // 5G1ojzh47Yt8KoYhuAjXpHcazvsoCXe3G8LZchKDvumozJJJ
+ hex!["aebb0211dbb07b4d335a657257b8ac5e53794c901e4f616d4a254f2490c43934"].into(),
+ // 5GeoZ1Mzix6Xnj32X8Xpj7q89X1SQHU5XTK1cnUVNXKTvXdK
+ hex!["caf27345aebc2fefeca85c9a67f4859eab3178d28ef92244714402290f3f415a"].into(),
+ // 5Et8y49AyE7ncVKiSRgzN6zbqbYtMK6y7kKuUaS8YqvfLBD9
+ hex!["7ca58770eb41c1a68ef77e92255e4635fc11f665cb89aee469e920511c48343a"].unchecked_into(),
+ // 5Hpn3HVViECsuxMDFtinWjRj2dNfpRp1kB24nZHvQCJsSUek
+ hex!["feca0be2c87141f6074b221c919c0161a1c468d9173c5c1be59b68fab9a0ff93"].unchecked_into(),
+ // 5Et8y49AyE7ncVKiSRgzN6zbqbYtMK6y7kKuUaS8YqvfLBD9
+ hex!["7ca58770eb41c1a68ef77e92255e4635fc11f665cb89aee469e920511c48343a"].unchecked_into(),
+ // 5Et8y49AyE7ncVKiSRgzN6zbqbYtMK6y7kKuUaS8YqvfLBD9
+ hex!["7ca58770eb41c1a68ef77e92255e4635fc11f665cb89aee469e920511c48343a"].unchecked_into(),
+ // 5Et8y49AyE7ncVKiSRgzN6zbqbYtMK6y7kKuUaS8YqvfLBD9
+ hex!["7ca58770eb41c1a68ef77e92255e4635fc11f665cb89aee469e920511c48343a"].unchecked_into(),
+ ),(
+ // 5HYYWyhyUQ7Ae11f8fCid58bhJ7ikLHM9bU8A6Ynwoc3dStR
+ hex!["f268995cc38974ce0686df1364875f26f2c32b246ddc18835512c3f9969f5836"].into(),
+ // 5DnUXT3xiQn6ZRttFT6eSCJbT9P2tiLdexr5WsvnbLG8igqW
+ hex!["4c17a9bfdd19411f452fa32420fa7acab622e87e57351f4ba3248ae40ce75123"].into(),
+ // 5EhnN1SumSv5KxwLAdwE8ugJaw1S8xARZb8V2BMYCKaD7ure
+ hex!["74bfb70627416e6e6c4785e928ced384c6c06e5c8dd173a094bc3118da7b673e"].unchecked_into(),
+ // 5Hmvd2qjb1zatrJTkPwgFicxPfZuwaTwa2L7adSRmz6mVxfb
+ hex!["fc9d33059580a69454179ffa41cbae6de2bc8d2bd2c3f1d018fe5484a5a91956"].unchecked_into(),
+ // 5EhnN1SumSv5KxwLAdwE8ugJaw1S8xARZb8V2BMYCKaD7ure
+ hex!["74bfb70627416e6e6c4785e928ced384c6c06e5c8dd173a094bc3118da7b673e"].unchecked_into(),
+ // 5EhnN1SumSv5KxwLAdwE8ugJaw1S8xARZb8V2BMYCKaD7ure
+ hex!["74bfb70627416e6e6c4785e928ced384c6c06e5c8dd173a094bc3118da7b673e"].unchecked_into(),
+ // 5EhnN1SumSv5KxwLAdwE8ugJaw1S8xARZb8V2BMYCKaD7ure
+ hex!["74bfb70627416e6e6c4785e928ced384c6c06e5c8dd173a094bc3118da7b673e"].unchecked_into(),
+ ),(
+ // 5CFPcUJgYgWryPaV1aYjSbTpbTLu42V32Ytw1L9rfoMAsfGh
+ hex!["08264834504a64ace1373f0c8ed5d57381ddf54a2f67a318fa42b1352681606d"].into(),
+ // 5F6z64cYZFRAmyMUhp7rnge6jaZmbY6o7XfA9czJyuAUiaFD
+ hex!["8671d451c3d4f6de8c16ea0bc61cf714914d6b2ffa2899872620525419327478"].into(),
+ // 5Ft7o2uqDq5pXCK4g5wR94BctmtLEzCBy5MvPqRa8753ZemD
+ hex!["a8ddd0891e14725841cd1b5581d23806a97f41c28a25436db6473c86e15dcd4f"].unchecked_into(),
+ // 5FgBijJLL6p7nDZgQed56L3BM7ovgwc4t4FYsv9apYtRGAGv
+ hex!["9fc415cce1d0b2eed702c9e05f476217d23b46a8723fd56f08cddad650be7c2d"].unchecked_into(),
+ // 5Ft7o2uqDq5pXCK4g5wR94BctmtLEzCBy5MvPqRa8753ZemD
+ hex!["a8ddd0891e14725841cd1b5581d23806a97f41c28a25436db6473c86e15dcd4f"].unchecked_into(),
+ // 5Ft7o2uqDq5pXCK4g5wR94BctmtLEzCBy5MvPqRa8753ZemD
+ hex!["a8ddd0891e14725841cd1b5581d23806a97f41c28a25436db6473c86e15dcd4f"].unchecked_into(),
+ // 5Ft7o2uqDq5pXCK4g5wR94BctmtLEzCBy5MvPqRa8753ZemD
+ hex!["a8ddd0891e14725841cd1b5581d23806a97f41c28a25436db6473c86e15dcd4f"].unchecked_into(),
+ )];
+
+ const ENDOWMENT: u128 = 1_000_000 * WND;
+ const STASH: u128 = 100 * WND;
+
+ westend::GenesisConfig {
+ system: Some(westend::SystemConfig {
+ code: westend::WASM_BINARY.to_vec(),
+ changes_trie_config: Default::default(),
+ }),
+ balances: Some(westend::BalancesConfig {
+ balances: endowed_accounts.iter()
+ .map(|k: &AccountId| (k.clone(), ENDOWMENT))
+ .chain(initial_authorities.iter().map(|x| (x.0.clone(), STASH)))
+ .collect(),
+ }),
+ indices: Some(westend::IndicesConfig {
+ indices: vec![],
+ }),
+ session: Some(westend::SessionConfig {
+ keys: initial_authorities.iter().map(|x| (
+ x.0.clone(),
+ x.0.clone(),
+ westend_session_keys(x.2.clone(), x.3.clone(), x.4.clone(), x.5.clone(), x.6.clone()),
+ )).collect::>(),
+ }),
+ staking: Some(westend::StakingConfig {
+ validator_count: 50,
+ minimum_validator_count: 4,
+ stakers: initial_authorities
+ .iter()
+ .map(|x| (x.0.clone(), x.1.clone(), STASH, westend::StakerStatus::Validator))
+ .collect(),
+ invulnerables: initial_authorities.iter().map(|x| x.0.clone()).collect(),
+ force_era: Forcing::ForceNone,
+ slash_reward_fraction: Perbill::from_percent(10),
+ .. Default::default()
+ }),
+ babe: Some(Default::default()),
+ grandpa: Some(Default::default()),
+ im_online: Some(Default::default()),
+ authority_discovery: Some(westend::AuthorityDiscoveryConfig {
+ keys: vec![],
+ }),
+ parachains: Some(westend::ParachainsConfig {
+ authorities: vec![],
+ }),
+ registrar: Some(westend::RegistrarConfig {
+ parachains: vec![],
+ _phdata: Default::default(),
+ }),
+ vesting: Some(westend::VestingConfig {
+ vesting: vec![],
+ }),
+ sudo: Some(westend::SudoConfig {
+ key: endowed_accounts[0].clone(),
+ }),
+ }
+}
+
+fn kusama_staging_testnet_config_genesis() -> kusama::GenesisConfig {
+ // subkey inspect "$SECRET"
+ let endowed_accounts = vec![
+ // 5CVFESwfkk7NmhQ6FwHCM9roBvr9BGa4vJHFYU8DnGQxrXvz
+ hex!["12b782529c22032ed4694e0f6e7d486be7daa6d12088f6bc74d593b3900b8438"].into(),
+ ];
+
+ // for i in 1 2 3 4; do for j in stash controller; do subkey inspect "$SECRET//$i//$j"; done; done
+ // for i in 1 2 3 4; do for j in babe; do subkey --sr25519 inspect "$SECRET//$i//$j"; done; done
+ // for i in 1 2 3 4; do for j in grandpa; do subkey --ed25519 inspect "$SECRET//$i//$j"; done; done
+ // for i in 1 2 3 4; do for j in im_online; do subkey --sr25519 inspect "$SECRET//$i//$j"; done; done
+ // for i in 1 2 3 4; do for j in parachains; do subkey --sr25519 inspect "$SECRET//$i//$j"; done; done
+ let initial_authorities: Vec<(
+ AccountId,
+ AccountId,
+ BabeId,
+ GrandpaId,
+ ImOnlineId,
+ ValidatorId,
+ AuthorityDiscoveryId
+ )> = vec![(
+ // 5DD7Q4VEfPTLEdn11CnThoHT5f9xKCrnofWJL5SsvpTghaAT
+ hex!["32a5718e87d16071756d4b1370c411bbbb947eb62f0e6e0b937d5cbfc0ea633b"].into(),
+ // 5GNzaEqhrZAtUQhbMe2gn9jBuNWfamWFZHULryFwBUXyd1cG
+ hex!["bee39fe862c85c91aaf343e130d30b643c6ea0b4406a980206f1df8331f7093b"].into(),
+ // 5FpewyS2VY8Cj3tKgSckq8ECkjd1HKHvBRnWhiHqRQsWfFC1
+ hex!["a639b507ee1585e0b6498ff141d6153960794523226866d1b44eba3f25f36356"].unchecked_into(),
+ // 5EjvdwATjyFFikdZibVvx1q5uBHhphS2Mnsq5c7yfaYK25vm
+ hex!["76620f7c98bce8619979c2b58cf2b0aff71824126d2b039358729dad993223db"].unchecked_into(),
+ // 5FpewyS2VY8Cj3tKgSckq8ECkjd1HKHvBRnWhiHqRQsWfFC1
+ hex!["a639b507ee1585e0b6498ff141d6153960794523226866d1b44eba3f25f36356"].unchecked_into(),
+ // 5FpewyS2VY8Cj3tKgSckq8ECkjd1HKHvBRnWhiHqRQsWfFC1
+ hex!["a639b507ee1585e0b6498ff141d6153960794523226866d1b44eba3f25f36356"].unchecked_into(),
+ // 5FpewyS2VY8Cj3tKgSckq8ECkjd1HKHvBRnWhiHqRQsWfFC1
+ hex!["a639b507ee1585e0b6498ff141d6153960794523226866d1b44eba3f25f36356"].unchecked_into(),
+ ),(
+ // 5G9VGb8ESBeS8Ca4or43RfhShzk9y7T5iTmxHk5RJsjZwsRx
+ hex!["b496c98a405ceab59b9e970e59ef61acd7765a19b704e02ab06c1cdfe171e40f"].into(),
+ // 5F7V9Y5FcxKXe1aroqvPeRiUmmeQwTFcL3u9rrPXcMuMiCNx
+ hex!["86d3a7571dd60139d297e55d8238d0c977b2e208c5af088f7f0136b565b0c103"].into(),
+ // 5GvuM53k1Z4nAB5zXJFgkRSHv4Bqo4BsvgbQWNWkiWZTMwWY
+ hex!["765e46067adac4d1fe6c783aa2070dfa64a19f84376659e12705d1734b3eae01"].unchecked_into(),
+ // 5HBDAaybNqjmY7ww8ZcZZY1L5LHxvpnyfqJwoB7HhR6raTmG
+ hex!["e2234d661bee4a04c38392c75d1566200aa9e6ae44dd98ee8765e4cc9af63cb7"].unchecked_into(),
+ // 5GvuM53k1Z4nAB5zXJFgkRSHv4Bqo4BsvgbQWNWkiWZTMwWY
+ hex!["765e46067adac4d1fe6c783aa2070dfa64a19f84376659e12705d1734b3eae01"].unchecked_into(),
+ // 5GvuM53k1Z4nAB5zXJFgkRSHv4Bqo4BsvgbQWNWkiWZTMwWY
+ hex!["765e46067adac4d1fe6c783aa2070dfa64a19f84376659e12705d1734b3eae01"].unchecked_into(),
+ // 5GvuM53k1Z4nAB5zXJFgkRSHv4Bqo4BsvgbQWNWkiWZTMwWY
+ hex!["765e46067adac4d1fe6c783aa2070dfa64a19f84376659e12705d1734b3eae01"].unchecked_into(),
+ ),(
+ // 5FzwpgGvk2kk9agow6KsywLYcPzjYc8suKej2bne5G5b9YU3
+ hex!["ae12f70078a22882bf5135d134468f77301927aa67c376e8c55b7ff127ace115"].into(),
+ // 5EqoZhVC2BcsM4WjvZNidu2muKAbu5THQTBKe3EjvxXkdP7A
+ hex!["7addb914ec8486bbc60643d2647685dcc06373401fa80e09813b630c5831d54b"].into(),
+ // 5CXNq1mSKJT4Sc2CbyBBdANeSkbUvdWvE4czJjKXfBHi9sX5
+ hex!["664eae1ca4713dd6abf8c15e6c041820cda3c60df97dc476c2cbf7cb82cb2d2e"].unchecked_into(),
+ // 5E8ULLQrDAtWhfnVfZmX41Yux86zNAwVJYguWJZVWrJvdhBe
+ hex!["5b57ed1443c8967f461db1f6eb2ada24794d163a668f1cf9d9ce3235dfad8799"].unchecked_into(),
+ // 5CXNq1mSKJT4Sc2CbyBBdANeSkbUvdWvE4czJjKXfBHi9sX5
+ hex!["664eae1ca4713dd6abf8c15e6c041820cda3c60df97dc476c2cbf7cb82cb2d2e"].unchecked_into(),
+ // 5CXNq1mSKJT4Sc2CbyBBdANeSkbUvdWvE4czJjKXfBHi9sX5
+ hex!["664eae1ca4713dd6abf8c15e6c041820cda3c60df97dc476c2cbf7cb82cb2d2e"].unchecked_into(),
+ // 5CXNq1mSKJT4Sc2CbyBBdANeSkbUvdWvE4czJjKXfBHi9sX5
+ hex!["664eae1ca4713dd6abf8c15e6c041820cda3c60df97dc476c2cbf7cb82cb2d2e"].unchecked_into(),
+ ),(
+ // 5CFj6Kg9rmVn1vrqpyjau2ztyBzKeVdRKwNPiA3tqhB5HPqq
+ hex!["0867dbb49721126df589db100dda728dc3b475cbf414dad8f72a1d5e84897252"].into(),
+ // 5CwQXP6nvWzigFqNhh2jvCaW9zWVzkdveCJY3tz2MhXMjTon
+ hex!["26ab2b4b2eba2263b1e55ceb48f687bb0018130a88df0712fbdaf6a347d50e2a"].into(),
+ // 5FCd9Y7RLNyxz5wnCAErfsLbXGG34L2BaZRHzhiJcMUMd5zd
+ hex!["2adb17a5cafbddc7c3e00ec45b6951a8b12ce2264235b4def342513a767e5d3d"].unchecked_into(),
+ // 5HGLmrZsiTFTPp3QoS1W8w9NxByt8PVq79reqvdxNcQkByqK
+ hex!["e60d23f49e93c1c1f2d7c115957df5bbd7faf5ebf138d1e9d02e8b39a1f63df0"].unchecked_into(),
+ // 5FCd9Y7RLNyxz5wnCAErfsLbXGG34L2BaZRHzhiJcMUMd5zd
+ hex!["2adb17a5cafbddc7c3e00ec45b6951a8b12ce2264235b4def342513a767e5d3d"].unchecked_into(),
+ // 5FCd9Y7RLNyxz5wnCAErfsLbXGG34L2BaZRHzhiJcMUMd5zd
+ hex!["2adb17a5cafbddc7c3e00ec45b6951a8b12ce2264235b4def342513a767e5d3d"].unchecked_into(),
+ // 5FCd9Y7RLNyxz5wnCAErfsLbXGG34L2BaZRHzhiJcMUMd5zd
+ hex!["2adb17a5cafbddc7c3e00ec45b6951a8b12ce2264235b4def342513a767e5d3d"].unchecked_into(),
+ )];
+
+ const ENDOWMENT: u128 = 1_000_000 * KSM;
+ const STASH: u128 = 100 * KSM;
+
+ kusama::GenesisConfig {
+ system: Some(kusama::SystemConfig {
+ code: kusama::WASM_BINARY.to_vec(),
+ changes_trie_config: Default::default(),
+ }),
+ balances: Some(kusama::BalancesConfig {
+ balances: endowed_accounts.iter()
+ .map(|k: &AccountId| (k.clone(), ENDOWMENT))
+ .chain(initial_authorities.iter().map(|x| (x.0.clone(), STASH)))
+ .collect(),
+ }),
+ indices: Some(kusama::IndicesConfig {
+ indices: vec![],
+ }),
+ session: Some(kusama::SessionConfig {
+ keys: initial_authorities.iter().map(|x| (
+ x.0.clone(),
+ x.0.clone(),
+ kusama_session_keys(x.2.clone(), x.3.clone(), x.4.clone(), x.5.clone(), x.6.clone()),
+ )).collect::>(),
+ }),
+ staking: Some(kusama::StakingConfig {
+ validator_count: 50,
+ minimum_validator_count: 4,
+ stakers: initial_authorities
+ .iter()
+ .map(|x| (x.0.clone(), x.1.clone(), STASH, kusama::StakerStatus::Validator))
+ .collect(),
+ invulnerables: initial_authorities.iter().map(|x| x.0.clone()).collect(),
+ force_era: Forcing::ForceNone,
+ slash_reward_fraction: Perbill::from_percent(10),
+ .. Default::default()
+ }),
+ elections_phragmen: Some(Default::default()),
+ democracy: Some(Default::default()),
+ collective_Instance1: Some(kusama::CouncilConfig {
+ members: vec![],
+ phantom: Default::default(),
+ }),
+ collective_Instance2: Some(kusama::TechnicalCommitteeConfig {
+ members: vec![],
+ phantom: Default::default(),
+ }),
+ membership_Instance1: Some(Default::default()),
+ babe: Some(Default::default()),
+ grandpa: Some(Default::default()),
+ im_online: Some(Default::default()),
+ authority_discovery: Some(kusama::AuthorityDiscoveryConfig {
+ keys: vec![],
+ }),
+ parachains: Some(kusama::ParachainsConfig {
+ authorities: vec![],
+ }),
+ registrar: Some(kusama::RegistrarConfig {
+ parachains: vec![],
+ _phdata: Default::default(),
+ }),
+ claims: Some(kusama::ClaimsConfig {
+ claims: vec![],
+ vesting: vec![],
+ }),
+ vesting: Some(kusama::VestingConfig {
+ vesting: vec![],
+ }),
+ }
+}
+
+/// Polkadot staging testnet config.
+pub fn polkadot_staging_testnet_config() -> PolkadotChainSpec {
+ let boot_nodes = vec![];
+ PolkadotChainSpec::from_genesis(
+ "Polkadot Staging Testnet",
+ "polkadot_staging_testnet",
+ ChainType::Live,
+ polkadot_staging_testnet_config_genesis,
+ boot_nodes,
+ Some(TelemetryEndpoints::new(vec![(POLKADOT_STAGING_TELEMETRY_URL.to_string(), 0)])
+ .expect("Polkadot Staging telemetry url is valid; qed")),
+ Some(DEFAULT_PROTOCOL_ID),
+ None,
+ Default::default(),
+ )
+}
+
+/// Staging testnet config.
+pub fn kusama_staging_testnet_config() -> KusamaChainSpec {
+ let boot_nodes = vec![];
+ KusamaChainSpec::from_genesis(
+ "Kusama Staging Testnet",
+ "kusama_staging_testnet",
+ ChainType::Live,
+ kusama_staging_testnet_config_genesis,
+ boot_nodes,
+ Some(TelemetryEndpoints::new(vec![(KUSAMA_STAGING_TELEMETRY_URL.to_string(), 0)])
+ .expect("Kusama Staging telemetry url is valid; qed")),
+ Some(DEFAULT_PROTOCOL_ID),
+ None,
+ Default::default(),
+ )
+}
+
+/// Westend staging testnet config.
+pub fn westend_staging_testnet_config() -> WestendChainSpec {
+ let boot_nodes = vec![];
+ WestendChainSpec::from_genesis(
+ "Westend Staging Testnet",
+ "westend_staging_testnet",
+ ChainType::Live,
+ westend_staging_testnet_config_genesis,
+ boot_nodes,
+ Some(TelemetryEndpoints::new(vec![(WESTEND_STAGING_TELEMETRY_URL.to_string(), 0)])
+ .expect("Westend Staging telemetry url is valid; qed")),
+ Some(DEFAULT_PROTOCOL_ID),
+ None,
+ Default::default(),
+ )
+}
+
+/// Helper function to generate a crypto pair from seed
+pub fn get_from_seed(seed: &str) -> ::Public {
+ TPublic::Pair::from_string(&format!("//{}", seed), None)
+ .expect("static values are valid; qed")
+ .public()
+}
+
+
+/// Helper function to generate an account ID from seed
+pub fn get_account_id_from_seed(seed: &str) -> AccountId where
+ AccountPublic: From<::Public>
+{
+ AccountPublic::from(get_from_seed::(seed)).into_account()
+}
+
+/// Helper function to generate stash, controller and session key from seed
+pub fn get_authority_keys_from_seed(seed: &str) -> (
+ AccountId,
+ AccountId,
+ BabeId,
+ GrandpaId,
+ ImOnlineId,
+ ValidatorId,
+ AuthorityDiscoveryId
+) {
+ (
+ get_account_id_from_seed::(&format!("{}//stash", seed)),
+ get_account_id_from_seed::(seed),
+ get_from_seed::(seed),
+ get_from_seed::(seed),
+ get_from_seed::(seed),
+ get_from_seed::(seed),
+ get_from_seed::(seed),
+ )
+}
+
+fn testnet_accounts() -> Vec {
+ vec![
+ get_account_id_from_seed::("Alice"),
+ get_account_id_from_seed::("Bob"),
+ get_account_id_from_seed::("Charlie"),
+ get_account_id_from_seed::("Dave"),
+ get_account_id_from_seed::("Eve"),
+ get_account_id_from_seed::("Ferdie"),
+ get_account_id_from_seed::("Alice//stash"),
+ get_account_id_from_seed::("Bob//stash"),
+ get_account_id_from_seed::("Charlie//stash"),
+ get_account_id_from_seed::("Dave//stash"),
+ get_account_id_from_seed::("Eve//stash"),
+ get_account_id_from_seed::("Ferdie//stash"),
+ ]
+}
+
+/// Helper function to create polkadot GenesisConfig for testing
+pub fn polkadot_testnet_genesis(
+ initial_authorities: Vec<(AccountId, AccountId, BabeId, GrandpaId, ImOnlineId, ValidatorId, AuthorityDiscoveryId)>,
+ root_key: AccountId,
+ endowed_accounts: Option>,
+) -> polkadot::GenesisConfig {
+ let endowed_accounts: Vec = endowed_accounts.unwrap_or_else(testnet_accounts);
+
+ const ENDOWMENT: u128 = 1_000_000 * DOTS;
+ const STASH: u128 = 100 * DOTS;
+
+ polkadot::GenesisConfig {
+ system: Some(polkadot::SystemConfig {
+ code: polkadot::WASM_BINARY.to_vec(),
+ changes_trie_config: Default::default(),
+ }),
+ indices: Some(polkadot::IndicesConfig {
+ indices: vec![],
+ }),
+ balances: Some(polkadot::BalancesConfig {
+ balances: endowed_accounts.iter().map(|k| (k.clone(), ENDOWMENT)).collect(),
+ }),
+ session: Some(polkadot::SessionConfig {
+ keys: initial_authorities.iter().map(|x| (
+ x.0.clone(),
+ x.0.clone(),
+ polkadot_session_keys(x.2.clone(), x.3.clone(), x.4.clone(), x.5.clone(), x.6.clone()),
+ )).collect::>(),
+ }),
+ staking: Some(polkadot::StakingConfig {
+ minimum_validator_count: 1,
+ validator_count: 2,
+ stakers: initial_authorities.iter()
+ .map(|x| (x.0.clone(), x.1.clone(), STASH, polkadot::StakerStatus::Validator))
+ .collect(),
+ invulnerables: initial_authorities.iter().map(|x| x.0.clone()).collect(),
+ force_era: Forcing::NotForcing,
+ slash_reward_fraction: Perbill::from_percent(10),
+ .. Default::default()
+ }),
+ elections_phragmen: Some(Default::default()),
+ democracy: Some(polkadot::DemocracyConfig::default()),
+ collective_Instance1: Some(polkadot::CouncilConfig {
+ members: vec![],
+ phantom: Default::default(),
+ }),
+ collective_Instance2: Some(polkadot::TechnicalCommitteeConfig {
+ members: vec![],
+ phantom: Default::default(),
+ }),
+ membership_Instance1: Some(Default::default()),
+ babe: Some(Default::default()),
+ grandpa: Some(Default::default()),
+ im_online: Some(Default::default()),
+ authority_discovery: Some(polkadot::AuthorityDiscoveryConfig {
+ keys: vec![],
+ }),
+ parachains: Some(polkadot::ParachainsConfig {
+ authorities: vec![],
+ }),
+ registrar: Some(polkadot::RegistrarConfig{
+ parachains: vec![],
+ _phdata: Default::default(),
+ }),
+ claims: Some(polkadot::ClaimsConfig {
+ claims: vec![],
+ vesting: vec![],
+ }),
+ vesting: Some(polkadot::VestingConfig {
+ vesting: vec![],
+ }),
+ sudo: Some(polkadot::SudoConfig {
+ key: root_key,
+ }),
+ }
+}
+
+/// Helper function to create kusama GenesisConfig for testing
+pub fn kusama_testnet_genesis(
+ initial_authorities: Vec<(AccountId, AccountId, BabeId, GrandpaId, ImOnlineId, ValidatorId, AuthorityDiscoveryId)>,
+ _root_key: AccountId,
+ endowed_accounts: Option>,
+) -> kusama::GenesisConfig {
+ let endowed_accounts: Vec = endowed_accounts.unwrap_or_else(testnet_accounts);
+
+ const ENDOWMENT: u128 = 1_000_000 * KSM;
+ const STASH: u128 = 100 * KSM;
+
+ kusama::GenesisConfig {
+ system: Some(kusama::SystemConfig {
+ code: kusama::WASM_BINARY.to_vec(),
+ changes_trie_config: Default::default(),
+ }),
+ indices: Some(kusama::IndicesConfig {
+ indices: vec![],
+ }),
+ balances: Some(kusama::BalancesConfig {
+ balances: endowed_accounts.iter().map(|k| (k.clone(), ENDOWMENT)).collect(),
+ }),
+ session: Some(kusama::SessionConfig {
+ keys: initial_authorities.iter().map(|x| (
+ x.0.clone(),
+ x.0.clone(),
+ kusama_session_keys(x.2.clone(), x.3.clone(), x.4.clone(), x.5.clone(), x.6.clone()),
+ )).collect::>(),
+ }),
+ staking: Some(kusama::StakingConfig {
+ minimum_validator_count: 1,
+ validator_count: 2,
+ stakers: initial_authorities.iter()
+ .map(|x| (x.0.clone(), x.1.clone(), STASH, kusama::StakerStatus::Validator))
+ .collect(),
+ invulnerables: initial_authorities.iter().map(|x| x.0.clone()).collect(),
+ force_era: Forcing::NotForcing,
+ slash_reward_fraction: Perbill::from_percent(10),
+ .. Default::default()
+ }),
+ elections_phragmen: Some(Default::default()),
+ democracy: Some(kusama::DemocracyConfig::default()),
+ collective_Instance1: Some(kusama::CouncilConfig {
+ members: vec![],
+ phantom: Default::default(),
+ }),
+ collective_Instance2: Some(kusama::TechnicalCommitteeConfig {
+ members: vec![],
+ phantom: Default::default(),
+ }),
+ membership_Instance1: Some(Default::default()),
+ babe: Some(Default::default()),
+ grandpa: Some(Default::default()),
+ im_online: Some(Default::default()),
+ authority_discovery: Some(kusama::AuthorityDiscoveryConfig {
+ keys: vec![],
+ }),
+ parachains: Some(kusama::ParachainsConfig {
+ authorities: vec![],
+ }),
+ registrar: Some(kusama::RegistrarConfig{
+ parachains: vec![],
+ _phdata: Default::default(),
+ }),
+ claims: Some(kusama::ClaimsConfig {
+ claims: vec![],
+ vesting: vec![],
+ }),
+ vesting: Some(kusama::VestingConfig {
+ vesting: vec![],
+ }),
+ }
+}
+
+/// Helper function to create polkadot GenesisConfig for testing
+pub fn westend_testnet_genesis(
+ initial_authorities: Vec<(AccountId, AccountId, BabeId, GrandpaId, ImOnlineId, ValidatorId, AuthorityDiscoveryId)>,
+ root_key: AccountId,
+ endowed_accounts: Option>,
+) -> westend::GenesisConfig {
+ let endowed_accounts: Vec = endowed_accounts.unwrap_or_else(testnet_accounts);
+
+ const ENDOWMENT: u128 = 1_000_000 * DOTS;
+ const STASH: u128 = 100 * DOTS;
+
+ westend::GenesisConfig {
+ system: Some(westend::SystemConfig {
+ code: westend::WASM_BINARY.to_vec(),
+ changes_trie_config: Default::default(),
+ }),
+ indices: Some(westend::IndicesConfig {
+ indices: vec![],
+ }),
+ balances: Some(westend::BalancesConfig {
+ balances: endowed_accounts.iter().map(|k| (k.clone(), ENDOWMENT)).collect(),
+ }),
+ session: Some(westend::SessionConfig {
+ keys: initial_authorities.iter().map(|x| (
+ x.0.clone(),
+ x.0.clone(),
+ westend_session_keys(x.2.clone(), x.3.clone(), x.4.clone(), x.5.clone(), x.6.clone()),
+ )).collect::>(),
+ }),
+ staking: Some(westend::StakingConfig {
+ minimum_validator_count: 1,
+ validator_count: 2,
+ stakers: initial_authorities.iter()
+ .map(|x| (x.0.clone(), x.1.clone(), STASH, westend::StakerStatus::Validator))
+ .collect(),
+ invulnerables: initial_authorities.iter().map(|x| x.0.clone()).collect(),
+ force_era: Forcing::NotForcing,
+ slash_reward_fraction: Perbill::from_percent(10),
+ .. Default::default()
+ }),
+ babe: Some(Default::default()),
+ grandpa: Some(Default::default()),
+ im_online: Some(Default::default()),
+ authority_discovery: Some(westend::AuthorityDiscoveryConfig {
+ keys: vec![],
+ }),
+ parachains: Some(westend::ParachainsConfig {
+ authorities: vec![],
+ }),
+ registrar: Some(westend::RegistrarConfig{
+ parachains: vec![],
+ _phdata: Default::default(),
+ }),
+ vesting: Some(westend::VestingConfig {
+ vesting: vec![],
+ }),
+ sudo: Some(westend::SudoConfig {
+ key: root_key,
+ }),
+ }
+}
+
+fn polkadot_development_config_genesis() -> polkadot::GenesisConfig {
+ polkadot_testnet_genesis(
+ vec![
+ get_authority_keys_from_seed("Alice"),
+ ],
+ get_account_id_from_seed::("Alice"),
+ None,
+ )
+}
+
+fn kusama_development_config_genesis() -> kusama::GenesisConfig {
+ kusama_testnet_genesis(
+ vec![
+ get_authority_keys_from_seed("Alice"),
+ ],
+ get_account_id_from_seed::("Alice"),
+ None,
+ )
+}
+
+fn westend_development_config_genesis() -> westend::GenesisConfig {
+ westend_testnet_genesis(
+ vec![
+ get_authority_keys_from_seed("Alice"),
+ ],
+ get_account_id_from_seed::("Alice"),
+ None,
+ )
+}
+
+/// Polkadot development config (single validator Alice)
+pub fn polkadot_development_config() -> PolkadotChainSpec {
+ PolkadotChainSpec::from_genesis(
+ "Development",
+ "dev",
+ ChainType::Development,
+ polkadot_development_config_genesis,
+ vec![],
+ None,
+ Some(DEFAULT_PROTOCOL_ID),
+ None,
+ Default::default(),
+ )
+}
+
+/// Kusama development config (single validator Alice)
+pub fn kusama_development_config() -> KusamaChainSpec {
+ KusamaChainSpec::from_genesis(
+ "Development",
+ "kusama_dev",
+ ChainType::Development,
+ kusama_development_config_genesis,
+ vec![],
+ None,
+ Some(DEFAULT_PROTOCOL_ID),
+ None,
+ Default::default(),
+ )
+}
+
+/// Westend development config (single validator Alice)
+pub fn westend_development_config() -> WestendChainSpec {
+ WestendChainSpec::from_genesis(
+ "Development",
+ "westend_dev",
+ ChainType::Development,
+ westend_development_config_genesis,
+ vec![],
+ None,
+ Some(DEFAULT_PROTOCOL_ID),
+ None,
+ Default::default(),
+ )
+}
+
+fn polkadot_local_testnet_genesis() -> polkadot::GenesisConfig {
+ polkadot_testnet_genesis(
+ vec![
+ get_authority_keys_from_seed("Alice"),
+ get_authority_keys_from_seed("Bob"),
+ ],
+ get_account_id_from_seed::("Alice"),
+ None,
+ )
+}
+
+/// Polkadot local testnet config (multivalidator Alice + Bob)
+pub fn polkadot_local_testnet_config() -> PolkadotChainSpec {
+ PolkadotChainSpec::from_genesis(
+ "Local Testnet",
+ "local_testnet",
+ ChainType::Local,
+ polkadot_local_testnet_genesis,
+ vec![],
+ None,
+ Some(DEFAULT_PROTOCOL_ID),
+ None,
+ Default::default(),
+ )
+}
+
+fn kusama_local_testnet_genesis() -> kusama::GenesisConfig {
+ kusama_testnet_genesis(
+ vec![
+ get_authority_keys_from_seed("Alice"),
+ get_authority_keys_from_seed("Bob"),
+ ],
+ get_account_id_from_seed::("Alice"),
+ None,
+ )
+}
+
+/// Kusama local testnet config (multivalidator Alice + Bob)
+pub fn kusama_local_testnet_config() -> KusamaChainSpec {
+ KusamaChainSpec::from_genesis(
+ "Kusama Local Testnet",
+ "kusama_local_testnet",
+ ChainType::Local,
+ kusama_local_testnet_genesis,
+ vec![],
+ None,
+ Some(DEFAULT_PROTOCOL_ID),
+ None,
+ Default::default(),
+ )
+}
+
+fn westend_local_testnet_genesis() -> westend::GenesisConfig {
+ westend_testnet_genesis(
+ vec![
+ get_authority_keys_from_seed("Alice"),
+ get_authority_keys_from_seed("Bob"),
+ ],
+ get_account_id_from_seed::("Alice"),
+ None,
+ )
+}
+
+/// Westend local testnet config (multivalidator Alice + Bob)
+pub fn westend_local_testnet_config() -> WestendChainSpec {
+ WestendChainSpec::from_genesis(
+ "Westend Local Testnet",
+ "westend_local_testnet",
+ ChainType::Local,
+ westend_local_testnet_genesis,
+ vec![],
+ None,
+ Some(DEFAULT_PROTOCOL_ID),
+ None,
+ Default::default(),
+ )
+}
diff --git a/node/service/src/client.rs b/node/service/src/client.rs
new file mode 100644
index 000000000000..28d2bccabbe5
--- /dev/null
+++ b/node/service/src/client.rs
@@ -0,0 +1,53 @@
+// Copyright 2017-2020 Parity Technologies (UK) Ltd.
+// This file is part of Polkadot.
+
+// Polkadot is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// Polkadot is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with Polkadot. If not, see .
+
+//! Polkadot Client meta trait
+
+use sp_api::{ProvideRuntimeApi, ConstructRuntimeApi, CallApiAt};
+use sp_blockchain::HeaderBackend;
+use sp_runtime::traits::Block as BlockT;
+use sc_client_api::{Backend as BackendT, BlockchainEvents};
+
+/// Polkadot client abstraction, this super trait only pulls in functionality required for
+/// polkadot internal crates like polkadot-collator.
+pub trait PolkadotClient:
+ BlockchainEvents + Sized + Send + Sync
+ + ProvideRuntimeApi
+ + HeaderBackend
+ + CallApiAt<
+ Block,
+ Error = sp_blockchain::Error,
+ StateBackend = Backend ::State
+ >
+ where
+ Block: BlockT,
+ Backend: BackendT,
+ Runtime: ConstructRuntimeApi
+{}
+
+impl PolkadotClient for Client
+ where
+ Block: BlockT,
+ Runtime: ConstructRuntimeApi,
+ Backend: BackendT,
+ Client: BlockchainEvents + ProvideRuntimeApi + HeaderBackend
+ + Sized + Send + Sync
+ + CallApiAt<
+ Block,
+ Error = sp_blockchain::Error,
+ StateBackend = Backend ::State
+ >
+{}
diff --git a/node/service/src/grandpa_support.rs b/node/service/src/grandpa_support.rs
new file mode 100644
index 000000000000..a875c4b45a37
--- /dev/null
+++ b/node/service/src/grandpa_support.rs
@@ -0,0 +1,363 @@
+// Copyright 2017-2020 Parity Technologies (UK) Ltd.
+// This file is part of Polkadot.
+
+// Polkadot is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// Polkadot is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with Polkadot. If not, see .
+
+//! Polkadot-specific GRANDPA integration utilities.
+
+use polkadot_primitives::Hash;
+use sp_runtime::traits::{Block as BlockT, NumberFor};
+
+/// A custom GRANDPA voting rule that "pauses" voting (i.e. keeps voting for the
+/// same last finalized block) after a given block at height `N` has been
+/// finalized and for a delay of `M` blocks, i.e. until the best block reaches
+/// `N` + `M`, the voter will keep voting for block `N`.
+pub(crate) struct PauseAfterBlockFor(pub(crate) N, pub(crate) N);
+
+impl grandpa::VotingRule for PauseAfterBlockFor> where
+ Block: BlockT,
+ B: sp_blockchain::HeaderBackend,
+{
+ fn restrict_vote(
+ &self,
+ backend: &B,
+ base: &Block::Header,
+ best_target: &Block::Header,
+ current_target: &Block::Header,
+ ) -> Option<(Block::Hash, NumberFor)> {
+ use sp_runtime::generic::BlockId;
+ use sp_runtime::traits::Header as _;
+
+ // walk backwards until we find the target block
+ let find_target = |
+ target_number: NumberFor,
+ current_header: &Block::Header
+ | {
+ let mut target_hash = current_header.hash();
+ let mut target_header = current_header.clone();
+
+ loop {
+ if *target_header.number() < target_number {
+ unreachable!(
+ "we are traversing backwards from a known block; \
+ blocks are stored contiguously; \
+ qed"
+ );
+ }
+
+ if *target_header.number() == target_number {
+ return Some((target_hash, target_number));
+ }
+
+ target_hash = *target_header.parent_hash();
+ target_header = backend.header(BlockId::Hash(target_hash)).ok()?
+ .expect("Header known to exist due to the existence of one of its descendents; qed");
+ }
+ };
+
+ // only restrict votes targeting a block higher than the block
+ // we've set for the pause
+ if *current_target.number() > self.0 {
+ // if we're past the pause period (i.e. `self.0 + self.1`)
+ // then we no longer need to restrict any votes
+ if *best_target.number() > self.0 + self.1 {
+ return None;
+ }
+
+ // if we've finalized the pause block, just keep returning it
+ // until best number increases enough to pass the condition above
+ if *base.number() >= self.0 {
+ return Some((base.hash(), *base.number()));
+ }
+
+ // otherwise find the target header at the pause block
+ // to vote on
+ return find_target(self.0, current_target);
+ }
+
+ None
+ }
+}
+
+/// GRANDPA hard forks due to borked migration of session keys after a runtime
+/// upgrade (at #1491596), the signalled authority set changes were invalid
+/// (blank keys) and were impossible to finalize. The authorities for these
+/// intermediary pending changes are replaced with a static list comprised of
+/// w3f validators and randomly selected validators from the latest session (at
+/// #1500988).
+pub(crate) fn kusama_hard_forks() -> Vec<(
+ grandpa_primitives::SetId,
+ (Hash, polkadot_primitives::BlockNumber),
+ grandpa_primitives::AuthorityList,
+)> {
+ use sp_core::crypto::Ss58Codec;
+ use std::str::FromStr;
+
+ let forks = vec![
+ (
+ 623,
+ "01e94e1e7e9cf07b3b0bf4e1717fce7448e5563901c2ef2e3b8e9ecaeba088b1",
+ 1492283,
+ ),
+ (
+ 624,
+ "ddc4323c5e8966844dfaa87e0c2f74ef6b43115f17bf8e4ff38845a62d02b9a9",
+ 1492436,
+ ),
+ (
+ 625,
+ "38ba115b296663e424e32d7b1655cd795719cef4fd7d579271a6d01086cf1628",
+ 1492586,
+ ),
+ (
+ 626,
+ "f3172b6b8497c10fc772f5dada4eeb1f4c4919c97de9de2e1a439444d5a057ff",
+ 1492955,
+ ),
+ (
+ 627,
+ "b26526aea299e9d24af29fdacd5cf4751a663d24894e3d0a37833aa14c58424a",
+ 1493338,
+ ),
+ (
+ 628,
+ "3980d024327d53b8d01ef0d198a052cd058dd579508d8ed6283fe3614e0a3694",
+ 1493913,
+ ),
+ (
+ 629,
+ "31f22997a786c25ee677786373368cae6fd501fd1bc4b212b8e267235c88179d",
+ 1495083,
+ ),
+ (
+ 630,
+ "1c65eb250cf54b466c64f1a4003d1415a7ee275e49615450c0e0525179857eef",
+ 1497404,
+ ),
+ (
+ 631,
+ "9e44116467cc9d7e224e36487bf2cf571698cae16b25f54a7430f1278331fdd8",
+ 1498598,
+ ),
+ ];
+
+ let authorities = vec![
+ "CwjLJ1zPWK5Ao9WChAFp7rWGEgN3AyXXjTRPrqgm5WwBpoS",
+ "Dp8FHpZTzvoKXztkfrUAkF6xNf6sjVU5ZLZ29NEGUazouou",
+ "DtK7YfkhNWU6wEPF1dShsFdhtosVAuJPLkoGhKhG1r5LjKq",
+ "FLnHYBuoyThzqJ45tdb8P6yMLdocM7ir27Pg1AnpYoygm1K",
+ "FWEfJ5UMghr52UopgYjawAg6hQg3ztbQek75pfeRtLVi8pB",
+ "ECoLHAu7HKWGTB9od82HAtequYj6hvNHigkGSB9g3ApxAwB",
+ "GL1Tg3Uppo8GYL9NjKj4dWKcS6tW98REop9G5hpu7HgFwTa",
+ "ExnjU5LZMktrgtQBE3An6FsQfvaKG1ukxPqwhJydgdgarmY",
+ "CagLpgCBu5qJqYF2tpFX6BnU4yHvMGSjc7r3Ed1jY3tMbQt",
+ "DsrtmMsD4ijh3n4uodxPoiW9NZ7v7no5wVvPVj8fL1dfrWB",
+ "HQB4EctrVR68ozZDyBiRJzLRAEGh1YKgCkAsFjJcegL9RQA",
+ "H2YTYbXTFkDY1cGnv164ecnDT3hsD2bQXtyiDbcQuXcQZUV",
+ "H5WL8jXmbkCoEcLfvqJkbLUeGrDFsJiMXkhhRWn3joct1tE",
+ "DpB37GDrJDYcmg2df2eqsrPKMay1u8hyZ6sQi2FuUiUeNLu",
+ "FR8yjKRA9MTjvFGK8kfzrdC23Fr6xd7rfBvZXSjAsmuxURE",
+ "DxHPty3B9fpj3duu6Gc6gCSCAvsydJHJEY5G3oVYT8S5BYJ",
+ "DbVKC8ZJjevrhqSnZyJMMvmPL7oPPL4ed1roxawYnHVgyin",
+ "DVJV81kab2J6oTyRJ9T3NCwW2DSrysbWCssvMcE6cwZHnAd",
+ "Fg4rDAyzoVzf39Zo8JFPo4W314ntNWNwm3shr4xKe8M1fJg",
+ "GUaNcnAruMVxHGTs7gGpSUpigRJboQYQBBQyPohkFcP6NMH",
+ "J4BMGF4W9yWiJz4pkhQW73X6QMGpKUzmPppVnqzBCqw5dQq",
+ "E1cR61L1tdDEop4WdWVqcq1H1x6VqsDpSHvFyUeC41uruVJ",
+ "GoWLzBsj1f23YtdDpyntnvN1LwXKhF5TEeZvBeTVxofgWGR",
+ "CwHwmbogSwtRbrkajVBNubPvWmHBGU4bhMido54M9CjuKZD",
+ "FLT63y9oVXJnyiWMAL4RvWxsQx21Vymw9961Z7NRFmSG7rw",
+ "FoQ2y6JuHuHTG4rHFL3f2hCxfJMvtrq8wwPWdv8tsdkcyA8",
+ "D7QQKqqs8ocGorRA12h4QoBSHDia1DkHeXT4eMfjWQ483QH",
+ "J6z7FP35F9DiiU985bhkDTS3WxyeTBeoo9MtLdLoD3GiWPj",
+ "EjapydCK25AagodRbDECavHAy8yQY1tmeRhwUXhVWx4cFPv",
+ "H8admATcRkGCrF1dTDDBCjQDsYjMkuPaN9YwR2mSCj4DWMQ",
+ "FtHMRU1fxsoswJjBvyCGvECepC7gP2X77QbNpyikYSqqR6k",
+ "DzY5gwr45GVRUFzRMmeg8iffpqYF47nm3XbJhmjG97FijaE",
+ "D3HKWAihSUmg8HrfeFrftSwNK7no261yA9RNr3LUUdsuzuJ",
+ "D82DwwGJGTcSvtB3SmNrZejnSertbPzpkYvDUp3ibScL3ne",
+ "FTPxLXLQvMDQYFA6VqNLGwWPKhemMYP791XVj8TmDpFuV3b",
+ "FzGfKmS7N8Z1tvCBU5JH1eBXZQ9pCtRNoMUnNVv38wZNq72",
+ "GDfm1MyLAQ7Rh8YPtF6FtMweV4hz91zzeDy2sSABNNqAbmg",
+ "DiVQbq7sozeKp7PXPM1HLFc2m7ih8oepKLRK99oBY3QZak1",
+ "HErWh7D2RzrjWWB2fTJfcAejD9MJpadeWWZM2Wnk7LiNWfG",
+ "Es4DbDauYZYyRJbr6VxrhdcM1iufP9GtdBYf3YtSEvdwNyb",
+ "EBgXT6FaVo4WsN2LmfnB2jnpDFf4zay3E492RGSn6v1tY99",
+ "Dr9Zg4fxZurexParztL9SezFeHsPwdP8uGgULeRMbk8DDHJ",
+ "JEnSTZJpLh91cSryptj57RtFxq9xXqf4U5wBH3qoP91ZZhN",
+ "DqtRkrmtPANa8wrYR7Ce2LxJxk2iNFtiCxv1cXbx54uqdTN",
+ "GaxmF53xbuTFKopVEseWiaCTa8fC6f99n4YfW8MGPSPYX3s",
+ "EiCesgkAaighBKMpwFSAUdvwE4mRjBjNmmd5fP6d4FG8DAx",
+ "HVbwWGUx7kCgUGap1Mfcs37g6JAZ5qsfsM7TsDRcSqvfxmd",
+ "G45bc8Ajrd6YSXav77gQwjjGoAsR2qiGd1aLzkMy7o1RLwd",
+ "Cqix2rD93Mdf7ytg8tBavAig2TvhXPgPZ2mejQvkq7qgRPq",
+ "GpodE2S5dPeVjzHB4Drm8R9rEwcQPtwAspXqCVz1ooFWf5K",
+ "CwfmfRmzPKLj3ntSCejuVwYmQ1F9iZWY4meQrAVoJ2G8Kce",
+ "Fhp5NPvutRCJ4Gx3G8vCYGaveGcU3KgTwfrn5Zr8sLSgwVx",
+ "GeYRRPkyi23wSF3cJGjq82117fKJZUbWsAGimUnzb5RPbB1",
+ "DzCJ4y5oT611dfKQwbBDVbtCfENTdMCjb4KGMU3Mq6nyUMu",
+ ];
+
+ let authorities = authorities
+ .into_iter()
+ .map(|address| {
+ (
+ grandpa_primitives::AuthorityId::from_ss58check(address)
+ .expect("hard fork authority addresses are static and they should be carefully defined; qed."),
+ 1,
+ )
+ })
+ .collect::>();
+
+ forks
+ .into_iter()
+ .map(|(set_id, hash, number)| {
+ let hash = Hash::from_str(hash)
+ .expect("hard fork hashes are static and they should be carefully defined; qed.");
+
+ (set_id, (hash, number), authorities.clone())
+ })
+ .collect()
+}
+
+#[cfg(test)]
+mod tests {
+ use polkadot_test_runtime_client::prelude::*;
+ use polkadot_test_runtime_client::sp_consensus::BlockOrigin;
+ use sc_block_builder::BlockBuilderProvider;
+ use grandpa::VotingRule;
+ use sp_blockchain::HeaderBackend;
+ use sp_runtime::generic::BlockId;
+ use sp_runtime::traits::Header;
+ use std::sync::Arc;
+
+ #[test]
+ fn grandpa_pause_voting_rule_works() {
+ let _ = env_logger::try_init();
+
+ let client = Arc::new(polkadot_test_runtime_client::new());
+
+ let mut push_blocks = {
+ let mut client = client.clone();
+ move |n| {
+ for _ in 0..n {
+ let mut builder = client.new_block(Default::default()).unwrap();
+
+ for extrinsic in polkadot_test_runtime_client::needed_extrinsics(vec![]) {
+ builder.push(extrinsic).unwrap()
+ }
+
+ let block = builder.build().unwrap().block;
+ client.import(BlockOrigin::Own, block).unwrap();
+ }
+ }
+ };
+
+ let get_header = {
+ let client = client.clone();
+ move |n| client.header(&BlockId::Number(n)).unwrap().unwrap()
+ };
+
+ // the rule should filter all votes after block #20
+ // is finalized until block #50 is imported.
+ let voting_rule = super::PauseAfterBlockFor(20, 30);
+
+ // add 10 blocks
+ push_blocks(10);
+ assert_eq!(
+ client.info().best_number,
+ 10,
+ );
+
+ // we have not reached the pause block
+ // therefore nothing should be restricted
+ assert_eq!(
+ voting_rule.restrict_vote(
+ &*client,
+ &get_header(0),
+ &get_header(10),
+ &get_header(10),
+ ),
+ None,
+ );
+
+ // add 15 more blocks
+ // best block: #25
+ push_blocks(15);
+
+ // we are targeting the pause block,
+ // the vote should not be restricted
+ assert_eq!(
+ voting_rule.restrict_vote(
+ &*client,
+ &get_header(10),
+ &get_header(20),
+ &get_header(20),
+ ),
+ None,
+ );
+
+ // we are past the pause block, votes should
+ // be limited to the pause block.
+ let pause_block = get_header(20);
+ assert_eq!(
+ voting_rule.restrict_vote(
+ &*client,
+ &get_header(10),
+ &get_header(21),
+ &get_header(21),
+ ),
+ Some((pause_block.hash(), *pause_block.number())),
+ );
+
+ // we've finalized the pause block, so we'll keep
+ // restricting our votes to it.
+ assert_eq!(
+ voting_rule.restrict_vote(
+ &*client,
+ &pause_block, // #20
+ &get_header(21),
+ &get_header(21),
+ ),
+ Some((pause_block.hash(), *pause_block.number())),
+ );
+
+ // add 30 more blocks
+ // best block: #55
+ push_blocks(30);
+
+ // we're at the last block of the pause, this block
+ // should still be considered in the pause period
+ assert_eq!(
+ voting_rule.restrict_vote(
+ &*client,
+ &pause_block, // #20
+ &get_header(50),
+ &get_header(50),
+ ),
+ Some((pause_block.hash(), *pause_block.number())),
+ );
+
+ // we're past the pause period, no votes should be filtered
+ assert_eq!(
+ voting_rule.restrict_vote(
+ &*client,
+ &pause_block, // #20
+ &get_header(51),
+ &get_header(51),
+ ),
+ None,
+ );
+ }
+}
diff --git a/node/service/src/lib.rs b/node/service/src/lib.rs
new file mode 100644
index 000000000000..af517adc0e9e
--- /dev/null
+++ b/node/service/src/lib.rs
@@ -0,0 +1,729 @@
+// Copyright 2017-2020 Parity Technologies (UK) Ltd.
+// This file is part of Polkadot.
+
+// Polkadot is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// Polkadot is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with Polkadot. If not, see .
+
+//! Polkadot service. Specialized wrapper over substrate service.
+
+pub mod chain_spec;
+mod grandpa_support;
+mod client;
+
+use std::sync::Arc;
+use std::time::Duration;
+use polkadot_primitives::{parachain, AccountId, Nonce, Balance};
+#[cfg(feature = "full-node")]
+use service::{error::Error as ServiceError, ServiceBuilder};
+use grandpa::{self, FinalityProofProvider as GrandpaFinalityProofProvider};
+use sc_executor::native_executor_instance;
+use log::info;
+use sp_blockchain::HeaderBackend;
+use polkadot_overseer::{
+ self as overseer,
+ BlockInfo, Overseer, OverseerHandler, Subsystem, SubsystemContext, SpawnedSubsystem,
+ ValidationSubsystemMessage, CandidateBackingSubsystemMessage,
+};
+pub use service::{
+ AbstractService, Role, PruningMode, TransactionPoolOptions, Error, RuntimeGenesis,
+ TFullClient, TLightClient, TFullBackend, TLightBackend, TFullCallExecutor, TLightCallExecutor,
+ Configuration, ChainSpec, ServiceBuilderCommand,
+};
+pub use service::config::{DatabaseConfig, PrometheusConfig};
+pub use sc_executor::NativeExecutionDispatch;
+pub use sc_client_api::{Backend, ExecutionStrategy, CallExecutor};
+pub use sc_consensus::LongestChain;
+pub use sp_api::{ApiRef, Core as CoreApi, ConstructRuntimeApi, ProvideRuntimeApi, StateBackend};
+pub use sp_runtime::traits::{DigestFor, HashFor, NumberFor};
+pub use consensus_common::{Proposal, SelectChain, BlockImport, RecordProof, block_validation::Chain};
+pub use polkadot_primitives::parachain::{CollatorId, ParachainHost};
+pub use polkadot_primitives::{Block, BlockId};
+pub use sp_runtime::traits::{Block as BlockT, self as runtime_traits, BlakeTwo256};
+pub use chain_spec::{PolkadotChainSpec, KusamaChainSpec, WestendChainSpec};
+#[cfg(feature = "full-node")]
+pub use codec::Codec;
+pub use polkadot_runtime;
+pub use kusama_runtime;
+pub use westend_runtime;
+use prometheus_endpoint::Registry;
+pub use self::client::PolkadotClient;
+
+native_executor_instance!(
+ pub PolkadotExecutor,
+ polkadot_runtime::api::dispatch,
+ polkadot_runtime::native_version,
+ frame_benchmarking::benchmarking::HostFunctions,
+);
+
+native_executor_instance!(
+ pub KusamaExecutor,
+ kusama_runtime::api::dispatch,
+ kusama_runtime::native_version,
+ frame_benchmarking::benchmarking::HostFunctions,
+);
+
+native_executor_instance!(
+ pub WestendExecutor,
+ westend_runtime::api::dispatch,
+ westend_runtime::native_version,
+ frame_benchmarking::benchmarking::HostFunctions,
+);
+
+/// A set of APIs that polkadot-like runtimes must implement.
+pub trait RuntimeApiCollection:
+ sp_transaction_pool::runtime_api::TaggedTransactionQueue
+ + sp_api::ApiExt
+ + babe_primitives::BabeApi
+ + grandpa_primitives::GrandpaApi
+ + ParachainHost
+ + sp_block_builder::BlockBuilder
+ + system_rpc_runtime_api::AccountNonceApi
+ + pallet_transaction_payment_rpc_runtime_api::TransactionPaymentApi
+ + sp_api::Metadata
+ + sp_offchain::OffchainWorkerApi
+ + sp_session::SessionKeys
+ + authority_discovery_primitives::AuthorityDiscoveryApi
+where
+ Extrinsic: RuntimeExtrinsic,
+ >::StateBackend: sp_api::StateBackend,
+{}
+
+impl RuntimeApiCollection for Api
+where
+ Api:
+ sp_transaction_pool::runtime_api::TaggedTransactionQueue
+ + sp_api::ApiExt
+ + babe_primitives::BabeApi
+ + grandpa_primitives::GrandpaApi
+ + ParachainHost
+ + sp_block_builder::BlockBuilder
+ + system_rpc_runtime_api::AccountNonceApi
+ + pallet_transaction_payment_rpc_runtime_api::TransactionPaymentApi
+ + sp_api::Metadata
+ + sp_offchain::OffchainWorkerApi
+ + sp_session::SessionKeys
+ + authority_discovery_primitives::AuthorityDiscoveryApi,
+ Extrinsic: RuntimeExtrinsic,
+ >::StateBackend: sp_api::StateBackend,
+{}
+
+pub trait RuntimeExtrinsic: codec::Codec + Send + Sync + 'static {}
+
+impl RuntimeExtrinsic for E where E: codec::Codec + Send + Sync + 'static {}
+
+/// Can be called for a `Configuration` to check if it is a configuration for the `Kusama` network.
+pub trait IdentifyVariant {
+ /// Returns if this is a configuration for the `Kusama` network.
+ fn is_kusama(&self) -> bool;
+
+ /// Returns if this is a configuration for the `Westend` network.
+ fn is_westend(&self) -> bool;
+}
+
+impl IdentifyVariant for Box {
+ fn is_kusama(&self) -> bool {
+ self.id().starts_with("kusama") || self.id().starts_with("ksm")
+ }
+ fn is_westend(&self) -> bool {
+ self.id().starts_with("westend") || self.id().starts_with("wnd")
+ }
+}
+
+// If we're using prometheus, use a registry with a prefix of `polkadot`.
+fn set_prometheus_registry(config: &mut Configuration) -> Result<(), ServiceError> {
+ if let Some(PrometheusConfig { registry, .. }) = config.prometheus_config.as_mut() {
+ *registry = Registry::new_custom(Some("polkadot".into()), None)?;
+ }
+
+ Ok(())
+}
+
+/// Starts a `ServiceBuilder` for a full service.
+///
+/// Use this macro if you don't actually need the full service, but just the builder in order to
+/// be able to perform chain operations.
+macro_rules! new_full_start {
+ ($config:expr, $runtime:ty, $executor:ty, $informant_prefix:expr $(,)?) => {{
+ set_prometheus_registry(&mut $config)?;
+
+ let mut import_setup = None;
+ let mut rpc_setup = None;
+ let inherent_data_providers = inherents::InherentDataProviders::new();
+ let builder = service::ServiceBuilder::new_full::<
+ Block, $runtime, $executor
+ >($config)?
+ .with_informant_prefix($informant_prefix.unwrap_or_default())?
+ .with_select_chain(|_, backend| {
+ Ok(sc_consensus::LongestChain::new(backend.clone()))
+ })?
+ .with_transaction_pool(|builder| {
+ let pool_api = sc_transaction_pool::FullChainApi::new(builder.client().clone());
+ let pool = sc_transaction_pool::BasicPool::new(
+ builder.config().transaction_pool.clone(),
+ std::sync::Arc::new(pool_api),
+ builder.prometheus_registry(),
+ );
+ Ok(pool)
+ })?
+ .with_import_queue(|
+ config,
+ client,
+ mut select_chain,
+ _,
+ spawn_task_handle,
+ registry,
+ | {
+ let select_chain = select_chain.take()
+ .ok_or_else(|| service::Error::SelectChainRequired)?;
+
+ let grandpa_hard_forks = if config.chain_spec.is_kusama() {
+ grandpa_support::kusama_hard_forks()
+ } else {
+ Vec::new()
+ };
+
+ let (grandpa_block_import, grandpa_link) =
+ grandpa::block_import_with_authority_set_hard_forks(
+ client.clone(),
+ &(client.clone() as Arc<_>),
+ select_chain,
+ grandpa_hard_forks,
+ )?;
+
+ let justification_import = grandpa_block_import.clone();
+
+ let (block_import, babe_link) = babe::block_import(
+ babe::Config::get_or_compute(&*client)?,
+ grandpa_block_import,
+ client.clone(),
+ )?;
+
+ let import_queue = babe::import_queue(
+ babe_link.clone(),
+ block_import.clone(),
+ Some(Box::new(justification_import)),
+ None,
+ client,
+ inherent_data_providers.clone(),
+ spawn_task_handle,
+ registry,
+ )?;
+
+ import_setup = Some((block_import, grandpa_link, babe_link));
+ Ok(import_queue)
+ })?
+ .with_rpc_extensions_builder(|builder| {
+ let grandpa_link = import_setup.as_ref().map(|s| &s.1)
+ .expect("GRANDPA LinkHalf is present for full services or set up failed; qed.");
+
+ let shared_authority_set = grandpa_link.shared_authority_set().clone();
+ let shared_voter_state = grandpa::SharedVoterState::empty();
+
+ rpc_setup = Some((shared_voter_state.clone()));
+
+ let babe_link = import_setup.as_ref().map(|s| &s.2)
+ .expect("BabeLink is present for full services or set up faile; qed.");
+
+ let babe_config = babe_link.config().clone();
+ let shared_epoch_changes = babe_link.epoch_changes().clone();
+
+ let client = builder.client().clone();
+ let pool = builder.pool().clone();
+ let select_chain = builder.select_chain().cloned()
+ .expect("SelectChain is present for full services or set up failed; qed.");
+ let keystore = builder.keystore().clone();
+
+ Ok(move |deny_unsafe| -> polkadot_rpc::RpcExtension {
+ let deps = polkadot_rpc::FullDeps {
+ client: client.clone(),
+ pool: pool.clone(),
+ select_chain: select_chain.clone(),
+ deny_unsafe,
+ babe: polkadot_rpc::BabeDeps {
+ babe_config: babe_config.clone(),
+ shared_epoch_changes: shared_epoch_changes.clone(),
+ keystore: keystore.clone(),
+ },
+ grandpa: polkadot_rpc::GrandpaDeps {
+ shared_voter_state: shared_voter_state.clone(),
+ shared_authority_set: shared_authority_set.clone(),
+ },
+ };
+
+ polkadot_rpc::create_full(deps)
+ })
+ })?;
+
+ (builder, import_setup, inherent_data_providers, rpc_setup)
+ }}
+}
+
+struct ValidationSubsystem;
+
+impl Subsystem for ValidationSubsystem {
+ fn start(&mut self, mut ctx: SubsystemContext) -> SpawnedSubsystem {
+ SpawnedSubsystem(Box::pin(async move {
+ while let Ok(_) = ctx.recv().await {}
+ }))
+ }
+}
+
+struct CandidateBackingSubsystem;
+
+impl Subsystem for CandidateBackingSubsystem {
+ fn start(&mut self, mut ctx: SubsystemContext) -> SpawnedSubsystem {
+ SpawnedSubsystem(Box::pin(async move {
+ while let Ok(_) = ctx.recv().await {}
+ }))
+ }
+}
+
+fn real_overseer(
+ leaves: impl IntoIterator- ,
+ s: S,
+) -> Result<(Overseer
, OverseerHandler), ServiceError> {
+ let validation = Box::new(ValidationSubsystem);
+ let candidate_backing = Box::new(CandidateBackingSubsystem);
+ Overseer::new(leaves, validation, candidate_backing, s)
+ .map_err(|e| ServiceError::Other(format!("Failed to create an Overseer: {:?}", e)))
+}
+
+/// Builds a new service for a full client.
+#[macro_export]
+macro_rules! new_full {
+ (
+ $config:expr,
+ $collating_for:expr,
+ $authority_discovery_enabled:expr,
+ $grandpa_pause:expr,
+ $runtime:ty,
+ $dispatch:ty,
+ $informant_prefix:expr $(,)?
+ ) => {{
+ use sc_client_api::ExecutorProvider;
+ use sp_core::traits::BareCryptoStorePtr;
+
+ let is_collator = $collating_for.is_some();
+ let role = $config.role.clone();
+ let is_authority = role.is_authority() && !is_collator;
+ let force_authoring = $config.force_authoring;
+ let disable_grandpa = $config.disable_grandpa;
+ let name = $config.network.node_name.clone();
+
+ let (builder, mut import_setup, inherent_data_providers, mut rpc_setup) =
+ new_full_start!($config, $runtime, $dispatch, $informant_prefix);
+
+ let service = builder
+ .with_finality_proof_provider(|client, backend| {
+ let provider = client as Arc>;
+ Ok(Arc::new(GrandpaFinalityProofProvider::new(backend, provider)) as _)
+ })?
+ .build_full()?;
+
+ let (block_import, link_half, babe_link) = import_setup.take()
+ .expect("Link Half and Block Import are present for Full Services or setup failed before. qed");
+
+ let shared_voter_state = rpc_setup.take()
+ .expect("The SharedVoterState is present for Full Services or setup failed before. qed");
+
+ let client = service.client();
+
+ let overseer_client = service.client();
+ let spawner = service.spawn_task_handle();
+ let leaves: Vec<_> = service.select_chain().ok_or(ServiceError::SelectChainRequired)?
+ .leaves()
+ .unwrap_or_else(|_| vec![])
+ .into_iter()
+ .filter_map(|hash| {
+ let number = client.number(hash).ok()??;
+ let parent_hash = client.header(&BlockId::Hash(hash)).ok()??.parent_hash;
+
+ Some(BlockInfo {
+ hash,
+ parent_hash,
+ number,
+ })
+ })
+ .collect();
+
+ let (overseer, handler) = real_overseer(leaves, spawner)?;
+
+ service.spawn_essential_task("overseer", Box::pin(async move {
+ use futures::{pin_mut, select, FutureExt};
+
+ let forward = overseer::forward_events(overseer_client, handler);
+
+ let forward = forward.fuse();
+ let overseer_fut = overseer.run().fuse();
+
+ pin_mut!(overseer_fut);
+ pin_mut!(forward);
+
+ loop {
+ select! {
+ _ = forward => break,
+ _ = overseer_fut => break,
+ complete => break,
+ }
+ }
+ }));
+
+ if role.is_authority() {
+ let select_chain = service.select_chain().ok_or(ServiceError::SelectChainRequired)?;
+ let can_author_with =
+ consensus_common::CanAuthorWithNativeVersion::new(client.executor().clone());
+
+ // TODO: custom proposer (https://github.com/paritytech/polkadot/issues/1248)
+ let proposer = sc_basic_authorship::ProposerFactory::new(
+ client.clone(),
+ service.transaction_pool(),
+ None,
+ );
+
+ let babe_config = babe::BabeParams {
+ keystore: service.keystore(),
+ client: client.clone(),
+ select_chain,
+ block_import,
+ env: proposer,
+ sync_oracle: service.network(),
+ inherent_data_providers: inherent_data_providers.clone(),
+ force_authoring,
+ babe_link,
+ can_author_with,
+ };
+
+ let babe = babe::start_babe(babe_config)?;
+ service.spawn_essential_task("babe", babe);
+ }
+
+ // if the node isn't actively participating in consensus then it doesn't
+ // need a keystore, regardless of which protocol we use below.
+ let keystore = if is_authority {
+ Some(service.keystore() as BareCryptoStorePtr)
+ } else {
+ None
+ };
+
+ let config = grandpa::Config {
+ // FIXME substrate#1578 make this available through chainspec
+ gossip_duration: Duration::from_millis(1000),
+ justification_period: 512,
+ name: Some(name),
+ observer_enabled: false,
+ keystore,
+ is_authority: role.is_network_authority(),
+ };
+
+ let enable_grandpa = !disable_grandpa;
+ if enable_grandpa {
+ // start the full GRANDPA voter
+ // NOTE: unlike in substrate we are currently running the full
+ // GRANDPA voter protocol for all full nodes (regardless of whether
+ // they're validators or not). at this point the full voter should
+ // provide better guarantees of block and vote data availability than
+ // the observer.
+
+ // add a custom voting rule to temporarily stop voting for new blocks
+ // after the given pause block is finalized and restarting after the
+ // given delay.
+ let voting_rule = match $grandpa_pause {
+ Some((block, delay)) => {
+ info!("GRANDPA scheduled voting pause set for block #{} with a duration of {} blocks.",
+ block,
+ delay,
+ );
+
+ grandpa::VotingRulesBuilder::default()
+ .add(grandpa_support::PauseAfterBlockFor(block, delay))
+ .build()
+ },
+ None =>
+ grandpa::VotingRulesBuilder::default()
+ .build(),
+ };
+
+ let grandpa_config = grandpa::GrandpaParams {
+ config,
+ link: link_half,
+ network: service.network(),
+ inherent_data_providers: inherent_data_providers.clone(),
+ telemetry_on_connect: Some(service.telemetry_on_connect_stream()),
+ voting_rule,
+ prometheus_registry: service.prometheus_registry(),
+ shared_voter_state,
+ };
+
+ service.spawn_essential_task(
+ "grandpa-voter",
+ grandpa::run_grandpa_voter(grandpa_config)?
+ );
+ } else {
+ grandpa::setup_disabled_grandpa(
+ client.clone(),
+ &inherent_data_providers,
+ service.network(),
+ )?;
+ }
+
+ (service, client)
+ }}
+}
+
+pub struct FullNodeHandles;
+
+/// Builds a new service for a light client.
+#[macro_export]
+macro_rules! new_light {
+ ($config:expr, $runtime:ty, $dispatch:ty) => {{
+ crate::set_prometheus_registry(&mut $config)?;
+ let inherent_data_providers = inherents::InherentDataProviders::new();
+
+ ServiceBuilder::new_light::($config)?
+ .with_select_chain(|_, backend| {
+ Ok(sc_consensus::LongestChain::new(backend.clone()))
+ })?
+ .with_transaction_pool(|builder| {
+ let fetcher = builder.fetcher()
+ .ok_or_else(|| "Trying to start light transaction pool without active fetcher")?;
+ let pool_api = sc_transaction_pool::LightChainApi::new(
+ builder.client().clone(),
+ fetcher,
+ );
+ let pool = sc_transaction_pool::BasicPool::with_revalidation_type(
+ builder.config().transaction_pool.clone(),
+ Arc::new(pool_api),
+ builder.prometheus_registry(),
+ sc_transaction_pool::RevalidationType::Light,
+ );
+ Ok(pool)
+ })?
+ .with_import_queue_and_fprb(|
+ _config,
+ client,
+ backend,
+ fetcher,
+ _select_chain,
+ _,
+ spawn_task_handle,
+ registry,
+ | {
+ let fetch_checker = fetcher
+ .map(|fetcher| fetcher.checker().clone())
+ .ok_or_else(|| "Trying to start light import queue without active fetch checker")?;
+ let grandpa_block_import = grandpa::light_block_import(
+ client.clone(), backend, &(client.clone() as Arc<_>), Arc::new(fetch_checker)
+ )?;
+
+ let finality_proof_import = grandpa_block_import.clone();
+ let finality_proof_request_builder =
+ finality_proof_import.create_finality_proof_request_builder();
+
+ let (babe_block_import, babe_link) = babe::block_import(
+ babe::Config::get_or_compute(&*client)?,
+ grandpa_block_import,
+ client.clone(),
+ )?;
+
+ // FIXME: pruning task isn't started since light client doesn't do `AuthoritySetup`.
+ let import_queue = babe::import_queue(
+ babe_link,
+ babe_block_import,
+ None,
+ Some(Box::new(finality_proof_import)),
+ client,
+ inherent_data_providers.clone(),
+ spawn_task_handle,
+ registry,
+ )?;
+
+ Ok((import_queue, finality_proof_request_builder))
+ })?
+ .with_finality_proof_provider(|client, backend| {
+ let provider = client as Arc>;
+ Ok(Arc::new(grandpa::FinalityProofProvider::new(backend, provider)) as _)
+ })?
+ .with_rpc_extensions(|builder| {
+ let fetcher = builder.fetcher()
+ .ok_or_else(|| "Trying to start node RPC without active fetcher")?;
+ let remote_blockchain = builder.remote_backend()
+ .ok_or_else(|| "Trying to start node RPC without active remote blockchain")?;
+
+ let light_deps = polkadot_rpc::LightDeps {
+ remote_blockchain,
+ fetcher,
+ client: builder.client().clone(),
+ pool: builder.pool(),
+ };
+ Ok(polkadot_rpc::create_light(light_deps))
+ })?
+ .build_light()
+ }}
+}
+
+/// Builds a new object suitable for chain operations.
+pub fn new_chain_ops(mut config: Configuration)
+ -> Result, ServiceError>
+where
+ Runtime: ConstructRuntimeApi> + Send + Sync + 'static,
+ Runtime::RuntimeApi:
+ RuntimeApiCollection, Block>>,
+ Dispatch: NativeExecutionDispatch + 'static,
+ Extrinsic: RuntimeExtrinsic,
+ >::StateBackend: sp_api::StateBackend,
+{
+ config.keystore = service::config::KeystoreConfig::InMemory;
+ Ok(new_full_start!(config, Runtime, Dispatch, None).0)
+}
+
+/// Create a new Polkadot service for a full node.
+#[cfg(feature = "full-node")]
+pub fn polkadot_new_full(
+ mut config: Configuration,
+ collating_for: Option<(CollatorId, parachain::Id)>,
+ _max_block_data_size: Option,
+ _authority_discovery_enabled: bool,
+ _slot_duration: u64,
+ grandpa_pause: Option<(u32, u32)>,
+ informant_prefix: Option,
+)
+ -> Result<(
+ impl AbstractService,
+ Arc,
+ polkadot_runtime::RuntimeApi
+ >>,
+ FullNodeHandles,
+ ), ServiceError>
+{
+ let (service, client) = new_full!(
+ config,
+ collating_for,
+ authority_discovery_enabled,
+ grandpa_pause,
+ polkadot_runtime::RuntimeApi,
+ PolkadotExecutor,
+ informant_prefix,
+ );
+
+ Ok((service, client, FullNodeHandles))
+}
+
+/// Create a new Kusama service for a full node.
+#[cfg(feature = "full-node")]
+pub fn kusama_new_full(
+ mut config: Configuration,
+ collating_for: Option<(CollatorId, parachain::Id)>,
+ _max_block_data_size: Option,
+ _authority_discovery_enabled: bool,
+ _slot_duration: u64,
+ grandpa_pause: Option<(u32, u32)>,
+ informant_prefix: Option,
+) -> Result<(
+ impl AbstractService,
+ Arc,
+ kusama_runtime::RuntimeApi
+ >
+ >,
+ FullNodeHandles,
+ ), ServiceError>
+{
+ let (service, client) = new_full!(
+ config,
+ collating_for,
+ authority_discovery_enabled,
+ grandpa_pause,
+ kusama_runtime::RuntimeApi,
+ KusamaExecutor,
+ informant_prefix,
+ );
+
+ Ok((service, client, FullNodeHandles))
+}
+
+/// Create a new Kusama service for a full node.
+#[cfg(feature = "full-node")]
+pub fn westend_new_full(
+ mut config: Configuration,
+ collating_for: Option<(CollatorId, parachain::Id)>,
+ _max_block_data_size: Option,
+ _authority_discovery_enabled: bool,
+ _slot_duration: u64,
+ grandpa_pause: Option<(u32, u32)>,
+ informant_prefix: Option,
+)
+ -> Result<(
+ impl AbstractService,
+ Arc,
+ westend_runtime::RuntimeApi
+ >>,
+ FullNodeHandles,
+ ), ServiceError>
+{
+ let (service, client) = new_full!(
+ config,
+ collating_for,
+ authority_discovery_enabled,
+ grandpa_pause,
+ westend_runtime::RuntimeApi,
+ WestendExecutor,
+ informant_prefix,
+ );
+
+ Ok((service, client, FullNodeHandles))
+}
+
+/// Create a new Polkadot service for a light client.
+pub fn polkadot_new_light(mut config: Configuration) -> Result<
+ impl AbstractService<
+ Block = Block,
+ RuntimeApi = polkadot_runtime::RuntimeApi,
+ Backend = TLightBackend,
+ SelectChain = LongestChain, Block>,
+ CallExecutor = TLightCallExecutor,
+ >, ServiceError>
+{
+ new_light!(config, polkadot_runtime::RuntimeApi, PolkadotExecutor)
+}
+
+/// Create a new Kusama service for a light client.
+pub fn kusama_new_light(mut config: Configuration) -> Result<
+ impl AbstractService<
+ Block = Block,
+ RuntimeApi = kusama_runtime::RuntimeApi,
+ Backend = TLightBackend,
+ SelectChain = LongestChain, Block>,
+ CallExecutor = TLightCallExecutor,
+ >, ServiceError>
+{
+ new_light!(config, kusama_runtime::RuntimeApi, KusamaExecutor)
+}
+
+/// Create a new Westend service for a light client.
+pub fn westend_new_light(mut config: Configuration, ) -> Result<
+ impl AbstractService<
+ Block = Block,
+ RuntimeApi = westend_runtime::RuntimeApi,
+ Backend = TLightBackend,
+ SelectChain = LongestChain, Block>,
+ CallExecutor = TLightCallExecutor
+ >,
+ ServiceError>
+{
+ new_light!(config, westend_runtime::RuntimeApi, KusamaExecutor)
+}