Skip to content

Commit

Permalink
A0-3094: Validators network details rpc call (#1447)
Browse files Browse the repository at this point in the history
# Description

Adding an RPC call to get network details of validators. This only pulls
and caches network data that was previously observed by a node, without
modifying or adding any new information flow between nodes in the
network.

Related PRs: #1448 #1449

<details>
  <summary> RPC query output on local network </summary>
  
```curl -H "Content-Type: application/json" -d '{"id":1,
"jsonrpc":"2.0", "method": "alephNode_unstable_validatorNetworkInfo",
"params": []}' http://localhost:9948/```
  ```
 {
    "jsonrpc": "2.0",
    "result": {
        "5F4H97f7nQovyrbiq4ZetaaviNwThSVcFobcA5aGab6167dK": {
            "session": 1,
            "network_level_address": "127.0.0.1:30346",
"validator_network_peer_id":
"5CwWuuXMCvcSC7hqeMdFSfNFzVGXCAtdSGAMjwV1nLwaqtqE"
        },
        "5GBNeWRhZc2jXu7D55rBimKYDk8PGk8itRYFTPfC8RJLKG5o": {
            "session": 1,
            "network_level_address": "127.0.0.1:30344",
"validator_network_peer_id":
"5H7yZo8EzYkSsZn7MgC4f9vaVYQLgNaS4kEZ29Q7WtiYMVF8"
        },
        "5Dfis6XL8J2P6JHUnUtArnFWndn62SydeP8ee8sG2ky9nfm9": {
            "session": 1,
            "network_level_address": "127.0.0.1:30345",
"validator_network_peer_id":
"5HZFGbT6tsY2iV2YT927wnN4q2TxmPT67SUJE99TqGQsjpGV"
        },
        "5D34dL5prEUaGNQtPPZ3yN5Y6BnkfXunKXXz6fo7ZJbLwRRH": {
            "session": 1,
            "network_level_address": "127.0.0.1:30343",
"validator_network_peer_id":
"5E1YcJyx4u3kQ4UiRPgPXPSvb2vbcCR2DsxS927GM6x8wz85"
        }
    },
    "id": 1
}                        
  ```

</details>

Has been run also on testnet, slowly collects network details for
authorities in each session (without `AccountId` because of the old
runtime version).

# Type of change

Please delete options that are not relevant.

- New feature (non-breaking change which adds functionality)

# Checklist:

<!-- delete when not applicable to your PR -->

- I have created new documentation
  • Loading branch information
ggawryal authored Nov 9, 2023
1 parent 1125e02 commit 97bc9cf
Show file tree
Hide file tree
Showing 8 changed files with 106 additions and 25 deletions.
9 changes: 9 additions & 0 deletions bin/node/src/aleph_cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -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
}
}
30 changes: 28 additions & 2 deletions bin/node/src/aleph_node_rpc.rs
Original file line number Diff line number Diff line change
@@ -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},
Expand Down Expand Up @@ -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.
Expand All @@ -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<Error> for JsonRpseeError {
fn from(e: Error) -> Self {
Expand Down Expand Up @@ -132,6 +140,11 @@ impl From<Error> 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()
}
Expand All @@ -156,6 +169,9 @@ pub trait AlephNodeApi<BE> {
///
#[method(name = "ready")]
fn ready(&self) -> RpcResult<bool>;

#[method(name = "unstable_validatorNetworkInfo")]
fn validator_network_info(&self) -> RpcResult<HashMap<AccountId, ValidatorAddressingInfo>>;
}

/// Aleph Node API implementation
Expand All @@ -164,6 +180,7 @@ pub struct AlephNode<Client, SO> {
justification_translator: JustificationTranslator,
client: Arc<Client>,
sync_oracle: SO,
validator_address_cache: Option<ValidatorAddressCache>,
}

impl<Client, SO> AlephNode<Client, SO>
Expand All @@ -175,12 +192,14 @@ where
justification_translator: JustificationTranslator,
client: Arc<Client>,
sync_oracle: SO,
validator_address_cache: Option<ValidatorAddressCache>,
) -> Self {
AlephNode {
import_justification_tx,
justification_translator,
client,
sync_oracle,
validator_address_cache,
}
}
}
Expand Down Expand Up @@ -248,6 +267,13 @@ where
fn ready(&self) -> RpcResult<bool> {
Ok(!self.sync_oracle.is_offline() && !self.sync_oracle.is_major_syncing())
}

