mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-04-29 12:37:57 +00:00
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:
@@ -72,16 +72,11 @@ macro_rules! new_full_start {
|
||||
pub fn new_full(config: Configuration)
|
||||
-> Result<impl AbstractService, ServiceError>
|
||||
{
|
||||
let is_authority = config.roles.is_authority();
|
||||
let role = config.role.clone();
|
||||
let force_authoring = config.force_authoring;
|
||||
let name = config.name.clone();
|
||||
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 (block_import, grandpa_link) =
|
||||
@@ -96,11 +91,9 @@ pub fn new_full(config: Configuration)
|
||||
})?
|
||||
.build()?;
|
||||
|
||||
if participates_in_consensus {
|
||||
let proposer = sc_basic_authorship::ProposerFactory::new(
|
||||
service.client(),
|
||||
service.transaction_pool()
|
||||
);
|
||||
if role.is_authority() {
|
||||
let proposer =
|
||||
sc_basic_authorship::ProposerFactory::new(service.client(), service.transaction_pool());
|
||||
|
||||
let client = service.client();
|
||||
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
|
||||
// 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())
|
||||
} else {
|
||||
None
|
||||
@@ -142,7 +135,7 @@ pub fn new_full(config: Configuration)
|
||||
name: Some(name),
|
||||
observer_enabled: false,
|
||||
keystore,
|
||||
is_authority,
|
||||
is_authority: role.is_network_authority(),
|
||||
};
|
||||
|
||||
let enable_grandpa = !disable_grandpa;
|
||||
|
||||
@@ -45,7 +45,7 @@ async fn start_inner(chain_spec: String, log_level: String) -> Result<Client, Bo
|
||||
info!("❤️ by Parity Technologies, 2017-2020");
|
||||
info!("📋 Chain specification: {}", config.expect_chain_spec().name());
|
||||
info!("🏷 Node name: {}", config.name);
|
||||
info!("👤 Roles: {:?}", config.roles);
|
||||
info!("👤 Role: {:?}", config.role);
|
||||
|
||||
// Create the service. This is the most heavy initialization step.
|
||||
let service = crate::service::new_light(config)
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
// along with Substrate. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
use sc_cli::VersionInfo;
|
||||
use sc_service::{Roles as ServiceRoles};
|
||||
use sc_service::{Role as ServiceRole};
|
||||
use node_transaction_factory::RuntimeAdapter;
|
||||
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.import_params.update_config(
|
||||
&mut config,
|
||||
ServiceRoles::FULL,
|
||||
&ServiceRole::Full,
|
||||
cli_args.shared_params.dev,
|
||||
)?;
|
||||
|
||||
|
||||
@@ -120,24 +120,17 @@ macro_rules! new_full {
|
||||
use sc_client_api::ExecutorProvider;
|
||||
|
||||
let (
|
||||
is_authority,
|
||||
role,
|
||||
force_authoring,
|
||||
name,
|
||||
disable_grandpa,
|
||||
sentry_nodes,
|
||||
) = (
|
||||
$config.roles.is_authority(),
|
||||
$config.role.clone(),
|
||||
$config.force_authoring,
|
||||
$config.name.clone(),
|
||||
$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 service = builder
|
||||
@@ -153,7 +146,7 @@ macro_rules! new_full {
|
||||
|
||||
($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(
|
||||
service.client(),
|
||||
service.transaction_pool()
|
||||
@@ -190,7 +183,7 @@ macro_rules! new_full {
|
||||
let authority_discovery = sc_authority_discovery::AuthorityDiscovery::new(
|
||||
service.client(),
|
||||
network,
|
||||
sentry_nodes,
|
||||
sentry_nodes.clone(),
|
||||
service.keystore(),
|
||||
dht_event_stream,
|
||||
service.prometheus_registry(),
|
||||
@@ -201,7 +194,7 @@ macro_rules! new_full {
|
||||
|
||||
// if the node isn't actively participating in consensus then it doesn't
|
||||
// need a keystore, regardless of which protocol we use below.
|
||||
let keystore = if participates_in_consensus {
|
||||
let keystore = if role.is_authority() {
|
||||
Some(service.keystore())
|
||||
} else {
|
||||
None
|
||||
@@ -214,7 +207,7 @@ macro_rules! new_full {
|
||||
name: Some(name),
|
||||
observer_enabled: false,
|
||||
keystore,
|
||||
is_authority,
|
||||
is_authority: role.is_network_authority(),
|
||||
};
|
||||
|
||||
let enable_grandpa = !disable_grandpa;
|
||||
|
||||
@@ -45,7 +45,7 @@ impl InspectCmd {
|
||||
// and all import params (especially pruning that has to match db meta)
|
||||
self.import_params.update_config(
|
||||
&mut config,
|
||||
sc_service::Roles::FULL,
|
||||
&sc_service::Role::Full,
|
||||
self.shared_params.dev,
|
||||
)?;
|
||||
|
||||
|
||||
@@ -56,12 +56,11 @@ use futures_timer::Delay;
|
||||
|
||||
use codec::{Decode, Encode};
|
||||
use error::{Error, Result};
|
||||
use libp2p::Multiaddr;
|
||||
use log::{debug, error, log_enabled, warn};
|
||||
use prometheus_endpoint::{Counter, CounterVec, Gauge, Opts, U64, register};
|
||||
use prost::Message;
|
||||
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_core::crypto::{key_types, CryptoTypePublicPair, Pair};
|
||||
use sp_core::traits::BareCryptoStorePtr;
|
||||
@@ -187,7 +186,7 @@ where
|
||||
pub fn new(
|
||||
client: Arc<Client>,
|
||||
network: Arc<Network>,
|
||||
sentry_nodes: Vec<String>,
|
||||
sentry_nodes: Vec<MultiaddrWithPeerId>,
|
||||
key_store: BareCryptoStorePtr,
|
||||
dht_event_rx: Pin<Box<dyn Stream<Item = DhtEvent> + Send>>,
|
||||
prometheus_registry: Option<prometheus_endpoint::Registry>,
|
||||
@@ -210,18 +209,7 @@ where
|
||||
);
|
||||
|
||||
let sentry_nodes = if !sentry_nodes.is_empty() {
|
||||
let addrs = sentry_nodes.into_iter().filter_map(|a| match a.parse() {
|
||||
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)
|
||||
Some(sentry_nodes.into_iter().map(|ma| ma.concat()).collect::<Vec<_>>())
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
@@ -27,7 +27,7 @@ use sp_runtime::BuildStorage;
|
||||
use serde_json as json;
|
||||
use crate::RuntimeGenesis;
|
||||
use crate::extension::GetExtension;
|
||||
use sc_network::Multiaddr;
|
||||
use sc_network::config::MultiaddrWithPeerId;
|
||||
use sc_telemetry::TelemetryEndpoints;
|
||||
|
||||
enum GenesisSource<G> {
|
||||
@@ -137,7 +137,7 @@ enum Genesis<G> {
|
||||
struct ClientSpec<E> {
|
||||
name: String,
|
||||
id: String,
|
||||
boot_nodes: Vec<String>,
|
||||
boot_nodes: Vec<MultiaddrWithPeerId>,
|
||||
telemetry_endpoints: Option<TelemetryEndpoints>,
|
||||
protocol_id: Option<String>,
|
||||
properties: Option<Properties>,
|
||||
@@ -174,7 +174,7 @@ impl<G, E: Clone> Clone for ChainSpec<G, E> {
|
||||
|
||||
impl<G, E> ChainSpec<G, E> {
|
||||
/// A list of bootnode addresses.
|
||||
pub fn boot_nodes(&self) -> &[String] {
|
||||
pub fn boot_nodes(&self) -> &[MultiaddrWithPeerId] {
|
||||
&self.client_spec.boot_nodes
|
||||
}
|
||||
|
||||
@@ -206,8 +206,8 @@ impl<G, E> ChainSpec<G, E> {
|
||||
}
|
||||
|
||||
/// Add a bootnode to the list.
|
||||
pub fn add_boot_node(&mut self, addr: Multiaddr) {
|
||||
self.client_spec.boot_nodes.push(addr.to_string())
|
||||
pub fn add_boot_node(&mut self, addr: MultiaddrWithPeerId) {
|
||||
self.client_spec.boot_nodes.push(addr)
|
||||
}
|
||||
|
||||
/// Returns a reference to defined chain spec extensions.
|
||||
@@ -220,7 +220,7 @@ impl<G, E> ChainSpec<G, E> {
|
||||
name: &str,
|
||||
id: &str,
|
||||
constructor: F,
|
||||
boot_nodes: Vec<String>,
|
||||
boot_nodes: Vec<MultiaddrWithPeerId>,
|
||||
telemetry_endpoints: Option<TelemetryEndpoints>,
|
||||
protocol_id: Option<&str>,
|
||||
properties: Option<Properties>,
|
||||
@@ -320,7 +320,7 @@ where
|
||||
G: RuntimeGenesis,
|
||||
E: GetExtension + serde::Serialize + Clone + Send,
|
||||
{
|
||||
fn boot_nodes(&self) -> &[String] {
|
||||
fn boot_nodes(&self) -> &[MultiaddrWithPeerId] {
|
||||
ChainSpec::boot_nodes(self)
|
||||
}
|
||||
|
||||
@@ -344,7 +344,7 @@ where
|
||||
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)
|
||||
}
|
||||
|
||||
|
||||
@@ -117,7 +117,7 @@ pub use sc_chain_spec_derive::{ChainSpecExtension, ChainSpecGroup};
|
||||
|
||||
use serde::{Serialize, de::DeserializeOwned};
|
||||
use sp_runtime::BuildStorage;
|
||||
use sc_network::Multiaddr;
|
||||
use sc_network::config::MultiaddrWithPeerId;
|
||||
use sc_telemetry::TelemetryEndpoints;
|
||||
|
||||
/// A set of traits for the runtime genesis config.
|
||||
@@ -131,7 +131,7 @@ pub trait ChainSpec: BuildStorage + Send {
|
||||
/// Spec id.
|
||||
fn id(&self) -> &str;
|
||||
/// A list of bootnode addresses.
|
||||
fn boot_nodes(&self) -> &[String];
|
||||
fn boot_nodes(&self) -> &[MultiaddrWithPeerId];
|
||||
/// Telemetry endpoints (if any)
|
||||
fn telemetry_endpoints(&self) -> &Option<TelemetryEndpoints>;
|
||||
/// Network protocol id.
|
||||
@@ -143,7 +143,7 @@ pub trait ChainSpec: BuildStorage + Send {
|
||||
/// Returns a reference to defined chain spec extensions.
|
||||
fn extensions(&self) -> &dyn GetExtension;
|
||||
/// 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.
|
||||
fn as_json(&self, raw: bool) -> Result<String, String>;
|
||||
/// Return StorageBuilder for this spec.
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
|
||||
use structopt::StructOpt;
|
||||
use log::info;
|
||||
use sc_network::config::build_multiaddr;
|
||||
use sc_network::config::{build_multiaddr, MultiaddrWithPeerId};
|
||||
use sc_service::{Configuration, ChainSpec};
|
||||
|
||||
use crate::error;
|
||||
@@ -60,11 +60,10 @@ impl BuildSpecCmd {
|
||||
if spec.boot_nodes().is_empty() && !self.disable_default_bootnode {
|
||||
let keys = config.network.node_key.into_keypair()?;
|
||||
let peer_id = keys.public().into_peer_id();
|
||||
let addr = build_multiaddr![
|
||||
Ip4([127, 0, 0, 1]),
|
||||
Tcp(30333u16),
|
||||
P2p(peer_id)
|
||||
];
|
||||
let addr = MultiaddrWithPeerId {
|
||||
multiaddr: build_multiaddr![Ip4([127, 0, 0, 1]), Tcp(30333u16)],
|
||||
peer_id,
|
||||
};
|
||||
spec.add_boot_node(addr)
|
||||
}
|
||||
|
||||
|
||||
@@ -18,7 +18,7 @@ use std::fmt::Debug;
|
||||
use std::str::FromStr;
|
||||
use structopt::StructOpt;
|
||||
use sc_service::{
|
||||
Configuration, ServiceBuilderCommand, Roles, ChainSpec,
|
||||
Configuration, ServiceBuilderCommand, Role, ChainSpec,
|
||||
};
|
||||
use sp_runtime::traits::{Block as BlockT, Header as HeaderT};
|
||||
use sp_runtime::generic::BlockId;
|
||||
@@ -93,7 +93,7 @@ impl CheckBlockCmd {
|
||||
F: FnOnce(&str) -> Result<Box<dyn ChainSpec>, String>,
|
||||
{
|
||||
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()?;
|
||||
|
||||
Ok(())
|
||||
|
||||
@@ -22,7 +22,7 @@ use log::info;
|
||||
use structopt::StructOpt;
|
||||
use sc_service::{
|
||||
Configuration, ServiceBuilderCommand, ChainSpec,
|
||||
config::DatabaseConfig, Roles,
|
||||
config::DatabaseConfig, Role,
|
||||
};
|
||||
use sp_runtime::traits::{Block as BlockT, Header as HeaderT};
|
||||
|
||||
@@ -105,7 +105,7 @@ impl ExportBlocksCmd {
|
||||
F: FnOnce(&str) -> Result<Box<dyn ChainSpec>, String>,
|
||||
{
|
||||
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()?;
|
||||
|
||||
Ok(())
|
||||
|
||||
@@ -20,7 +20,7 @@ use std::fs;
|
||||
use std::path::PathBuf;
|
||||
use structopt::StructOpt;
|
||||
use sc_service::{
|
||||
Configuration, ServiceBuilderCommand, ChainSpec, Roles,
|
||||
Configuration, ServiceBuilderCommand, ChainSpec, Role,
|
||||
};
|
||||
use sp_runtime::traits::{Block as BlockT, Header as HeaderT};
|
||||
|
||||
@@ -95,7 +95,7 @@ impl ImportBlocksCmd {
|
||||
F: FnOnce(&str) -> Result<Box<dyn ChainSpec>, String>,
|
||||
{
|
||||
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()?;
|
||||
|
||||
Ok(())
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
use std::fmt::Debug;
|
||||
use structopt::StructOpt;
|
||||
use sc_service::{
|
||||
Configuration, ServiceBuilderCommand, ChainSpec, Roles,
|
||||
Configuration, ServiceBuilderCommand, ChainSpec, Role,
|
||||
};
|
||||
use sp_runtime::traits::{Block as BlockT, Header as HeaderT};
|
||||
|
||||
@@ -71,7 +71,7 @@ impl RevertCmd {
|
||||
F: FnOnce(&str) -> Result<Box<dyn ChainSpec>, String>,
|
||||
{
|
||||
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()?;
|
||||
|
||||
Ok(())
|
||||
|
||||
@@ -23,8 +23,8 @@ use names::{Generator, Name};
|
||||
use regex::Regex;
|
||||
use chrono::prelude::*;
|
||||
use sc_service::{
|
||||
AbstractService, Configuration, ChainSpec, Roles,
|
||||
config::{KeystoreConfig, PrometheusConfig},
|
||||
AbstractService, Configuration, ChainSpec, Role,
|
||||
config::{MultiaddrWithPeerId, KeystoreConfig, PrometheusConfig},
|
||||
};
|
||||
use sc_telemetry::TelemetryEndpoints;
|
||||
|
||||
@@ -78,9 +78,10 @@ pub struct RunCmd {
|
||||
/// available to relay to private nodes.
|
||||
#[structopt(
|
||||
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.
|
||||
#[structopt(long = "no-grandpa")]
|
||||
@@ -329,18 +330,20 @@ impl RunCmd {
|
||||
let keyring = self.get_keyring();
|
||||
let is_dev = self.shared_params.dev;
|
||||
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;
|
||||
let role =
|
||||
if is_light {
|
||||
sc_service::Roles::LIGHT
|
||||
sc_service::Role::Light
|
||||
} 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 {
|
||||
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) {
|
||||
(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.sentry_mode = self.sentry;
|
||||
|
||||
config.offchain_worker = match (&self.offchain_worker, role) {
|
||||
(OffchainWorkerEnabled::WhenValidating, sc_service::Roles::AUTHORITY) => true,
|
||||
config.offchain_worker = match (&self.offchain_worker, &role) {
|
||||
(OffchainWorkerEnabled::WhenValidating, sc_service::Role::Authority { .. }) => true,
|
||||
(OffchainWorkerEnabled::Always, _) => true,
|
||||
(OffchainWorkerEnabled::Never, _) => false,
|
||||
(OffchainWorkerEnabled::WhenValidating, _) => false,
|
||||
};
|
||||
|
||||
config.roles = role;
|
||||
config.role = role;
|
||||
config.disable_grandpa = self.no_grandpa;
|
||||
|
||||
let client_id = config.client_id();
|
||||
@@ -463,10 +463,10 @@ impl RunCmd {
|
||||
info!("❤️ by {}, {}-{}", version.author, version.copyright_start_year, Local::today().year());
|
||||
info!("📋 Chain specification: {}", config.expect_chain_spec().name());
|
||||
info!("🏷 Node name: {}", config.name);
|
||||
info!("👤 Roles: {}", config.display_role());
|
||||
info!("👤 Role: {}", config.display_role());
|
||||
|
||||
match config.roles {
|
||||
Roles::LIGHT => run_service_until_exit(
|
||||
match config.role {
|
||||
Role::Light => run_service_until_exit(
|
||||
config,
|
||||
new_light,
|
||||
),
|
||||
@@ -688,7 +688,7 @@ mod tests {
|
||||
"test",
|
||||
"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)])
|
||||
.expect("provided url should be valid")),
|
||||
None,
|
||||
|
||||
@@ -82,7 +82,7 @@ impl ImportParams {
|
||||
pub fn update_config(
|
||||
&self,
|
||||
mut config: &mut Configuration,
|
||||
role: sc_service::Roles,
|
||||
role: &sc_service::Role,
|
||||
is_dev: bool,
|
||||
) -> error::Result<()> {
|
||||
use sc_client_api::execution_extensions::ExecutionStrategies;
|
||||
|
||||
@@ -19,7 +19,7 @@ use std::iter;
|
||||
use std::net::Ipv4Addr;
|
||||
use structopt::StructOpt;
|
||||
use sc_network::{
|
||||
config::{NonReservedPeerMode, TransportConfig}, multiaddr::Protocol,
|
||||
config::{MultiaddrWithPeerId, NonReservedPeerMode, TransportConfig}, multiaddr::Protocol, Multiaddr,
|
||||
};
|
||||
use sc_service::Configuration;
|
||||
|
||||
@@ -30,12 +30,12 @@ use crate::params::node_key_params::NodeKeyParams;
|
||||
#[derive(Debug, StructOpt, Clone)]
|
||||
pub struct NetworkConfigurationParams {
|
||||
/// Specify a list of bootnodes.
|
||||
#[structopt(long = "bootnodes", value_name = "URL")]
|
||||
pub bootnodes: Vec<String>,
|
||||
#[structopt(long = "bootnodes", value_name = "ADDR")]
|
||||
pub bootnodes: Vec<MultiaddrWithPeerId>,
|
||||
|
||||
/// Specify a list of reserved node addresses.
|
||||
#[structopt(long = "reserved-nodes", value_name = "URL")]
|
||||
pub reserved_nodes: Vec<String>,
|
||||
#[structopt(long = "reserved-nodes", value_name = "ADDR")]
|
||||
pub reserved_nodes: Vec<MultiaddrWithPeerId>,
|
||||
|
||||
/// Whether to only allow connections to/from reserved nodes.
|
||||
///
|
||||
@@ -47,14 +47,14 @@ pub struct NetworkConfigurationParams {
|
||||
/// Specify a list of sentry node public addresses.
|
||||
#[structopt(
|
||||
long = "sentry-nodes",
|
||||
value_name = "URL",
|
||||
value_name = "ADDR",
|
||||
conflicts_with_all = &[ "sentry" ]
|
||||
)]
|
||||
pub sentry_nodes: Vec<String>,
|
||||
pub sentry_nodes: Vec<MultiaddrWithPeerId>,
|
||||
|
||||
/// Listen on this multiaddress.
|
||||
#[structopt(long = "listen-addr", value_name = "LISTEN_ADDR")]
|
||||
pub listen_addr: Vec<String>,
|
||||
pub listen_addr: Vec<Multiaddr>,
|
||||
|
||||
/// Specify p2p protocol TCP port.
|
||||
///
|
||||
@@ -117,13 +117,7 @@ impl NetworkConfigurationParams {
|
||||
config.network.non_reserved_mode = NonReservedPeerMode::Deny;
|
||||
}
|
||||
|
||||
config.network.sentry_nodes.extend(self.sentry_nodes.clone());
|
||||
|
||||
for addr in self.listen_addr.iter() {
|
||||
let addr = addr.parse().ok().ok_or(error::Error::InvalidListenMultiaddress)?;
|
||||
config.network.listen_addresses.push(addr);
|
||||
}
|
||||
|
||||
config.network.listen_addresses.extend(self.listen_addr.iter().cloned());
|
||||
if config.network.listen_addresses.is_empty() {
|
||||
let port = match self.port {
|
||||
Some(port) => port,
|
||||
|
||||
@@ -36,7 +36,7 @@ impl PruningParams {
|
||||
pub fn update_config(
|
||||
&self,
|
||||
mut config: &mut Configuration,
|
||||
role: sc_service::Roles,
|
||||
role: &sc_service::Role,
|
||||
unsafe_pruning: bool,
|
||||
) -> error::Result<()> {
|
||||
// by default we disable pruning if the node is an authority (i.e.
|
||||
@@ -45,10 +45,10 @@ impl PruningParams {
|
||||
// unless `unsafe_pruning` is set.
|
||||
config.pruning = match &self.pruning {
|
||||
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(),
|
||||
Some(s) => {
|
||||
if role == sc_service::Roles::AUTHORITY && !unsafe_pruning {
|
||||
if role.is_network_authority() && !unsafe_pruning {
|
||||
return Err(error::Error::Input(
|
||||
"Validators should run with state pruning disabled (i.e. archive). \
|
||||
You can ignore this check with `--unsafe-pruning`.".to_string()
|
||||
|
||||
@@ -84,7 +84,7 @@
|
||||
|
||||
use sp_runtime::traits::{NumberFor, Block as BlockT, Zero};
|
||||
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 sp_finality_grandpa::AuthorityId;
|
||||
|
||||
@@ -439,11 +439,11 @@ impl Misbehavior {
|
||||
|
||||
struct PeerInfo<N> {
|
||||
view: View<N>,
|
||||
roles: Roles,
|
||||
roles: ObservedRole,
|
||||
}
|
||||
|
||||
impl<N> PeerInfo<N> {
|
||||
fn new(roles: Roles) -> Self {
|
||||
fn new(roles: ObservedRole) -> Self {
|
||||
PeerInfo {
|
||||
view: View::default(),
|
||||
roles,
|
||||
@@ -469,14 +469,17 @@ impl<N> Default for Peers<N> {
|
||||
}
|
||||
|
||||
impl<N: Ord> Peers<N> {
|
||||
fn new_peer(&mut self, who: PeerId, roles: Roles) {
|
||||
if roles.is_authority() && self.lucky_authorities.len() < MIN_LUCKY {
|
||||
self.lucky_authorities.insert(who.clone());
|
||||
fn new_peer(&mut self, who: PeerId, role: ObservedRole) {
|
||||
match role {
|
||||
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.lucky_peers.insert(who.clone());
|
||||
}
|
||||
self.inner.insert(who, PeerInfo::new(roles));
|
||||
self.inner.insert(who, PeerInfo::new(role));
|
||||
}
|
||||
|
||||
fn peer_disconnected(&mut self, who: &PeerId) {
|
||||
@@ -539,21 +542,28 @@ impl<N: Ord> Peers<N> {
|
||||
}
|
||||
|
||||
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 {
|
||||
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) {
|
||||
let mut lucky_peers: Vec<_> = self.inner
|
||||
.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();
|
||||
let mut lucky_authorities: Vec<_> = self.inner
|
||||
.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();
|
||||
|
||||
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 {
|
||||
match self {
|
||||
CatchUpConfig::Disabled => false,
|
||||
CatchUpConfig::Enabled { only_from_authorities, .. } =>
|
||||
!only_from_authorities || peer.roles.is_authority(),
|
||||
CatchUpConfig::Enabled { only_from_authorities, .. } => match peer.roles {
|
||||
ObservedRole::Authority | ObservedRole::OurSentry |
|
||||
ObservedRole::OurGuardedAuthority => true,
|
||||
_ => !only_from_authorities
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1121,34 +1134,38 @@ impl<Block: BlockT> Inner<Block> {
|
||||
return false;
|
||||
}
|
||||
|
||||
if peer.roles.is_authority() {
|
||||
let authorities = self.peers.authorities();
|
||||
match peer.roles {
|
||||
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
|
||||
// sending the message to only `sqrt(authorities)` (if we're
|
||||
// connected to at least `MIN_LUCKY`).
|
||||
if round_elapsed < round_duration * PROPAGATION_ALL_AUTHORITIES
|
||||
&& authorities > MIN_LUCKY
|
||||
{
|
||||
self.peers.lucky_authorities.contains(who)
|
||||
} else {
|
||||
// otherwise we already went through the step above, so
|
||||
// we won't filter the message and send it to all
|
||||
// authorities for whom it is polite to do so
|
||||
true
|
||||
}
|
||||
} else {
|
||||
// the node is not an authority so we apply stricter filters
|
||||
if round_elapsed >= round_duration * PROPAGATION_ALL {
|
||||
// if we waited for 3 (or more) rounds
|
||||
// then it is allowed to be sent to all peers.
|
||||
true
|
||||
} else if round_elapsed >= round_duration * PROPAGATION_SOME_NON_AUTHORITIES {
|
||||
// otherwise we only send it to `sqrt(non-authorities)`.
|
||||
self.peers.lucky_peers.contains(who)
|
||||
} else {
|
||||
false
|
||||
}
|
||||
// the target node is an authority, on the first round duration we start by
|
||||
// sending the message to only `sqrt(authorities)` (if we're
|
||||
// connected to at least `MIN_LUCKY`).
|
||||
if round_elapsed < round_duration * PROPAGATION_ALL_AUTHORITIES
|
||||
&& authorities > MIN_LUCKY
|
||||
{
|
||||
self.peers.lucky_authorities.contains(who)
|
||||
} else {
|
||||
// otherwise we already went through the step above, so
|
||||
// we won't filter the message and send it to all
|
||||
// authorities for whom it is polite to do so
|
||||
true
|
||||
}
|
||||
},
|
||||
ObservedRole::Full | ObservedRole::Light => {
|
||||
// the node is not an authority so we apply stricter filters
|
||||
if round_elapsed >= round_duration * PROPAGATION_ALL {
|
||||
// if we waited for 3 (or more) rounds
|
||||
// then it is allowed to be sent to all peers.
|
||||
true
|
||||
} else if round_elapsed >= round_duration * PROPAGATION_SOME_NON_AUTHORITIES {
|
||||
// otherwise we only send it to `sqrt(non-authorities)`.
|
||||
self.peers.lucky_peers.contains(who)
|
||||
} else {
|
||||
false
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1170,38 +1187,42 @@ impl<Block: BlockT> Inner<Block> {
|
||||
let round_duration = self.config.gossip_duration * ROUND_DURATION;
|
||||
let round_elapsed = self.round_start.elapsed();
|
||||
|
||||
if peer.roles.is_authority() {
|
||||
let authorities = self.peers.authorities();
|
||||
match peer.roles {
|
||||
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
|
||||
// sending the message to only `sqrt(authorities)` (if we're
|
||||
// connected to at least `MIN_LUCKY`).
|
||||
if round_elapsed < round_duration * PROPAGATION_ALL_AUTHORITIES
|
||||
&& authorities > MIN_LUCKY
|
||||
{
|
||||
self.peers.lucky_authorities.contains(who)
|
||||
} else {
|
||||
// otherwise we already went through the step above, so
|
||||
// we won't filter the message and send it to all
|
||||
// authorities for whom it is polite to do so
|
||||
true
|
||||
}
|
||||
} else {
|
||||
let non_authorities = self.peers.non_authorities();
|
||||
// the target node is an authority, on the first round duration we start by
|
||||
// sending the message to only `sqrt(authorities)` (if we're
|
||||
// connected to at least `MIN_LUCKY`).
|
||||
if round_elapsed < round_duration * PROPAGATION_ALL_AUTHORITIES
|
||||
&& authorities > MIN_LUCKY
|
||||
{
|
||||
self.peers.lucky_authorities.contains(who)
|
||||
} else {
|
||||
// otherwise we already went through the step above, so
|
||||
// we won't filter the message and send it to all
|
||||
// authorities for whom it is polite to do so
|
||||
true
|
||||
}
|
||||
},
|
||||
ObservedRole::Full | ObservedRole::Light => {
|
||||
let non_authorities = self.peers.non_authorities();
|
||||
|
||||
// the target node is not an authority, on the first and second
|
||||
// round duration we start by sending the message to only
|
||||
// `sqrt(non_authorities)` (if we're connected to at least
|
||||
// `MIN_LUCKY`).
|
||||
if round_elapsed < round_duration * PROPAGATION_SOME_NON_AUTHORITIES
|
||||
&& non_authorities > MIN_LUCKY
|
||||
{
|
||||
self.peers.lucky_peers.contains(who)
|
||||
} else {
|
||||
// otherwise we already went through the step above, so
|
||||
// we won't filter the message and send it to all
|
||||
// non-authorities for whom it is polite to do so
|
||||
true
|
||||
// the target node is not an authority, on the first and second
|
||||
// round duration we start by sending the message to only
|
||||
// `sqrt(non_authorities)` (if we're connected to at least
|
||||
// `MIN_LUCKY`).
|
||||
if round_elapsed < round_duration * PROPAGATION_SOME_NON_AUTHORITIES
|
||||
&& non_authorities > MIN_LUCKY
|
||||
{
|
||||
self.peers.lucky_peers.contains(who)
|
||||
} else {
|
||||
// otherwise we already went through the step above, so
|
||||
// we won't filter the message and send it to all
|
||||
// non-authorities for whom it is polite to do so
|
||||
true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1397,7 +1418,7 @@ impl<Block: BlockT> 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 mut inner = self.inner.write();
|
||||
inner.peers.new_peer(who.clone(), roles);
|
||||
@@ -1657,7 +1678,7 @@ mod tests {
|
||||
assert!(res.unwrap().is_none());
|
||||
|
||||
// connect & disconnect.
|
||||
peers.new_peer(id.clone(), Roles::AUTHORITY);
|
||||
peers.new_peer(id.clone(), ObservedRole::Authority);
|
||||
peers.peer_disconnected(&id);
|
||||
|
||||
let res = peers.update_peer_state(&id, update.clone());
|
||||
@@ -1693,7 +1714,7 @@ mod tests {
|
||||
let mut peers = Peers::default();
|
||||
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 view = peers.update_peer_state(&id, update.clone()).unwrap().unwrap();
|
||||
@@ -1713,7 +1734,7 @@ mod tests {
|
||||
let mut peers = Peers::default();
|
||||
|
||||
let id = PeerId::random();
|
||||
peers.new_peer(id.clone(), Roles::AUTHORITY);
|
||||
peers.new_peer(id.clone(), ObservedRole::Authority);
|
||||
|
||||
peers.update_peer_state(&id, NeighborPacket {
|
||||
round: Round(10),
|
||||
@@ -1914,7 +1935,7 @@ mod tests {
|
||||
// add the peer making the request to the validator,
|
||||
// otherwise it is discarded
|
||||
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(
|
||||
&peer,
|
||||
@@ -1965,7 +1986,7 @@ mod tests {
|
||||
// add the peer making the request to the validator,
|
||||
// otherwise it is discarded
|
||||
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 mut inner = val.inner.write();
|
||||
@@ -2045,7 +2066,7 @@ mod tests {
|
||||
// add the peer making the request to the validator,
|
||||
// otherwise it is discarded.
|
||||
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 (_, _, catch_up_request, _) = val.inner.write().import_neighbor_message(
|
||||
@@ -2119,7 +2140,7 @@ mod tests {
|
||||
// add the peer making the request to the validator,
|
||||
// otherwise it is discarded.
|
||||
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
|
||||
// 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_full = PeerId::random();
|
||||
|
||||
val.inner.write().peers.new_peer(peer_authority.clone(), Roles::AUTHORITY);
|
||||
val.inner.write().peers.new_peer(peer_full.clone(), Roles::FULL);
|
||||
val.inner.write().peers.new_peer(peer_authority.clone(), ObservedRole::Authority);
|
||||
val.inner.write().peers.new_peer(peer_full.clone(), ObservedRole::Full);
|
||||
|
||||
let import_neighbor_message = |peer| {
|
||||
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
|
||||
// discarded.
|
||||
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(
|
||||
&peer_full,
|
||||
@@ -2290,8 +2311,8 @@ mod tests {
|
||||
full_nodes.resize_with(30, || PeerId::random());
|
||||
|
||||
for i in 0..30 {
|
||||
val.inner.write().peers.new_peer(authorities[i].clone(), Roles::AUTHORITY);
|
||||
val.inner.write().peers.new_peer(full_nodes[i].clone(), Roles::FULL);
|
||||
val.inner.write().peers.new_peer(authorities[i].clone(), ObservedRole::Authority);
|
||||
val.inner.write().peers.new_peer(full_nodes[i].clone(), ObservedRole::Full);
|
||||
}
|
||||
|
||||
let test = |num_round, peers| {
|
||||
@@ -2363,7 +2384,7 @@ mod tests {
|
||||
let mut authorities = Vec::new();
|
||||
for _ in 0..5 {
|
||||
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);
|
||||
}
|
||||
|
||||
@@ -2403,7 +2424,7 @@ mod tests {
|
||||
let mut authorities = Vec::new();
|
||||
for _ in 0..100 {
|
||||
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);
|
||||
}
|
||||
|
||||
@@ -2454,7 +2475,7 @@ mod tests {
|
||||
val.inner
|
||||
.write()
|
||||
.peers
|
||||
.new_peer(peer1.clone(), Roles::AUTHORITY);
|
||||
.new_peer(peer1.clone(), ObservedRole::Authority);
|
||||
|
||||
val.inner
|
||||
.write()
|
||||
@@ -2474,7 +2495,7 @@ mod tests {
|
||||
val.inner
|
||||
.write()
|
||||
.peers
|
||||
.new_peer(peer2.clone(), Roles::AUTHORITY);
|
||||
.new_peer(peer2.clone(), ObservedRole::Authority);
|
||||
|
||||
// create a commit for round 1 of set id 1
|
||||
// targeting a block at height 2
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
|
||||
use futures::channel::mpsc;
|
||||
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_gossip::Validator;
|
||||
use std::sync::Arc;
|
||||
@@ -256,7 +256,7 @@ fn good_commit_leads_to_relay() {
|
||||
let test = make_test_network().0
|
||||
.then(move |tester| {
|
||||
// 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))
|
||||
})
|
||||
.then(move |(tester, id)| {
|
||||
@@ -284,7 +284,7 @@ fn good_commit_leads_to_relay() {
|
||||
let _ = sender.unbounded_send(NetworkEvent::NotificationStreamOpened {
|
||||
remote: sender_id.clone(),
|
||||
engine_id: GRANDPA_ENGINE_ID,
|
||||
roles: Roles::FULL,
|
||||
role: ObservedRole::Full,
|
||||
});
|
||||
|
||||
let _ = sender.unbounded_send(NetworkEvent::NotificationsReceived {
|
||||
@@ -297,7 +297,7 @@ fn good_commit_leads_to_relay() {
|
||||
let _ = sender.unbounded_send(NetworkEvent::NotificationStreamOpened {
|
||||
remote: receiver_id.clone(),
|
||||
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
|
||||
@@ -404,7 +404,7 @@ fn bad_commit_leads_to_report() {
|
||||
let test = make_test_network().0
|
||||
.map(move |tester| {
|
||||
// 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)
|
||||
})
|
||||
.then(move |(tester, id)| {
|
||||
@@ -431,7 +431,7 @@ fn bad_commit_leads_to_report() {
|
||||
let _ = sender.unbounded_send(NetworkEvent::NotificationStreamOpened {
|
||||
remote: sender_id.clone(),
|
||||
engine_id: GRANDPA_ENGINE_ID,
|
||||
roles: Roles::FULL,
|
||||
role: ObservedRole::Full,
|
||||
});
|
||||
let _ = sender.unbounded_send(NetworkEvent::NotificationsReceived {
|
||||
remote: sender_id.clone(),
|
||||
@@ -482,7 +482,7 @@ fn peer_with_higher_view_leads_to_catch_up_request() {
|
||||
let test = tester
|
||||
.map(move |tester| {
|
||||
// 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)
|
||||
})
|
||||
.then(move |(tester, id)| {
|
||||
|
||||
@@ -22,7 +22,7 @@ use sc_network_test::{
|
||||
Block, Hash, TestNetFactory, BlockImportAdapter, Peer,
|
||||
PeersClient, PassThroughVerifier, PeersFullClient,
|
||||
};
|
||||
use sc_network::config::{ProtocolConfig, Roles, BoxFinalityProofRequestBuilder};
|
||||
use sc_network::config::{ProtocolConfig, BoxFinalityProofRequestBuilder};
|
||||
use parking_lot::Mutex;
|
||||
use futures_timer::Delay;
|
||||
use tokio::runtime::{Runtime, Handle};
|
||||
@@ -74,9 +74,8 @@ impl GrandpaTestNet {
|
||||
peers: Vec::with_capacity(n_peers),
|
||||
test_config,
|
||||
};
|
||||
let config = Self::default_config();
|
||||
for _ in 0..n_peers {
|
||||
net.add_full_peer(&config);
|
||||
net.add_full_peer();
|
||||
}
|
||||
net
|
||||
}
|
||||
@@ -95,10 +94,8 @@ impl TestNetFactory for GrandpaTestNet {
|
||||
}
|
||||
|
||||
fn default_config() -> ProtocolConfig {
|
||||
// the authority role ensures gossip hits all nodes here.
|
||||
let mut config = ProtocolConfig::default();
|
||||
config.roles = Roles::AUTHORITY;
|
||||
config
|
||||
// This is unused.
|
||||
ProtocolConfig::default()
|
||||
}
|
||||
|
||||
fn make_verifier(
|
||||
@@ -1303,7 +1300,7 @@ fn finality_proof_is_fetched_by_light_client_when_consensus_data_changes() {
|
||||
|
||||
let peers = &[Ed25519Keyring::Alice];
|
||||
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
|
||||
// && 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);
|
||||
|
||||
// request finalization by light client
|
||||
net.lock().add_light_peer(&GrandpaTestNet::default_config());
|
||||
net.lock().add_light_peer();
|
||||
net.lock().block_until_sync();
|
||||
|
||||
// check block, finalized on light client
|
||||
|
||||
@@ -137,11 +137,11 @@ impl<B: BlockT> Future for GossipEngine<B> {
|
||||
loop {
|
||||
match this.network_event_stream.poll_next_unpin(cx) {
|
||||
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 {
|
||||
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 } => {
|
||||
if msg_engine_id != this.engine_id {
|
||||
|
||||
@@ -26,7 +26,7 @@ use lru::LruCache;
|
||||
use libp2p::PeerId;
|
||||
use sp_runtime::traits::{Block as BlockT, Hash, HashFor};
|
||||
use sp_runtime::ConsensusEngineId;
|
||||
use sc_network::config::Roles;
|
||||
use sc_network::ObservedRole;
|
||||
use wasm_timer::Instant;
|
||||
|
||||
// FIXME: Add additional spam/DoS attack protection: https://github.com/paritytech/substrate/issues/1115
|
||||
@@ -51,7 +51,7 @@ mod rep {
|
||||
|
||||
struct PeerConsensus<H> {
|
||||
known_messages: HashSet<H>,
|
||||
roles: Roles,
|
||||
role: ObservedRole,
|
||||
}
|
||||
|
||||
/// Topic stream message with sender.
|
||||
@@ -192,10 +192,10 @@ impl<B: BlockT> ConsensusGossip<B> {
|
||||
validator: Arc<dyn Validator<B>>
|
||||
) {
|
||||
self.register_validator_internal(engine_id, validator.clone());
|
||||
let peers: Vec<_> = self.peers.iter().map(|(id, peer)| (id.clone(), peer.roles)).collect();
|
||||
for (id, roles) in peers {
|
||||
let peers: Vec<_> = self.peers.iter().map(|(id, peer)| (id.clone(), peer.role.clone())).collect();
|
||||
for (id, role) in peers {
|
||||
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.
|
||||
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
|
||||
if !roles.is_full() {
|
||||
if role.is_light() {
|
||||
return;
|
||||
}
|
||||
|
||||
trace!(target:"gossip", "Registering {:?} {}", roles, who);
|
||||
trace!(target:"gossip", "Registering {:?} {}", role, who);
|
||||
self.peers.insert(who.clone(), PeerConsensus {
|
||||
known_messages: HashSet::new(),
|
||||
roles,
|
||||
role: role.clone(),
|
||||
});
|
||||
for (engine_id, v) in self.validators.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 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));
|
||||
|
||||
consensus.peer_disconnected(&mut network, peer_id.clone());
|
||||
|
||||
@@ -14,13 +14,13 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// 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;
|
||||
|
||||
/// Validates consensus messages.
|
||||
pub trait Validator<B: BlockT>: Send + Sync {
|
||||
/// 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.
|
||||
|
||||
@@ -15,18 +15,19 @@
|
||||
// along with Substrate. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
use crate::{
|
||||
config::Role,
|
||||
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::core::{Multiaddr, PeerId, PublicKey};
|
||||
use libp2p::kad::record;
|
||||
use libp2p::swarm::{NetworkBehaviourAction, NetworkBehaviourEventProcess, PollParameters};
|
||||
use log::debug;
|
||||
use sp_consensus::{BlockOrigin, import_queue::{IncomingBlock, Origin}};
|
||||
use sp_runtime::{traits::{Block as BlockT, NumberFor}, Justification};
|
||||
use std::{iter, task::Context, task::Poll};
|
||||
use sp_runtime::{traits::{Block as BlockT, NumberFor}, ConsensusEngineId, Justification};
|
||||
use std::{borrow::Cow, iter, task::Context, task::Poll};
|
||||
use void;
|
||||
|
||||
/// 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>,
|
||||
/// Light client request handling.
|
||||
light_client_handler: protocol::LightClientHandler<B>,
|
||||
|
||||
/// Queue of events to produce for the outside.
|
||||
#[behaviour(ignore)]
|
||||
events: Vec<BehaviourOut<B>>,
|
||||
|
||||
/// Role of our local node, as originally passed from the configuration.
|
||||
#[behaviour(ignore)]
|
||||
role: Role,
|
||||
}
|
||||
|
||||
/// Event generated by `Behaviour`.
|
||||
@@ -63,6 +69,7 @@ impl<B: BlockT, H: ExHashT> Behaviour<B, H> {
|
||||
/// Builds a new `Behaviour`.
|
||||
pub async fn new(
|
||||
substrate: Protocol<B, H>,
|
||||
role: Role,
|
||||
user_agent: String,
|
||||
local_public_key: PublicKey,
|
||||
known_addresses: Vec<(PeerId, Multiaddr)>,
|
||||
@@ -84,7 +91,8 @@ impl<B: BlockT, H: ExHashT> Behaviour<B, H> {
|
||||
).await,
|
||||
block_requests,
|
||||
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)
|
||||
}
|
||||
|
||||
/// 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.
|
||||
pub fn user_protocol(&self) -> &Protocol<B, H> {
|
||||
&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
|
||||
Behaviour<B, H> {
|
||||
fn inject_event(&mut self, event: void::Void) {
|
||||
@@ -155,14 +205,16 @@ Behaviour<B, H> {
|
||||
self.events.push(BehaviourOut::JustificationImport(origin, hash, nb, justification)),
|
||||
CustomMessageOutcome::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 {
|
||||
self.events.push(BehaviourOut::Event(Event::NotificationStreamOpened {
|
||||
remote: remote.clone(),
|
||||
engine_id,
|
||||
roles,
|
||||
role: role.clone(),
|
||||
}));
|
||||
},
|
||||
}
|
||||
},
|
||||
CustomMessageOutcome::NotificationStreamClosed { remote, protocols } =>
|
||||
for engine_id in protocols {
|
||||
self.events.push(BehaviourOut::Event(Event::NotificationStreamClosed {
|
||||
|
||||
@@ -31,23 +31,21 @@ pub use crate::protocol::ProtocolConfig;
|
||||
|
||||
use crate::service::ExHashT;
|
||||
|
||||
use bitflags::bitflags;
|
||||
use sp_consensus::{block_validation::BlockAnnounceValidator, import_queue::ImportQueue};
|
||||
use sp_runtime::traits::{Block as BlockT};
|
||||
use libp2p::identity::{Keypair, ed25519};
|
||||
use libp2p::wasm_ext;
|
||||
use libp2p::{PeerId, Multiaddr, multiaddr};
|
||||
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 zeroize::Zeroize;
|
||||
use prometheus_endpoint::Registry;
|
||||
|
||||
|
||||
/// Network initialization parameters.
|
||||
pub struct Params<B: BlockT, H: ExHashT> {
|
||||
/// Assigned roles for our node (full, light, ...).
|
||||
pub roles: Roles,
|
||||
/// Assigned role for our node (full, light, ...).
|
||||
pub role: Role,
|
||||
|
||||
/// How to spawn background tasks. If you pass `None`, then a threads pool will be used by
|
||||
/// default.
|
||||
@@ -97,54 +95,48 @@ pub struct Params<B: BlockT, H: ExHashT> {
|
||||
pub metrics_registry: Option<Registry>,
|
||||
}
|
||||
|
||||
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;
|
||||
/// Role of the local node.
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum Role {
|
||||
/// Regular full node.
|
||||
Full,
|
||||
/// Regular light node.
|
||||
Light,
|
||||
/// Sentry node that guards an authority. Will be reported as "authority" on the wire protocol.
|
||||
Sentry {
|
||||
/// Address and identity of the validator nodes that we're guarding.
|
||||
///
|
||||
/// 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 {
|
||||
/// 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?
|
||||
impl Role {
|
||||
/// True for `Role::Authority`
|
||||
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?
|
||||
pub fn is_light(&self) -> bool {
|
||||
!self.is_full()
|
||||
/// True for `Role::Authority` and `Role::Sentry` since they're both
|
||||
/// announced as having the authority role to the network.
|
||||
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 {
|
||||
write!(f, "{:?}", self)
|
||||
}
|
||||
}
|
||||
|
||||
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"))
|
||||
match self {
|
||||
Role::Full => write!(f, "FULL"),
|
||||
Role::Light => write!(f, "LIGHT"),
|
||||
Role::Sentry { .. } => write!(f, "SENTRY"),
|
||||
Role::Authority { .. } => write!(f, "AUTHORITY"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -214,6 +206,67 @@ pub fn parse_addr(mut addr: Multiaddr)-> Result<(PeerId, Multiaddr), ParseErr> {
|
||||
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`.
|
||||
#[derive(Debug)]
|
||||
pub enum ParseErr {
|
||||
@@ -263,7 +316,7 @@ pub struct NetworkConfiguration {
|
||||
/// Multiaddresses to advertise. Detected automatically if empty.
|
||||
pub public_addresses: Vec<Multiaddr>,
|
||||
/// 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.
|
||||
pub node_key: NodeKeyConfig,
|
||||
/// Maximum allowed number of incoming connections.
|
||||
@@ -271,11 +324,9 @@ pub struct NetworkConfiguration {
|
||||
/// Number of outgoing connections we're trying to maintain.
|
||||
pub out_peers: u32,
|
||||
/// List of reserved node addresses.
|
||||
pub reserved_nodes: Vec<String>,
|
||||
pub reserved_nodes: Vec<MultiaddrWithPeerId>,
|
||||
/// The non-reserved peer mode.
|
||||
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.
|
||||
pub client_version: String,
|
||||
/// Name of the node. Sent over the wire for debugging purposes.
|
||||
@@ -299,7 +350,6 @@ impl Default for NetworkConfiguration {
|
||||
out_peers: 75,
|
||||
reserved_nodes: Vec::new(),
|
||||
non_reserved_mode: NonReservedPeerMode::Accept,
|
||||
sentry_nodes: Vec::new(),
|
||||
client_version: "unknown".into(),
|
||||
node_name: "unknown".into(),
|
||||
transport: TransportConfig::Normal {
|
||||
|
||||
@@ -248,7 +248,7 @@ pub mod network_state;
|
||||
|
||||
pub use service::{NetworkService, NetworkStateInfo, NetworkWorker, ExHashT, ReportHandle};
|
||||
pub use protocol::PeerInfo;
|
||||
pub use protocol::event::{Event, DhtEvent};
|
||||
pub use protocol::event::{Event, DhtEvent, ObservedRole};
|
||||
pub use protocol::sync::SyncState;
|
||||
pub use libp2p::{Multiaddr, PeerId};
|
||||
#[doc(inline)]
|
||||
|
||||
@@ -39,11 +39,11 @@ use sp_runtime::traits::{
|
||||
};
|
||||
use sp_arithmetic::traits::SaturatedConversion;
|
||||
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 sync::{ChainSync, SyncState};
|
||||
use crate::service::{TransactionPool, ExHashT};
|
||||
use crate::config::{BoxFinalityProofRequestBuilder, Roles};
|
||||
use crate::config::BoxFinalityProofRequestBuilder;
|
||||
use std::borrow::Cow;
|
||||
use std::collections::{BTreeMap, HashMap, HashSet, VecDeque};
|
||||
use std::sync::Arc;
|
||||
@@ -338,7 +338,7 @@ impl<B: BlockT, H: ExHashT> Protocol<B, H> {
|
||||
|
||||
let important_peers = {
|
||||
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.shrink_to_fit();
|
||||
@@ -1033,13 +1033,14 @@ impl<B: BlockT, H: ExHashT> Protocol<B, H> {
|
||||
|
||||
/// Registers a new notifications protocol.
|
||||
///
|
||||
/// 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,
|
||||
/// While registering a protocol while we already have open connections is discouraged, we
|
||||
/// nonetheless handle it by notifying that we opened channels with everyone. This function
|
||||
/// returns a list of substreams to open as a result.
|
||||
pub fn register_notifications_protocol<'a>(
|
||||
&'a mut self,
|
||||
engine_id: ConsensusEngineId,
|
||||
protocol_name: impl Into<Cow<'static, [u8]>>,
|
||||
) -> Vec<event::Event> {
|
||||
) -> impl ExactSizeIterator<Item = (&'a PeerId, Roles)> + 'a {
|
||||
let protocol_name = protocol_name.into();
|
||||
if self.protocol_name_by_engine.insert(engine_id, protocol_name.clone()).is_some() {
|
||||
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));
|
||||
}
|
||||
|
||||
// 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()
|
||||
.map(|(peer_id, peer)|
|
||||
event::Event::NotificationStreamOpened {
|
||||
remote: peer_id.clone(),
|
||||
engine_id,
|
||||
roles: peer.info.roles,
|
||||
})
|
||||
.collect()
|
||||
.map(|(peer_id, peer)| (peer_id, peer.info.roles))
|
||||
}
|
||||
|
||||
/// Called when peer sends us new extrinsics
|
||||
@@ -2021,7 +2014,7 @@ impl<B: BlockT, H: ExHashT> Drop for Protocol<B, H> {
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::PeerId;
|
||||
use crate::config::{EmptyTransactionPool, Roles};
|
||||
use crate::config::EmptyTransactionPool;
|
||||
use super::{CustomMessageOutcome, Protocol, ProtocolConfig};
|
||||
|
||||
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 (mut protocol, _) = Protocol::<Block, Hash>::new(
|
||||
ProtocolConfig {
|
||||
roles: Roles::FULL,
|
||||
max_parallel_downloads: 10,
|
||||
},
|
||||
ProtocolConfig::default(),
|
||||
client.clone(),
|
||||
Arc::new(EmptyTransactionPool),
|
||||
None,
|
||||
@@ -2048,7 +2038,7 @@ mod tests {
|
||||
out_peers: 10,
|
||||
bootnodes: Vec::new(),
|
||||
reserved_only: false,
|
||||
reserved_nodes: Vec::new(),
|
||||
priority_groups: Vec::new(),
|
||||
},
|
||||
Box::new(DefaultBlockAnnounceValidator::new(client.clone())),
|
||||
None,
|
||||
|
||||
@@ -17,7 +17,6 @@
|
||||
//! 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.
|
||||
|
||||
use crate::config::Roles;
|
||||
use bytes::Bytes;
|
||||
use libp2p::core::PeerId;
|
||||
use libp2p::kad::record::Key;
|
||||
@@ -55,8 +54,8 @@ pub enum Event {
|
||||
remote: PeerId,
|
||||
/// The concerned protocol. Each protocol uses a different substream.
|
||||
engine_id: ConsensusEngineId,
|
||||
/// Roles that the remote .
|
||||
roles: Roles,
|
||||
/// Role of the remote.
|
||||
role: ObservedRole,
|
||||
},
|
||||
|
||||
/// Closed a substream with the given node. Always matches a corresponding previous
|
||||
@@ -76,3 +75,26 @@ pub enum Event {
|
||||
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![]
|
||||
},
|
||||
reserved_only: false,
|
||||
reserved_nodes: Vec::new(),
|
||||
priority_groups: Vec::new(),
|
||||
});
|
||||
|
||||
let behaviour = CustomProtoWithAddr {
|
||||
|
||||
@@ -1423,7 +1423,7 @@ mod tests {
|
||||
out_peers: 128,
|
||||
bootnodes: Vec::new(),
|
||||
reserved_only: false,
|
||||
reserved_nodes: Vec::new(),
|
||||
priority_groups: Vec::new(),
|
||||
};
|
||||
sc_peerset::Peerset::from_config(cfg)
|
||||
}
|
||||
|
||||
@@ -24,7 +24,7 @@ pub use self::generic::{
|
||||
RemoteHeaderRequest, RemoteHeaderResponse,
|
||||
RemoteChangesRequest, RemoteChangesResponse,
|
||||
FinalityProofRequest, FinalityProofResponse,
|
||||
FromBlock, RemoteReadChildRequest,
|
||||
FromBlock, RemoteReadChildRequest, Roles,
|
||||
};
|
||||
use sc_client_api::StorageProof;
|
||||
|
||||
@@ -137,14 +137,71 @@ pub struct RemoteReadResponse {
|
||||
|
||||
/// Generic types.
|
||||
pub mod generic {
|
||||
use bitflags::bitflags;
|
||||
use codec::{Encode, Decode, Input, Output};
|
||||
use sp_runtime::Justification;
|
||||
use crate::config::Roles;
|
||||
use super::{
|
||||
RemoteReadResponse, Transactions, Direction,
|
||||
RequestId, BlockAttributes, RemoteCallResponse, ConsensusEngineId,
|
||||
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
|
||||
#[derive(Debug, PartialEq, Eq, Clone, Encode, Decode)]
|
||||
pub struct ConsensusMessage {
|
||||
|
||||
@@ -34,9 +34,9 @@ use sp_consensus::{BlockOrigin, BlockStatus,
|
||||
import_queue::{IncomingBlock, BlockImportResult, BlockImportError}
|
||||
};
|
||||
use crate::{
|
||||
config::{Roles, BoxFinalityProofRequestBuilder},
|
||||
config::BoxFinalityProofRequestBuilder,
|
||||
protocol::message::{self, generic::FinalityProofRequest, BlockAnnounce, BlockAttributes, BlockRequest, BlockResponse,
|
||||
FinalityProofResponse},
|
||||
FinalityProofResponse, Roles},
|
||||
};
|
||||
use either::Either;
|
||||
use extra_requests::ExtraRequests;
|
||||
|
||||
@@ -27,7 +27,7 @@
|
||||
|
||||
use crate::{
|
||||
behaviour::{Behaviour, BehaviourOut},
|
||||
config::{parse_addr, parse_str_addr, NonReservedPeerMode, Params, TransportConfig},
|
||||
config::{parse_addr, parse_str_addr, NonReservedPeerMode, Params, Role, TransportConfig},
|
||||
error::Error,
|
||||
network_state::{
|
||||
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.
|
||||
let mut known_addresses = Vec::new();
|
||||
let mut bootnodes = Vec::new();
|
||||
let mut reserved_nodes = Vec::new();
|
||||
let mut boot_node_ids = HashSet::new();
|
||||
|
||||
// Process the bootnodes.
|
||||
for bootnode in params.network_config.boot_nodes.iter() {
|
||||
match parse_str_addr(bootnode) {
|
||||
Ok((peer_id, addr)) => {
|
||||
bootnodes.push(peer_id.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),
|
||||
}
|
||||
bootnodes.push(bootnode.peer_id.clone());
|
||||
boot_node_ids.insert(bootnode.peer_id.clone());
|
||||
known_addresses.push((bootnode.peer_id.clone(), bootnode.multiaddr.clone()));
|
||||
}
|
||||
|
||||
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.
|
||||
for reserved in params.network_config.reserved_nodes.iter() {
|
||||
if let Ok((peer_id, addr)) = parse_str_addr(reserved) {
|
||||
reserved_nodes.push(peer_id.clone());
|
||||
known_addresses.push((peer_id, addr));
|
||||
} else {
|
||||
warn!(target: "sub-libp2p", "Not a valid reserved node address: {}", reserved);
|
||||
// Initialize the peers we should always be connected to.
|
||||
let priority_groups = {
|
||||
let mut reserved_nodes = HashSet::new();
|
||||
for reserved in params.network_config.reserved_nodes.iter() {
|
||||
reserved_nodes.insert(reserved.peer_id.clone());
|
||||
known_addresses.push((reserved.peer_id.clone(), reserved.multiaddr.clone()));
|
||||
}
|
||||
}
|
||||
|
||||
let mut sentries_and_validators = HashSet::new();
|
||||
match ¶ms.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 {
|
||||
in_peers: params.network_config.in_peers,
|
||||
out_peers: params.network_config.out_peers,
|
||||
bootnodes,
|
||||
reserved_only: params.network_config.non_reserved_mode == NonReservedPeerMode::Deny,
|
||||
reserved_nodes,
|
||||
priority_groups,
|
||||
};
|
||||
|
||||
// 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 (protocol, peerset_handle) = Protocol::new(
|
||||
protocol::ProtocolConfig {
|
||||
roles: params.roles,
|
||||
roles: From::from(¶ms.role),
|
||||
max_parallel_downloads: params.network_config.max_parallel_downloads,
|
||||
},
|
||||
params.chain.clone(),
|
||||
@@ -285,6 +300,7 @@ impl<B: BlockT + 'static, H: ExHashT> NetworkWorker<B, H> {
|
||||
};
|
||||
let behaviour = futures::executor::block_on(Behaviour::new(
|
||||
protocol,
|
||||
params.role,
|
||||
user_agent,
|
||||
local_public,
|
||||
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)
|
||||
},
|
||||
ServiceToWorkerMsg::RegisterNotifProtocol { engine_id, protocol_name } => {
|
||||
let events = this.network_service.user_protocol_mut()
|
||||
this.network_service
|
||||
.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) =>
|
||||
this.network_service.user_protocol_mut().disconnect_peer(&who),
|
||||
|
||||
@@ -32,7 +32,7 @@ use sp_blockchain::{
|
||||
use sc_client_api::{BlockchainEvents, BlockImportNotification, FinalityNotifications, ImportNotifications, FinalityNotification, backend::{TransactionFor, AuxStore, Backend, Finalizer}, BlockBackend};
|
||||
use sc_block_builder::{BlockBuilder, BlockBuilderProvider};
|
||||
use sc_client::LongestChain;
|
||||
use sc_network::config::Roles;
|
||||
use sc_network::config::Role;
|
||||
use sp_consensus::block_validation::DefaultBlockAnnounceValidator;
|
||||
use sp_consensus::import_queue::{
|
||||
BasicQueue, BoxJustificationImport, Verifier, BoxFinalityProofImport,
|
||||
@@ -557,17 +557,17 @@ pub trait TestNetFactory: Sized {
|
||||
|
||||
for i in 0..n {
|
||||
trace!(target: "test_network", "Adding peer {}", i);
|
||||
net.add_full_peer(&config);
|
||||
net.add_full_peer();
|
||||
}
|
||||
net
|
||||
}
|
||||
|
||||
fn add_full_peer(&mut self, config: &ProtocolConfig) {
|
||||
self.add_full_peer_with_states(config, None)
|
||||
fn add_full_peer(&mut self) {
|
||||
self.add_full_peer_with_states(None)
|
||||
}
|
||||
|
||||
/// 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 {
|
||||
Some(keep_blocks) => TestClientBuilder::with_pruning_window(keep_blocks),
|
||||
None => TestClientBuilder::with_default_backend(),
|
||||
@@ -586,7 +586,7 @@ pub trait TestNetFactory: Sized {
|
||||
|
||||
let verifier = self.make_verifier(
|
||||
PeersClient::Full(client.clone(), backend.clone()),
|
||||
config,
|
||||
&Default::default(),
|
||||
&data,
|
||||
);
|
||||
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 network = NetworkWorker::new(sc_network::config::Params {
|
||||
roles: config.roles,
|
||||
role: Role::Full,
|
||||
executor: None,
|
||||
network_config: NetworkConfiguration {
|
||||
listen_addresses: vec![listen_addr.clone()],
|
||||
@@ -644,10 +644,7 @@ pub trait TestNetFactory: Sized {
|
||||
}
|
||||
|
||||
/// Add a light peer.
|
||||
fn add_light_peer(&mut self, config: &ProtocolConfig) {
|
||||
let mut config = config.clone();
|
||||
config.roles = Roles::LIGHT;
|
||||
|
||||
fn add_light_peer(&mut self) {
|
||||
let (c, backend) = substrate_test_runtime_client::new_light();
|
||||
let client = Arc::new(c);
|
||||
let (
|
||||
@@ -660,7 +657,7 @@ pub trait TestNetFactory: Sized {
|
||||
|
||||
let verifier = self.make_verifier(
|
||||
PeersClient::Light(client.clone(), backend.clone()),
|
||||
&config,
|
||||
&Default::default(),
|
||||
&data,
|
||||
);
|
||||
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 network = NetworkWorker::new(sc_network::config::Params {
|
||||
roles: config.roles,
|
||||
role: Role::Light,
|
||||
executor: None,
|
||||
network_config: NetworkConfiguration {
|
||||
listen_addresses: vec![listen_addr.clone()],
|
||||
|
||||
@@ -14,7 +14,6 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Substrate. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
use sc_network::config::Roles;
|
||||
use sp_consensus::BlockOrigin;
|
||||
use std::time::Duration;
|
||||
use futures::executor::block_on;
|
||||
@@ -372,10 +371,8 @@ fn blocks_are_not_announced_by_light_nodes() {
|
||||
|
||||
// full peer0 is connected to light peer
|
||||
// light peer1 is connected to full peer2
|
||||
let mut light_config = ProtocolConfig::default();
|
||||
light_config.roles = Roles::LIGHT;
|
||||
net.add_full_peer(&ProtocolConfig::default());
|
||||
net.add_light_peer(&light_config);
|
||||
net.add_full_peer();
|
||||
net.add_light_peer();
|
||||
|
||||
// Sync between 0 and 1.
|
||||
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);
|
||||
|
||||
// Add another node and remove node 0.
|
||||
net.add_full_peer(&ProtocolConfig::default());
|
||||
net.add_full_peer();
|
||||
net.peers.remove(0);
|
||||
|
||||
// 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)
|
||||
let mut net = TestNet::new(1);
|
||||
net.add_light_peer(&Default::default());
|
||||
net.add_light_peer();
|
||||
|
||||
// generate some blocks on #0
|
||||
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);
|
||||
|
||||
// add new full client (#2) && remove #0
|
||||
net.add_full_peer(&Default::default());
|
||||
net.add_full_peer();
|
||||
net.peers.remove(0);
|
||||
|
||||
// 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)
|
||||
let mut net = TestNet::new(1);
|
||||
net.add_light_peer(&Default::default());
|
||||
net.add_light_peer();
|
||||
|
||||
// let them connect to each other
|
||||
net.block_until_sync();
|
||||
@@ -583,9 +580,8 @@ fn can_sync_explicit_forks() {
|
||||
fn syncs_header_only_forks() {
|
||||
let _ = ::env_logger::try_init();
|
||||
let mut net = TestNet::new(0);
|
||||
let config = ProtocolConfig::default();
|
||||
net.add_full_peer_with_states(&config, None);
|
||||
net.add_full_peer_with_states(&config, Some(3));
|
||||
net.add_full_peer_with_states(None);
|
||||
net.add_full_peer_with_states(Some(3));
|
||||
net.peer(0).push_blocks(2, false);
|
||||
net.peer(1).push_blocks(2, false);
|
||||
|
||||
|
||||
@@ -163,14 +163,14 @@ pub struct PeersetConfig {
|
||||
/// > otherwise it will not be able to connect to them.
|
||||
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,
|
||||
|
||||
/// 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,
|
||||
/// > 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.
|
||||
@@ -215,7 +215,10 @@ impl Peerset {
|
||||
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 {
|
||||
if let peersstate::Peer::Unknown(entry) = peerset.data.peer(&peer_id) {
|
||||
entry.discover();
|
||||
@@ -597,7 +600,7 @@ mod tests {
|
||||
out_peers: 2,
|
||||
bootnodes: vec![bootnode],
|
||||
reserved_only: true,
|
||||
reserved_nodes: Vec::new(),
|
||||
priority_groups: Vec::new(),
|
||||
};
|
||||
|
||||
let (peerset, handle) = Peerset::from_config(config);
|
||||
@@ -625,7 +628,7 @@ mod tests {
|
||||
out_peers: 1,
|
||||
bootnodes: vec![bootnode.clone()],
|
||||
reserved_only: false,
|
||||
reserved_nodes: Vec::new(),
|
||||
priority_groups: Vec::new(),
|
||||
};
|
||||
|
||||
let (mut peerset, _handle) = Peerset::from_config(config);
|
||||
@@ -652,7 +655,7 @@ mod tests {
|
||||
out_peers: 2,
|
||||
bootnodes: vec![bootnode.clone()],
|
||||
reserved_only: false,
|
||||
reserved_nodes: vec![],
|
||||
priority_groups: vec![],
|
||||
};
|
||||
|
||||
let (mut peerset, _handle) = Peerset::from_config(config);
|
||||
@@ -673,7 +676,7 @@ mod tests {
|
||||
out_peers: 25,
|
||||
bootnodes: vec![],
|
||||
reserved_only: false,
|
||||
reserved_nodes: vec![],
|
||||
priority_groups: vec![],
|
||||
});
|
||||
|
||||
// We ban a node by setting its reputation under the threshold.
|
||||
|
||||
@@ -43,12 +43,15 @@ fn test_once() {
|
||||
known_nodes.insert(id.clone());
|
||||
id
|
||||
}).collect(),
|
||||
reserved_nodes: (0 .. Uniform::new_inclusive(0, 2).sample(&mut rng)).map(|_| {
|
||||
let id = PeerId::random();
|
||||
known_nodes.insert(id.clone());
|
||||
reserved_nodes.insert(id.clone());
|
||||
id
|
||||
}).collect(),
|
||||
priority_groups: {
|
||||
let list = (0 .. Uniform::new_inclusive(0, 2).sample(&mut rng)).map(|_| {
|
||||
let id = PeerId::random();
|
||||
known_nodes.insert(id.clone());
|
||||
reserved_nodes.insert(id.clone());
|
||||
id
|
||||
}).collect();
|
||||
vec![("reserved".to_owned(), list)]
|
||||
},
|
||||
reserved_only: Uniform::new_inclusive(0, 10).sample(&mut rng) == 0,
|
||||
in_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,
|
||||
/// The node is an authority
|
||||
Authority,
|
||||
/// An unknown role with a bit number
|
||||
UnknownRole(u8)
|
||||
/// The node is a sentry
|
||||
Sentry,
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
use super::*;
|
||||
|
||||
use sc_network::{self, PeerId};
|
||||
use sc_network::config::Roles;
|
||||
use sc_network::config::Role;
|
||||
use substrate_test_runtime_client::runtime::Block;
|
||||
use assert_matches::assert_matches;
|
||||
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 {
|
||||
peers.push(PeerInfo {
|
||||
peer_id: status.peer_id.to_base58(),
|
||||
roles: format!("{:?}", Roles::FULL),
|
||||
roles: format!("{}", Role::Full),
|
||||
protocol_version: 1,
|
||||
best_hash: Default::default(),
|
||||
best_number: 1,
|
||||
|
||||
@@ -35,7 +35,7 @@ use futures::{
|
||||
};
|
||||
use sc_keystore::{Store as Keystore};
|
||||
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 parking_lot::{Mutex, RwLock};
|
||||
use sp_runtime::generic::BlockId;
|
||||
@@ -840,7 +840,7 @@ ServiceBuilder<
|
||||
.register_transaction_pool(Arc::downgrade(&transaction_pool) as _);
|
||||
|
||||
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(),
|
||||
client: client.clone(),
|
||||
executor: tasks_builder.spawn_handle(),
|
||||
@@ -863,7 +863,7 @@ ServiceBuilder<
|
||||
Box::new(sp_consensus::block_validation::DefaultBlockAnnounceValidator::new(client.clone()));
|
||||
|
||||
let network_params = sc_network::config::Params {
|
||||
roles: config.roles,
|
||||
role: config.role.clone(),
|
||||
executor: {
|
||||
let spawn_handle = tasks_builder.spawn_handle();
|
||||
Some(Box::new(move |fut| {
|
||||
@@ -913,7 +913,7 @@ ServiceBuilder<
|
||||
let offchain = offchain_workers.as_ref().map(Arc::downgrade);
|
||||
let notifications_spawn_handle = tasks_builder.spawn_handle();
|
||||
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) = (
|
||||
client.import_notification_stream().map(|n| ChainEvent::NewBlock {
|
||||
@@ -1003,9 +1003,16 @@ ServiceBuilder<
|
||||
.const_label("version", config.impl_version)
|
||||
.const_label("commit", config.impl_commit),
|
||||
)?, ®istry)?.set(1);
|
||||
|
||||
let role_bits = match config.role {
|
||||
Role::Full => 1,
|
||||
Role::Light => 2,
|
||||
Role::Sentry { .. } => 3,
|
||||
Role::Authority { .. } => 4,
|
||||
};
|
||||
register(Gauge::<U64>::new(
|
||||
"node_roles", "The roles the node is running as",
|
||||
)?, ®istry)?.set(u64::from(config.roles.bits()));
|
||||
"node_role", "The role the node is running as",
|
||||
)?, ®istry)?.set(role_bits);
|
||||
|
||||
let metrics = ServiceMetrics::register(®istry)?;
|
||||
|
||||
@@ -1198,7 +1205,7 @@ ServiceBuilder<
|
||||
spawn_handle.spawn(
|
||||
"network-worker",
|
||||
build_network_future(
|
||||
config.roles,
|
||||
config.role.clone(),
|
||||
network_mut,
|
||||
client.clone(),
|
||||
network_status_sinks.clone(),
|
||||
@@ -1212,7 +1219,7 @@ ServiceBuilder<
|
||||
|
||||
// Telemetry
|
||||
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 name = config.name.clone();
|
||||
let impl_name = config.impl_name.to_owned();
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
|
||||
pub use sc_client::ExecutionStrategies;
|
||||
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;
|
||||
|
||||
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,
|
||||
/// Git commit if any.
|
||||
pub impl_commit: &'static str,
|
||||
/// Node roles.
|
||||
pub roles: Roles,
|
||||
/// Node role.
|
||||
pub role: Role,
|
||||
/// 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>>,
|
||||
/// Extrinsic pool configuration.
|
||||
@@ -105,10 +105,6 @@ pub struct Configuration {
|
||||
pub default_heap_pages: Option<u64>,
|
||||
/// Should offchain workers be executed.
|
||||
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.
|
||||
pub force_authoring: bool,
|
||||
/// Disable GRANDPA when running in validator mode
|
||||
@@ -204,7 +200,7 @@ impl Default for Configuration {
|
||||
chain_spec: None,
|
||||
config_dir: None,
|
||||
name: Default::default(),
|
||||
roles: Roles::FULL,
|
||||
role: Role::Full,
|
||||
task_executor: None,
|
||||
transaction_pool: Default::default(),
|
||||
network: Default::default(),
|
||||
@@ -224,7 +220,6 @@ impl Default for Configuration {
|
||||
telemetry_external_transport: None,
|
||||
default_heap_pages: None,
|
||||
offchain_worker: Default::default(),
|
||||
sentry_mode: false,
|
||||
force_authoring: false,
|
||||
disable_grandpa: false,
|
||||
dev_key_seed: None,
|
||||
@@ -286,15 +281,9 @@ impl Configuration {
|
||||
self.database.as_ref().expect("database must be specified")
|
||||
}
|
||||
|
||||
/// Returns a string displaying the node role, special casing the sentry mode
|
||||
/// (returning `SENTRY`), since the node technically has an `AUTHORITY` role but
|
||||
/// doesn't participate.
|
||||
/// Returns a string displaying the node role.
|
||||
pub fn display_role(&self) -> String {
|
||||
if self.sentry_mode {
|
||||
"SENTRY".to_string()
|
||||
} else {
|
||||
self.roles.to_string()
|
||||
}
|
||||
self.role.to_string()
|
||||
}
|
||||
|
||||
/// Use in memory keystore config when it is not required at all.
|
||||
|
||||
@@ -58,7 +58,7 @@ pub use self::builder::{
|
||||
ServiceBuilder, ServiceBuilderCommand, TFullClient, TLightClient, TFullBackend, TLightBackend,
|
||||
TFullCallExecutor, TLightCallExecutor,
|
||||
};
|
||||
pub use config::{Configuration, Roles, PruningMode, DatabaseConfig};
|
||||
pub use config::{Configuration, Role, PruningMode, DatabaseConfig};
|
||||
pub use sc_chain_spec::{
|
||||
ChainSpec, GenericChainSpec, Properties, RuntimeGenesis, Extension as ChainSpecExtension
|
||||
};
|
||||
@@ -322,7 +322,7 @@ fn build_network_future<
|
||||
C: sc_client::BlockchainEvents<B>,
|
||||
H: sc_network::ExHashT
|
||||
> (
|
||||
roles: Roles,
|
||||
role: Role,
|
||||
mut network: sc_network::NetworkWorker<B, H>,
|
||||
client: Arc<C>,
|
||||
status_sinks: Arc<Mutex<status_sinks::StatusSinks<(NetworkStatus<B>, NetworkState)>>>,
|
||||
@@ -399,17 +399,14 @@ fn build_network_future<
|
||||
sc_rpc::system::Request::NodeRoles(sender) => {
|
||||
use sc_rpc::system::NodeRole;
|
||||
|
||||
let node_roles = (0 .. 8)
|
||||
.filter(|&bit_number| (roles.bits() >> bit_number) & 1 == 1)
|
||||
.map(|bit_number| match Roles::from_bits(1 << bit_number) {
|
||||
Some(Roles::AUTHORITY) => NodeRole::Authority,
|
||||
Some(Roles::LIGHT) => NodeRole::LightClient,
|
||||
Some(Roles::FULL) => NodeRole::Full,
|
||||
_ => NodeRole::UnknownRole(bit_number),
|
||||
})
|
||||
.collect();
|
||||
let node_role = match role {
|
||||
Role::Authority { .. } => NodeRole::Authority,
|
||||
Role::Light => NodeRole::LightClient,
|
||||
Role::Full => NodeRole::Full,
|
||||
Role::Sentry { .. } => NodeRole::Sentry,
|
||||
};
|
||||
|
||||
let _ = sender.send(node_roles);
|
||||
let _ = sender.send(vec![node_role]);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@@ -34,7 +34,7 @@ use sc_service::{
|
||||
Configuration,
|
||||
config::{DatabaseConfig, KeystoreConfig},
|
||||
RuntimeGenesis,
|
||||
Roles,
|
||||
Role,
|
||||
Error,
|
||||
};
|
||||
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> (
|
||||
index: usize,
|
||||
spec: &GenericChainSpec<G, E>,
|
||||
role: Roles,
|
||||
role: Role,
|
||||
task_executor: Arc<dyn Fn(Pin<Box<dyn futures::Future<Output = ()> + Send>>) + Send + Sync>,
|
||||
key_seed: Option<String>,
|
||||
base_port: u16,
|
||||
@@ -161,7 +161,6 @@ fn node_config<G: RuntimeGenesis + 'static, E: ChainSpecExtension + Clone + 'sta
|
||||
out_peers: 450,
|
||||
reserved_nodes: vec![],
|
||||
non_reserved_mode: NonReservedPeerMode::Accept,
|
||||
sentry_nodes: vec![],
|
||||
client_version: "network/test/0.1".to_owned(),
|
||||
node_name: "unknown".to_owned(),
|
||||
transport: TransportConfig::Normal {
|
||||
@@ -177,7 +176,7 @@ fn node_config<G: RuntimeGenesis + 'static, E: ChainSpecExtension + Clone + 'sta
|
||||
impl_name: "network-test-impl",
|
||||
impl_version: "0.1",
|
||||
impl_commit: "",
|
||||
roles: role,
|
||||
role,
|
||||
task_executor: Some(task_executor),
|
||||
transaction_pool: Default::default(),
|
||||
network: network_config,
|
||||
@@ -206,7 +205,6 @@ fn node_config<G: RuntimeGenesis + 'static, E: ChainSpecExtension + Clone + 'sta
|
||||
telemetry_external_transport: None,
|
||||
default_heap_pages: None,
|
||||
offchain_worker: false,
|
||||
sentry_mode: false,
|
||||
force_authoring: false,
|
||||
disable_grandpa: false,
|
||||
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(
|
||||
self.nodes,
|
||||
&self.chain_spec,
|
||||
Roles::AUTHORITY,
|
||||
Role::Authority { sentry_nodes: Vec::new() },
|
||||
task_executor,
|
||||
Some(key),
|
||||
self.base_port,
|
||||
@@ -288,7 +286,7 @@ impl<G, E, F, L, U> TestNet<G, E, F, L, U> where
|
||||
let executor = executor.clone();
|
||||
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 (service, user_data) = full(node_config).expect("Error creating test node 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();
|
||||
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 service = SyncService::from(light(node_config).expect("Error creating test node service"));
|
||||
|
||||
|
||||
@@ -18,7 +18,7 @@ use futures01::sync::mpsc as mpsc01;
|
||||
use log::{debug, info};
|
||||
use std::sync::Arc;
|
||||
use sc_service::{
|
||||
AbstractService, RpcSession, Roles, Configuration, config::{DatabaseConfig, KeystoreConfig},
|
||||
AbstractService, RpcSession, Role, Configuration, config::{DatabaseConfig, KeystoreConfig},
|
||||
GenericChainSpec, RuntimeGenesis
|
||||
};
|
||||
use wasm_bindgen::prelude::*;
|
||||
@@ -57,7 +57,7 @@ where
|
||||
wasm_bindgen_futures::spawn_local(fut)
|
||||
}));
|
||||
config.telemetry_external_transport = Some(transport);
|
||||
config.roles = Roles::LIGHT;
|
||||
config.role = Role::Light;
|
||||
config.name = format!("{} (Browser)", name);
|
||||
config.database = Some({
|
||||
info!("Opening Indexed DB database '{}'...", name);
|
||||
|
||||
Reference in New Issue
Block a user