Split the Roles in three types (#5520)

* Split the Roles bitfield in three

* Forgot to include some changes

* Fix cli test

* More test fixes

* Oh God, merging master broke other tests

* Didn't run the doctests

* Address review

* I'm trying to fix the build blindly because it's taking a good hour to compile on my machine

* Address some review

* Also update the peerset's API to make sense

* Fix peerset tests

* Fix browser node

* client: distinguish between local and network authority

Co-authored-by: André Silva <andre.beat@gmail.com>
This commit is contained in:
Pierre Krieger
2020-04-03 19:08:14 +02:00
committed by GitHub
parent 9dbcb11f66
commit 8c03a4fcef
44 changed files with 591 additions and 432 deletions
@@ -72,16 +72,11 @@ macro_rules! new_full_start {
pub fn new_full(config: Configuration) pub fn new_full(config: Configuration)
-> Result<impl AbstractService, ServiceError> -> Result<impl AbstractService, ServiceError>
{ {
let is_authority = config.roles.is_authority(); let role = config.role.clone();
let force_authoring = config.force_authoring; let force_authoring = config.force_authoring;
let name = config.name.clone(); let name = config.name.clone();
let disable_grandpa = config.disable_grandpa; let disable_grandpa = config.disable_grandpa;
// sentry nodes announce themselves as authorities to the network
// and should run the same protocols authorities do, but it should
// never actively participate in any consensus process.
let participates_in_consensus = is_authority && !config.sentry_mode;
let (builder, mut import_setup, inherent_data_providers) = new_full_start!(config); let (builder, mut import_setup, inherent_data_providers) = new_full_start!(config);
let (block_import, grandpa_link) = let (block_import, grandpa_link) =
@@ -96,11 +91,9 @@ pub fn new_full(config: Configuration)
})? })?
.build()?; .build()?;
if participates_in_consensus { if role.is_authority() {
let proposer = sc_basic_authorship::ProposerFactory::new( let proposer =
service.client(), sc_basic_authorship::ProposerFactory::new(service.client(), service.transaction_pool());
service.transaction_pool()
);
let client = service.client(); let client = service.client();
let select_chain = service.select_chain() let select_chain = service.select_chain()
@@ -129,7 +122,7 @@ pub fn new_full(config: Configuration)
// if the node isn't actively participating in consensus then it doesn't // if the node isn't actively participating in consensus then it doesn't
// need a keystore, regardless of which protocol we use below. // need a keystore, regardless of which protocol we use below.
let keystore = if participates_in_consensus { let keystore = if role.is_authority() {
Some(service.keystore()) Some(service.keystore())
} else { } else {
None None
@@ -142,7 +135,7 @@ pub fn new_full(config: Configuration)
name: Some(name), name: Some(name),
observer_enabled: false, observer_enabled: false,
keystore, keystore,
is_authority, is_authority: role.is_network_authority(),
}; };
let enable_grandpa = !disable_grandpa; let enable_grandpa = !disable_grandpa;
+1 -1
View File
@@ -45,7 +45,7 @@ async fn start_inner(chain_spec: String, log_level: String) -> Result<Client, Bo
info!("❤️ by Parity Technologies, 2017-2020"); info!("❤️ by Parity Technologies, 2017-2020");
info!("📋 Chain specification: {}", config.expect_chain_spec().name()); info!("📋 Chain specification: {}", config.expect_chain_spec().name());
info!("🏷 Node name: {}", config.name); info!("🏷 Node name: {}", config.name);
info!("👤 Roles: {:?}", config.roles); info!("👤 Role: {:?}", config.role);
// Create the service. This is the most heavy initialization step. // Create the service. This is the most heavy initialization step.
let service = crate::service::new_light(config) let service = crate::service::new_light(config)
+2 -2
View File
@@ -15,7 +15,7 @@
// along with Substrate. If not, see <http://www.gnu.org/licenses/>. // along with Substrate. If not, see <http://www.gnu.org/licenses/>.
use sc_cli::VersionInfo; use sc_cli::VersionInfo;
use sc_service::{Roles as ServiceRoles}; use sc_service::{Role as ServiceRole};
use node_transaction_factory::RuntimeAdapter; use node_transaction_factory::RuntimeAdapter;
use crate::{Cli, service, ChainSpec, load_spec, Subcommand, factory_impl::FactoryState}; use crate::{Cli, service, ChainSpec, load_spec, Subcommand, factory_impl::FactoryState};
@@ -65,7 +65,7 @@ where
cli_args.shared_params.update_config(&mut config, load_spec, &version)?; cli_args.shared_params.update_config(&mut config, load_spec, &version)?;
cli_args.import_params.update_config( cli_args.import_params.update_config(
&mut config, &mut config,
ServiceRoles::FULL, &ServiceRole::Full,
cli_args.shared_params.dev, cli_args.shared_params.dev,
)?; )?;
+6 -13
View File
@@ -120,24 +120,17 @@ macro_rules! new_full {
use sc_client_api::ExecutorProvider; use sc_client_api::ExecutorProvider;
let ( let (
is_authority, role,
force_authoring, force_authoring,
name, name,
disable_grandpa, disable_grandpa,
sentry_nodes,
) = ( ) = (
$config.roles.is_authority(), $config.role.clone(),
$config.force_authoring, $config.force_authoring,
$config.name.clone(), $config.name.clone(),
$config.disable_grandpa, $config.disable_grandpa,
$config.network.sentry_nodes.clone(),
); );
// sentry nodes announce themselves as authorities to the network
// and should run the same protocols authorities do, but it should
// never actively participate in any consensus process.
let participates_in_consensus = is_authority && !$config.sentry_mode;
let (builder, mut import_setup, inherent_data_providers) = new_full_start!($config); let (builder, mut import_setup, inherent_data_providers) = new_full_start!($config);
let service = builder let service = builder
@@ -153,7 +146,7 @@ macro_rules! new_full {
($with_startup_data)(&block_import, &babe_link); ($with_startup_data)(&block_import, &babe_link);
if participates_in_consensus { if let sc_service::config::Role::Authority { sentry_nodes } = &role {
let proposer = sc_basic_authorship::ProposerFactory::new( let proposer = sc_basic_authorship::ProposerFactory::new(
service.client(), service.client(),
service.transaction_pool() service.transaction_pool()
@@ -190,7 +183,7 @@ macro_rules! new_full {
let authority_discovery = sc_authority_discovery::AuthorityDiscovery::new( let authority_discovery = sc_authority_discovery::AuthorityDiscovery::new(
service.client(), service.client(),
network, network,
sentry_nodes, sentry_nodes.clone(),
service.keystore(), service.keystore(),
dht_event_stream, dht_event_stream,
service.prometheus_registry(), service.prometheus_registry(),
@@ -201,7 +194,7 @@ macro_rules! new_full {
// if the node isn't actively participating in consensus then it doesn't // if the node isn't actively participating in consensus then it doesn't
// need a keystore, regardless of which protocol we use below. // need a keystore, regardless of which protocol we use below.
let keystore = if participates_in_consensus { let keystore = if role.is_authority() {
Some(service.keystore()) Some(service.keystore())
} else { } else {
None None
@@ -214,7 +207,7 @@ macro_rules! new_full {
name: Some(name), name: Some(name),
observer_enabled: false, observer_enabled: false,
keystore, keystore,
is_authority, is_authority: role.is_network_authority(),
}; };
let enable_grandpa = !disable_grandpa; let enable_grandpa = !disable_grandpa;
+1 -1
View File
@@ -45,7 +45,7 @@ impl InspectCmd {
// and all import params (especially pruning that has to match db meta) // and all import params (especially pruning that has to match db meta)
self.import_params.update_config( self.import_params.update_config(
&mut config, &mut config,
sc_service::Roles::FULL, &sc_service::Role::Full,
self.shared_params.dev, self.shared_params.dev,
)?; )?;
@@ -56,12 +56,11 @@ use futures_timer::Delay;
use codec::{Decode, Encode}; use codec::{Decode, Encode};
use error::{Error, Result}; use error::{Error, Result};
use libp2p::Multiaddr;
use log::{debug, error, log_enabled, warn}; use log::{debug, error, log_enabled, warn};
use prometheus_endpoint::{Counter, CounterVec, Gauge, Opts, U64, register}; use prometheus_endpoint::{Counter, CounterVec, Gauge, Opts, U64, register};
use prost::Message; use prost::Message;
use sc_client_api::blockchain::HeaderBackend; use sc_client_api::blockchain::HeaderBackend;
use sc_network::{DhtEvent, ExHashT, NetworkStateInfo}; use sc_network::{Multiaddr, config::MultiaddrWithPeerId, DhtEvent, ExHashT, NetworkStateInfo};
use sp_authority_discovery::{AuthorityDiscoveryApi, AuthorityId, AuthoritySignature, AuthorityPair}; use sp_authority_discovery::{AuthorityDiscoveryApi, AuthorityId, AuthoritySignature, AuthorityPair};
use sp_core::crypto::{key_types, CryptoTypePublicPair, Pair}; use sp_core::crypto::{key_types, CryptoTypePublicPair, Pair};
use sp_core::traits::BareCryptoStorePtr; use sp_core::traits::BareCryptoStorePtr;
@@ -187,7 +186,7 @@ where
pub fn new( pub fn new(
client: Arc<Client>, client: Arc<Client>,
network: Arc<Network>, network: Arc<Network>,
sentry_nodes: Vec<String>, sentry_nodes: Vec<MultiaddrWithPeerId>,
key_store: BareCryptoStorePtr, key_store: BareCryptoStorePtr,
dht_event_rx: Pin<Box<dyn Stream<Item = DhtEvent> + Send>>, dht_event_rx: Pin<Box<dyn Stream<Item = DhtEvent> + Send>>,
prometheus_registry: Option<prometheus_endpoint::Registry>, prometheus_registry: Option<prometheus_endpoint::Registry>,
@@ -210,18 +209,7 @@ where
); );
let sentry_nodes = if !sentry_nodes.is_empty() { let sentry_nodes = if !sentry_nodes.is_empty() {
let addrs = sentry_nodes.into_iter().filter_map(|a| match a.parse() { Some(sentry_nodes.into_iter().map(|ma| ma.concat()).collect::<Vec<_>>())
Ok(addr) => Some(addr),
Err(e) => {
error!(
target: "sub-authority-discovery",
"Failed to parse sentry node public address '{:?}', continuing anyways.", e,
);
None
}
}).collect::<Vec<Multiaddr>>();
Some(addrs)
} else { } else {
None None
}; };
@@ -27,7 +27,7 @@ use sp_runtime::BuildStorage;
use serde_json as json; use serde_json as json;
use crate::RuntimeGenesis; use crate::RuntimeGenesis;
use crate::extension::GetExtension; use crate::extension::GetExtension;
use sc_network::Multiaddr; use sc_network::config::MultiaddrWithPeerId;
use sc_telemetry::TelemetryEndpoints; use sc_telemetry::TelemetryEndpoints;
enum GenesisSource<G> { enum GenesisSource<G> {
@@ -137,7 +137,7 @@ enum Genesis<G> {
struct ClientSpec<E> { struct ClientSpec<E> {
name: String, name: String,
id: String, id: String,
boot_nodes: Vec<String>, boot_nodes: Vec<MultiaddrWithPeerId>,
telemetry_endpoints: Option<TelemetryEndpoints>, telemetry_endpoints: Option<TelemetryEndpoints>,
protocol_id: Option<String>, protocol_id: Option<String>,
properties: Option<Properties>, properties: Option<Properties>,
@@ -174,7 +174,7 @@ impl<G, E: Clone> Clone for ChainSpec<G, E> {
impl<G, E> ChainSpec<G, E> { impl<G, E> ChainSpec<G, E> {
/// A list of bootnode addresses. /// A list of bootnode addresses.
pub fn boot_nodes(&self) -> &[String] { pub fn boot_nodes(&self) -> &[MultiaddrWithPeerId] {
&self.client_spec.boot_nodes &self.client_spec.boot_nodes
} }
@@ -206,8 +206,8 @@ impl<G, E> ChainSpec<G, E> {
} }
/// Add a bootnode to the list. /// Add a bootnode to the list.
pub fn add_boot_node(&mut self, addr: Multiaddr) { pub fn add_boot_node(&mut self, addr: MultiaddrWithPeerId) {
self.client_spec.boot_nodes.push(addr.to_string()) self.client_spec.boot_nodes.push(addr)
} }
/// Returns a reference to defined chain spec extensions. /// Returns a reference to defined chain spec extensions.
@@ -220,7 +220,7 @@ impl<G, E> ChainSpec<G, E> {
name: &str, name: &str,
id: &str, id: &str,
constructor: F, constructor: F,
boot_nodes: Vec<String>, boot_nodes: Vec<MultiaddrWithPeerId>,
telemetry_endpoints: Option<TelemetryEndpoints>, telemetry_endpoints: Option<TelemetryEndpoints>,
protocol_id: Option<&str>, protocol_id: Option<&str>,
properties: Option<Properties>, properties: Option<Properties>,
@@ -320,7 +320,7 @@ where
G: RuntimeGenesis, G: RuntimeGenesis,
E: GetExtension + serde::Serialize + Clone + Send, E: GetExtension + serde::Serialize + Clone + Send,
{ {
fn boot_nodes(&self) -> &[String] { fn boot_nodes(&self) -> &[MultiaddrWithPeerId] {
ChainSpec::boot_nodes(self) ChainSpec::boot_nodes(self)
} }
@@ -344,7 +344,7 @@ where
ChainSpec::properties(self) ChainSpec::properties(self)
} }
fn add_boot_node(&mut self, addr: Multiaddr) { fn add_boot_node(&mut self, addr: MultiaddrWithPeerId) {
ChainSpec::add_boot_node(self, addr) ChainSpec::add_boot_node(self, addr)
} }
+3 -3
View File
@@ -117,7 +117,7 @@ pub use sc_chain_spec_derive::{ChainSpecExtension, ChainSpecGroup};
use serde::{Serialize, de::DeserializeOwned}; use serde::{Serialize, de::DeserializeOwned};
use sp_runtime::BuildStorage; use sp_runtime::BuildStorage;
use sc_network::Multiaddr; use sc_network::config::MultiaddrWithPeerId;
use sc_telemetry::TelemetryEndpoints; use sc_telemetry::TelemetryEndpoints;
/// A set of traits for the runtime genesis config. /// A set of traits for the runtime genesis config.
@@ -131,7 +131,7 @@ pub trait ChainSpec: BuildStorage + Send {
/// Spec id. /// Spec id.
fn id(&self) -> &str; fn id(&self) -> &str;
/// A list of bootnode addresses. /// A list of bootnode addresses.
fn boot_nodes(&self) -> &[String]; fn boot_nodes(&self) -> &[MultiaddrWithPeerId];
/// Telemetry endpoints (if any) /// Telemetry endpoints (if any)
fn telemetry_endpoints(&self) -> &Option<TelemetryEndpoints>; fn telemetry_endpoints(&self) -> &Option<TelemetryEndpoints>;
/// Network protocol id. /// Network protocol id.
@@ -143,7 +143,7 @@ pub trait ChainSpec: BuildStorage + Send {
/// Returns a reference to defined chain spec extensions. /// Returns a reference to defined chain spec extensions.
fn extensions(&self) -> &dyn GetExtension; fn extensions(&self) -> &dyn GetExtension;
/// Add a bootnode to the list. /// Add a bootnode to the list.
fn add_boot_node(&mut self, addr: Multiaddr); fn add_boot_node(&mut self, addr: MultiaddrWithPeerId);
/// Return spec as JSON. /// Return spec as JSON.
fn as_json(&self, raw: bool) -> Result<String, String>; fn as_json(&self, raw: bool) -> Result<String, String>;
/// Return StorageBuilder for this spec. /// Return StorageBuilder for this spec.
@@ -16,7 +16,7 @@
use structopt::StructOpt; use structopt::StructOpt;
use log::info; use log::info;
use sc_network::config::build_multiaddr; use sc_network::config::{build_multiaddr, MultiaddrWithPeerId};
use sc_service::{Configuration, ChainSpec}; use sc_service::{Configuration, ChainSpec};
use crate::error; use crate::error;
@@ -60,11 +60,10 @@ impl BuildSpecCmd {
if spec.boot_nodes().is_empty() && !self.disable_default_bootnode { if spec.boot_nodes().is_empty() && !self.disable_default_bootnode {
let keys = config.network.node_key.into_keypair()?; let keys = config.network.node_key.into_keypair()?;
let peer_id = keys.public().into_peer_id(); let peer_id = keys.public().into_peer_id();
let addr = build_multiaddr![ let addr = MultiaddrWithPeerId {
Ip4([127, 0, 0, 1]), multiaddr: build_multiaddr![Ip4([127, 0, 0, 1]), Tcp(30333u16)],
Tcp(30333u16), peer_id,
P2p(peer_id) };
];
spec.add_boot_node(addr) spec.add_boot_node(addr)
} }
@@ -18,7 +18,7 @@ use std::fmt::Debug;
use std::str::FromStr; use std::str::FromStr;
use structopt::StructOpt; use structopt::StructOpt;
use sc_service::{ use sc_service::{
Configuration, ServiceBuilderCommand, Roles, ChainSpec, Configuration, ServiceBuilderCommand, Role, ChainSpec,
}; };
use sp_runtime::traits::{Block as BlockT, Header as HeaderT}; use sp_runtime::traits::{Block as BlockT, Header as HeaderT};
use sp_runtime::generic::BlockId; use sp_runtime::generic::BlockId;
@@ -93,7 +93,7 @@ impl CheckBlockCmd {
F: FnOnce(&str) -> Result<Box<dyn ChainSpec>, String>, F: FnOnce(&str) -> Result<Box<dyn ChainSpec>, String>,
{ {
self.shared_params.update_config(&mut config, spec_factory, version)?; self.shared_params.update_config(&mut config, spec_factory, version)?;
self.import_params.update_config(&mut config, Roles::FULL, self.shared_params.dev)?; self.import_params.update_config(&mut config, &Role::Full, self.shared_params.dev)?;
config.use_in_memory_keystore()?; config.use_in_memory_keystore()?;
Ok(()) Ok(())
@@ -22,7 +22,7 @@ use log::info;
use structopt::StructOpt; use structopt::StructOpt;
use sc_service::{ use sc_service::{
Configuration, ServiceBuilderCommand, ChainSpec, Configuration, ServiceBuilderCommand, ChainSpec,
config::DatabaseConfig, Roles, config::DatabaseConfig, Role,
}; };
use sp_runtime::traits::{Block as BlockT, Header as HeaderT}; use sp_runtime::traits::{Block as BlockT, Header as HeaderT};
@@ -105,7 +105,7 @@ impl ExportBlocksCmd {
F: FnOnce(&str) -> Result<Box<dyn ChainSpec>, String>, F: FnOnce(&str) -> Result<Box<dyn ChainSpec>, String>,
{ {
self.shared_params.update_config(&mut config, spec_factory, version)?; self.shared_params.update_config(&mut config, spec_factory, version)?;
self.pruning_params.update_config(&mut config, Roles::FULL, true)?; self.pruning_params.update_config(&mut config, &Role::Full, true)?;
config.use_in_memory_keystore()?; config.use_in_memory_keystore()?;
Ok(()) Ok(())
@@ -20,7 +20,7 @@ use std::fs;
use std::path::PathBuf; use std::path::PathBuf;
use structopt::StructOpt; use structopt::StructOpt;
use sc_service::{ use sc_service::{
Configuration, ServiceBuilderCommand, ChainSpec, Roles, Configuration, ServiceBuilderCommand, ChainSpec, Role,
}; };
use sp_runtime::traits::{Block as BlockT, Header as HeaderT}; use sp_runtime::traits::{Block as BlockT, Header as HeaderT};
@@ -95,7 +95,7 @@ impl ImportBlocksCmd {
F: FnOnce(&str) -> Result<Box<dyn ChainSpec>, String>, F: FnOnce(&str) -> Result<Box<dyn ChainSpec>, String>,
{ {
self.shared_params.update_config(&mut config, spec_factory, version)?; self.shared_params.update_config(&mut config, spec_factory, version)?;
self.import_params.update_config(&mut config, Roles::FULL, self.shared_params.dev)?; self.import_params.update_config(&mut config, &Role::Full, self.shared_params.dev)?;
config.use_in_memory_keystore()?; config.use_in_memory_keystore()?;
Ok(()) Ok(())
@@ -17,7 +17,7 @@
use std::fmt::Debug; use std::fmt::Debug;
use structopt::StructOpt; use structopt::StructOpt;
use sc_service::{ use sc_service::{
Configuration, ServiceBuilderCommand, ChainSpec, Roles, Configuration, ServiceBuilderCommand, ChainSpec, Role,
}; };
use sp_runtime::traits::{Block as BlockT, Header as HeaderT}; use sp_runtime::traits::{Block as BlockT, Header as HeaderT};
@@ -71,7 +71,7 @@ impl RevertCmd {
F: FnOnce(&str) -> Result<Box<dyn ChainSpec>, String>, F: FnOnce(&str) -> Result<Box<dyn ChainSpec>, String>,
{ {
self.shared_params.update_config(&mut config, spec_factory, version)?; self.shared_params.update_config(&mut config, spec_factory, version)?;
self.pruning_params.update_config(&mut config, Roles::FULL, true)?; self.pruning_params.update_config(&mut config, &Role::Full, true)?;
config.use_in_memory_keystore()?; config.use_in_memory_keystore()?;
Ok(()) Ok(())
+19 -19
View File
@@ -23,8 +23,8 @@ use names::{Generator, Name};
use regex::Regex; use regex::Regex;
use chrono::prelude::*; use chrono::prelude::*;
use sc_service::{ use sc_service::{
AbstractService, Configuration, ChainSpec, Roles, AbstractService, Configuration, ChainSpec, Role,
config::{KeystoreConfig, PrometheusConfig}, config::{MultiaddrWithPeerId, KeystoreConfig, PrometheusConfig},
}; };
use sc_telemetry::TelemetryEndpoints; use sc_telemetry::TelemetryEndpoints;
@@ -78,9 +78,10 @@ pub struct RunCmd {
/// available to relay to private nodes. /// available to relay to private nodes.
#[structopt( #[structopt(
long = "sentry", long = "sentry",
conflicts_with_all = &[ "validator", "light" ] conflicts_with_all = &[ "validator", "light" ],
parse(try_from_str)
)] )]
pub sentry: bool, pub sentry: Vec<MultiaddrWithPeerId>,
/// Disable GRANDPA voter when running in validator mode, otherwise disable the GRANDPA observer. /// Disable GRANDPA voter when running in validator mode, otherwise disable the GRANDPA observer.
#[structopt(long = "no-grandpa")] #[structopt(long = "no-grandpa")]
@@ -329,18 +330,20 @@ impl RunCmd {
let keyring = self.get_keyring(); let keyring = self.get_keyring();
let is_dev = self.shared_params.dev; let is_dev = self.shared_params.dev;
let is_light = self.light; let is_light = self.light;
let is_authority = (self.validator || self.sentry || is_dev || keyring.is_some()) let is_authority = (self.validator || is_dev || keyring.is_some())
&& !is_light; && !is_light;
let role = let role =
if is_light { if is_light {
sc_service::Roles::LIGHT sc_service::Role::Light
} else if is_authority { } else if is_authority {
sc_service::Roles::AUTHORITY sc_service::Role::Authority { sentry_nodes: self.network_config.sentry_nodes.clone() }
} else if !self.sentry.is_empty() {
sc_service::Role::Sentry { validators: self.sentry.clone() }
} else { } else {
sc_service::Roles::FULL sc_service::Role::Full
}; };
self.import_params.update_config(&mut config, role, is_dev)?; self.import_params.update_config(&mut config, &role, is_dev)?;
config.name = match (self.name.as_ref(), keyring) { config.name = match (self.name.as_ref(), keyring) {
(Some(name), _) => name.to_string(), (Some(name), _) => name.to_string(),
@@ -356,17 +359,14 @@ impl RunCmd {
)); ));
} }
// set sentry mode (i.e. act as an authority but **never** actively participate) config.offchain_worker = match (&self.offchain_worker, &role) {
config.sentry_mode = self.sentry; (OffchainWorkerEnabled::WhenValidating, sc_service::Role::Authority { .. }) => true,
config.offchain_worker = match (&self.offchain_worker, role) {
(OffchainWorkerEnabled::WhenValidating, sc_service::Roles::AUTHORITY) => true,
(OffchainWorkerEnabled::Always, _) => true, (OffchainWorkerEnabled::Always, _) => true,
(OffchainWorkerEnabled::Never, _) => false, (OffchainWorkerEnabled::Never, _) => false,
(OffchainWorkerEnabled::WhenValidating, _) => false, (OffchainWorkerEnabled::WhenValidating, _) => false,
}; };
config.roles = role; config.role = role;
config.disable_grandpa = self.no_grandpa; config.disable_grandpa = self.no_grandpa;
let client_id = config.client_id(); let client_id = config.client_id();
@@ -463,10 +463,10 @@ impl RunCmd {
info!("❤️ by {}, {}-{}", version.author, version.copyright_start_year, Local::today().year()); info!("❤️ by {}, {}-{}", version.author, version.copyright_start_year, Local::today().year());
info!("📋 Chain specification: {}", config.expect_chain_spec().name()); info!("📋 Chain specification: {}", config.expect_chain_spec().name());
info!("🏷 Node name: {}", config.name); info!("🏷 Node name: {}", config.name);
info!("👤 Roles: {}", config.display_role()); info!("👤 Role: {}", config.display_role());
match config.roles { match config.role {
Roles::LIGHT => run_service_until_exit( Role::Light => run_service_until_exit(
config, config,
new_light, new_light,
), ),
@@ -688,7 +688,7 @@ mod tests {
"test", "test",
"test-id", "test-id",
|| (), || (),
vec!["boo".to_string()], vec!["/ip4/127.0.0.1/tcp/30333/p2p/QmdSHZLmwEL5Axz5JvWNE2mmxU7qyd7xHBFpyUfktgAdg7".parse().unwrap()],
Some(TelemetryEndpoints::new(vec![("wss://foo/bar".to_string(), 42)]) Some(TelemetryEndpoints::new(vec![("wss://foo/bar".to_string(), 42)])
.expect("provided url should be valid")), .expect("provided url should be valid")),
None, None,
@@ -82,7 +82,7 @@ impl ImportParams {
pub fn update_config( pub fn update_config(
&self, &self,
mut config: &mut Configuration, mut config: &mut Configuration,
role: sc_service::Roles, role: &sc_service::Role,
is_dev: bool, is_dev: bool,
) -> error::Result<()> { ) -> error::Result<()> {
use sc_client_api::execution_extensions::ExecutionStrategies; use sc_client_api::execution_extensions::ExecutionStrategies;
@@ -19,7 +19,7 @@ use std::iter;
use std::net::Ipv4Addr; use std::net::Ipv4Addr;
use structopt::StructOpt; use structopt::StructOpt;
use sc_network::{ use sc_network::{
config::{NonReservedPeerMode, TransportConfig}, multiaddr::Protocol, config::{MultiaddrWithPeerId, NonReservedPeerMode, TransportConfig}, multiaddr::Protocol, Multiaddr,
}; };
use sc_service::Configuration; use sc_service::Configuration;
@@ -30,12 +30,12 @@ use crate::params::node_key_params::NodeKeyParams;
#[derive(Debug, StructOpt, Clone)] #[derive(Debug, StructOpt, Clone)]
pub struct NetworkConfigurationParams { pub struct NetworkConfigurationParams {
/// Specify a list of bootnodes. /// Specify a list of bootnodes.
#[structopt(long = "bootnodes", value_name = "URL")] #[structopt(long = "bootnodes", value_name = "ADDR")]
pub bootnodes: Vec<String>, pub bootnodes: Vec<MultiaddrWithPeerId>,
/// Specify a list of reserved node addresses. /// Specify a list of reserved node addresses.
#[structopt(long = "reserved-nodes", value_name = "URL")] #[structopt(long = "reserved-nodes", value_name = "ADDR")]
pub reserved_nodes: Vec<String>, pub reserved_nodes: Vec<MultiaddrWithPeerId>,
/// Whether to only allow connections to/from reserved nodes. /// Whether to only allow connections to/from reserved nodes.
/// ///
@@ -47,14 +47,14 @@ pub struct NetworkConfigurationParams {
/// Specify a list of sentry node public addresses. /// Specify a list of sentry node public addresses.
#[structopt( #[structopt(
long = "sentry-nodes", long = "sentry-nodes",
value_name = "URL", value_name = "ADDR",
conflicts_with_all = &[ "sentry" ] conflicts_with_all = &[ "sentry" ]
)] )]
pub sentry_nodes: Vec<String>, pub sentry_nodes: Vec<MultiaddrWithPeerId>,
/// Listen on this multiaddress. /// Listen on this multiaddress.
#[structopt(long = "listen-addr", value_name = "LISTEN_ADDR")] #[structopt(long = "listen-addr", value_name = "LISTEN_ADDR")]
pub listen_addr: Vec<String>, pub listen_addr: Vec<Multiaddr>,
/// Specify p2p protocol TCP port. /// Specify p2p protocol TCP port.
/// ///
@@ -117,13 +117,7 @@ impl NetworkConfigurationParams {
config.network.non_reserved_mode = NonReservedPeerMode::Deny; config.network.non_reserved_mode = NonReservedPeerMode::Deny;
} }
config.network.sentry_nodes.extend(self.sentry_nodes.clone()); config.network.listen_addresses.extend(self.listen_addr.iter().cloned());
for addr in self.listen_addr.iter() {
let addr = addr.parse().ok().ok_or(error::Error::InvalidListenMultiaddress)?;
config.network.listen_addresses.push(addr);
}
if config.network.listen_addresses.is_empty() { if config.network.listen_addresses.is_empty() {
let port = match self.port { let port = match self.port {
Some(port) => port, Some(port) => port,
@@ -36,7 +36,7 @@ impl PruningParams {
pub fn update_config( pub fn update_config(
&self, &self,
mut config: &mut Configuration, mut config: &mut Configuration,
role: sc_service::Roles, role: &sc_service::Role,
unsafe_pruning: bool, unsafe_pruning: bool,
) -> error::Result<()> { ) -> error::Result<()> {
// by default we disable pruning if the node is an authority (i.e. // by default we disable pruning if the node is an authority (i.e.
@@ -45,10 +45,10 @@ impl PruningParams {
// unless `unsafe_pruning` is set. // unless `unsafe_pruning` is set.
config.pruning = match &self.pruning { config.pruning = match &self.pruning {
Some(ref s) if s == "archive" => PruningMode::ArchiveAll, Some(ref s) if s == "archive" => PruningMode::ArchiveAll,
None if role == sc_service::Roles::AUTHORITY => PruningMode::ArchiveAll, None if role.is_network_authority() => PruningMode::ArchiveAll,
None => PruningMode::default(), None => PruningMode::default(),
Some(s) => { Some(s) => {
if role == sc_service::Roles::AUTHORITY && !unsafe_pruning { if role.is_network_authority() && !unsafe_pruning {
return Err(error::Error::Input( return Err(error::Error::Input(
"Validators should run with state pruning disabled (i.e. archive). \ "Validators should run with state pruning disabled (i.e. archive). \
You can ignore this check with `--unsafe-pruning`.".to_string() You can ignore this check with `--unsafe-pruning`.".to_string()
@@ -84,7 +84,7 @@
use sp_runtime::traits::{NumberFor, Block as BlockT, Zero}; use sp_runtime::traits::{NumberFor, Block as BlockT, Zero};
use sc_network_gossip::{MessageIntent, ValidatorContext}; use sc_network_gossip::{MessageIntent, ValidatorContext};
use sc_network::{config::Roles, PeerId, ReputationChange}; use sc_network::{ObservedRole, PeerId, ReputationChange};
use parity_scale_codec::{Encode, Decode}; use parity_scale_codec::{Encode, Decode};
use sp_finality_grandpa::AuthorityId; use sp_finality_grandpa::AuthorityId;
@@ -439,11 +439,11 @@ impl Misbehavior {
struct PeerInfo<N> { struct PeerInfo<N> {
view: View<N>, view: View<N>,
roles: Roles, roles: ObservedRole,
} }
impl<N> PeerInfo<N> { impl<N> PeerInfo<N> {
fn new(roles: Roles) -> Self { fn new(roles: ObservedRole) -> Self {
PeerInfo { PeerInfo {
view: View::default(), view: View::default(),
roles, roles,
@@ -469,14 +469,17 @@ impl<N> Default for Peers<N> {
} }
impl<N: Ord> Peers<N> { impl<N: Ord> Peers<N> {
fn new_peer(&mut self, who: PeerId, roles: Roles) { fn new_peer(&mut self, who: PeerId, role: ObservedRole) {
if roles.is_authority() && self.lucky_authorities.len() < MIN_LUCKY { match role {
self.lucky_authorities.insert(who.clone()); ObservedRole::Authority if self.lucky_authorities.len() < MIN_LUCKY => {
self.lucky_authorities.insert(who.clone());
},
ObservedRole::Full | ObservedRole::Light if self.lucky_peers.len() < MIN_LUCKY => {
self.lucky_peers.insert(who.clone());
},
_ => {}
} }
if !roles.is_authority() && self.lucky_peers.len() < MIN_LUCKY { self.inner.insert(who, PeerInfo::new(role));
self.lucky_peers.insert(who.clone());
}
self.inner.insert(who, PeerInfo::new(roles));
} }
fn peer_disconnected(&mut self, who: &PeerId) { fn peer_disconnected(&mut self, who: &PeerId) {
@@ -539,21 +542,28 @@ impl<N: Ord> Peers<N> {
} }
fn authorities(&self) -> usize { fn authorities(&self) -> usize {
self.inner.iter().filter(|(_, info)| info.roles.is_authority()).count() // Note that our sentry and our validator are neither authorities nor non-authorities.
self.inner.iter().filter(|(_, info)| matches!(info.roles, ObservedRole::Authority)).count()
} }
fn non_authorities(&self) -> usize { fn non_authorities(&self) -> usize {
self.inner.iter().filter(|(_, info)| !info.roles.is_authority()).count() // Note that our sentry and our validator are neither authorities nor non-authorities.
self.inner
.iter()
.filter(|(_, info)| matches!(info.roles, ObservedRole::Full | ObservedRole::Light))
.count()
} }
fn reshuffle(&mut self) { fn reshuffle(&mut self) {
let mut lucky_peers: Vec<_> = self.inner let mut lucky_peers: Vec<_> = self.inner
.iter() .iter()
.filter_map(|(id, info)| if !info.roles.is_authority() { Some(id.clone()) } else { None }) .filter_map(|(id, info)|
if matches!(info.roles, ObservedRole::Full | ObservedRole::Light) { Some(id.clone()) } else { None })
.collect(); .collect();
let mut lucky_authorities: Vec<_> = self.inner let mut lucky_authorities: Vec<_> = self.inner
.iter() .iter()
.filter_map(|(id, info)| if info.roles.is_authority() { Some(id.clone()) } else { None }) .filter_map(|(id, info)|
if matches!(info.roles, ObservedRole::Authority) { Some(id.clone()) } else { None })
.collect(); .collect();
let num_non_authorities = ((lucky_peers.len() as f32).sqrt() as usize) let num_non_authorities = ((lucky_peers.len() as f32).sqrt() as usize)
@@ -633,8 +643,11 @@ impl CatchUpConfig {
fn request_allowed<N>(&self, peer: &PeerInfo<N>) -> bool { fn request_allowed<N>(&self, peer: &PeerInfo<N>) -> bool {
match self { match self {
CatchUpConfig::Disabled => false, CatchUpConfig::Disabled => false,
CatchUpConfig::Enabled { only_from_authorities, .. } => CatchUpConfig::Enabled { only_from_authorities, .. } => match peer.roles {
!only_from_authorities || peer.roles.is_authority(), ObservedRole::Authority | ObservedRole::OurSentry |
ObservedRole::OurGuardedAuthority => true,
_ => !only_from_authorities
}
} }
} }
} }
@@ -1121,34 +1134,38 @@ impl<Block: BlockT> Inner<Block> {
return false; return false;
} }
if peer.roles.is_authority() { match peer.roles {
let authorities = self.peers.authorities(); ObservedRole::OurGuardedAuthority | ObservedRole::OurSentry => true,
ObservedRole::Authority => {
let authorities = self.peers.authorities();
// the target node is an authority, on the first round duration we start by // the target node is an authority, on the first round duration we start by
// sending the message to only `sqrt(authorities)` (if we're // sending the message to only `sqrt(authorities)` (if we're
// connected to at least `MIN_LUCKY`). // connected to at least `MIN_LUCKY`).
if round_elapsed < round_duration * PROPAGATION_ALL_AUTHORITIES if round_elapsed < round_duration * PROPAGATION_ALL_AUTHORITIES
&& authorities > MIN_LUCKY && authorities > MIN_LUCKY
{ {
self.peers.lucky_authorities.contains(who) self.peers.lucky_authorities.contains(who)
} else { } else {
// otherwise we already went through the step above, so // otherwise we already went through the step above, so
// we won't filter the message and send it to all // we won't filter the message and send it to all
// authorities for whom it is polite to do so // authorities for whom it is polite to do so
true true
} }
} else { },
// the node is not an authority so we apply stricter filters ObservedRole::Full | ObservedRole::Light => {
if round_elapsed >= round_duration * PROPAGATION_ALL { // the node is not an authority so we apply stricter filters
// if we waited for 3 (or more) rounds if round_elapsed >= round_duration * PROPAGATION_ALL {
// then it is allowed to be sent to all peers. // if we waited for 3 (or more) rounds
true // then it is allowed to be sent to all peers.
} else if round_elapsed >= round_duration * PROPAGATION_SOME_NON_AUTHORITIES { true
// otherwise we only send it to `sqrt(non-authorities)`. } else if round_elapsed >= round_duration * PROPAGATION_SOME_NON_AUTHORITIES {
self.peers.lucky_peers.contains(who) // otherwise we only send it to `sqrt(non-authorities)`.
} else { self.peers.lucky_peers.contains(who)
false } else {
} false
}
},
} }
} }
@@ -1170,38 +1187,42 @@ impl<Block: BlockT> Inner<Block> {
let round_duration = self.config.gossip_duration * ROUND_DURATION; let round_duration = self.config.gossip_duration * ROUND_DURATION;
let round_elapsed = self.round_start.elapsed(); let round_elapsed = self.round_start.elapsed();
if peer.roles.is_authority() { match peer.roles {
let authorities = self.peers.authorities(); ObservedRole::OurSentry | ObservedRole::OurGuardedAuthority => true,
ObservedRole::Authority => {
let authorities = self.peers.authorities();
// the target node is an authority, on the first round duration we start by // the target node is an authority, on the first round duration we start by
// sending the message to only `sqrt(authorities)` (if we're // sending the message to only `sqrt(authorities)` (if we're
// connected to at least `MIN_LUCKY`). // connected to at least `MIN_LUCKY`).
if round_elapsed < round_duration * PROPAGATION_ALL_AUTHORITIES if round_elapsed < round_duration * PROPAGATION_ALL_AUTHORITIES
&& authorities > MIN_LUCKY && authorities > MIN_LUCKY
{ {
self.peers.lucky_authorities.contains(who) self.peers.lucky_authorities.contains(who)
} else { } else {
// otherwise we already went through the step above, so // otherwise we already went through the step above, so
// we won't filter the message and send it to all // we won't filter the message and send it to all
// authorities for whom it is polite to do so // authorities for whom it is polite to do so
true true
} }
} else { },
let non_authorities = self.peers.non_authorities(); ObservedRole::Full | ObservedRole::Light => {
let non_authorities = self.peers.non_authorities();
// the target node is not an authority, on the first and second // the target node is not an authority, on the first and second
// round duration we start by sending the message to only // round duration we start by sending the message to only
// `sqrt(non_authorities)` (if we're connected to at least // `sqrt(non_authorities)` (if we're connected to at least
// `MIN_LUCKY`). // `MIN_LUCKY`).
if round_elapsed < round_duration * PROPAGATION_SOME_NON_AUTHORITIES if round_elapsed < round_duration * PROPAGATION_SOME_NON_AUTHORITIES
&& non_authorities > MIN_LUCKY && non_authorities > MIN_LUCKY
{ {
self.peers.lucky_peers.contains(who) self.peers.lucky_peers.contains(who)
} else { } else {
// otherwise we already went through the step above, so // otherwise we already went through the step above, so
// we won't filter the message and send it to all // we won't filter the message and send it to all
// non-authorities for whom it is polite to do so // non-authorities for whom it is polite to do so
true true
}
} }
} }
} }
@@ -1397,7 +1418,7 @@ impl<Block: BlockT> GossipValidator<Block> {
} }
impl<Block: BlockT> sc_network_gossip::Validator<Block> for GossipValidator<Block> { impl<Block: BlockT> sc_network_gossip::Validator<Block> for GossipValidator<Block> {
fn new_peer(&self, context: &mut dyn ValidatorContext<Block>, who: &PeerId, roles: Roles) { fn new_peer(&self, context: &mut dyn ValidatorContext<Block>, who: &PeerId, roles: ObservedRole) {
let packet = { let packet = {
let mut inner = self.inner.write(); let mut inner = self.inner.write();
inner.peers.new_peer(who.clone(), roles); inner.peers.new_peer(who.clone(), roles);
@@ -1657,7 +1678,7 @@ mod tests {
assert!(res.unwrap().is_none()); assert!(res.unwrap().is_none());
// connect & disconnect. // connect & disconnect.
peers.new_peer(id.clone(), Roles::AUTHORITY); peers.new_peer(id.clone(), ObservedRole::Authority);
peers.peer_disconnected(&id); peers.peer_disconnected(&id);
let res = peers.update_peer_state(&id, update.clone()); let res = peers.update_peer_state(&id, update.clone());
@@ -1693,7 +1714,7 @@ mod tests {
let mut peers = Peers::default(); let mut peers = Peers::default();
let id = PeerId::random(); let id = PeerId::random();
peers.new_peer(id.clone(), Roles::AUTHORITY); peers.new_peer(id.clone(), ObservedRole::Authority);
let mut check_update = move |update: NeighborPacket<_>| { let mut check_update = move |update: NeighborPacket<_>| {
let view = peers.update_peer_state(&id, update.clone()).unwrap().unwrap(); let view = peers.update_peer_state(&id, update.clone()).unwrap().unwrap();
@@ -1713,7 +1734,7 @@ mod tests {
let mut peers = Peers::default(); let mut peers = Peers::default();
let id = PeerId::random(); let id = PeerId::random();
peers.new_peer(id.clone(), Roles::AUTHORITY); peers.new_peer(id.clone(), ObservedRole::Authority);
peers.update_peer_state(&id, NeighborPacket { peers.update_peer_state(&id, NeighborPacket {
round: Round(10), round: Round(10),
@@ -1914,7 +1935,7 @@ mod tests {
// add the peer making the request to the validator, // add the peer making the request to the validator,
// otherwise it is discarded // otherwise it is discarded
let mut inner = val.inner.write(); let mut inner = val.inner.write();
inner.peers.new_peer(peer.clone(), Roles::AUTHORITY); inner.peers.new_peer(peer.clone(), ObservedRole::Authority);
let res = inner.handle_catch_up_request( let res = inner.handle_catch_up_request(
&peer, &peer,
@@ -1965,7 +1986,7 @@ mod tests {
// add the peer making the request to the validator, // add the peer making the request to the validator,
// otherwise it is discarded // otherwise it is discarded
let peer = PeerId::random(); let peer = PeerId::random();
val.inner.write().peers.new_peer(peer.clone(), Roles::AUTHORITY); val.inner.write().peers.new_peer(peer.clone(), ObservedRole::Authority);
let send_request = |set_id, round| { let send_request = |set_id, round| {
let mut inner = val.inner.write(); let mut inner = val.inner.write();
@@ -2045,7 +2066,7 @@ mod tests {
// add the peer making the request to the validator, // add the peer making the request to the validator,
// otherwise it is discarded. // otherwise it is discarded.
let peer = PeerId::random(); let peer = PeerId::random();
val.inner.write().peers.new_peer(peer.clone(), Roles::AUTHORITY); val.inner.write().peers.new_peer(peer.clone(), ObservedRole::Authority);
let import_neighbor_message = |set_id, round| { let import_neighbor_message = |set_id, round| {
let (_, _, catch_up_request, _) = val.inner.write().import_neighbor_message( let (_, _, catch_up_request, _) = val.inner.write().import_neighbor_message(
@@ -2119,7 +2140,7 @@ mod tests {
// add the peer making the request to the validator, // add the peer making the request to the validator,
// otherwise it is discarded. // otherwise it is discarded.
let peer = PeerId::random(); let peer = PeerId::random();
val.inner.write().peers.new_peer(peer.clone(), Roles::AUTHORITY); val.inner.write().peers.new_peer(peer.clone(), ObservedRole::Authority);
// importing a neighbor message from a peer in the same set in a later // importing a neighbor message from a peer in the same set in a later
// round should lead to a catch up request but since they're disabled // round should lead to a catch up request but since they're disabled
@@ -2155,8 +2176,8 @@ mod tests {
let peer_authority = PeerId::random(); let peer_authority = PeerId::random();
let peer_full = PeerId::random(); let peer_full = PeerId::random();
val.inner.write().peers.new_peer(peer_authority.clone(), Roles::AUTHORITY); val.inner.write().peers.new_peer(peer_authority.clone(), ObservedRole::Authority);
val.inner.write().peers.new_peer(peer_full.clone(), Roles::FULL); val.inner.write().peers.new_peer(peer_full.clone(), ObservedRole::Full);
let import_neighbor_message = |peer| { let import_neighbor_message = |peer| {
let (_, _, catch_up_request, _) = val.inner.write().import_neighbor_message( let (_, _, catch_up_request, _) = val.inner.write().import_neighbor_message(
@@ -2213,7 +2234,7 @@ mod tests {
// add the peer making the requests to the validator, otherwise it is // add the peer making the requests to the validator, otherwise it is
// discarded. // discarded.
let peer_full = PeerId::random(); let peer_full = PeerId::random();
val.inner.write().peers.new_peer(peer_full.clone(), Roles::FULL); val.inner.write().peers.new_peer(peer_full.clone(), ObservedRole::Full);
let (_, _, catch_up_request, _) = val.inner.write().import_neighbor_message( let (_, _, catch_up_request, _) = val.inner.write().import_neighbor_message(
&peer_full, &peer_full,
@@ -2290,8 +2311,8 @@ mod tests {
full_nodes.resize_with(30, || PeerId::random()); full_nodes.resize_with(30, || PeerId::random());
for i in 0..30 { for i in 0..30 {
val.inner.write().peers.new_peer(authorities[i].clone(), Roles::AUTHORITY); val.inner.write().peers.new_peer(authorities[i].clone(), ObservedRole::Authority);
val.inner.write().peers.new_peer(full_nodes[i].clone(), Roles::FULL); val.inner.write().peers.new_peer(full_nodes[i].clone(), ObservedRole::Full);
} }
let test = |num_round, peers| { let test = |num_round, peers| {
@@ -2363,7 +2384,7 @@ mod tests {
let mut authorities = Vec::new(); let mut authorities = Vec::new();
for _ in 0..5 { for _ in 0..5 {
let peer_id = PeerId::random(); let peer_id = PeerId::random();
val.inner.write().peers.new_peer(peer_id.clone(), Roles::AUTHORITY); val.inner.write().peers.new_peer(peer_id.clone(), ObservedRole::Authority);
authorities.push(peer_id); authorities.push(peer_id);
} }
@@ -2403,7 +2424,7 @@ mod tests {
let mut authorities = Vec::new(); let mut authorities = Vec::new();
for _ in 0..100 { for _ in 0..100 {
let peer_id = PeerId::random(); let peer_id = PeerId::random();
val.inner.write().peers.new_peer(peer_id.clone(), Roles::AUTHORITY); val.inner.write().peers.new_peer(peer_id.clone(), ObservedRole::Authority);
authorities.push(peer_id); authorities.push(peer_id);
} }
@@ -2454,7 +2475,7 @@ mod tests {
val.inner val.inner
.write() .write()
.peers .peers
.new_peer(peer1.clone(), Roles::AUTHORITY); .new_peer(peer1.clone(), ObservedRole::Authority);
val.inner val.inner
.write() .write()
@@ -2474,7 +2495,7 @@ mod tests {
val.inner val.inner
.write() .write()
.peers .peers
.new_peer(peer2.clone(), Roles::AUTHORITY); .new_peer(peer2.clone(), ObservedRole::Authority);
// create a commit for round 1 of set id 1 // create a commit for round 1 of set id 1
// targeting a block at height 2 // targeting a block at height 2
@@ -18,7 +18,7 @@
use futures::channel::mpsc; use futures::channel::mpsc;
use futures::prelude::*; use futures::prelude::*;
use sc_network::{Event as NetworkEvent, PeerId, config::Roles}; use sc_network::{Event as NetworkEvent, ObservedRole, PeerId};
use sc_network_test::{Block, Hash}; use sc_network_test::{Block, Hash};
use sc_network_gossip::Validator; use sc_network_gossip::Validator;
use std::sync::Arc; use std::sync::Arc;
@@ -256,7 +256,7 @@ fn good_commit_leads_to_relay() {
let test = make_test_network().0 let test = make_test_network().0
.then(move |tester| { .then(move |tester| {
// register a peer. // register a peer.
tester.gossip_validator.new_peer(&mut NoopContext, &id, sc_network::config::Roles::FULL); tester.gossip_validator.new_peer(&mut NoopContext, &id, ObservedRole::Full);
future::ready((tester, id)) future::ready((tester, id))
}) })
.then(move |(tester, id)| { .then(move |(tester, id)| {
@@ -284,7 +284,7 @@ fn good_commit_leads_to_relay() {
let _ = sender.unbounded_send(NetworkEvent::NotificationStreamOpened { let _ = sender.unbounded_send(NetworkEvent::NotificationStreamOpened {
remote: sender_id.clone(), remote: sender_id.clone(),
engine_id: GRANDPA_ENGINE_ID, engine_id: GRANDPA_ENGINE_ID,
roles: Roles::FULL, role: ObservedRole::Full,
}); });
let _ = sender.unbounded_send(NetworkEvent::NotificationsReceived { let _ = sender.unbounded_send(NetworkEvent::NotificationsReceived {
@@ -297,7 +297,7 @@ fn good_commit_leads_to_relay() {
let _ = sender.unbounded_send(NetworkEvent::NotificationStreamOpened { let _ = sender.unbounded_send(NetworkEvent::NotificationStreamOpened {
remote: receiver_id.clone(), remote: receiver_id.clone(),
engine_id: GRANDPA_ENGINE_ID, engine_id: GRANDPA_ENGINE_ID,
roles: Roles::FULL, role: ObservedRole::Full,
}); });
// Announce its local set has being on the current set id through a neighbor // Announce its local set has being on the current set id through a neighbor
@@ -404,7 +404,7 @@ fn bad_commit_leads_to_report() {
let test = make_test_network().0 let test = make_test_network().0
.map(move |tester| { .map(move |tester| {
// register a peer. // register a peer.
tester.gossip_validator.new_peer(&mut NoopContext, &id, sc_network::config::Roles::FULL); tester.gossip_validator.new_peer(&mut NoopContext, &id, ObservedRole::Full);
(tester, id) (tester, id)
}) })
.then(move |(tester, id)| { .then(move |(tester, id)| {
@@ -431,7 +431,7 @@ fn bad_commit_leads_to_report() {
let _ = sender.unbounded_send(NetworkEvent::NotificationStreamOpened { let _ = sender.unbounded_send(NetworkEvent::NotificationStreamOpened {
remote: sender_id.clone(), remote: sender_id.clone(),
engine_id: GRANDPA_ENGINE_ID, engine_id: GRANDPA_ENGINE_ID,
roles: Roles::FULL, role: ObservedRole::Full,
}); });
let _ = sender.unbounded_send(NetworkEvent::NotificationsReceived { let _ = sender.unbounded_send(NetworkEvent::NotificationsReceived {
remote: sender_id.clone(), remote: sender_id.clone(),
@@ -482,7 +482,7 @@ fn peer_with_higher_view_leads_to_catch_up_request() {
let test = tester let test = tester
.map(move |tester| { .map(move |tester| {
// register a peer with authority role. // register a peer with authority role.
tester.gossip_validator.new_peer(&mut NoopContext, &id, sc_network::config::Roles::AUTHORITY); tester.gossip_validator.new_peer(&mut NoopContext, &id, ObservedRole::Authority);
(tester, id) (tester, id)
}) })
.then(move |(tester, id)| { .then(move |(tester, id)| {
@@ -22,7 +22,7 @@ use sc_network_test::{
Block, Hash, TestNetFactory, BlockImportAdapter, Peer, Block, Hash, TestNetFactory, BlockImportAdapter, Peer,
PeersClient, PassThroughVerifier, PeersFullClient, PeersClient, PassThroughVerifier, PeersFullClient,
}; };
use sc_network::config::{ProtocolConfig, Roles, BoxFinalityProofRequestBuilder}; use sc_network::config::{ProtocolConfig, BoxFinalityProofRequestBuilder};
use parking_lot::Mutex; use parking_lot::Mutex;
use futures_timer::Delay; use futures_timer::Delay;
use tokio::runtime::{Runtime, Handle}; use tokio::runtime::{Runtime, Handle};
@@ -74,9 +74,8 @@ impl GrandpaTestNet {
peers: Vec::with_capacity(n_peers), peers: Vec::with_capacity(n_peers),
test_config, test_config,
}; };
let config = Self::default_config();
for _ in 0..n_peers { for _ in 0..n_peers {
net.add_full_peer(&config); net.add_full_peer();
} }
net net
} }
@@ -95,10 +94,8 @@ impl TestNetFactory for GrandpaTestNet {
} }
fn default_config() -> ProtocolConfig { fn default_config() -> ProtocolConfig {
// the authority role ensures gossip hits all nodes here. // This is unused.
let mut config = ProtocolConfig::default(); ProtocolConfig::default()
config.roles = Roles::AUTHORITY;
config
} }
fn make_verifier( fn make_verifier(
@@ -1303,7 +1300,7 @@ fn finality_proof_is_fetched_by_light_client_when_consensus_data_changes() {
let peers = &[Ed25519Keyring::Alice]; let peers = &[Ed25519Keyring::Alice];
let mut net = GrandpaTestNet::new(TestApi::new(make_ids(peers)), 1); let mut net = GrandpaTestNet::new(TestApi::new(make_ids(peers)), 1);
net.add_light_peer(&GrandpaTestNet::default_config()); net.add_light_peer();
// import block#1 WITH consensus data change. Light client ignores justification // import block#1 WITH consensus data change. Light client ignores justification
// && instead fetches finality proof for block #1 // && instead fetches finality proof for block #1
@@ -1380,7 +1377,7 @@ fn empty_finality_proof_is_returned_to_light_client_when_authority_set_is_differ
run_to_completion(&mut runtime, 11, net.clone(), peers_a); run_to_completion(&mut runtime, 11, net.clone(), peers_a);
// request finalization by light client // request finalization by light client
net.lock().add_light_peer(&GrandpaTestNet::default_config()); net.lock().add_light_peer();
net.lock().block_until_sync(); net.lock().block_until_sync();
// check block, finalized on light client // check block, finalized on light client
@@ -137,11 +137,11 @@ impl<B: BlockT> Future for GossipEngine<B> {
loop { loop {
match this.network_event_stream.poll_next_unpin(cx) { match this.network_event_stream.poll_next_unpin(cx) {
Poll::Ready(Some(event)) => match event { Poll::Ready(Some(event)) => match event {
Event::NotificationStreamOpened { remote, engine_id: msg_engine_id, roles } => { Event::NotificationStreamOpened { remote, engine_id: msg_engine_id, role } => {
if msg_engine_id != this.engine_id { if msg_engine_id != this.engine_id {
continue; continue;
} }
this.state_machine.new_peer(&mut *this.network, remote, roles); this.state_machine.new_peer(&mut *this.network, remote, role);
} }
Event::NotificationStreamClosed { remote, engine_id: msg_engine_id } => { Event::NotificationStreamClosed { remote, engine_id: msg_engine_id } => {
if msg_engine_id != this.engine_id { if msg_engine_id != this.engine_id {
@@ -26,7 +26,7 @@ use lru::LruCache;
use libp2p::PeerId; use libp2p::PeerId;
use sp_runtime::traits::{Block as BlockT, Hash, HashFor}; use sp_runtime::traits::{Block as BlockT, Hash, HashFor};
use sp_runtime::ConsensusEngineId; use sp_runtime::ConsensusEngineId;
use sc_network::config::Roles; use sc_network::ObservedRole;
use wasm_timer::Instant; use wasm_timer::Instant;
// FIXME: Add additional spam/DoS attack protection: https://github.com/paritytech/substrate/issues/1115 // FIXME: Add additional spam/DoS attack protection: https://github.com/paritytech/substrate/issues/1115
@@ -51,7 +51,7 @@ mod rep {
struct PeerConsensus<H> { struct PeerConsensus<H> {
known_messages: HashSet<H>, known_messages: HashSet<H>,
roles: Roles, role: ObservedRole,
} }
/// Topic stream message with sender. /// Topic stream message with sender.
@@ -192,10 +192,10 @@ impl<B: BlockT> ConsensusGossip<B> {
validator: Arc<dyn Validator<B>> validator: Arc<dyn Validator<B>>
) { ) {
self.register_validator_internal(engine_id, validator.clone()); self.register_validator_internal(engine_id, validator.clone());
let peers: Vec<_> = self.peers.iter().map(|(id, peer)| (id.clone(), peer.roles)).collect(); let peers: Vec<_> = self.peers.iter().map(|(id, peer)| (id.clone(), peer.role.clone())).collect();
for (id, roles) in peers { for (id, role) in peers {
let mut context = NetworkContext { gossip: self, network, engine_id: engine_id.clone() }; let mut context = NetworkContext { gossip: self, network, engine_id: engine_id.clone() };
validator.new_peer(&mut context, &id, roles); validator.new_peer(&mut context, &id, role);
} }
} }
@@ -204,20 +204,20 @@ impl<B: BlockT> ConsensusGossip<B> {
} }
/// Handle new connected peer. /// Handle new connected peer.
pub fn new_peer(&mut self, network: &mut dyn Network<B>, who: PeerId, roles: Roles) { pub fn new_peer(&mut self, network: &mut dyn Network<B>, who: PeerId, role: ObservedRole) {
// light nodes are not valid targets for consensus gossip messages // light nodes are not valid targets for consensus gossip messages
if !roles.is_full() { if role.is_light() {
return; return;
} }
trace!(target:"gossip", "Registering {:?} {}", roles, who); trace!(target:"gossip", "Registering {:?} {}", role, who);
self.peers.insert(who.clone(), PeerConsensus { self.peers.insert(who.clone(), PeerConsensus {
known_messages: HashSet::new(), known_messages: HashSet::new(),
roles, role: role.clone(),
}); });
for (engine_id, v) in self.validators.clone() { for (engine_id, v) in self.validators.clone() {
let mut context = NetworkContext { gossip: self, network, engine_id: engine_id.clone() }; let mut context = NetworkContext { gossip: self, network, engine_id: engine_id.clone() };
v.new_peer(&mut context, &who, roles); v.new_peer(&mut context, &who, role.clone());
} }
} }
@@ -696,7 +696,7 @@ mod tests {
let mut network = TestNetwork; let mut network = TestNetwork;
let peer_id = PeerId::random(); let peer_id = PeerId::random();
consensus.new_peer(&mut network, peer_id.clone(), Roles::FULL); consensus.new_peer(&mut network, peer_id.clone(), ObservedRole::Full);
assert!(consensus.peers.contains_key(&peer_id)); assert!(consensus.peers.contains_key(&peer_id));
consensus.peer_disconnected(&mut network, peer_id.clone()); consensus.peer_disconnected(&mut network, peer_id.clone());
@@ -14,13 +14,13 @@
// You should have received a copy of the GNU General Public License // You should have received a copy of the GNU General Public License
// along with Substrate. If not, see <http://www.gnu.org/licenses/>. // along with Substrate. If not, see <http://www.gnu.org/licenses/>.
use sc_network::{config::Roles, PeerId}; use sc_network::{ObservedRole, PeerId};
use sp_runtime::traits::Block as BlockT; use sp_runtime::traits::Block as BlockT;
/// Validates consensus messages. /// Validates consensus messages.
pub trait Validator<B: BlockT>: Send + Sync { pub trait Validator<B: BlockT>: Send + Sync {
/// New peer is connected. /// New peer is connected.
fn new_peer(&self, _context: &mut dyn ValidatorContext<B>, _who: &PeerId, _roles: Roles) { fn new_peer(&self, _context: &mut dyn ValidatorContext<B>, _who: &PeerId, _role: ObservedRole) {
} }
/// New connection is dropped. /// New connection is dropped.
+60 -8
View File
@@ -15,18 +15,19 @@
// along with Substrate. If not, see <http://www.gnu.org/licenses/>. // along with Substrate. If not, see <http://www.gnu.org/licenses/>.
use crate::{ use crate::{
config::Role,
debug_info, discovery::DiscoveryBehaviour, discovery::DiscoveryOut, debug_info, discovery::DiscoveryBehaviour, discovery::DiscoveryOut,
Event, protocol::event::DhtEvent, ExHashT, Event, ObservedRole, DhtEvent, ExHashT,
}; };
use crate::protocol::{self, light_client_handler, CustomMessageOutcome, Protocol}; use crate::protocol::{self, light_client_handler, message::Roles, CustomMessageOutcome, Protocol};
use libp2p::NetworkBehaviour; use libp2p::NetworkBehaviour;
use libp2p::core::{Multiaddr, PeerId, PublicKey}; use libp2p::core::{Multiaddr, PeerId, PublicKey};
use libp2p::kad::record; use libp2p::kad::record;
use libp2p::swarm::{NetworkBehaviourAction, NetworkBehaviourEventProcess, PollParameters}; use libp2p::swarm::{NetworkBehaviourAction, NetworkBehaviourEventProcess, PollParameters};
use log::debug; use log::debug;
use sp_consensus::{BlockOrigin, import_queue::{IncomingBlock, Origin}}; use sp_consensus::{BlockOrigin, import_queue::{IncomingBlock, Origin}};
use sp_runtime::{traits::{Block as BlockT, NumberFor}, Justification}; use sp_runtime::{traits::{Block as BlockT, NumberFor}, ConsensusEngineId, Justification};
use std::{iter, task::Context, task::Poll}; use std::{borrow::Cow, iter, task::Context, task::Poll};
use void; use void;
/// General behaviour of the network. Combines all protocols together. /// General behaviour of the network. Combines all protocols together.
@@ -44,9 +45,14 @@ pub struct Behaviour<B: BlockT, H: ExHashT> {
block_requests: protocol::BlockRequests<B>, block_requests: protocol::BlockRequests<B>,
/// Light client request handling. /// Light client request handling.
light_client_handler: protocol::LightClientHandler<B>, light_client_handler: protocol::LightClientHandler<B>,
/// Queue of events to produce for the outside. /// Queue of events to produce for the outside.
#[behaviour(ignore)] #[behaviour(ignore)]
events: Vec<BehaviourOut<B>>, events: Vec<BehaviourOut<B>>,
/// Role of our local node, as originally passed from the configuration.
#[behaviour(ignore)]
role: Role,
} }
/// Event generated by `Behaviour`. /// Event generated by `Behaviour`.
@@ -63,6 +69,7 @@ impl<B: BlockT, H: ExHashT> Behaviour<B, H> {
/// Builds a new `Behaviour`. /// Builds a new `Behaviour`.
pub async fn new( pub async fn new(
substrate: Protocol<B, H>, substrate: Protocol<B, H>,
role: Role,
user_agent: String, user_agent: String,
local_public_key: PublicKey, local_public_key: PublicKey,
known_addresses: Vec<(PeerId, Multiaddr)>, known_addresses: Vec<(PeerId, Multiaddr)>,
@@ -84,7 +91,8 @@ impl<B: BlockT, H: ExHashT> Behaviour<B, H> {
).await, ).await,
block_requests, block_requests,
light_client_handler, light_client_handler,
events: Vec::new() events: Vec::new(),
role,
} }
} }
@@ -112,6 +120,32 @@ impl<B: BlockT, H: ExHashT> Behaviour<B, H> {
self.debug_info.node(peer_id) self.debug_info.node(peer_id)
} }
/// Registers a new notifications protocol.
///
/// After that, you can call `write_notifications`.
///
/// Please call `event_stream` before registering a protocol, otherwise you may miss events
/// about the protocol that you have registered.
///
/// You are very strongly encouraged to call this method very early on. Any connection open
/// will retain the protocols that were registered then, and not any new one.
pub fn register_notifications_protocol(
&mut self,
engine_id: ConsensusEngineId,
protocol_name: impl Into<Cow<'static, [u8]>>,
) {
let list = self.substrate.register_notifications_protocol(engine_id, protocol_name);
for (remote, roles) in list {
let role = reported_roles_to_observed_role(&self.role, remote, roles);
let ev = Event::NotificationStreamOpened {
remote: remote.clone(),
engine_id,
role,
};
self.events.push(BehaviourOut::Event(ev));
}
}
/// Returns a shared reference to the user protocol. /// Returns a shared reference to the user protocol.
pub fn user_protocol(&self) -> &Protocol<B, H> { pub fn user_protocol(&self) -> &Protocol<B, H> {
&self.substrate &self.substrate
@@ -138,6 +172,22 @@ impl<B: BlockT, H: ExHashT> Behaviour<B, H> {
} }
} }
fn reported_roles_to_observed_role(local_role: &Role, remote: &PeerId, roles: Roles) -> ObservedRole {
if roles.is_authority() {
match local_role {
Role::Authority { sentry_nodes }
if sentry_nodes.iter().any(|s| s.peer_id == *remote) => ObservedRole::OurSentry,
Role::Sentry { validators }
if validators.iter().any(|s| s.peer_id == *remote) => ObservedRole::OurGuardedAuthority,
_ => ObservedRole::Authority
}
} else if roles.is_full() {
ObservedRole::Full
} else {
ObservedRole::Light
}
}
impl<B: BlockT, H: ExHashT> NetworkBehaviourEventProcess<void::Void> for impl<B: BlockT, H: ExHashT> NetworkBehaviourEventProcess<void::Void> for
Behaviour<B, H> { Behaviour<B, H> {
fn inject_event(&mut self, event: void::Void) { fn inject_event(&mut self, event: void::Void) {
@@ -155,14 +205,16 @@ Behaviour<B, H> {
self.events.push(BehaviourOut::JustificationImport(origin, hash, nb, justification)), self.events.push(BehaviourOut::JustificationImport(origin, hash, nb, justification)),
CustomMessageOutcome::FinalityProofImport(origin, hash, nb, proof) => CustomMessageOutcome::FinalityProofImport(origin, hash, nb, proof) =>
self.events.push(BehaviourOut::FinalityProofImport(origin, hash, nb, proof)), self.events.push(BehaviourOut::FinalityProofImport(origin, hash, nb, proof)),
CustomMessageOutcome::NotificationStreamOpened { remote, protocols, roles } => CustomMessageOutcome::NotificationStreamOpened { remote, protocols, roles } => {
let role = reported_roles_to_observed_role(&self.role, &remote, roles);
for engine_id in protocols { for engine_id in protocols {
self.events.push(BehaviourOut::Event(Event::NotificationStreamOpened { self.events.push(BehaviourOut::Event(Event::NotificationStreamOpened {
remote: remote.clone(), remote: remote.clone(),
engine_id, engine_id,
roles, role: role.clone(),
})); }));
}, }
},
CustomMessageOutcome::NotificationStreamClosed { remote, protocols } => CustomMessageOutcome::NotificationStreamClosed { remote, protocols } =>
for engine_id in protocols { for engine_id in protocols {
self.events.push(BehaviourOut::Event(Event::NotificationStreamClosed { self.events.push(BehaviourOut::Event(Event::NotificationStreamClosed {
+98 -48
View File
@@ -31,23 +31,21 @@ pub use crate::protocol::ProtocolConfig;
use crate::service::ExHashT; use crate::service::ExHashT;
use bitflags::bitflags;
use sp_consensus::{block_validation::BlockAnnounceValidator, import_queue::ImportQueue}; use sp_consensus::{block_validation::BlockAnnounceValidator, import_queue::ImportQueue};
use sp_runtime::traits::{Block as BlockT}; use sp_runtime::traits::{Block as BlockT};
use libp2p::identity::{Keypair, ed25519}; use libp2p::identity::{Keypair, ed25519};
use libp2p::wasm_ext; use libp2p::wasm_ext;
use libp2p::{PeerId, Multiaddr, multiaddr}; use libp2p::{PeerId, Multiaddr, multiaddr};
use core::{fmt, iter}; use core::{fmt, iter};
use std::{future::Future, pin::Pin}; use std::{convert::TryFrom, future::Future, pin::Pin, str::FromStr};
use std::{error::Error, fs, io::{self, Write}, net::Ipv4Addr, path::{Path, PathBuf}, sync::Arc}; use std::{error::Error, fs, io::{self, Write}, net::Ipv4Addr, path::{Path, PathBuf}, sync::Arc};
use zeroize::Zeroize; use zeroize::Zeroize;
use prometheus_endpoint::Registry; use prometheus_endpoint::Registry;
/// Network initialization parameters. /// Network initialization parameters.
pub struct Params<B: BlockT, H: ExHashT> { pub struct Params<B: BlockT, H: ExHashT> {
/// Assigned roles for our node (full, light, ...). /// Assigned role for our node (full, light, ...).
pub roles: Roles, pub role: Role,
/// How to spawn background tasks. If you pass `None`, then a threads pool will be used by /// How to spawn background tasks. If you pass `None`, then a threads pool will be used by
/// default. /// default.
@@ -97,54 +95,48 @@ pub struct Params<B: BlockT, H: ExHashT> {
pub metrics_registry: Option<Registry>, pub metrics_registry: Option<Registry>,
} }
bitflags! { /// Role of the local node.
/// Bitmask of the roles that a node fulfills. #[derive(Debug, Clone)]
pub struct Roles: u8 { pub enum Role {
/// No network. /// Regular full node.
const NONE = 0b00000000; Full,
/// Full node, does not participate in consensus. /// Regular light node.
const FULL = 0b00000001; Light,
/// Light client node. /// Sentry node that guards an authority. Will be reported as "authority" on the wire protocol.
const LIGHT = 0b00000010; Sentry {
/// Act as an authority /// Address and identity of the validator nodes that we're guarding.
const AUTHORITY = 0b00000100; ///
/// The nodes will be granted some priviledged status.
validators: Vec<MultiaddrWithPeerId>,
},
/// Actual authority.
Authority {
/// List of public addresses and identities of our sentry nodes.
sentry_nodes: Vec<MultiaddrWithPeerId>,
} }
} }
impl Roles { impl Role {
/// Does this role represents a client that holds full chain data locally? /// True for `Role::Authority`
pub fn is_full(&self) -> bool {
self.intersects(Roles::FULL | Roles::AUTHORITY)
}
/// Does this role represents a client that does not participates in the consensus?
pub fn is_authority(&self) -> bool { pub fn is_authority(&self) -> bool {
*self == Roles::AUTHORITY matches!(self, Role::Authority { .. })
} }
/// Does this role represents a client that does not hold full chain data locally? /// True for `Role::Authority` and `Role::Sentry` since they're both
pub fn is_light(&self) -> bool { /// announced as having the authority role to the network.
!self.is_full() pub fn is_network_authority(&self) -> bool {
matches!(self, Role::Authority { .. } | Role::Sentry { .. })
} }
} }
impl fmt::Display for Roles { impl fmt::Display for Role {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{:?}", self) match self {
} Role::Full => write!(f, "FULL"),
} Role::Light => write!(f, "LIGHT"),
Role::Sentry { .. } => write!(f, "SENTRY"),
impl codec::Encode for Roles { Role::Authority { .. } => write!(f, "AUTHORITY"),
fn encode_to<T: codec::Output>(&self, dest: &mut T) { }
dest.push_byte(self.bits())
}
}
impl codec::EncodeLike for Roles {}
impl codec::Decode for Roles {
fn decode<I: codec::Input>(input: &mut I) -> Result<Self, codec::Error> {
Self::from_bits(input.read_byte()?).ok_or_else(|| codec::Error::from("Invalid bytes"))
} }
} }
@@ -214,6 +206,67 @@ pub fn parse_addr(mut addr: Multiaddr)-> Result<(PeerId, Multiaddr), ParseErr> {
Ok((who, addr)) Ok((who, addr))
} }
/// Address of a node, including its identity.
///
/// This struct represents a decoded version of a multiaddress that ends with `/p2p/<peerid>`.
///
/// # Example
///
/// ```
/// # use sc_network::{Multiaddr, PeerId, config::MultiaddrWithPeerId};
/// let addr: MultiaddrWithPeerId =
/// "/ip4/198.51.100.19/tcp/30333/p2p/QmSk5HQbn6LhUwDiNMseVUjuRYhEtYj4aUZ6WfWoGURpdV".parse().unwrap();
/// assert_eq!(addr.peer_id.to_base58(), "QmSk5HQbn6LhUwDiNMseVUjuRYhEtYj4aUZ6WfWoGURpdV");
/// assert_eq!(addr.multiaddr.to_string(), "/ip4/198.51.100.19/tcp/30333");
/// ```
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
#[serde(try_from = "String", into = "String")]
pub struct MultiaddrWithPeerId {
/// Address of the node.
pub multiaddr: Multiaddr,
/// Its identity.
pub peer_id: PeerId,
}
impl MultiaddrWithPeerId {
/// Concatenates the multiaddress and peer ID into one multiaddress containing both.
pub fn concat(&self) -> Multiaddr {
let proto = multiaddr::Protocol::P2p(From::from(self.peer_id.clone()));
self.multiaddr.clone().with(proto)
}
}
impl fmt::Display for MultiaddrWithPeerId {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
fmt::Display::fmt(&self.concat(), f)
}
}
impl FromStr for MultiaddrWithPeerId {
type Err = ParseErr;
fn from_str(s: &str) -> Result<Self, Self::Err> {
let (peer_id, multiaddr) = parse_str_addr(s)?;
Ok(MultiaddrWithPeerId {
peer_id,
multiaddr,
})
}
}
impl From<MultiaddrWithPeerId> for String {
fn from(ma: MultiaddrWithPeerId) -> String {
format!("{}", ma)
}
}
impl TryFrom<String> for MultiaddrWithPeerId {
type Error = ParseErr;
fn try_from(string: String) -> Result<Self, Self::Error> {
string.parse()
}
}
/// Error that can be generated by `parse_str_addr`. /// Error that can be generated by `parse_str_addr`.
#[derive(Debug)] #[derive(Debug)]
pub enum ParseErr { pub enum ParseErr {
@@ -263,7 +316,7 @@ pub struct NetworkConfiguration {
/// Multiaddresses to advertise. Detected automatically if empty. /// Multiaddresses to advertise. Detected automatically if empty.
pub public_addresses: Vec<Multiaddr>, pub public_addresses: Vec<Multiaddr>,
/// List of initial node addresses /// List of initial node addresses
pub boot_nodes: Vec<String>, pub boot_nodes: Vec<MultiaddrWithPeerId>,
/// The node key configuration, which determines the node's network identity keypair. /// The node key configuration, which determines the node's network identity keypair.
pub node_key: NodeKeyConfig, pub node_key: NodeKeyConfig,
/// Maximum allowed number of incoming connections. /// Maximum allowed number of incoming connections.
@@ -271,11 +324,9 @@ pub struct NetworkConfiguration {
/// Number of outgoing connections we're trying to maintain. /// Number of outgoing connections we're trying to maintain.
pub out_peers: u32, pub out_peers: u32,
/// List of reserved node addresses. /// List of reserved node addresses.
pub reserved_nodes: Vec<String>, pub reserved_nodes: Vec<MultiaddrWithPeerId>,
/// The non-reserved peer mode. /// The non-reserved peer mode.
pub non_reserved_mode: NonReservedPeerMode, pub non_reserved_mode: NonReservedPeerMode,
/// List of sentry node public addresses.
pub sentry_nodes: Vec<String>,
/// Client identifier. Sent over the wire for debugging purposes. /// Client identifier. Sent over the wire for debugging purposes.
pub client_version: String, pub client_version: String,
/// Name of the node. Sent over the wire for debugging purposes. /// Name of the node. Sent over the wire for debugging purposes.
@@ -299,7 +350,6 @@ impl Default for NetworkConfiguration {
out_peers: 75, out_peers: 75,
reserved_nodes: Vec::new(), reserved_nodes: Vec::new(),
non_reserved_mode: NonReservedPeerMode::Accept, non_reserved_mode: NonReservedPeerMode::Accept,
sentry_nodes: Vec::new(),
client_version: "unknown".into(), client_version: "unknown".into(),
node_name: "unknown".into(), node_name: "unknown".into(),
transport: TransportConfig::Normal { transport: TransportConfig::Normal {
+1 -1
View File
@@ -248,7 +248,7 @@ pub mod network_state;
pub use service::{NetworkService, NetworkStateInfo, NetworkWorker, ExHashT, ReportHandle}; pub use service::{NetworkService, NetworkStateInfo, NetworkWorker, ExHashT, ReportHandle};
pub use protocol::PeerInfo; pub use protocol::PeerInfo;
pub use protocol::event::{Event, DhtEvent}; pub use protocol::event::{Event, DhtEvent, ObservedRole};
pub use protocol::sync::SyncState; pub use protocol::sync::SyncState;
pub use libp2p::{Multiaddr, PeerId}; pub use libp2p::{Multiaddr, PeerId};
#[doc(inline)] #[doc(inline)]
+13 -23
View File
@@ -39,11 +39,11 @@ use sp_runtime::traits::{
}; };
use sp_arithmetic::traits::SaturatedConversion; use sp_arithmetic::traits::SaturatedConversion;
use message::{BlockAnnounce, Message}; use message::{BlockAnnounce, Message};
use message::generic::{Message as GenericMessage, ConsensusMessage}; use message::generic::{Message as GenericMessage, ConsensusMessage, Roles};
use prometheus_endpoint::{Registry, Gauge, GaugeVec, HistogramVec, PrometheusError, Opts, register, U64}; use prometheus_endpoint::{Registry, Gauge, GaugeVec, HistogramVec, PrometheusError, Opts, register, U64};
use sync::{ChainSync, SyncState}; use sync::{ChainSync, SyncState};
use crate::service::{TransactionPool, ExHashT}; use crate::service::{TransactionPool, ExHashT};
use crate::config::{BoxFinalityProofRequestBuilder, Roles}; use crate::config::BoxFinalityProofRequestBuilder;
use std::borrow::Cow; use std::borrow::Cow;
use std::collections::{BTreeMap, HashMap, HashSet, VecDeque}; use std::collections::{BTreeMap, HashMap, HashSet, VecDeque};
use std::sync::Arc; use std::sync::Arc;
@@ -338,7 +338,7 @@ impl<B: BlockT, H: ExHashT> Protocol<B, H> {
let important_peers = { let important_peers = {
let mut imp_p = HashSet::new(); let mut imp_p = HashSet::new();
for reserved in &peerset_config.reserved_nodes { for reserved in peerset_config.priority_groups.iter().flat_map(|(_, l)| l.iter()) {
imp_p.insert(reserved.clone()); imp_p.insert(reserved.clone());
} }
imp_p.shrink_to_fit(); imp_p.shrink_to_fit();
@@ -1033,13 +1033,14 @@ impl<B: BlockT, H: ExHashT> Protocol<B, H> {
/// Registers a new notifications protocol. /// Registers a new notifications protocol.
/// ///
/// You are very strongly encouraged to call this method very early on. Any connection open /// While registering a protocol while we already have open connections is discouraged, we
/// will retain the protocols that were registered then, and not any new one. /// nonetheless handle it by notifying that we opened channels with everyone. This function
pub fn register_notifications_protocol( /// returns a list of substreams to open as a result.
&mut self, pub fn register_notifications_protocol<'a>(
&'a mut self,
engine_id: ConsensusEngineId, engine_id: ConsensusEngineId,
protocol_name: impl Into<Cow<'static, [u8]>>, protocol_name: impl Into<Cow<'static, [u8]>>,
) -> Vec<event::Event> { ) -> impl ExactSizeIterator<Item = (&'a PeerId, Roles)> + 'a {
let protocol_name = protocol_name.into(); let protocol_name = protocol_name.into();
if self.protocol_name_by_engine.insert(engine_id, protocol_name.clone()).is_some() { if self.protocol_name_by_engine.insert(engine_id, protocol_name.clone()).is_some() {
error!(target: "sub-libp2p", "Notifications protocol already registered: {:?}", protocol_name); error!(target: "sub-libp2p", "Notifications protocol already registered: {:?}", protocol_name);
@@ -1048,16 +1049,8 @@ impl<B: BlockT, H: ExHashT> Protocol<B, H> {
self.legacy_equiv_by_name.insert(protocol_name, Fallback::Consensus(engine_id)); self.legacy_equiv_by_name.insert(protocol_name, Fallback::Consensus(engine_id));
} }
// Registering a protocol while we already have open connections isn't great, but for now
// we handle it by notifying that we opened channels with everyone.
self.context_data.peers.iter() self.context_data.peers.iter()
.map(|(peer_id, peer)| .map(|(peer_id, peer)| (peer_id, peer.info.roles))
event::Event::NotificationStreamOpened {
remote: peer_id.clone(),
engine_id,
roles: peer.info.roles,
})
.collect()
} }
/// Called when peer sends us new extrinsics /// Called when peer sends us new extrinsics
@@ -2021,7 +2014,7 @@ impl<B: BlockT, H: ExHashT> Drop for Protocol<B, H> {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use crate::PeerId; use crate::PeerId;
use crate::config::{EmptyTransactionPool, Roles}; use crate::config::EmptyTransactionPool;
use super::{CustomMessageOutcome, Protocol, ProtocolConfig}; use super::{CustomMessageOutcome, Protocol, ProtocolConfig};
use sp_consensus::block_validation::DefaultBlockAnnounceValidator; use sp_consensus::block_validation::DefaultBlockAnnounceValidator;
@@ -2034,10 +2027,7 @@ mod tests {
let client = Arc::new(TestClientBuilder::with_default_backend().build_with_longest_chain().0); let client = Arc::new(TestClientBuilder::with_default_backend().build_with_longest_chain().0);
let (mut protocol, _) = Protocol::<Block, Hash>::new( let (mut protocol, _) = Protocol::<Block, Hash>::new(
ProtocolConfig { ProtocolConfig::default(),
roles: Roles::FULL,
max_parallel_downloads: 10,
},
client.clone(), client.clone(),
Arc::new(EmptyTransactionPool), Arc::new(EmptyTransactionPool),
None, None,
@@ -2048,7 +2038,7 @@ mod tests {
out_peers: 10, out_peers: 10,
bootnodes: Vec::new(), bootnodes: Vec::new(),
reserved_only: false, reserved_only: false,
reserved_nodes: Vec::new(), priority_groups: Vec::new(),
}, },
Box::new(DefaultBlockAnnounceValidator::new(client.clone())), Box::new(DefaultBlockAnnounceValidator::new(client.clone())),
None, None,
+25 -3
View File
@@ -17,7 +17,6 @@
//! Network event types. These are are not the part of the protocol, but rather //! Network event types. These are are not the part of the protocol, but rather
//! events that happen on the network like DHT get/put results received. //! events that happen on the network like DHT get/put results received.
use crate::config::Roles;
use bytes::Bytes; use bytes::Bytes;
use libp2p::core::PeerId; use libp2p::core::PeerId;
use libp2p::kad::record::Key; use libp2p::kad::record::Key;
@@ -55,8 +54,8 @@ pub enum Event {
remote: PeerId, remote: PeerId,
/// The concerned protocol. Each protocol uses a different substream. /// The concerned protocol. Each protocol uses a different substream.
engine_id: ConsensusEngineId, engine_id: ConsensusEngineId,
/// Roles that the remote . /// Role of the remote.
roles: Roles, role: ObservedRole,
}, },
/// Closed a substream with the given node. Always matches a corresponding previous /// Closed a substream with the given node. Always matches a corresponding previous
@@ -76,3 +75,26 @@ pub enum Event {
messages: Vec<(ConsensusEngineId, Bytes)>, messages: Vec<(ConsensusEngineId, Bytes)>,
}, },
} }
/// Role that the peer sent to us during the handshake, with the addition of what our local node
/// knows about that peer.
#[derive(Debug, Clone)]
pub enum ObservedRole {
/// Full node.
Full,
/// Light node.
Light,
/// When we are a validator node, this is a sentry that protects us.
OurSentry,
/// When we are a sentry node, this is the authority we are protecting.
OurGuardedAuthority,
/// Third-party authority.
Authority,
}
impl ObservedRole {
/// Returns `true` for `ObservedRole::Light`.
pub fn is_light(&self) -> bool {
matches!(self, ObservedRole::Light)
}
}
@@ -78,7 +78,7 @@ fn build_nodes() -> (Swarm<CustomProtoWithAddr>, Swarm<CustomProtoWithAddr>) {
vec![] vec![]
}, },
reserved_only: false, reserved_only: false,
reserved_nodes: Vec::new(), priority_groups: Vec::new(),
}); });
let behaviour = CustomProtoWithAddr { let behaviour = CustomProtoWithAddr {
@@ -1423,7 +1423,7 @@ mod tests {
out_peers: 128, out_peers: 128,
bootnodes: Vec::new(), bootnodes: Vec::new(),
reserved_only: false, reserved_only: false,
reserved_nodes: Vec::new(), priority_groups: Vec::new(),
}; };
sc_peerset::Peerset::from_config(cfg) sc_peerset::Peerset::from_config(cfg)
} }
@@ -24,7 +24,7 @@ pub use self::generic::{
RemoteHeaderRequest, RemoteHeaderResponse, RemoteHeaderRequest, RemoteHeaderResponse,
RemoteChangesRequest, RemoteChangesResponse, RemoteChangesRequest, RemoteChangesResponse,
FinalityProofRequest, FinalityProofResponse, FinalityProofRequest, FinalityProofResponse,
FromBlock, RemoteReadChildRequest, FromBlock, RemoteReadChildRequest, Roles,
}; };
use sc_client_api::StorageProof; use sc_client_api::StorageProof;
@@ -137,14 +137,71 @@ pub struct RemoteReadResponse {
/// Generic types. /// Generic types.
pub mod generic { pub mod generic {
use bitflags::bitflags;
use codec::{Encode, Decode, Input, Output}; use codec::{Encode, Decode, Input, Output};
use sp_runtime::Justification; use sp_runtime::Justification;
use crate::config::Roles;
use super::{ use super::{
RemoteReadResponse, Transactions, Direction, RemoteReadResponse, Transactions, Direction,
RequestId, BlockAttributes, RemoteCallResponse, ConsensusEngineId, RequestId, BlockAttributes, RemoteCallResponse, ConsensusEngineId,
BlockState, StorageProof, BlockState, StorageProof,
}; };
bitflags! {
/// Bitmask of the roles that a node fulfills.
pub struct Roles: u8 {
/// No network.
const NONE = 0b00000000;
/// Full node, does not participate in consensus.
const FULL = 0b00000001;
/// Light client node.
const LIGHT = 0b00000010;
/// Act as an authority
const AUTHORITY = 0b00000100;
}
}
impl Roles {
/// Does this role represents a client that holds full chain data locally?
pub fn is_full(&self) -> bool {
self.intersects(Roles::FULL | Roles::AUTHORITY)
}
/// Does this role represents a client that does not participates in the consensus?
pub fn is_authority(&self) -> bool {
*self == Roles::AUTHORITY
}
/// Does this role represents a client that does not hold full chain data locally?
pub fn is_light(&self) -> bool {
!self.is_full()
}
}
impl<'a> From<&'a crate::config::Role> for Roles {
fn from(roles: &'a crate::config::Role) -> Self {
match roles {
crate::config::Role::Full => Roles::FULL,
crate::config::Role::Light => Roles::LIGHT,
crate::config::Role::Sentry { .. } => Roles::AUTHORITY,
crate::config::Role::Authority { .. } => Roles::AUTHORITY,
}
}
}
impl codec::Encode for Roles {
fn encode_to<T: codec::Output>(&self, dest: &mut T) {
dest.push_byte(self.bits())
}
}
impl codec::EncodeLike for Roles {}
impl codec::Decode for Roles {
fn decode<I: codec::Input>(input: &mut I) -> Result<Self, codec::Error> {
Self::from_bits(input.read_byte()?).ok_or_else(|| codec::Error::from("Invalid bytes"))
}
}
/// Consensus is mostly opaque to us /// Consensus is mostly opaque to us
#[derive(Debug, PartialEq, Eq, Clone, Encode, Decode)] #[derive(Debug, PartialEq, Eq, Clone, Encode, Decode)]
pub struct ConsensusMessage { pub struct ConsensusMessage {
@@ -34,9 +34,9 @@ use sp_consensus::{BlockOrigin, BlockStatus,
import_queue::{IncomingBlock, BlockImportResult, BlockImportError} import_queue::{IncomingBlock, BlockImportResult, BlockImportError}
}; };
use crate::{ use crate::{
config::{Roles, BoxFinalityProofRequestBuilder}, config::BoxFinalityProofRequestBuilder,
protocol::message::{self, generic::FinalityProofRequest, BlockAnnounce, BlockAttributes, BlockRequest, BlockResponse, protocol::message::{self, generic::FinalityProofRequest, BlockAnnounce, BlockAttributes, BlockRequest, BlockResponse,
FinalityProofResponse}, FinalityProofResponse, Roles},
}; };
use either::Either; use either::Either;
use extra_requests::ExtraRequests; use extra_requests::ExtraRequests;
+37 -24
View File
@@ -27,7 +27,7 @@
use crate::{ use crate::{
behaviour::{Behaviour, BehaviourOut}, behaviour::{Behaviour, BehaviourOut},
config::{parse_addr, parse_str_addr, NonReservedPeerMode, Params, TransportConfig}, config::{parse_addr, parse_str_addr, NonReservedPeerMode, Params, Role, TransportConfig},
error::Error, error::Error,
network_state::{ network_state::{
NetworkState, NotConnectedPeer as NetworkStateNotConnectedPeer, Peer as NetworkStatePeer, NetworkState, NotConnectedPeer as NetworkStateNotConnectedPeer, Peer as NetworkStatePeer,
@@ -181,19 +181,13 @@ impl<B: BlockT + 'static, H: ExHashT> NetworkWorker<B, H> {
// List of multiaddresses that we know in the network. // List of multiaddresses that we know in the network.
let mut known_addresses = Vec::new(); let mut known_addresses = Vec::new();
let mut bootnodes = Vec::new(); let mut bootnodes = Vec::new();
let mut reserved_nodes = Vec::new();
let mut boot_node_ids = HashSet::new(); let mut boot_node_ids = HashSet::new();
// Process the bootnodes. // Process the bootnodes.
for bootnode in params.network_config.boot_nodes.iter() { for bootnode in params.network_config.boot_nodes.iter() {
match parse_str_addr(bootnode) { bootnodes.push(bootnode.peer_id.clone());
Ok((peer_id, addr)) => { boot_node_ids.insert(bootnode.peer_id.clone());
bootnodes.push(peer_id.clone()); known_addresses.push((bootnode.peer_id.clone(), bootnode.multiaddr.clone()));
boot_node_ids.insert(peer_id.clone());
known_addresses.push((peer_id, addr));
},
Err(_) => warn!(target: "sub-libp2p", "Not a valid bootnode address: {}", bootnode),
}
} }
let boot_node_ids = Arc::new(boot_node_ids); let boot_node_ids = Arc::new(boot_node_ids);
@@ -215,22 +209,43 @@ impl<B: BlockT + 'static, H: ExHashT> NetworkWorker<B, H> {
} }
)?; )?;
// Initialize the reserved peers. // Initialize the peers we should always be connected to.
for reserved in params.network_config.reserved_nodes.iter() { let priority_groups = {
if let Ok((peer_id, addr)) = parse_str_addr(reserved) { let mut reserved_nodes = HashSet::new();
reserved_nodes.push(peer_id.clone()); for reserved in params.network_config.reserved_nodes.iter() {
known_addresses.push((peer_id, addr)); reserved_nodes.insert(reserved.peer_id.clone());
} else { known_addresses.push((reserved.peer_id.clone(), reserved.multiaddr.clone()));
warn!(target: "sub-libp2p", "Not a valid reserved node address: {}", reserved);
} }
}
let mut sentries_and_validators = HashSet::new();
match &params.role {
Role::Sentry { validators } => {
for validator in validators {
sentries_and_validators.insert(validator.peer_id.clone());
known_addresses.push((validator.peer_id.clone(), validator.multiaddr.clone()));
}
}
Role::Authority { sentry_nodes } => {
for sentry_node in sentry_nodes {
sentries_and_validators.insert(sentry_node.peer_id.clone());
known_addresses.push((sentry_node.peer_id.clone(), sentry_node.multiaddr.clone()));
}
}
_ => {}
}
vec![
("reserved".to_owned(), reserved_nodes),
("sentries_and_validators".to_owned(), sentries_and_validators),
]
};
let peerset_config = sc_peerset::PeersetConfig { let peerset_config = sc_peerset::PeersetConfig {
in_peers: params.network_config.in_peers, in_peers: params.network_config.in_peers,
out_peers: params.network_config.out_peers, out_peers: params.network_config.out_peers,
bootnodes, bootnodes,
reserved_only: params.network_config.non_reserved_mode == NonReservedPeerMode::Deny, reserved_only: params.network_config.non_reserved_mode == NonReservedPeerMode::Deny,
reserved_nodes, priority_groups,
}; };
// Private and public keys configuration. // Private and public keys configuration.
@@ -253,7 +268,7 @@ impl<B: BlockT + 'static, H: ExHashT> NetworkWorker<B, H> {
let is_major_syncing = Arc::new(AtomicBool::new(false)); let is_major_syncing = Arc::new(AtomicBool::new(false));
let (protocol, peerset_handle) = Protocol::new( let (protocol, peerset_handle) = Protocol::new(
protocol::ProtocolConfig { protocol::ProtocolConfig {
roles: params.roles, roles: From::from(&params.role),
max_parallel_downloads: params.network_config.max_parallel_downloads, max_parallel_downloads: params.network_config.max_parallel_downloads,
}, },
params.chain.clone(), params.chain.clone(),
@@ -285,6 +300,7 @@ impl<B: BlockT + 'static, H: ExHashT> NetworkWorker<B, H> {
}; };
let behaviour = futures::executor::block_on(Behaviour::new( let behaviour = futures::executor::block_on(Behaviour::new(
protocol, protocol,
params.role,
user_agent, user_agent,
local_public, local_public,
known_addresses, known_addresses,
@@ -971,11 +987,8 @@ impl<B: BlockT + 'static, H: ExHashT> Future for NetworkWorker<B, H> {
this.network_service.user_protocol_mut().write_notification(target, engine_id, message) this.network_service.user_protocol_mut().write_notification(target, engine_id, message)
}, },
ServiceToWorkerMsg::RegisterNotifProtocol { engine_id, protocol_name } => { ServiceToWorkerMsg::RegisterNotifProtocol { engine_id, protocol_name } => {
let events = this.network_service.user_protocol_mut() this.network_service
.register_notifications_protocol(engine_id, protocol_name); .register_notifications_protocol(engine_id, protocol_name);
for event in events {
this.event_streams.retain(|sender| sender.unbounded_send(event.clone()).is_ok());
}
}, },
ServiceToWorkerMsg::DisconnectPeer(who) => ServiceToWorkerMsg::DisconnectPeer(who) =>
this.network_service.user_protocol_mut().disconnect_peer(&who), this.network_service.user_protocol_mut().disconnect_peer(&who),
+10 -13
View File
@@ -32,7 +32,7 @@ use sp_blockchain::{
use sc_client_api::{BlockchainEvents, BlockImportNotification, FinalityNotifications, ImportNotifications, FinalityNotification, backend::{TransactionFor, AuxStore, Backend, Finalizer}, BlockBackend}; use sc_client_api::{BlockchainEvents, BlockImportNotification, FinalityNotifications, ImportNotifications, FinalityNotification, backend::{TransactionFor, AuxStore, Backend, Finalizer}, BlockBackend};
use sc_block_builder::{BlockBuilder, BlockBuilderProvider}; use sc_block_builder::{BlockBuilder, BlockBuilderProvider};
use sc_client::LongestChain; use sc_client::LongestChain;
use sc_network::config::Roles; use sc_network::config::Role;
use sp_consensus::block_validation::DefaultBlockAnnounceValidator; use sp_consensus::block_validation::DefaultBlockAnnounceValidator;
use sp_consensus::import_queue::{ use sp_consensus::import_queue::{
BasicQueue, BoxJustificationImport, Verifier, BoxFinalityProofImport, BasicQueue, BoxJustificationImport, Verifier, BoxFinalityProofImport,
@@ -557,17 +557,17 @@ pub trait TestNetFactory: Sized {
for i in 0..n { for i in 0..n {
trace!(target: "test_network", "Adding peer {}", i); trace!(target: "test_network", "Adding peer {}", i);
net.add_full_peer(&config); net.add_full_peer();
} }
net net
} }
fn add_full_peer(&mut self, config: &ProtocolConfig) { fn add_full_peer(&mut self) {
self.add_full_peer_with_states(config, None) self.add_full_peer_with_states(None)
} }
/// Add a full peer. /// Add a full peer.
fn add_full_peer_with_states(&mut self, config: &ProtocolConfig, keep_blocks: Option<u32>) { fn add_full_peer_with_states(&mut self, keep_blocks: Option<u32>) {
let test_client_builder = match keep_blocks { let test_client_builder = match keep_blocks {
Some(keep_blocks) => TestClientBuilder::with_pruning_window(keep_blocks), Some(keep_blocks) => TestClientBuilder::with_pruning_window(keep_blocks),
None => TestClientBuilder::with_default_backend(), None => TestClientBuilder::with_default_backend(),
@@ -586,7 +586,7 @@ pub trait TestNetFactory: Sized {
let verifier = self.make_verifier( let verifier = self.make_verifier(
PeersClient::Full(client.clone(), backend.clone()), PeersClient::Full(client.clone(), backend.clone()),
config, &Default::default(),
&data, &data,
); );
let verifier = VerifierAdapter::new(Arc::new(Mutex::new(Box::new(verifier) as Box<_>))); let verifier = VerifierAdapter::new(Arc::new(Mutex::new(Box::new(verifier) as Box<_>)));
@@ -601,7 +601,7 @@ pub trait TestNetFactory: Sized {
let listen_addr = build_multiaddr![Memory(rand::random::<u64>())]; let listen_addr = build_multiaddr![Memory(rand::random::<u64>())];
let network = NetworkWorker::new(sc_network::config::Params { let network = NetworkWorker::new(sc_network::config::Params {
roles: config.roles, role: Role::Full,
executor: None, executor: None,
network_config: NetworkConfiguration { network_config: NetworkConfiguration {
listen_addresses: vec![listen_addr.clone()], listen_addresses: vec![listen_addr.clone()],
@@ -644,10 +644,7 @@ pub trait TestNetFactory: Sized {
} }
/// Add a light peer. /// Add a light peer.
fn add_light_peer(&mut self, config: &ProtocolConfig) { fn add_light_peer(&mut self) {
let mut config = config.clone();
config.roles = Roles::LIGHT;
let (c, backend) = substrate_test_runtime_client::new_light(); let (c, backend) = substrate_test_runtime_client::new_light();
let client = Arc::new(c); let client = Arc::new(c);
let ( let (
@@ -660,7 +657,7 @@ pub trait TestNetFactory: Sized {
let verifier = self.make_verifier( let verifier = self.make_verifier(
PeersClient::Light(client.clone(), backend.clone()), PeersClient::Light(client.clone(), backend.clone()),
&config, &Default::default(),
&data, &data,
); );
let verifier = VerifierAdapter::new(Arc::new(Mutex::new(Box::new(verifier) as Box<_>))); let verifier = VerifierAdapter::new(Arc::new(Mutex::new(Box::new(verifier) as Box<_>)));
@@ -675,7 +672,7 @@ pub trait TestNetFactory: Sized {
let listen_addr = build_multiaddr![Memory(rand::random::<u64>())]; let listen_addr = build_multiaddr![Memory(rand::random::<u64>())];
let network = NetworkWorker::new(sc_network::config::Params { let network = NetworkWorker::new(sc_network::config::Params {
roles: config.roles, role: Role::Light,
executor: None, executor: None,
network_config: NetworkConfiguration { network_config: NetworkConfiguration {
listen_addresses: vec![listen_addr.clone()], listen_addresses: vec![listen_addr.clone()],
+8 -12
View File
@@ -14,7 +14,6 @@
// You should have received a copy of the GNU General Public License // You should have received a copy of the GNU General Public License
// along with Substrate. If not, see <http://www.gnu.org/licenses/>. // along with Substrate. If not, see <http://www.gnu.org/licenses/>.
use sc_network::config::Roles;
use sp_consensus::BlockOrigin; use sp_consensus::BlockOrigin;
use std::time::Duration; use std::time::Duration;
use futures::executor::block_on; use futures::executor::block_on;
@@ -372,10 +371,8 @@ fn blocks_are_not_announced_by_light_nodes() {
// full peer0 is connected to light peer // full peer0 is connected to light peer
// light peer1 is connected to full peer2 // light peer1 is connected to full peer2
let mut light_config = ProtocolConfig::default(); net.add_full_peer();
light_config.roles = Roles::LIGHT; net.add_light_peer();
net.add_full_peer(&ProtocolConfig::default());
net.add_light_peer(&light_config);
// Sync between 0 and 1. // Sync between 0 and 1.
net.peer(0).push_blocks(1, false); net.peer(0).push_blocks(1, false);
@@ -384,7 +381,7 @@ fn blocks_are_not_announced_by_light_nodes() {
assert_eq!(net.peer(1).client.info().best_number, 1); assert_eq!(net.peer(1).client.info().best_number, 1);
// Add another node and remove node 0. // Add another node and remove node 0.
net.add_full_peer(&ProtocolConfig::default()); net.add_full_peer();
net.peers.remove(0); net.peers.remove(0);
// Poll for a few seconds and make sure 1 and 2 (now 0 and 1) don't sync together. // Poll for a few seconds and make sure 1 and 2 (now 0 and 1) don't sync together.
@@ -465,7 +462,7 @@ fn can_not_sync_from_light_peer() {
// given the network with 1 full nodes (#0) and 1 light node (#1) // given the network with 1 full nodes (#0) and 1 light node (#1)
let mut net = TestNet::new(1); let mut net = TestNet::new(1);
net.add_light_peer(&Default::default()); net.add_light_peer();
// generate some blocks on #0 // generate some blocks on #0
net.peer(0).push_blocks(1, false); net.peer(0).push_blocks(1, false);
@@ -481,7 +478,7 @@ fn can_not_sync_from_light_peer() {
assert_eq!(light_info.best_hash, full0_info.best_hash); assert_eq!(light_info.best_hash, full0_info.best_hash);
// add new full client (#2) && remove #0 // add new full client (#2) && remove #0
net.add_full_peer(&Default::default()); net.add_full_peer();
net.peers.remove(0); net.peers.remove(0);
// ensure that the #2 (now #1) fails to sync block #1 even after 5 seconds // ensure that the #2 (now #1) fails to sync block #1 even after 5 seconds
@@ -511,7 +508,7 @@ fn light_peer_imports_header_from_announce() {
// given the network with 1 full nodes (#0) and 1 light node (#1) // given the network with 1 full nodes (#0) and 1 light node (#1)
let mut net = TestNet::new(1); let mut net = TestNet::new(1);
net.add_light_peer(&Default::default()); net.add_light_peer();
// let them connect to each other // let them connect to each other
net.block_until_sync(); net.block_until_sync();
@@ -583,9 +580,8 @@ fn can_sync_explicit_forks() {
fn syncs_header_only_forks() { fn syncs_header_only_forks() {
let _ = ::env_logger::try_init(); let _ = ::env_logger::try_init();
let mut net = TestNet::new(0); let mut net = TestNet::new(0);
let config = ProtocolConfig::default(); net.add_full_peer_with_states(None);
net.add_full_peer_with_states(&config, None); net.add_full_peer_with_states(Some(3));
net.add_full_peer_with_states(&config, Some(3));
net.peer(0).push_blocks(2, false); net.peer(0).push_blocks(2, false);
net.peer(1).push_blocks(2, false); net.peer(1).push_blocks(2, false);
+11 -8
View File
@@ -163,14 +163,14 @@ pub struct PeersetConfig {
/// > otherwise it will not be able to connect to them. /// > otherwise it will not be able to connect to them.
pub bootnodes: Vec<PeerId>, pub bootnodes: Vec<PeerId>,
/// If true, we only accept reserved nodes. /// If true, we only accept nodes in [`PeersetConfig::priority_groups`].
pub reserved_only: bool, pub reserved_only: bool,
/// List of nodes that we should always be connected to. /// Lists of nodes we should always be connected to.
/// ///
/// > **Note**: Keep in mind that the networking has to know an address for these nodes, /// > **Note**: Keep in mind that the networking has to know an address for these nodes,
/// > otherwise it will not be able to connect to them. /// > otherwise it will not be able to connect to them.
pub reserved_nodes: Vec<PeerId>, pub priority_groups: Vec<(String, HashSet<PeerId>)>,
} }
/// Side of the peer set manager owned by the network. In other words, the "receiving" side. /// Side of the peer set manager owned by the network. In other words, the "receiving" side.
@@ -215,7 +215,10 @@ impl Peerset {
latest_time_update: now, latest_time_update: now,
}; };
peerset.data.set_priority_group(RESERVED_NODES, config.reserved_nodes.into_iter().collect()); for (group, nodes) in config.priority_groups {
peerset.data.set_priority_group(&group, nodes);
}
for peer_id in config.bootnodes { for peer_id in config.bootnodes {
if let peersstate::Peer::Unknown(entry) = peerset.data.peer(&peer_id) { if let peersstate::Peer::Unknown(entry) = peerset.data.peer(&peer_id) {
entry.discover(); entry.discover();
@@ -597,7 +600,7 @@ mod tests {
out_peers: 2, out_peers: 2,
bootnodes: vec![bootnode], bootnodes: vec![bootnode],
reserved_only: true, reserved_only: true,
reserved_nodes: Vec::new(), priority_groups: Vec::new(),
}; };
let (peerset, handle) = Peerset::from_config(config); let (peerset, handle) = Peerset::from_config(config);
@@ -625,7 +628,7 @@ mod tests {
out_peers: 1, out_peers: 1,
bootnodes: vec![bootnode.clone()], bootnodes: vec![bootnode.clone()],
reserved_only: false, reserved_only: false,
reserved_nodes: Vec::new(), priority_groups: Vec::new(),
}; };
let (mut peerset, _handle) = Peerset::from_config(config); let (mut peerset, _handle) = Peerset::from_config(config);
@@ -652,7 +655,7 @@ mod tests {
out_peers: 2, out_peers: 2,
bootnodes: vec![bootnode.clone()], bootnodes: vec![bootnode.clone()],
reserved_only: false, reserved_only: false,
reserved_nodes: vec![], priority_groups: vec![],
}; };
let (mut peerset, _handle) = Peerset::from_config(config); let (mut peerset, _handle) = Peerset::from_config(config);
@@ -673,7 +676,7 @@ mod tests {
out_peers: 25, out_peers: 25,
bootnodes: vec![], bootnodes: vec![],
reserved_only: false, reserved_only: false,
reserved_nodes: vec![], priority_groups: vec![],
}); });
// We ban a node by setting its reputation under the threshold. // We ban a node by setting its reputation under the threshold.
+9 -6
View File
@@ -43,12 +43,15 @@ fn test_once() {
known_nodes.insert(id.clone()); known_nodes.insert(id.clone());
id id
}).collect(), }).collect(),
reserved_nodes: (0 .. Uniform::new_inclusive(0, 2).sample(&mut rng)).map(|_| { priority_groups: {
let id = PeerId::random(); let list = (0 .. Uniform::new_inclusive(0, 2).sample(&mut rng)).map(|_| {
known_nodes.insert(id.clone()); let id = PeerId::random();
reserved_nodes.insert(id.clone()); known_nodes.insert(id.clone());
id reserved_nodes.insert(id.clone());
}).collect(), id
}).collect();
vec![("reserved".to_owned(), list)]
},
reserved_only: Uniform::new_inclusive(0, 10).sample(&mut rng) == 0, reserved_only: Uniform::new_inclusive(0, 10).sample(&mut rng) == 0,
in_peers: Uniform::new_inclusive(0, 25).sample(&mut rng), in_peers: Uniform::new_inclusive(0, 25).sample(&mut rng),
out_peers: Uniform::new_inclusive(0, 25).sample(&mut rng), out_peers: Uniform::new_inclusive(0, 25).sample(&mut rng),
@@ -83,8 +83,8 @@ pub enum NodeRole {
LightClient, LightClient,
/// The node is an authority /// The node is an authority
Authority, Authority,
/// An unknown role with a bit number /// The node is a sentry
UnknownRole(u8) Sentry,
} }
#[cfg(test)] #[cfg(test)]
+2 -2
View File
@@ -17,7 +17,7 @@
use super::*; use super::*;
use sc_network::{self, PeerId}; use sc_network::{self, PeerId};
use sc_network::config::Roles; use sc_network::config::Role;
use substrate_test_runtime_client::runtime::Block; use substrate_test_runtime_client::runtime::Block;
use assert_matches::assert_matches; use assert_matches::assert_matches;
use futures::{prelude::*, channel::mpsc}; use futures::{prelude::*, channel::mpsc};
@@ -60,7 +60,7 @@ fn api<T: Into<Option<Status>>>(sync: T) -> System<Block> {
for _peer in 0..status.peers { for _peer in 0..status.peers {
peers.push(PeerInfo { peers.push(PeerInfo {
peer_id: status.peer_id.to_base58(), peer_id: status.peer_id.to_base58(),
roles: format!("{:?}", Roles::FULL), roles: format!("{}", Role::Full),
protocol_version: 1, protocol_version: 1,
best_hash: Default::default(), best_hash: Default::default(),
best_number: 1, best_number: 1,
+15 -8
View File
@@ -35,7 +35,7 @@ use futures::{
}; };
use sc_keystore::{Store as Keystore}; use sc_keystore::{Store as Keystore};
use log::{info, warn, error}; use log::{info, warn, error};
use sc_network::config::{FinalityProofProvider, OnDemand, BoxFinalityProofRequestBuilder}; use sc_network::config::{Role, FinalityProofProvider, OnDemand, BoxFinalityProofRequestBuilder};
use sc_network::{NetworkService, NetworkStateInfo}; use sc_network::{NetworkService, NetworkStateInfo};
use parking_lot::{Mutex, RwLock}; use parking_lot::{Mutex, RwLock};
use sp_runtime::generic::BlockId; use sp_runtime::generic::BlockId;
@@ -840,7 +840,7 @@ ServiceBuilder<
.register_transaction_pool(Arc::downgrade(&transaction_pool) as _); .register_transaction_pool(Arc::downgrade(&transaction_pool) as _);
let transaction_pool_adapter = Arc::new(TransactionPoolAdapter { let transaction_pool_adapter = Arc::new(TransactionPoolAdapter {
imports_external_transactions: !config.roles.is_light(), imports_external_transactions: !matches!(config.role, Role::Light),
pool: transaction_pool.clone(), pool: transaction_pool.clone(),
client: client.clone(), client: client.clone(),
executor: tasks_builder.spawn_handle(), executor: tasks_builder.spawn_handle(),
@@ -863,7 +863,7 @@ ServiceBuilder<
Box::new(sp_consensus::block_validation::DefaultBlockAnnounceValidator::new(client.clone())); Box::new(sp_consensus::block_validation::DefaultBlockAnnounceValidator::new(client.clone()));
let network_params = sc_network::config::Params { let network_params = sc_network::config::Params {
roles: config.roles, role: config.role.clone(),
executor: { executor: {
let spawn_handle = tasks_builder.spawn_handle(); let spawn_handle = tasks_builder.spawn_handle();
Some(Box::new(move |fut| { Some(Box::new(move |fut| {
@@ -913,7 +913,7 @@ ServiceBuilder<
let offchain = offchain_workers.as_ref().map(Arc::downgrade); let offchain = offchain_workers.as_ref().map(Arc::downgrade);
let notifications_spawn_handle = tasks_builder.spawn_handle(); let notifications_spawn_handle = tasks_builder.spawn_handle();
let network_state_info: Arc<dyn NetworkStateInfo + Send + Sync> = network.clone(); let network_state_info: Arc<dyn NetworkStateInfo + Send + Sync> = network.clone();
let is_validator = config.roles.is_authority(); let is_validator = config.role.is_authority();
let (import_stream, finality_stream) = ( let (import_stream, finality_stream) = (
client.import_notification_stream().map(|n| ChainEvent::NewBlock { client.import_notification_stream().map(|n| ChainEvent::NewBlock {
@@ -1003,9 +1003,16 @@ ServiceBuilder<
.const_label("version", config.impl_version) .const_label("version", config.impl_version)
.const_label("commit", config.impl_commit), .const_label("commit", config.impl_commit),
)?, &registry)?.set(1); )?, &registry)?.set(1);
let role_bits = match config.role {
Role::Full => 1,
Role::Light => 2,
Role::Sentry { .. } => 3,
Role::Authority { .. } => 4,
};
register(Gauge::<U64>::new( register(Gauge::<U64>::new(
"node_roles", "The roles the node is running as", "node_role", "The role the node is running as",
)?, &registry)?.set(u64::from(config.roles.bits())); )?, &registry)?.set(role_bits);
let metrics = ServiceMetrics::register(&registry)?; let metrics = ServiceMetrics::register(&registry)?;
@@ -1198,7 +1205,7 @@ ServiceBuilder<
spawn_handle.spawn( spawn_handle.spawn(
"network-worker", "network-worker",
build_network_future( build_network_future(
config.roles, config.role.clone(),
network_mut, network_mut,
client.clone(), client.clone(),
network_status_sinks.clone(), network_status_sinks.clone(),
@@ -1212,7 +1219,7 @@ ServiceBuilder<
// Telemetry // Telemetry
let telemetry = config.telemetry_endpoints.clone().map(|endpoints| { let telemetry = config.telemetry_endpoints.clone().map(|endpoints| {
let is_authority = config.roles.is_authority(); let is_authority = config.role.is_authority();
let network_id = network.local_peer_id().to_base58(); let network_id = network.local_peer_id().to_base58();
let name = config.name.clone(); let name = config.name.clone();
let impl_name = config.impl_name.to_owned(); let impl_name = config.impl_name.to_owned();
+6 -17
View File
@@ -18,7 +18,7 @@
pub use sc_client::ExecutionStrategies; pub use sc_client::ExecutionStrategies;
pub use sc_client_db::{kvdb::KeyValueDB, PruningMode}; pub use sc_client_db::{kvdb::KeyValueDB, PruningMode};
pub use sc_network::config::{ExtTransport, NetworkConfiguration, Roles}; pub use sc_network::{Multiaddr, config::{MultiaddrWithPeerId, ExtTransport, NetworkConfiguration, Role}};
pub use sc_executor::WasmExecutionMethod; pub use sc_executor::WasmExecutionMethod;
use std::{future::Future, path::{PathBuf, Path}, pin::Pin, net::SocketAddr, sync::Arc}; use std::{future::Future, path::{PathBuf, Path}, pin::Pin, net::SocketAddr, sync::Arc};
@@ -58,8 +58,8 @@ pub struct Configuration {
pub impl_version: &'static str, pub impl_version: &'static str,
/// Git commit if any. /// Git commit if any.
pub impl_commit: &'static str, pub impl_commit: &'static str,
/// Node roles. /// Node role.
pub roles: Roles, pub role: Role,
/// How to spawn background tasks. Mandatory, otherwise creating a `Service` will error. /// How to spawn background tasks. Mandatory, otherwise creating a `Service` will error.
pub task_executor: Option<Arc<dyn Fn(Pin<Box<dyn Future<Output = ()> + Send>>) + Send + Sync>>, pub task_executor: Option<Arc<dyn Fn(Pin<Box<dyn Future<Output = ()> + Send>>) + Send + Sync>>,
/// Extrinsic pool configuration. /// Extrinsic pool configuration.
@@ -105,10 +105,6 @@ pub struct Configuration {
pub default_heap_pages: Option<u64>, pub default_heap_pages: Option<u64>,
/// Should offchain workers be executed. /// Should offchain workers be executed.
pub offchain_worker: bool, pub offchain_worker: bool,
/// Sentry mode is enabled, the node's role is AUTHORITY but it should not
/// actively participate in consensus (i.e. no keystores should be passed to
/// consensus modules).
pub sentry_mode: bool,
/// Enable authoring even when offline. /// Enable authoring even when offline.
pub force_authoring: bool, pub force_authoring: bool,
/// Disable GRANDPA when running in validator mode /// Disable GRANDPA when running in validator mode
@@ -204,7 +200,7 @@ impl Default for Configuration {
chain_spec: None, chain_spec: None,
config_dir: None, config_dir: None,
name: Default::default(), name: Default::default(),
roles: Roles::FULL, role: Role::Full,
task_executor: None, task_executor: None,
transaction_pool: Default::default(), transaction_pool: Default::default(),
network: Default::default(), network: Default::default(),
@@ -224,7 +220,6 @@ impl Default for Configuration {
telemetry_external_transport: None, telemetry_external_transport: None,
default_heap_pages: None, default_heap_pages: None,
offchain_worker: Default::default(), offchain_worker: Default::default(),
sentry_mode: false,
force_authoring: false, force_authoring: false,
disable_grandpa: false, disable_grandpa: false,
dev_key_seed: None, dev_key_seed: None,
@@ -286,15 +281,9 @@ impl Configuration {
self.database.as_ref().expect("database must be specified") self.database.as_ref().expect("database must be specified")
} }
/// Returns a string displaying the node role, special casing the sentry mode /// Returns a string displaying the node role.
/// (returning `SENTRY`), since the node technically has an `AUTHORITY` role but
/// doesn't participate.
pub fn display_role(&self) -> String { pub fn display_role(&self) -> String {
if self.sentry_mode { self.role.to_string()
"SENTRY".to_string()
} else {
self.roles.to_string()
}
} }
/// Use in memory keystore config when it is not required at all. /// Use in memory keystore config when it is not required at all.
+9 -12
View File
@@ -58,7 +58,7 @@ pub use self::builder::{
ServiceBuilder, ServiceBuilderCommand, TFullClient, TLightClient, TFullBackend, TLightBackend, ServiceBuilder, ServiceBuilderCommand, TFullClient, TLightClient, TFullBackend, TLightBackend,
TFullCallExecutor, TLightCallExecutor, TFullCallExecutor, TLightCallExecutor,
}; };
pub use config::{Configuration, Roles, PruningMode, DatabaseConfig}; pub use config::{Configuration, Role, PruningMode, DatabaseConfig};
pub use sc_chain_spec::{ pub use sc_chain_spec::{
ChainSpec, GenericChainSpec, Properties, RuntimeGenesis, Extension as ChainSpecExtension ChainSpec, GenericChainSpec, Properties, RuntimeGenesis, Extension as ChainSpecExtension
}; };
@@ -322,7 +322,7 @@ fn build_network_future<
C: sc_client::BlockchainEvents<B>, C: sc_client::BlockchainEvents<B>,
H: sc_network::ExHashT H: sc_network::ExHashT
> ( > (
roles: Roles, role: Role,
mut network: sc_network::NetworkWorker<B, H>, mut network: sc_network::NetworkWorker<B, H>,
client: Arc<C>, client: Arc<C>,
status_sinks: Arc<Mutex<status_sinks::StatusSinks<(NetworkStatus<B>, NetworkState)>>>, status_sinks: Arc<Mutex<status_sinks::StatusSinks<(NetworkStatus<B>, NetworkState)>>>,
@@ -399,17 +399,14 @@ fn build_network_future<
sc_rpc::system::Request::NodeRoles(sender) => { sc_rpc::system::Request::NodeRoles(sender) => {
use sc_rpc::system::NodeRole; use sc_rpc::system::NodeRole;
let node_roles = (0 .. 8) let node_role = match role {
.filter(|&bit_number| (roles.bits() >> bit_number) & 1 == 1) Role::Authority { .. } => NodeRole::Authority,
.map(|bit_number| match Roles::from_bits(1 << bit_number) { Role::Light => NodeRole::LightClient,
Some(Roles::AUTHORITY) => NodeRole::Authority, Role::Full => NodeRole::Full,
Some(Roles::LIGHT) => NodeRole::LightClient, Role::Sentry { .. } => NodeRole::Sentry,
Some(Roles::FULL) => NodeRole::Full, };
_ => NodeRole::UnknownRole(bit_number),
})
.collect();
let _ = sender.send(node_roles); let _ = sender.send(vec![node_role]);
} }
}; };
} }
+6 -8
View File
@@ -34,7 +34,7 @@ use sc_service::{
Configuration, Configuration,
config::{DatabaseConfig, KeystoreConfig}, config::{DatabaseConfig, KeystoreConfig},
RuntimeGenesis, RuntimeGenesis,
Roles, Role,
Error, Error,
}; };
use sc_network::{multiaddr, Multiaddr, NetworkStateInfo}; use sc_network::{multiaddr, Multiaddr, NetworkStateInfo};
@@ -134,7 +134,7 @@ where F: Send + 'static, L: Send +'static, U: Clone + Send + 'static
fn node_config<G: RuntimeGenesis + 'static, E: ChainSpecExtension + Clone + 'static + Send> ( fn node_config<G: RuntimeGenesis + 'static, E: ChainSpecExtension + Clone + 'static + Send> (
index: usize, index: usize,
spec: &GenericChainSpec<G, E>, spec: &GenericChainSpec<G, E>,
role: Roles, role: Role,
task_executor: Arc<dyn Fn(Pin<Box<dyn futures::Future<Output = ()> + Send>>) + Send + Sync>, task_executor: Arc<dyn Fn(Pin<Box<dyn futures::Future<Output = ()> + Send>>) + Send + Sync>,
key_seed: Option<String>, key_seed: Option<String>,
base_port: u16, base_port: u16,
@@ -161,7 +161,6 @@ fn node_config<G: RuntimeGenesis + 'static, E: ChainSpecExtension + Clone + 'sta
out_peers: 450, out_peers: 450,
reserved_nodes: vec![], reserved_nodes: vec![],
non_reserved_mode: NonReservedPeerMode::Accept, non_reserved_mode: NonReservedPeerMode::Accept,
sentry_nodes: vec![],
client_version: "network/test/0.1".to_owned(), client_version: "network/test/0.1".to_owned(),
node_name: "unknown".to_owned(), node_name: "unknown".to_owned(),
transport: TransportConfig::Normal { transport: TransportConfig::Normal {
@@ -177,7 +176,7 @@ fn node_config<G: RuntimeGenesis + 'static, E: ChainSpecExtension + Clone + 'sta
impl_name: "network-test-impl", impl_name: "network-test-impl",
impl_version: "0.1", impl_version: "0.1",
impl_commit: "", impl_commit: "",
roles: role, role,
task_executor: Some(task_executor), task_executor: Some(task_executor),
transaction_pool: Default::default(), transaction_pool: Default::default(),
network: network_config, network: network_config,
@@ -206,7 +205,6 @@ fn node_config<G: RuntimeGenesis + 'static, E: ChainSpecExtension + Clone + 'sta
telemetry_external_transport: None, telemetry_external_transport: None,
default_heap_pages: None, default_heap_pages: None,
offchain_worker: false, offchain_worker: false,
sentry_mode: false,
force_authoring: false, force_authoring: false,
disable_grandpa: false, disable_grandpa: false,
dev_key_seed: key_seed, dev_key_seed: key_seed,
@@ -267,7 +265,7 @@ impl<G, E, F, L, U> TestNet<G, E, F, L, U> where
let node_config = node_config( let node_config = node_config(
self.nodes, self.nodes,
&self.chain_spec, &self.chain_spec,
Roles::AUTHORITY, Role::Authority { sentry_nodes: Vec::new() },
task_executor, task_executor,
Some(key), Some(key),
self.base_port, self.base_port,
@@ -288,7 +286,7 @@ impl<G, E, F, L, U> TestNet<G, E, F, L, U> where
let executor = executor.clone(); let executor = executor.clone();
Arc::new(move |fut: Pin<Box<dyn futures::Future<Output = ()> + Send>>| executor.spawn(fut.unit_error().compat())) Arc::new(move |fut: Pin<Box<dyn futures::Future<Output = ()> + Send>>| executor.spawn(fut.unit_error().compat()))
}; };
let node_config = node_config(self.nodes, &self.chain_spec, Roles::FULL, task_executor, None, self.base_port, &temp); let node_config = node_config(self.nodes, &self.chain_spec, Role::Full, task_executor, None, self.base_port, &temp);
let addr = node_config.network.listen_addresses.iter().next().unwrap().clone(); let addr = node_config.network.listen_addresses.iter().next().unwrap().clone();
let (service, user_data) = full(node_config).expect("Error creating test node service"); let (service, user_data) = full(node_config).expect("Error creating test node service");
let service = SyncService::from(service); let service = SyncService::from(service);
@@ -304,7 +302,7 @@ impl<G, E, F, L, U> TestNet<G, E, F, L, U> where
let executor = executor.clone(); let executor = executor.clone();
Arc::new(move |fut: Pin<Box<dyn futures::Future<Output = ()> + Send>>| executor.spawn(fut.unit_error().compat())) Arc::new(move |fut: Pin<Box<dyn futures::Future<Output = ()> + Send>>| executor.spawn(fut.unit_error().compat()))
}; };
let node_config = node_config(self.nodes, &self.chain_spec, Roles::LIGHT, task_executor, None, self.base_port, &temp); let node_config = node_config(self.nodes, &self.chain_spec, Role::Light, task_executor, None, self.base_port, &temp);
let addr = node_config.network.listen_addresses.iter().next().unwrap().clone(); let addr = node_config.network.listen_addresses.iter().next().unwrap().clone();
let service = SyncService::from(light(node_config).expect("Error creating test node service")); let service = SyncService::from(light(node_config).expect("Error creating test node service"));
+2 -2
View File
@@ -18,7 +18,7 @@ use futures01::sync::mpsc as mpsc01;
use log::{debug, info}; use log::{debug, info};
use std::sync::Arc; use std::sync::Arc;
use sc_service::{ use sc_service::{
AbstractService, RpcSession, Roles, Configuration, config::{DatabaseConfig, KeystoreConfig}, AbstractService, RpcSession, Role, Configuration, config::{DatabaseConfig, KeystoreConfig},
GenericChainSpec, RuntimeGenesis GenericChainSpec, RuntimeGenesis
}; };
use wasm_bindgen::prelude::*; use wasm_bindgen::prelude::*;
@@ -57,7 +57,7 @@ where
wasm_bindgen_futures::spawn_local(fut) wasm_bindgen_futures::spawn_local(fut)
})); }));
config.telemetry_external_transport = Some(transport); config.telemetry_external_transport = Some(transport);
config.roles = Roles::LIGHT; config.role = Role::Light;
config.name = format!("{} (Browser)", name); config.name = format!("{} (Browser)", name);
config.database = Some({ config.database = Some({
info!("Opening Indexed DB database '{}'...", name); info!("Opening Indexed DB database '{}'...", name);