diff --git a/bin/node-template/node/src/service.rs b/bin/node-template/node/src/service.rs index 8269017072cb3..e90c833c9c4a5 100644 --- a/bin/node-template/node/src/service.rs +++ b/bin/node-template/node/src/service.rs @@ -141,6 +141,7 @@ pub fn new_full(config: Configuration) justification_period: 512, name: Some(name), observer_enabled: false, + favorite_peers: Default::default(), keystore, is_authority, }; diff --git a/bin/node/cli/src/service.rs b/bin/node/cli/src/service.rs index 452b1fa3e62db..bb02b19309edc 100644 --- a/bin/node/cli/src/service.rs +++ b/bin/node/cli/src/service.rs @@ -125,12 +125,14 @@ macro_rules! new_full { name, disable_grandpa, sentry_nodes, + reserved_nodes, ) = ( $config.roles.is_authority(), $config.force_authoring, $config.name.clone(), $config.disable_grandpa, $config.network.sentry_nodes.clone(), + $config.network.reserved_nodes.clone(), ); // sentry nodes announce themselves as authorities to the network @@ -190,7 +192,7 @@ macro_rules! new_full { let authority_discovery = sc_authority_discovery::AuthorityDiscovery::new( service.client(), network, - sentry_nodes, + sentry_nodes.clone(), service.keystore(), dht_event_stream, service.prometheus_registry(), @@ -207,12 +209,21 @@ macro_rules! new_full { None }; + // add reserved and sentry nodes as favorite peers to GRANDPA + let favorite_peers = reserved_nodes + .into_iter() + .chain(sentry_nodes.into_iter()) + .filter_map(|n| sc_network::config::parse_str_addr(&n).ok()) + .map(|(peer_id, _)| peer_id) + .collect(); + let config = grandpa::Config { // FIXME #1578 make this available through chainspec gossip_duration: std::time::Duration::from_millis(333), justification_period: 512, name: Some(name), observer_enabled: false, + favorite_peers, keystore, is_authority, }; diff --git a/client/finality-grandpa/src/communication/gossip.rs b/client/finality-grandpa/src/communication/gossip.rs index 6b245a4652a5f..db2896af89a11 100644 --- a/client/finality-grandpa/src/communication/gossip.rs +++ b/client/finality-grandpa/src/communication/gossip.rs @@ -1110,6 +1110,9 @@ impl Inner { let round_duration = self.config.gossip_duration * ROUND_DURATION; let round_elapsed = self.round_start.elapsed(); + if self.config.favorite_peers.contains(who) { + return true; + } if !self.config.is_authority && round_elapsed < round_duration * PROPAGATION_ALL @@ -1170,6 +1173,10 @@ impl Inner { let round_duration = self.config.gossip_duration * ROUND_DURATION; let round_elapsed = self.round_start.elapsed(); + if self.config.favorite_peers.contains(who) { + return true; + } + if peer.roles.is_authority() { let authorities = self.peers.authorities(); diff --git a/client/finality-grandpa/src/lib.rs b/client/finality-grandpa/src/lib.rs index d8e5846a56c1e..48cd92bdb986c 100644 --- a/client/finality-grandpa/src/lib.rs +++ b/client/finality-grandpa/src/lib.rs @@ -52,6 +52,8 @@ //! or prune any signaled changes based on whether the signaling block is //! included in the newly-finalized chain. +use std::collections::HashSet; + use futures::prelude::*; use futures::StreamExt; use log::{debug, info}; @@ -204,6 +206,10 @@ pub struct Config { pub is_authority: bool, /// Some local identifier of the voter. pub name: Option, + /// The set of favorite peers which we should treat preferably when gossiping messages + /// (i.e. we prioritize sending any data to them over other peers). The favorite peers + /// are usually reserved nodes and/or sentry nodes. + pub favorite_peers: HashSet, /// The keystore that manages the keys of this node. pub keystore: Option, } diff --git a/client/network/src/service.rs b/client/network/src/service.rs index 2c93d70e268bc..1851d18635da3 100644 --- a/client/network/src/service.rs +++ b/client/network/src/service.rs @@ -205,15 +205,30 @@ impl NetworkWorker { )?; // Initialize the reserved peers. - for reserved in params.network_config.reserved_nodes.iter() { - if let Ok((peer_id, addr)) = parse_str_addr(reserved) { + let mut add_reserved = |node| { + if let Ok((peer_id, addr)) = parse_str_addr(node) { reserved_nodes.push(peer_id.clone()); known_addresses.push((peer_id, addr)); - } else { + return true; + } + + false + }; + + for reserved in params.network_config.reserved_nodes.iter() { + if !add_reserved(reserved) { warn!(target: "sub-libp2p", "Not a valid reserved node address: {}", reserved); } } + // treat sentry nodes as reserved for the peerset, we always want to maintain connections to + // our sentries. + for sentry in params.network_config.sentry_nodes.iter() { + if !add_reserved(sentry) { + warn!(target: "sub-libp2p", "Not a valid sentry node address: {}", sentry); + } + } + let peerset_config = sc_peerset::PeersetConfig { in_peers: params.network_config.in_peers, out_peers: params.network_config.out_peers,