Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add search by validator key to whois #339

Merged
merged 5 commits into from
May 2, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,3 +33,4 @@ Use the output file to replace the older in the `assets` folder then rebuild.
- [polkadot-parachain-tracer](parachain-tracer/README.md) - Parachain progress monitoring and debugging utility
- [polkadot-block-time](block-time/README.md) - display the current block time in the substrate based network
- [polkadot-kvdb](kvdb/README.md) - inspect key-value database used by parachains or the relay chain
- [polkadot-whois](whois/README.md) - tracking of validators using a substrate telemetry data.
33 changes: 24 additions & 9 deletions essentials/src/api/subxt_wrapper.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,21 +25,14 @@ pub use crate::metadata::polkadot::{
},
};
use crate::{
types::{AccountId32, Timestamp, H256},
types::{AccountId32, SessionKeys, SubxtCall, Timestamp, H256},
utils::{Retry, RetryOptions},
};
use codec::Decode;
use log::error;
use thiserror::Error;

#[cfg(feature = "rococo")]
pub use subxt_runtime_types::rococo_runtime::RuntimeCall as SubxtCall;

#[cfg(feature = "polkadot")]
pub use subxt_runtime_types::polkadot_runtime::RuntimeCall as SubxtCall;

use std::{collections::hash_map::HashMap, fmt::Debug};
use subxt::{OnlineClient, PolkadotConfig};
use thiserror::Error;

