Skip to content

Commit 76b8cab

Browse files
drcpu-githubaesedepece
authored andcommitted
feat(cli): add queryPowers to CLI
1 parent 1b0420c commit 76b8cab

File tree

8 files changed

+147
-19
lines changed

8 files changed

+147
-19
lines changed

Cargo.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

data_structures/src/capabilities.rs

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,21 @@
11
use serde::{Deserialize, Serialize};
2+
use strum_macros::{EnumString, IntoStaticStr};
23

34
#[repr(u8)]
4-
#[derive(Clone, Copy, Debug, Default, Eq, PartialEq, serde::Deserialize, serde::Serialize)]
5+
#[derive(
6+
Clone,
7+
Copy,
8+
Debug,
9+
Default,
10+
EnumString,
11+
Eq,
12+
IntoStaticStr,
13+
PartialEq,
14+
serde::Deserialize,
15+
serde::Serialize,
16+
)]
517
#[serde(rename_all = "lowercase")]
18+
#[strum(serialize_all = "snake_case")]
619
pub enum Capability {
720
/// The base block mining and superblock voting capability
821
#[default]

node/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ pin-project-lite = "0.2"
3030
sentry = { version = "0.29.3", features = ["log"], optional = true }
3131
serde = { version = "1.0.104", features = ["derive"] }
3232
serde_json = "1.0.47"
33+
strum_macros = "0.26.4"
3334
tokio = { version = "1.0.1", features = ["io-util", "net", "time", "sync"] }
3435
tokio-util = { version = "0.7", features = ["codec"] }
3536
trust-dns-resolver = { version = "0.20.0" , default-features = false, features = ["tokio-runtime", "system-config"] }

node/src/actors/chain_manager/handlers.rs

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1471,10 +1471,19 @@ impl Handler<QueryStakePowers> for ChainManager {
14711471
type Result = <QueryStakePowers as Message>::Result;
14721472

14731473
fn handle(&mut self, msg: QueryStakePowers, _ctx: &mut Self::Context) -> Self::Result {
1474-
self.chain_state
1475-
.stakes
1476-
.by_rank(msg.capability, self.current_epoch.unwrap())
1477-
.collect()
1474+
let mut powers = HashMap::new();
1475+
let current_epoch = self.current_epoch.unwrap();
1476+
for capability in msg.capabilities {
1477+
for (key, power) in self
1478+
.chain_state
1479+
.stakes
1480+
.by_rank(capability, current_epoch)
1481+
{
1482+
powers.entry(key).or_insert(vec![]).push(power);
1483+
}
1484+
}
1485+
1486+
powers.into_iter().collect()
14781487
}
14791488
}
14801489

node/src/actors/json_rpc/api.rs

Lines changed: 23 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ use itertools::Itertools;
1919
use jsonrpc_core::{BoxFuture, Error, Params, Value};
2020
use jsonrpc_pubsub::{Subscriber, SubscriptionId};
2121
use serde::{Deserialize, Serialize};
22+
use strum_macros::IntoStaticStr;
2223

2324
use witnet_crypto::key::KeyPath;
2425
use witnet_data_structures::{
@@ -2267,31 +2268,44 @@ pub async fn query_stakes(params: Result<Option<QueryStakesParams>, Error>) -> J
22672268
.await
22682269
}
22692270

2270-
/// Format of the output of getTransaction
2271+
/// Param for query_stakes
2272+
#[derive(Clone, Debug, Deserialize, Eq, PartialEq, IntoStaticStr, Serialize)]
2273+
#[serde(rename_all = "lowercase")]
2274+
pub enum QueryPowersParams {
2275+
/// To query all validators' power for a specific capability
2276+
Capability(Capability),
2277+
/// To query all powers
2278+
All(bool),
2279+
}
2280+
2281+
/// Format of the output of query_powers
22712282
#[derive(Clone, Debug, PartialEq, Eq, serde::Deserialize, serde::Serialize)]
22722283
pub struct QueryPowersRecord {
22732284
/// Current power
2274-
pub power: u64,
2285+
pub powers: Vec<u64>,
22752286
/// Validator's stringified pkh
22762287
pub validator: String,
22772288
/// Withdrawer's stringified pkh
22782289
pub withdrawer: String,
22792290
}
22802291

22812292
/// Query the amount of nanowits staked by an address.
2282-
pub async fn query_powers(params: Result<(Capability,), Error>) -> JsonRpcResult {
2283-
let capability = match params {
2284-
Ok(x) => x.0,
2285-
Err(_) => Capability::Mining,
2293+
pub async fn query_powers(params: Result<QueryPowersParams, Error>) -> JsonRpcResult {
2294+
// Short-circuit if parameters are wrong
2295+
let params = params?;
2296+
2297+
let capabilities = match params {
2298+
QueryPowersParams::All(_) => ALL_CAPABILITIES.to_vec(),
2299+
QueryPowersParams::Capability(c) => vec![c],
22862300
};
22872301
ChainManager::from_registry()
2288-
.send(QueryStakePowers { capability })
2302+
.send(QueryStakePowers { capabilities })
22892303
.map(|res| match res {
22902304
Ok(candidates) => {
22912305
let candidates: Vec<QueryPowersRecord> = candidates
22922306
.iter()
2293-
.map(|(key, power)| QueryPowersRecord {
2294-
power: *power,
2307+
.map(|(key, powers)| QueryPowersRecord {
2308+
powers: powers.clone(),
22952309
validator: key.validator.to_string(),
22962310
withdrawer: key.withdrawer.to_string(),
22972311
})

node/src/actors/messages.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -347,12 +347,12 @@ impl Message for StakeAuthorization {
347347
/// Message for querying stakes
348348
#[derive(Clone, Debug, Default, Eq, PartialEq, Serialize, Deserialize)]
349349
pub struct QueryStakePowers {
350-
/// capability being searched for
351-
pub capability: Capability,
350+
/// capabilities being searched for
351+
pub capabilities: Vec<Capability>,
352352
}
353353

354354
impl Message for QueryStakePowers {
355-
type Result = Vec<(StakeKey<PublicKeyHash>, Power)>;
355+
type Result = Vec<(StakeKey<PublicKeyHash>, Vec<Power>)>;
356356
}
357357

358358
/// Stake key for quering stakes

src/cli/node/json_rpc_client.rs

Lines changed: 72 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ use ansi_term::Color::{Purple, Red, White, Yellow};
1414
use failure::{bail, Fail};
1515
use itertools::Itertools;
1616
use num_format::{Locale, ToFormattedString};
17-
use prettytable::{row, Table};
17+
use prettytable::{row, Cell, Row, Table};
1818
use qrcode::render::unicode;
1919
use serde::{de::DeserializeOwned, Deserialize, Serialize};
2020

@@ -24,6 +24,7 @@ use witnet_crypto::{
2424
key::{ExtendedPK, ExtendedSK},
2525
};
2626
use witnet_data_structures::{
27+
capabilities::{Capability, ALL_CAPABILITIES},
2728
chain::{
2829
priority::{PrioritiesEstimate, Priority, PriorityEstimate, TimeToBlock},
2930
tapi::{current_active_wips, ActiveWips},
@@ -49,7 +50,8 @@ use witnet_data_structures::{
4950
use witnet_node::actors::{
5051
chain_manager::run_dr_locally,
5152
json_rpc::api::{
52-
AddrType, GetBlockChainParams, GetTransactionOutput, PeersResult, QueryStakesParams,
53+
AddrType, GetBlockChainParams, GetTransactionOutput, PeersResult, QueryPowersParams,
54+
QueryPowersRecord, QueryStakesParams,
5355
},
5456
messages::{
5557
AuthorizeStake, BuildDrt, BuildStakeParams, BuildStakeResponse, BuildUnstakeParams,
@@ -2009,6 +2011,74 @@ pub fn query_stakes(
20092011
Ok(())
20102012
}
20112013

2014+
pub fn query_powers(
2015+
addr: SocketAddr,
2016+
capability: Option<String>,
2017+
all: bool,
2018+
) -> Result<(), failure::Error> {
2019+
let mut stream = start_client(addr)?;
2020+
let params = if all {
2021+
QueryPowersParams::All(true)
2022+
} else {
2023+
match capability {
2024+
Some(c) => match Capability::from_str(&c) {
2025+
Ok(c) => QueryPowersParams::Capability(c),
2026+
Err(_) => QueryPowersParams::Capability(Capability::Mining),
2027+
},
2028+
None => QueryPowersParams::Capability(Capability::Mining),
2029+
}
2030+
};
2031+
2032+
let response = send_request(
2033+
&mut stream,
2034+
&format!(
2035+
r#"{{"jsonrpc": "2.0","method": "queryPowers", "params": {}, "id": 1}}"#,
2036+
serde_json::to_string(&params).unwrap()
2037+
),
2038+
)?;
2039+
2040+
let mut powers: Vec<QueryPowersRecord> = parse_response(&response)?;
2041+
powers.sort_by_key(|power| Reverse(power.powers[0]));
2042+
2043+
let mut powers_table = Table::new();
2044+
powers_table.set_format(*prettytable::format::consts::FORMAT_NO_BORDER_LINE_SEPARATOR);
2045+
if all {
2046+
let mut header = vec![
2047+
Cell::new("Validator").style_spec("c"),
2048+
Cell::new("Withdrawer").style_spec("c"),
2049+
];
2050+
for capability in ALL_CAPABILITIES {
2051+
let capability_str: &'static str = capability.into();
2052+
header.push(Cell::new(capability_str).style_spec("c"));
2053+
}
2054+
powers_table.set_titles(Row::new(header));
2055+
for power in powers.iter() {
2056+
let mut row = vec![
2057+
Cell::new(&power.validator.to_string()),
2058+
Cell::new(&power.withdrawer.to_string()),
2059+
];
2060+
for p in &power.powers {
2061+
row.push(Cell::new(&p.to_formatted_string(&Locale::en)).style_spec("r"));
2062+
}
2063+
powers_table.add_row(Row::new(row));
2064+
}
2065+
} else {
2066+
let capability_str: &'static str = params.into();
2067+
powers_table.set_titles(row![c->"Validator", c->"Withdrawer", c->capability_str]);
2068+
for power in powers.iter() {
2069+
powers_table.add_row(row![
2070+
power.validator,
2071+
power.withdrawer,
2072+
r->(power.powers[0]).to_formatted_string(&Locale::en),
2073+
]);
2074+
}
2075+
}
2076+
powers_table.printstd();
2077+
println!();
2078+
2079+
Ok(())
2080+
}
2081+
20122082
#[derive(Serialize, Deserialize)]
20132083
struct SignatureWithData {
20142084
address: String,

src/cli/node/with_node.rs

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -304,6 +304,11 @@ pub fn exec_cmd(
304304
all,
305305
long,
306306
),
307+
Command::QueryPowers {
308+
node,
309+
capability,
310+
all,
311+
} => rpc::query_powers(node.unwrap_or(default_jsonrpc), capability, all),
307312
Command::Unstake {
308313
node,
309314
operator,
@@ -840,6 +845,21 @@ pub enum Command {
840845
#[structopt(short = "l", long = "long")]
841846
long: bool,
842847
},
848+
849+
#[structopt(
850+
name = "queryPowers",
851+
alias = "powers",
852+
about = "Retrieve information about powers"
853+
)]
854+
QueryPowers {
855+
/// Socket address of the Witnet node to query
856+
#[structopt(short = "n", long = "node")]
857+
node: Option<SocketAddr>,
858+
#[structopt(short = "c", long = "capability")]
859+
capability: Option<String>,
860+
#[structopt(short = "a", long = "all")]
861+
all: bool,
862+
},
843863
#[structopt(name = "unstake", about = "Create an unstake transaction")]
844864
Unstake {
845865
/// Socket address of the Witnet node to query

0 commit comments

Comments
 (0)