diff --git a/Cargo.lock b/Cargo.lock index 70f8db075251..3f2ce678f707 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3714,6 +3714,7 @@ version = "0.7.0" dependencies = [ "exit-future 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.1.29 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "hex-literal 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", @@ -3735,6 +3736,7 @@ dependencies = [ "sr-io 2.0.0 (git+https://github.com/paritytech/substrate?branch=polkadot-master)", "sr-primitives 2.0.0 (git+https://github.com/paritytech/substrate?branch=polkadot-master)", "substrate-authority-discovery 2.0.0 (git+https://github.com/paritytech/substrate?branch=polkadot-master)", + "substrate-authority-discovery-primitives 2.0.0 (git+https://github.com/paritytech/substrate?branch=polkadot-master)", "substrate-client 2.0.0 (git+https://github.com/paritytech/substrate?branch=polkadot-master)", "substrate-client-api 2.0.0 (git+https://github.com/paritytech/substrate?branch=polkadot-master)", "substrate-client-db 2.0.0 (git+https://github.com/paritytech/substrate?branch=polkadot-master)", diff --git a/cli/src/lib.rs b/cli/src/lib.rs index d72322321a01..072421cf2f35 100644 --- a/cli/src/lib.rs +++ b/cli/src/lib.rs @@ -87,13 +87,25 @@ struct ValidationWorkerCommand { pub mem_id: String, } +#[derive(Debug, StructOpt, Clone)] +struct PolkadotSubParams { + #[structopt(long = "enable-authority-discovery")] + pub authority_discovery_enabled: bool, +} + +cli::impl_augment_clap!(PolkadotSubParams); + /// Parses polkadot specific CLI arguments and run the service. pub fn run(worker: W, version: cli::VersionInfo) -> error::Result<()> where W: Worker, { - match cli::parse_and_prepare::(&version, "parity-polkadot", std::env::args()) { + match cli::parse_and_prepare::( + &version, + "parity-polkadot", + std::env::args(), + ) { cli::ParseAndPrepare::Run(cmd) => cmd.run(load_spec, worker, - |worker, _cli_args, _custom_args, mut config| { + |worker, _cli_args, custom_args, mut config| { info!("{}", version.name); info!(" version {}", config.full_version()); info!(" by {}, 2017-2019", version.author); @@ -108,6 +120,7 @@ pub fn run(worker: W, version: cli::VersionInfo) -> error::Result<()> where info!("Node name: {}", config.name); info!("Roles: {}", display_role(&config)); config.custom = worker.configuration(); + config.custom.authority_discovery_enabled = custom_args.authority_discovery_enabled; let runtime = Runtime::new().map_err(|e| format!("{:?}", e))?; match config.roles { service::Roles::LIGHT => diff --git a/runtime/src/lib.rs b/runtime/src/lib.rs index 0ffa30404505..8ece60307627 100644 --- a/runtime/src/lib.rs +++ b/runtime/src/lib.rs @@ -53,6 +53,7 @@ use frame_support::{ weights::{Weight, DispatchInfo}, }; use im_online::sr25519::AuthorityId as ImOnlineId; +use authority_discovery_primitives::AuthorityId as AuthorityDiscoveryId; use system::offchain::TransactionSubmitter; use pallet_transaction_payment_rpc_runtime_api::RuntimeDispatchInfo; @@ -258,6 +259,7 @@ impl_opaque_keys! { pub babe: Babe, pub im_online: ImOnline, pub parachain_validator: Parachains, + pub authority_discovery: AuthorityDiscovery, } } @@ -433,6 +435,8 @@ impl offences::Trait for Runtime { type OnOffenceHandler = Staking; } +impl authority_discovery::Trait for Runtime {} + type SubmitTransaction = TransactionSubmitter; parameter_types! { @@ -572,6 +576,7 @@ construct_runtime!( FinalityTracker: finality_tracker::{Module, Call, Inherent}, Grandpa: grandpa::{Module, Call, Storage, Config, Event}, ImOnline: im_online::{Module, Call, Storage, Event, ValidateUnsigned, Config}, + AuthorityDiscovery: authority_discovery::{Module, Call, Config}, // Governance stuff; uncallable initially. Democracy: democracy::{Module, Call, Storage, Config, Event}, @@ -734,6 +739,12 @@ sr_api::impl_runtime_apis! { } } + impl authority_discovery_primitives::AuthorityDiscoveryApi for Runtime { + fn authorities() -> Vec { + AuthorityDiscovery::authorities() + } + } + impl substrate_session::SessionKeys for Runtime { fn generate_session_keys(seed: Option>) -> Vec { SessionKeys::generate(seed) diff --git a/service/Cargo.toml b/service/Cargo.toml index eaca14d055c2..8322382d1298 100644 --- a/service/Cargo.toml +++ b/service/Cargo.toml @@ -9,6 +9,7 @@ parking_lot = "0.9.0" lazy_static = "1.4.0" log = "0.4.8" futures = "0.1.29" +futures03 = { package = "futures", version = "0.3.1", features = ["compat"] } exit-future = "0.1.4" slog = "2.5.2" hex-literal = "0.2.1" @@ -41,5 +42,6 @@ pallet-babe = { git = "https://github.com/paritytech/substrate", default-feature pallet-staking = { git = "https://github.com/paritytech/substrate", default-features = false, branch = "polkadot-master" } im-online = { package = "pallet-im-online", git = "https://github.com/paritytech/substrate", default-features = false, branch = "polkadot-master" } authority-discovery = { package = "substrate-authority-discovery", git = "https://github.com/paritytech/substrate", branch = "polkadot-master" } +authority-discovery-primitives = { package = "substrate-authority-discovery-primitives", git = "https://github.com/paritytech/substrate", branch = "polkadot-master" } babe = { package = "substrate-consensus-babe", git = "https://github.com/paritytech/substrate", branch = "polkadot-master" } babe-primitives = { package = "substrate-consensus-babe-primitives", git = "https://github.com/paritytech/substrate", default-features = false, branch = "polkadot-master" } diff --git a/service/src/chain_spec.rs b/service/src/chain_spec.rs index 399e595e4a1e..bd3ff39bc925 100644 --- a/service/src/chain_spec.rs +++ b/service/src/chain_spec.rs @@ -19,9 +19,9 @@ use primitives::{Pair, Public, crypto::UncheckedInto, sr25519}; use polkadot_primitives::{AccountId, AccountPublic, parachain::ValidatorId}; use polkadot_runtime::{ - GenesisConfig, CouncilConfig, DemocracyConfig, SystemConfig, SessionConfig, StakingConfig, - BalancesConfig, SessionKeys, TechnicalCommitteeConfig, SudoConfig, IndicesConfig, StakerStatus, - WASM_BINARY, ClaimsConfig, ParachainsConfig, RegistrarConfig + AuthorityDiscoveryConfig, GenesisConfig, CouncilConfig, DemocracyConfig, SystemConfig, + SessionConfig, StakingConfig, BalancesConfig, SessionKeys, TechnicalCommitteeConfig, SudoConfig, + IndicesConfig, StakerStatus, WASM_BINARY, ClaimsConfig, ParachainsConfig, RegistrarConfig }; use polkadot_runtime::constants::currency::DOTS; use sr_primitives::{traits::IdentifyAccount, Perbill}; @@ -30,6 +30,7 @@ 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 STAGING_TELEMETRY_URL: &str = "wss://telemetry.polkadot.io/submit/"; @@ -46,9 +47,10 @@ fn session_keys( babe: BabeId, grandpa: GrandpaId, im_online: ImOnlineId, - parachain_validator: ValidatorId + parachain_validator: ValidatorId, + authority_discovery: AuthorityDiscoveryId ) -> SessionKeys { - SessionKeys { babe, grandpa, im_online, parachain_validator } + SessionKeys { babe, grandpa, im_online, parachain_validator, authority_discovery } } fn staging_testnet_config_genesis() -> GenesisConfig { @@ -62,13 +64,14 @@ fn staging_testnet_config_genesis() -> GenesisConfig { // 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)> = vec![( + let initial_authorities: Vec<(AccountId, AccountId, BabeId, GrandpaId, ImOnlineId, ValidatorId, AuthorityDiscoveryId)> = vec![( hex!["32a5718e87d16071756d4b1370c411bbbb947eb62f0e6e0b937d5cbfc0ea633b"].into(), // 5DD7Q4VEfPTLEdn11CnThoHT5f9xKCrnofWJL5SsvpTghaAT hex!["bee39fe862c85c91aaf343e130d30b643c6ea0b4406a980206f1df8331f7093b"].into(), // 5GNzaEqhrZAtUQhbMe2gn9jBuNWfamWFZHULryFwBUXyd1cG hex!["a639b507ee1585e0b6498ff141d6153960794523226866d1b44eba3f25f36356"].unchecked_into(), // 5FpewyS2VY8Cj3tKgSckq8ECkjd1HKHvBRnWhiHqRQsWfFC1 hex!["76620f7c98bce8619979c2b58cf2b0aff71824126d2b039358729dad993223db"].unchecked_into(), // 5EjvdwATjyFFikdZibVvx1q5uBHhphS2Mnsq5c7yfaYK25vm hex!["a639b507ee1585e0b6498ff141d6153960794523226866d1b44eba3f25f36356"].unchecked_into(), // 5FpewyS2VY8Cj3tKgSckq8ECkjd1HKHvBRnWhiHqRQsWfFC1 hex!["a639b507ee1585e0b6498ff141d6153960794523226866d1b44eba3f25f36356"].unchecked_into(), // 5FpewyS2VY8Cj3tKgSckq8ECkjd1HKHvBRnWhiHqRQsWfFC1 + hex!["a639b507ee1585e0b6498ff141d6153960794523226866d1b44eba3f25f36356"].unchecked_into(), // 5FpewyS2VY8Cj3tKgSckq8ECkjd1HKHvBRnWhiHqRQsWfFC1 ),( hex!["b496c98a405ceab59b9e970e59ef61acd7765a19b704e02ab06c1cdfe171e40f"].into(), // 5G9VGb8ESBeS8Ca4or43RfhShzk9y7T5iTmxHk5RJsjZwsRx hex!["86d3a7571dd60139d297e55d8238d0c977b2e208c5af088f7f0136b565b0c103"].into(), // 5F7V9Y5FcxKXe1aroqvPeRiUmmeQwTFcL3u9rrPXcMuMiCNx @@ -76,6 +79,7 @@ fn staging_testnet_config_genesis() -> GenesisConfig { hex!["e2234d661bee4a04c38392c75d1566200aa9e6ae44dd98ee8765e4cc9af63cb7"].unchecked_into(), // 5HBDAaybNqjmY7ww8ZcZZY1L5LHxvpnyfqJwoB7HhR6raTmG hex!["765e46067adac4d1fe6c783aa2070dfa64a19f84376659e12705d1734b3eae01"].unchecked_into(), // 5GvuM53k1Z4nAB5zXJFgkRSHv4Bqo4BsvgbQWNWkiWZTMwWY hex!["765e46067adac4d1fe6c783aa2070dfa64a19f84376659e12705d1734b3eae01"].unchecked_into(), // 5GvuM53k1Z4nAB5zXJFgkRSHv4Bqo4BsvgbQWNWkiWZTMwWY + hex!["765e46067adac4d1fe6c783aa2070dfa64a19f84376659e12705d1734b3eae01"].unchecked_into(), // 5GvuM53k1Z4nAB5zXJFgkRSHv4Bqo4BsvgbQWNWkiWZTMwWY ),( hex!["ae12f70078a22882bf5135d134468f77301927aa67c376e8c55b7ff127ace115"].into(), // 5FzwpgGvk2kk9agow6KsywLYcPzjYc8suKej2bne5G5b9YU3 hex!["7addb914ec8486bbc60643d2647685dcc06373401fa80e09813b630c5831d54b"].into(), // 5EqoZhVC2BcsM4WjvZNidu2muKAbu5THQTBKe3EjvxXkdP7A @@ -83,6 +87,7 @@ fn staging_testnet_config_genesis() -> GenesisConfig { hex!["5b57ed1443c8967f461db1f6eb2ada24794d163a668f1cf9d9ce3235dfad8799"].unchecked_into(), // 5E8ULLQrDAtWhfnVfZmX41Yux86zNAwVJYguWJZVWrJvdhBe hex!["664eae1ca4713dd6abf8c15e6c041820cda3c60df97dc476c2cbf7cb82cb2d2e"].unchecked_into(), // 5CXNq1mSKJT4Sc2CbyBBdANeSkbUvdWvE4czJjKXfBHi9sX5 hex!["664eae1ca4713dd6abf8c15e6c041820cda3c60df97dc476c2cbf7cb82cb2d2e"].unchecked_into(), // 5CXNq1mSKJT4Sc2CbyBBdANeSkbUvdWvE4czJjKXfBHi9sX5 + hex!["664eae1ca4713dd6abf8c15e6c041820cda3c60df97dc476c2cbf7cb82cb2d2e"].unchecked_into(), // 5CXNq1mSKJT4Sc2CbyBBdANeSkbUvdWvE4czJjKXfBHi9sX5 ),( hex!["0867dbb49721126df589db100dda728dc3b475cbf414dad8f72a1d5e84897252"].into(), // 5CFj6Kg9rmVn1vrqpyjau2ztyBzKeVdRKwNPiA3tqhB5HPqq hex!["26ab2b4b2eba2263b1e55ceb48f687bb0018130a88df0712fbdaf6a347d50e2a"].into(), // 5CwQXP6nvWzigFqNhh2jvCaW9zWVzkdveCJY3tz2MhXMjTon @@ -90,6 +95,7 @@ fn staging_testnet_config_genesis() -> GenesisConfig { hex!["e60d23f49e93c1c1f2d7c115957df5bbd7faf5ebf138d1e9d02e8b39a1f63df0"].unchecked_into(), // 5HGLmrZsiTFTPp3QoS1W8w9NxByt8PVq79reqvdxNcQkByqK hex!["2adb17a5cafbddc7c3e00ec45b6951a8b12ce2264235b4def342513a767e5d3d"].unchecked_into(), // 5FCd9Y7RLNyxz5wnCAErfsLbXGG34L2BaZRHzhiJcMUMd5zd hex!["2adb17a5cafbddc7c3e00ec45b6951a8b12ce2264235b4def342513a767e5d3d"].unchecked_into(), // 5FCd9Y7RLNyxz5wnCAErfsLbXGG34L2BaZRHzhiJcMUMd5zd + hex!["2adb17a5cafbddc7c3e00ec45b6951a8b12ce2264235b4def342513a767e5d3d"].unchecked_into(), // 5FCd9Y7RLNyxz5wnCAErfsLbXGG34L2BaZRHzhiJcMUMd5zd )]; const ENDOWMENT: u128 = 1_000_000 * DOTS; @@ -115,7 +121,7 @@ fn staging_testnet_config_genesis() -> GenesisConfig { session: Some(SessionConfig { keys: initial_authorities.iter().map(|x| ( x.0.clone(), - session_keys(x.2.clone(), x.3.clone(), x.4.clone(), x.5.clone()), + session_keys(x.2.clone(), x.3.clone(), x.4.clone(), x.5.clone(), x.6.clone()), )).collect::>(), }), staking: Some(StakingConfig { @@ -141,6 +147,9 @@ fn staging_testnet_config_genesis() -> GenesisConfig { babe: Some(Default::default()), grandpa: Some(Default::default()), im_online: Some(Default::default()), + authority_discovery: Some(AuthorityDiscoveryConfig { + keys: vec![], + }), parachains: Some(ParachainsConfig { authorities: vec![], }), @@ -194,7 +203,8 @@ pub fn get_authority_keys_from_seed(seed: &str) -> ( BabeId, GrandpaId, ImOnlineId, - ValidatorId + ValidatorId, + AuthorityDiscoveryId ) { ( get_account_id_from_seed::(&format!("{}//stash", seed)), @@ -203,12 +213,13 @@ pub fn get_authority_keys_from_seed(seed: &str) -> ( get_from_seed::(seed), get_from_seed::(seed), get_from_seed::(seed), + get_from_seed::(seed), ) } /// Helper function to create GenesisConfig for testing pub fn testnet_genesis( - initial_authorities: Vec<(AccountId, AccountId, BabeId, GrandpaId, ImOnlineId, ValidatorId)>, + initial_authorities: Vec<(AccountId, AccountId, BabeId, GrandpaId, ImOnlineId, ValidatorId, AuthorityDiscoveryId)>, root_key: AccountId, endowed_accounts: Option>, ) -> GenesisConfig { @@ -247,7 +258,7 @@ pub fn testnet_genesis( session: Some(SessionConfig { keys: initial_authorities.iter().map(|x| ( x.0.clone(), - session_keys(x.2.clone(), x.3.clone(), x.4.clone(), x.5.clone()), + session_keys(x.2.clone(), x.3.clone(), x.4.clone(), x.5.clone(), x.6.clone()), )).collect::>(), }), staking: Some(StakingConfig { @@ -275,6 +286,9 @@ pub fn testnet_genesis( babe: Some(Default::default()), grandpa: Some(Default::default()), im_online: Some(Default::default()), + authority_discovery: Some(AuthorityDiscoveryConfig { + keys: vec![], + }), parachains: Some(ParachainsConfig { authorities: vec![], }), diff --git a/service/src/lib.rs b/service/src/lib.rs index 90ec097a3b79..7dda3146698b 100644 --- a/service/src/lib.rs +++ b/service/src/lib.rs @@ -54,6 +54,9 @@ pub struct CustomConfiguration { /// Maximal `block_data` size. pub max_block_data_size: Option, + + /// Whether to enable or disable the authority discovery module. + pub authority_discovery_enabled: bool, } impl Default for CustomConfiguration { @@ -61,6 +64,7 @@ impl Default for CustomConfiguration { Self { collating_for: None, max_block_data_size: None, + authority_discovery_enabled: false, } } } @@ -147,6 +151,11 @@ pub fn new_full(config: Configuration) >, ServiceError> { use substrate_network::DhtEvent; + use futures03::{ + compat::Stream01CompatExt, + stream::StreamExt, + future::{FutureExt, TryFutureExt}, + }; let is_collator = config.custom.collating_for.is_some(); let is_authority = config.roles.is_authority() && !is_collator; @@ -159,6 +168,7 @@ pub fn new_full(config: Configuration) }; let disable_grandpa = config.disable_grandpa; let name = config.name.clone(); + let authority_discovery_enabled = config.custom.authority_discovery_enabled; // sentry nodes announce themselves as authorities to the network // and should run the same protocols authorities do, but it should @@ -172,7 +182,7 @@ pub fn new_full(config: Configuration) // event per authority within the current authority set. This estimates the // authority set size to be somewhere below 10 000 thereby setting the channel // buffer size to 10 000. - let (dht_event_tx, _dht_event_rx) = mpsc::channel::(10000); + let (dht_event_tx, dht_event_rx) = mpsc::channel::(10000); let service = builder .with_network_protocol(|config| Ok(PolkadotProtocol::new(config.custom.collating_for.clone())))? @@ -277,6 +287,21 @@ pub fn new_full(config: Configuration) let babe = babe::start_babe(babe_config)?; service.spawn_essential_task(babe); + + if authority_discovery_enabled { + let future03_dht_event_rx = dht_event_rx.compat() + .map(|x| x.expect(" never returns an error; qed")) + .boxed(); + let authority_discovery = authority_discovery::AuthorityDiscovery::new( + service.client(), + service.network(), + service.keystore(), + future03_dht_event_rx, + ); + let future01_authority_discovery = authority_discovery.map(|x| Ok(x)).compat(); + + service.spawn_task(future01_authority_discovery); + } } // if the node isn't actively participating in consensus then it doesn't