diff --git a/bin/node/src/aleph_cli.rs b/bin/node/src/aleph_cli.rs index 30319d2bac..f8569296f0 100644 --- a/bin/node/src/aleph_cli.rs +++ b/bin/node/src/aleph_cli.rs @@ -51,6 +51,11 @@ pub struct AlephCli { /// Maximum bit-rate per node in bytes per second of the alephbft validator network. #[clap(long, default_value_t = 64 * 1024)] alephbft_bit_rate_per_connection: u64, + + /// Don't spend some extra time to collect more debugging data (e.g. validator network details). + /// By default collecting is enabled, as the impact on performance is negligible, if any. + #[clap(long, default_value_t = false)] + no_collection_of_extra_debugging_data: bool, } impl AlephCli { @@ -92,4 +97,8 @@ impl AlephCli { pub fn alephbft_bit_rate_per_connection(&self) -> u64 { self.alephbft_bit_rate_per_connection } + + pub fn no_collection_of_extra_debugging_data(&self) -> bool { + self.no_collection_of_extra_debugging_data + } } diff --git a/bin/node/src/aleph_node_rpc.rs b/bin/node/src/aleph_node_rpc.rs index 13dd7f5079..9697d90c44 100644 --- a/bin/node/src/aleph_node_rpc.rs +++ b/bin/node/src/aleph_node_rpc.rs @@ -1,6 +1,9 @@ -use std::sync::Arc; +use std::{collections::HashMap, sync::Arc}; -use finality_aleph::{AlephJustification, BlockId, Justification, JustificationTranslator}; +use finality_aleph::{ + AlephJustification, BlockId, Justification, JustificationTranslator, ValidatorAddressCache, + ValidatorAddressingInfo, +}; use futures::channel::mpsc; use jsonrpsee::{ core::{error::Error as JsonRpseeError, RpcResult}, @@ -55,6 +58,9 @@ pub enum Error { /// Failed to find a block with provided hash. #[error("Failed to find a block with hash {0}.")] UnknownHash(String), + /// Network info caching is not enabled. + #[error("Unable to get any data, because network info caching is not enabled.")] + NetworkInfoCachingNotEnabled, } // Base code for all system errors. @@ -77,6 +83,8 @@ const FAILED_STORAGE_DECODING_ERROR: i32 = BASE_ERROR + 7; const FAILED_HEADER_DECODING_ERROR: i32 = BASE_ERROR + 8; /// Failed to find a block with provided hash. const UNKNOWN_HASH_ERROR: i32 = BASE_ERROR + 9; +/// Network info caching is not enabled. +const NETWORK_INFO_CACHING_NOT_ENABLED_ERROR: i32 = BASE_ERROR + 10; impl From for JsonRpseeError { fn from(e: Error) -> Self { @@ -132,6 +140,11 @@ impl From for JsonRpseeError { format!("Failed to find a block with hash {hash}.",), None::<()>, )), + Error::NetworkInfoCachingNotEnabled => CallError::Custom(ErrorObject::owned( + NETWORK_INFO_CACHING_NOT_ENABLED_ERROR, + "Unable to get any data, because network info caching is not enabled.", + None::<()>, + )), } .into() } @@ -156,6 +169,9 @@ pub trait AlephNodeApi { /// #[method(name = "ready")] fn ready(&self) -> RpcResult; + + #[method(name = "unstable_validatorNetworkInfo")] + fn validator_network_info(&self) -> RpcResult>; } /// Aleph Node API implementation @@ -164,6 +180,7 @@ pub struct AlephNode { justification_translator: JustificationTranslator, client: Arc, sync_oracle: SO, + validator_address_cache: Option, } impl AlephNode @@ -175,12 +192,14 @@ where justification_translator: JustificationTranslator, client: Arc, sync_oracle: SO, + validator_address_cache: Option, ) -> Self { AlephNode { import_justification_tx, justification_translator, client, sync_oracle, + validator_address_cache, } } } @@ -248,6 +267,13 @@ where fn ready(&self) -> RpcResult { Ok(!self.sync_oracle.is_offline() && !self.sync_oracle.is_major_syncing()) } + + fn validator_network_info(&self) -> RpcResult> { + self.validator_address_cache + .as_ref() + .map(|c| c.snapshot()) + .ok_or(Error::NetworkInfoCachingNotEnabled.into()) + } } fn read_storage< diff --git a/bin/node/src/rpc.rs b/bin/node/src/rpc.rs index e201fac646..235f8df85e 100644 --- a/bin/node/src/rpc.rs +++ b/bin/node/src/rpc.rs @@ -8,7 +8,7 @@ use std::sync::Arc; use aleph_runtime::{opaque::Block, AccountId, Balance, Nonce}; -use finality_aleph::{Justification, JustificationTranslator}; +use finality_aleph::{Justification, JustificationTranslator, ValidatorAddressCache}; use futures::channel::mpsc; use jsonrpsee::RpcModule; use sc_client_api::StorageProvider; @@ -30,6 +30,7 @@ pub struct FullDeps { pub import_justification_tx: mpsc::UnboundedSender, pub justification_translator: JustificationTranslator, pub sync_oracle: SO, + pub validator_address_cache: Option, } /// Instantiate all full RPC extensions. @@ -62,6 +63,7 @@ where import_justification_tx, justification_translator, sync_oracle, + validator_address_cache, } = deps; module.merge(System::new(client.clone(), pool, deny_unsafe).into_rpc())?; @@ -75,6 +77,7 @@ where justification_translator, client, sync_oracle, + validator_address_cache, ) .into_rpc(), )?; diff --git a/bin/node/src/service.rs b/bin/node/src/service.rs index 502e113b63..c9bb990628 100644 --- a/bin/node/src/service.rs +++ b/bin/node/src/service.rs @@ -10,7 +10,7 @@ use finality_aleph::{ run_validator_node, AlephBlockImport, AlephConfig, BlockImporter, Justification, JustificationTranslator, MillisecsPerBlock, Protocol, ProtocolNaming, RateLimiterConfig, RedirectingBlockImport, SessionPeriod, SubstrateChainStatus, SyncOracle, TimingBlockMetrics, - TracingBlockImport, + TracingBlockImport, ValidatorAddressCache, }; use futures::channel::mpsc; use log::warn; @@ -210,6 +210,7 @@ fn setup( client: Arc, telemetry: &mut Option, import_justification_tx: mpsc::UnboundedSender, + collect_extra_debugging_data: bool, ) -> Result< ( RpcHandlers, @@ -218,6 +219,7 @@ fn setup( ProtocolNaming, NetworkStarter, SyncOracle, + Option, ), ServiceError, > { @@ -254,10 +256,17 @@ fn setup( })?; let sync_oracle = SyncOracle::new(); + + let validator_address_cache = match collect_extra_debugging_data { + true => Some(ValidatorAddressCache::new()), + false => None, + }; + let rpc_builder = { let client = client.clone(); let pool = transaction_pool.clone(); let sync_oracle = sync_oracle.clone(); + let validator_address_cache = validator_address_cache.clone(); Box::new(move |deny_unsafe, _| { let deps = RpcFullDeps { client: client.clone(), @@ -266,6 +275,7 @@ fn setup( import_justification_tx: import_justification_tx.clone(), justification_translator: JustificationTranslator::new(chain_status.clone()), sync_oracle: sync_oracle.clone(), + validator_address_cache: validator_address_cache.clone(), }; Ok(create_full_rpc(deps)?) @@ -294,6 +304,7 @@ fn setup( protocol_naming, network_starter, sync_oracle, + validator_address_cache, )) } @@ -332,19 +343,30 @@ pub fn new_authority( let chain_status = SubstrateChainStatus::new(backend.clone()) .map_err(|e| ServiceError::Other(format!("failed to set up chain status: {e}")))?; - let (_rpc_handlers, network, sync_network, protocol_naming, network_starter, sync_oracle) = - setup( - config, - backend, - chain_status.clone(), - &keystore_container, - import_queue, - transaction_pool.clone(), - &mut task_manager, - client.clone(), - &mut telemetry, - justification_tx, - )?; + + let collect_extra_debugging_data = !aleph_config.no_collection_of_extra_debugging_data(); + + let ( + _rpc_handlers, + network, + sync_network, + protocol_naming, + network_starter, + sync_oracle, + validator_address_cache, + ) = setup( + config, + backend, + chain_status.clone(), + &keystore_container, + import_queue, + transaction_pool.clone(), + &mut task_manager, + client.clone(), + &mut telemetry, + justification_tx, + collect_extra_debugging_data, + )?; let mut proposer_factory = sc_basic_authorship::ProposerFactory::new( task_manager.spawn_handle(), @@ -402,8 +424,6 @@ pub fn new_authority( .unwrap_or(usize::MAX), }; - let validator_address_cache = None; - let aleph_config = AlephConfig { network, sync_network, diff --git a/bin/runtime/src/lib.rs b/bin/runtime/src/lib.rs index f1afea9970..c1edc8b5d7 100644 --- a/bin/runtime/src/lib.rs +++ b/bin/runtime/src/lib.rs @@ -1023,7 +1023,7 @@ impl_runtime_apis! { queued_keys.into_iter().filter_map(|(_, keys)| keys.get(AURA)).collect() } - fn key_owner(key: AlephId) -> Option { + fn key_owner(key: AlephId) -> Option { Session::key_owner(primitives::KEY_TYPE, key.as_ref()) } } diff --git a/finality-aleph/src/lib.rs b/finality-aleph/src/lib.rs index b5f4845453..15b5834ac7 100644 --- a/finality-aleph/src/lib.rs +++ b/finality-aleph/src/lib.rs @@ -64,7 +64,10 @@ pub use crate::{ import::{AlephBlockImport, RedirectingBlockImport, TracingBlockImport}, justification::AlephJustification, metrics::TimingBlockMetrics, - network::{address_cache::ValidatorAddressCache, Protocol, ProtocolNaming}, + network::{ + address_cache::{ValidatorAddressCache, ValidatorAddressingInfo}, + Protocol, ProtocolNaming, + }, nodes::run_validator_node, session::SessionPeriod, sync::{ diff --git a/finality-aleph/src/network/address_cache.rs b/finality-aleph/src/network/address_cache.rs index 469a08ea7b..a74434e8ce 100644 --- a/finality-aleph/src/network/address_cache.rs +++ b/finality-aleph/src/network/address_cache.rs @@ -1,15 +1,16 @@ -use std::{fmt::Debug, num::NonZeroUsize, sync::Arc}; +use std::{collections::HashMap, fmt::Debug, num::NonZeroUsize, sync::Arc}; use lru::LruCache; use parking_lot::Mutex; use primitives::AccountId; +use serde::{Deserialize, Serialize}; use crate::{ abft::NodeIndex, idx_to_account::ValidatorIndexToAccountIdConverter, session::SessionId, }; /// Network details for a given validator in a given session. -#[derive(Debug, Clone)] +#[derive(Debug, Clone, Serialize, Deserialize)] pub struct ValidatorAddressingInfo { /// Session to which given information applies. pub session: SessionId, @@ -20,7 +21,7 @@ pub struct ValidatorAddressingInfo { } /// Stores most recent information about validator addresses. -#[derive(Debug, Clone)] +#[derive(Clone)] pub struct ValidatorAddressCache { data: Arc>>, } @@ -40,6 +41,10 @@ impl ValidatorAddressCache { pub fn insert(&self, validator_stash: AccountId, info: ValidatorAddressingInfo) { self.data.lock().put(validator_stash, info); } + + pub fn snapshot(&self) -> HashMap { + HashMap::from_iter(self.data.lock().iter().map(|(k, v)| (k.clone(), v.clone()))) + } } impl Default for ValidatorAddressCache { diff --git a/finality-aleph/src/session.rs b/finality-aleph/src/session.rs index a8266014d9..71198a2624 100644 --- a/finality-aleph/src/session.rs +++ b/finality-aleph/src/session.rs @@ -1,4 +1,5 @@ use parity_scale_codec::{Decode, Encode}; +use serde::{Deserialize, Serialize}; use crate::aleph_primitives::BlockNumber; @@ -68,7 +69,21 @@ pub mod testing { } } -#[derive(Copy, Clone, Debug, Default, Eq, PartialEq, Hash, Ord, PartialOrd, Encode, Decode)] +#[derive( + Copy, + Clone, + Debug, + Default, + Eq, + PartialEq, + Hash, + Ord, + PartialOrd, + Encode, + Decode, + Serialize, + Deserialize, +)] pub struct SessionId(pub u32); impl SessionId {