/// Subxt based APIs for fetching via RPC and processing of extrinsics.
pub enum RequestType {
Expand All @@ -65,6 +58,8 @@ pub enum RequestType {
GetSessionInfo(u32),
/// Get information about validators account keys in some session.
GetSessionAccountKeys(u32),
/// Get information about validator's next session keys.
GetSessionNextKeys(AccountId32),
/// Get information about inbound HRMP channels, accepts block hash and destination ParaId
GetInboundHRMPChannels(<PolkadotConfig as subxt::Config>::Hash, u32),
/// Get data from a specific inbound HRMP channel
Expand Down Expand Up @@ -112,6 +107,9 @@ impl Debug for RequestType {
RequestType::GetSessionAccountKeys(id) => {
format!("get session account keys: {:?}", id)
},
RequestType::GetSessionNextKeys(account) => {
format!("get next session account keys: {:?}", account)
},
RequestType::GetInboundHRMPChannels(h, para_id) => {
format!("get inbound channels: {:?}; para id: {}", h, para_id)
},
Expand Down Expand Up @@ -159,6 +157,8 @@ pub enum Response {
SessionInfo(Option<polkadot_rt_primitives::v2::SessionInfo>),
/// Session keys
SessionAccountKeys(Option<Vec<AccountId32>>),
/// Session next keys for a validator
SessionNextKeys(Option<SessionKeys>),
/// HRMP channels for some parachain (e.g. who are sending messages to us)
HRMPChannels(BTreeMap<u32, SubxtHrmpChannel>),
/// HRMP content for a specific channel
Expand Down Expand Up @@ -226,6 +226,7 @@ impl RequestExecutor {
RequestType::GetSessionInfo(session_index) => subxt_get_session_info(&api, session_index).await,
RequestType::GetSessionAccountKeys(session_index) =>
subxt_get_session_account_keys(&api, session_index).await,
RequestType::GetSessionNextKeys(ref account) => subxt_get_session_next_keys(&api, account).await,
RequestType::GetInboundHRMPChannels(hash, para_id) =>
subxt_get_inbound_hrmp_channels(&api, hash, para_id).await,
RequestType::GetOutboundHRMPChannels(hash, para_id) =>
Expand Down Expand Up @@ -347,6 +348,14 @@ impl RequestExecutor {
wrap_subxt_call!(self, GetSessionAccountKeys, SessionAccountKeys, url, session_index)
}

pub async fn get_session_next_keys(
&mut self,
url: &str,
account: AccountId32,
) -> std::result::Result<Option<SessionKeys>, SubxtWrapperError> {
wrap_subxt_call!(self, GetSessionNextKeys, SessionNextKeys, url, account)
}

pub async fn get_inbound_hrmp_channels(
&mut self,
url: &str,
Expand Down Expand Up @@ -485,6 +494,12 @@ async fn subxt_get_session_account_keys(api: &OnlineClient<PolkadotConfig>, sess
Ok(Response::SessionAccountKeys(session_keys))
}

async fn subxt_get_session_next_keys(api: &OnlineClient<PolkadotConfig>, account: &AccountId32) -> Result {
let addr = polkadot::storage().session().next_keys(account);
let next_keys = api.storage().at_latest().await?.fetch(&addr).await?;
Ok(Response::SessionNextKeys(next_keys))
}

/// A wrapper over subxt HRMP channel configuration
#[derive(Debug, Clone)]
pub struct SubxtHrmpChannel {
Expand Down
167 changes: 166 additions & 1 deletion essentials/src/telemetry_feed.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,25 @@
// along with polkadot-introspector. If not, see <http://www.gnu.org/licenses/>.
//

use crate::types::{BlockNumber, Timestamp, H256};
use serde::{Deserialize, Serialize};
use serde_json::value::RawValue;

use crate::types::{BlockNumber, Timestamp, H256};
macro_rules! display_or {
($option:expr, $none:expr) => {
if let Some(value) = &$option {
format!("{}", value)
} else {
$none.to_string()
}
};
}

macro_rules! join {
($iter:expr) => {
$iter.iter().map(|x| format!("{}", x)).collect::<Vec<String>>().join(", ")
};
}

pub type FeedNodeId = usize;

Expand All @@ -36,6 +51,25 @@ pub struct BlockDetails {
pub propagation_time: Option<u64>,
}

impl std::fmt::Display for BlockDetails {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(
f,
"Block
block_hash: {}
block_height: {}
block_time: {}
block_timestamp: {}
propagation_time: {}",
self.block.hash,
self.block.height,
self.block_time,
self.block_timestamp,
display_or!(self.propagation_time, "none"),
)
}
}

#[derive(Debug, PartialEq)]
pub struct NodeDetails {
pub name: String,
Expand All @@ -47,6 +81,30 @@ pub struct NodeDetails {
pub sysinfo: Option<NodeSysInfo>,
}

impl std::fmt::Display for NodeDetails {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(
f,
"Details
name: {}
implementation: {}
version: {}
validator: {}
network_id: {}
ip: {}

{}",
self.name,
self.implementation,
self.version,
display_or!(self.validator, "none"),
display_or!(self.network_id, "none"),
display_or!(self.ip, "none"),
display_or!(self.sysinfo, "SysInfo\nnone")
)
}
}

#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
pub struct NodeSysInfo {
pub cpu: Option<Box<str>>,
Expand All @@ -57,31 +115,103 @@ pub struct NodeSysInfo {
pub is_virtual_machine: Option<bool>,
}

impl std::fmt::Display for NodeSysInfo {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(
f,
"SysInfo
cpu: {}
memory: {}
core_count: {}
linux_kernel: {}
linux_distro: {}
is_virtual_machine: {}",
display_or!(self.cpu, "none"),
display_or!(self.memory, "none"),
display_or!(self.core_count, "none"),
display_or!(self.linux_kernel, "none"),
display_or!(self.linux_distro, "none"),
display_or!(self.is_virtual_machine, "none"),
)
}
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
pub struct NodeStats {
pub peers: u64,
pub txcount: u64,
}

impl std::fmt::Display for NodeStats {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(
f,
"Stats
peers: {}
txcount: {}",
self.peers, self.txcount
)
}
}

#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
pub struct NodeLocation {
lat: f32,
long: f32,
city: String,
}

impl std::fmt::Display for NodeLocation {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(
f,
"Location
city: {}
lat: {}
long: {}",
self.city, self.lat, self.long
)
}
}

#[derive(Debug, Default, PartialEq)]
pub struct NodeIO {
pub used_state_cache_size: Vec<f32>,
}

impl std::fmt::Display for NodeIO {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(
f,
"IO
used_state_cache_size: {}",
join!(self.used_state_cache_size)
)
}
}

#[derive(Debug, Default, PartialEq)]
pub struct NodeHardware {
pub upload: Vec<f64>,
pub download: Vec<f64>,
pub chart_stamps: Vec<f64>,
}

impl std::fmt::Display for NodeHardware {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(
f,
"Hardware
upload: {}
download: {}
chart_stamps: {}",
join!(self.upload),
join!(self.download),
join!(self.chart_stamps)
)
}
}

#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
pub struct NodeHwBench {
pub cpu_hashrate_score: u64,
Expand All @@ -90,6 +220,23 @@ pub struct NodeHwBench {
pub disk_random_write_score: Option<u64>,
}

impl std::fmt::Display for NodeHwBench {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(
f,
"NodeHwBench
cpu_hashrate_score: {}
memory_memcpy_score: {}
disk_sequential_write_score: {}
disk_random_write_score: {}",
self.cpu_hashrate_score,
self.memory_memcpy_score,
display_or!(self.disk_sequential_write_score, "none"),
display_or!(self.disk_random_write_score, "none"),
)
}
}

#[derive(Serialize, Deserialize, PartialEq, Eq, Debug, Default)]
pub struct Ranking<K> {
pub list: Vec<(K, u64)>,
Expand Down Expand Up @@ -143,6 +290,24 @@ pub struct AddedNode {
hwbench: Option<NodeHwBench>,
}

impl std::fmt::Display for AddedNode {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(
f,
"node_id: {}\nstartup_time: {}\n\n{}\n\n{}\n\n{}\n\n{}\n\n{}\n\n{}\n\n{}",
self.node_id,
display_or!(self.startup_time, "none"),
self.details,
self.block_details,
display_or!(self.location, "Location:\nnone"),
display_or!(self.hwbench, "HwBench:\nnone"),
self.stats,
self.io,
self.hardware
)
}
}

#[derive(Debug, PartialEq)]
pub struct RemovedNode {
pub node_id: FeedNodeId,
Expand Down
2 changes: 1 addition & 1 deletion essentials/src/telemetry_subscription.rs
Original file line number Diff line number Diff line change
Expand Up @@ -182,7 +182,7 @@ async fn choose_chain(chains: &HashMap<H256, AddedChain>) -> color_eyre::Result<
return Ok(list[0].genesis_hash)
}

println!("Found {} chains.\n", list.len());
println!("Connected to telemetry backend, {} chains found.\n", list.len());

let chain_index: usize;
let indexed_list: Vec<(usize, &AddedChain)> = list.iter().enumerate().map(|(i, c)| (i + 1, c)).collect();
Expand Down
8 changes: 8 additions & 0 deletions essentials/src/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,17 @@
// along with polkadot-introspector. If not, see <http://www.gnu.org/licenses/>.
//

use crate::metadata::polkadot::runtime_types as subxt_runtime_types;
use subxt::utils;

#[cfg(feature = "polkadot")]
use subxt_runtime_types::polkadot_runtime as runtime;
#[cfg(feature = "rococo")]
use subxt_runtime_types::rococo_runtime as runtime;

pub type BlockNumber = u32;
pub type H256 = utils::H256;
pub type AccountId32 = utils::AccountId32;
pub type Timestamp = u64;
pub type SessionKeys = runtime::SessionKeys;
pub type SubxtCall = runtime::RuntimeCall;
1 change: 1 addition & 0 deletions whois/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,5 @@ futures = "0.3.28"
log = "0.4.17"
polkadot-introspector-essentials = { path = "../essentials" }
polkadot-introspector-priority-channel = { path = "../priority-channel" }
thiserror = "1.0.39"
tokio = { version = "1.28.0", features = ["macros", "rt-multi-thread", "signal"] }
9 changes: 9 additions & 0 deletions whois/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# polkadot-whois

Tracking of validators using a substrate telemetry data.

Usage:

```
cargo run --features=polkadot --bin polkadot-whois 1497QNdycmxqMi3VJDxZDhaJh4s9tytr5RFWyrLcNse2xqPD --ws=wss://rpc.polkadot.io:443 --feed=wss://feed.telemetry.polkadot.io/feed
```
Loading