fn validator_network_info(&self) -> RpcResult<HashMap<AccountId, ValidatorAddressingInfo>> {
self.validator_address_cache
.as_ref()
.map(|c| c.snapshot())
.ok_or(Error::NetworkInfoCachingNotEnabled.into())
}
}

fn read_storage<
Expand Down
5 changes: 4 additions & 1 deletion bin/node/src/rpc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -30,6 +30,7 @@ pub struct FullDeps<C, P, SO> {
pub import_justification_tx: mpsc::UnboundedSender<Justification>,
pub justification_translator: JustificationTranslator,
pub sync_oracle: SO,
pub validator_address_cache: Option<ValidatorAddressCache>,
}

/// Instantiate all full RPC extensions.
Expand Down Expand Up @@ -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())?;
Expand All @@ -75,6 +77,7 @@ where
justification_translator,
client,
sync_oracle,
validator_address_cache,
)
.into_rpc(),
)?;
Expand Down
52 changes: 36 additions & 16 deletions bin/node/src/service.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -210,6 +210,7 @@ fn setup(
client: Arc<FullClient>,
telemetry: &mut Option<Telemetry>,
import_justification_tx: mpsc::UnboundedSender<Justification>,
collect_extra_debugging_data: bool,
) -> Result<
(
RpcHandlers,
Expand All @@ -218,6 +219,7 @@ fn setup(
ProtocolNaming,
NetworkStarter,
SyncOracle,
Option<ValidatorAddressCache>,
),
ServiceError,
> {
Expand Down Expand Up @@ -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(),
Expand All @@ -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)?)
Expand Down Expand Up @@ -294,6 +304,7 @@ fn setup(
protocol_naming,
network_starter,
sync_oracle,
validator_address_cache,
))
}

Expand Down Expand Up @@ -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(),
Expand Down Expand Up @@ -402,8 +424,6 @@ pub fn new_authority(
.unwrap_or(usize::MAX),
};

let validator_address_cache = None;

let aleph_config = AlephConfig {
network,
sync_network,
Expand Down
2 changes: 1 addition & 1 deletion bin/runtime/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1023,7 +1023,7 @@ impl_runtime_apis! {
queued_keys.into_iter().filter_map(|(_, keys)| keys.get(AURA)).collect()
}

fn key_owner(key: AlephId) -> Option<AccountId> {
fn key_owner(key: AlephId) -> Option<AccountId> {
Session::key_owner(primitives::KEY_TYPE, key.as_ref())
}
}
Expand Down
5 changes: 4 additions & 1 deletion finality-aleph/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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::{
Expand Down
11 changes: 8 additions & 3 deletions finality-aleph/src/network/address_cache.rs
Original file line number Diff line number Diff line change
@@ -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,
Expand All @@ -20,7 +21,7 @@ pub struct ValidatorAddressingInfo {
}

/// Stores most recent information about validator addresses.
#[derive(Debug, Clone)]
#[derive(Clone)]
pub struct ValidatorAddressCache {
data: Arc<Mutex<LruCache<AccountId, ValidatorAddressingInfo>>>,
}
Expand All @@ -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<AccountId, ValidatorAddressingInfo> {
HashMap::from_iter(self.data.lock().iter().map(|(k, v)| (k.clone(), v.clone())))
}
}

impl Default for ValidatorAddressCache {
Expand Down
17 changes: 16 additions & 1 deletion finality-aleph/src/session.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use parity_scale_codec::{Decode, Encode};
use serde::{Deserialize, Serialize};

use crate::aleph_primitives::BlockNumber;

Expand Down Expand Up @@ -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 {
Expand Down

0 comments on commit 97bc9cf

Please sign in to comment.