Skip to content

Commit cf41b56

Browse files
guidiazaesedepece
authored andcommitted
feat(json_rpc): improve queryPowers: distinct, limit, offset, order_by.
1 parent 380e4b1 commit cf41b56

File tree

7 files changed

+107
-98
lines changed

7 files changed

+107
-98
lines changed

data_structures/src/capabilities.rs

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

44
#[repr(u8)]
55
#[derive(
66
Clone,
77
Copy,
88
Debug,
99
Default,
10+
EnumIter,
1011
EnumString,
1112
Eq,
13+
Hash,
1214
IntoStaticStr,
1315
PartialEq,
1416
serde::Deserialize,

data_structures/src/transaction_factory.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -96,8 +96,8 @@ pub enum NodeBalance2 {
9696
impl NodeBalance2 {
9797
pub fn add_utxo_value(&mut self, utxo_value: u64, utxo_locked: bool) {
9898
if let NodeBalance2::One {
99-
unlocked, locked, ..
100-
} = self
99+
unlocked, locked, ..
100+
} = self
101101
{
102102
if utxo_locked {
103103
locked.add_assign(utxo_value);

node/src/actors/chain_manager/handlers.rs

Lines changed: 35 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,11 @@ use witnet_data_structures::{
2020
get_protocol_version,
2121
proto::versioning::ProtocolVersion,
2222
refresh_protocol_version,
23-
staking::{errors::StakesError, prelude::StakeKey, stakes::QueryStakesKey},
23+
staking::{
24+
errors::StakesError,
25+
prelude::{Power, StakeKey},
26+
stakes::QueryStakesKey,
27+
},
2428
transaction::{
2529
DRTransaction, StakeTransaction, Transaction, UnstakeTransaction, VTTransaction,
2630
},
@@ -46,7 +50,7 @@ use crate::{
4650
GetMemoryTransaction, GetMempool, GetMempoolResult, GetNodeStats, GetProtocolInfo,
4751
GetReputation, GetReputationResult, GetSignalingInfo, GetState, GetSuperBlockVotes,
4852
GetSupplyInfo, GetSupplyInfo2, GetUtxoInfo, IsConfirmedBlock, PeersBeacons,
49-
QueryStakePowers, QueryStakes, QueryStakesOrderByOptions, ReputationStats, Rewind,
53+
QueryStakes, QueryStakesOrderByOptions, QueryStakingPowers, ReputationStats, Rewind,
5054
SendLastBeacon, SessionUnitResult, SetLastBeacon, SetPeersLimits, SignalingInfo,
5155
SnapshotExport, SnapshotImport, TryMineBlock,
5256
},
@@ -1652,19 +1656,38 @@ impl Handler<QueryStakes> for ChainManager {
16521656
}
16531657
}
16541658

1655-
impl Handler<QueryStakePowers> for ChainManager {
1656-
type Result = <QueryStakePowers as Message>::Result;
1659+
impl Handler<QueryStakingPowers> for ChainManager {
1660+
type Result = <QueryStakingPowers as Message>::Result;
16571661

1658-
fn handle(&mut self, msg: QueryStakePowers, _ctx: &mut Self::Context) -> Self::Result {
1659-
let mut powers = HashMap::new();
1662+
fn handle(&mut self, msg: QueryStakingPowers, _ctx: &mut Self::Context) -> Self::Result {
16601663
let current_epoch = self.current_epoch.unwrap();
1661-
for capability in msg.capabilities {
1662-
for (key, power) in self.chain_state.stakes.by_rank(capability, current_epoch) {
1663-
powers.entry(key).or_insert(vec![]).push(power);
1664-
}
1665-
}
1664+
let limit = msg.limit.unwrap_or(u16::MAX) as usize;
1665+
let offset = msg.offset.unwrap_or_default();
1666+
1667+
// Enumerate power entries order by specified capability,
1668+
// mapping into a record containing: the ranking, the stake key and current power
1669+
let powers = self
1670+
.chain_state
1671+
.stakes
1672+
.by_rank(msg.order_by, current_epoch)
1673+
.enumerate()
1674+
.map(|(index, record)| (index, record.0, record.1));
1675+
1676+
// Skip first `offset` entries and take next `limit`.
1677+
// If distinct is specified, retain just first appearance per validator.
1678+
let powers: Vec<(usize, StakeKey<PublicKeyHash>, Power)> = if msg.distinct.unwrap_or(false)
1679+
{
1680+
powers
1681+
.unique_by(|(_, key, _)| key.validator)
1682+
.skip(offset)
1683+
.take(limit)
1684+
.into_iter()
1685+
.collect()
1686+
} else {
1687+
powers.skip(offset).take(limit).into_iter().collect()
1688+
};
16661689

1667-
powers.into_iter().collect()
1690+
powers
16681691
}
16691692
}
16701693

node/src/actors/json_rpc/api.rs

Lines changed: 13 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@ 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;
2322

2423
use witnet_crypto::key::KeyPath;
2524
use witnet_data_structures::{
@@ -49,7 +48,7 @@ use crate::{
4948
GetItemTransaction, GetKnownPeers, GetMemoryTransaction, GetMempool, GetNodeStats,
5049
GetProtocolInfo, GetReputation, GetSignalingInfo, GetState, GetSupplyInfo,
5150
GetSupplyInfo2, GetUtxoInfo, InitializePeers, IsConfirmedBlock, MagicEither,
52-
QueryStakePowers, QueryStakes, Rewind, SnapshotExport, SnapshotImport,
51+
QueryStakes, QueryStakingPowers, Rewind, SnapshotExport, SnapshotImport,
5352
StakeAuthorization,
5453
},
5554
peers_manager::PeersManager,
@@ -2267,44 +2266,33 @@ pub async fn query_stakes(params: Result<Option<QueryStakes>, Error>) -> JsonRpc
22672266
.await
22682267
}
22692268

2270-
/// Param for query_stakes
2271-
#[derive(Clone, Debug, Deserialize, Eq, PartialEq, IntoStaticStr, Serialize)]
2272-
#[serde(rename_all = "lowercase")]
2273-
pub enum QueryPowersParams {
2274-
/// To query all validators' power for a specific capability
2275-
Capability(Capability),
2276-
/// To query all powers
2277-
All(bool),
2278-
}
2279-
22802269
/// Format of the output of query_powers
22812270
#[derive(Clone, Debug, PartialEq, Eq, serde::Deserialize, serde::Serialize)]
2282-
pub struct QueryPowersRecord {
2283-
/// Current power
2284-
pub powers: Vec<u64>,
2271+
pub struct QueryStakingPowersRecord {
2272+
/// Staking power
2273+
pub power: u64,
2274+
/// Ranking index (1 .. N)
2275+
pub ranking: usize,
22852276
/// Validator's stringified pkh
22862277
pub validator: String,
22872278
/// Withdrawer's stringified pkh
22882279
pub withdrawer: String,
22892280
}
22902281

22912282
/// Query the amount of nanowits staked by an address.
2292-
pub async fn query_powers(params: Result<QueryPowersParams, Error>) -> JsonRpcResult {
2283+
pub async fn query_powers(params: Result<QueryStakingPowers, Error>) -> JsonRpcResult {
22932284
// Short-circuit if parameters are wrong
2294-
let params = params?;
2285+
let msg = params?;
22952286

2296-
let capabilities = match params {
2297-
QueryPowersParams::All(_) => ALL_CAPABILITIES.to_vec(),
2298-
QueryPowersParams::Capability(c) => vec![c],
2299-
};
23002287
ChainManager::from_registry()
2301-
.send(QueryStakePowers { capabilities })
2288+
.send(msg)
23022289
.map(|res| match res {
23032290
Ok(candidates) => {
2304-
let candidates: Vec<QueryPowersRecord> = candidates
2291+
let candidates: Vec<QueryStakingPowersRecord> = candidates
23052292
.iter()
2306-
.map(|(key, powers)| QueryPowersRecord {
2307-
powers: powers.clone(),
2293+
.map(|(ranking, key, power)| QueryStakingPowersRecord {
2294+
power: *power,
2295+
ranking: *ranking,
23082296
validator: key.validator.to_string(),
23092297
withdrawer: key.withdrawer.to_string(),
23102298
})

node/src/actors/messages.rs

Lines changed: 24 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -346,14 +346,32 @@ impl Message for StakeAuthorization {
346346
}
347347

348348
/// Message for querying stakes
349-
#[derive(Clone, Debug, Default, Eq, PartialEq, Serialize, Deserialize)]
350-
pub struct QueryStakePowers {
351-
/// capabilities being searched for
352-
pub capabilities: Vec<Capability>,
349+
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq, serde::Deserialize, serde::Serialize)]
350+
#[serde(rename_all = "camelCase")]
351+
pub struct QueryStakingPowers {
352+
/// Retrieve only first appearence for every distinct validator (default: false)
353+
pub distinct: Option<bool>,
354+
/// Limits max number of entries to return (default: 0 == u16::MAX)
355+
pub limit: Option<u16>,
356+
/// Skips first found entries (default: 0)
357+
pub offset: Option<usize>,
358+
/// Order by specified capability (default: reverse order by coins)
359+
pub order_by: Capability,
360+
}
361+
362+
impl Default for QueryStakingPowers {
363+
fn default() -> Self {
364+
QueryStakingPowers {
365+
distinct: Some(false),
366+
limit: Some(u16::MAX),
367+
offset: Some(0),
368+
order_by: Capability::Mining,
369+
}
370+
}
353371
}
354372

355-
impl Message for QueryStakePowers {
356-
type Result = Vec<(StakeKey<PublicKeyHash>, Vec<Power>)>;
373+
impl Message for QueryStakingPowers {
374+
type Result = Vec<(usize, StakeKey<PublicKeyHash>, Power)>;
357375
}
358376

359377
/// Stake key for quering stakes

src/cli/node/json_rpc_client.rs

Lines changed: 26 additions & 48 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, Cell, Row, Table};
17+
use prettytable::{row, Table};
1818
use qrcode::render::unicode;
1919
use serde::{de::DeserializeOwned, Deserialize, Serialize};
2020

@@ -24,7 +24,7 @@ use witnet_crypto::{
2424
key::{ExtendedPK, ExtendedSK},
2525
};
2626
use witnet_data_structures::{
27-
capabilities::{Capability, ALL_CAPABILITIES},
27+
capabilities::Capability,
2828
chain::{
2929
priority::{PrioritiesEstimate, Priority, PriorityEstimate, TimeToBlock},
3030
tapi::{current_active_wips, ActiveWips},
@@ -50,13 +50,12 @@ use witnet_data_structures::{
5050
use witnet_node::actors::{
5151
chain_manager::run_dr_locally,
5252
json_rpc::api::{
53-
AddrType, GetBlockChainParams, GetTransactionOutput, PeersResult, QueryPowersParams,
54-
QueryPowersRecord,
53+
AddrType, GetBlockChainParams, GetTransactionOutput, PeersResult, QueryStakingPowersRecord,
5554
},
5655
messages::{
5756
AuthorizeStake, BuildDrt, BuildStakeParams, BuildStakeResponse, BuildUnstakeParams,
5857
BuildVtt, GetBalanceTarget, GetReputationResult, MagicEither, QueryStakes,
59-
QueryStakesFilter, SignalingInfo, StakeAuthorization,
58+
QueryStakesFilter, QueryStakingPowers, SignalingInfo, StakeAuthorization,
6059
},
6160
};
6261
use witnet_rad::types::RadonTypes;
@@ -2019,19 +2018,18 @@ pub fn query_stakes(
20192018
pub fn query_powers(
20202019
addr: SocketAddr,
20212020
capability: Option<String>,
2022-
all: bool,
2021+
distinct: bool,
20232022
) -> Result<(), failure::Error> {
20242023
let mut stream = start_client(addr)?;
2025-
let params = if all {
2026-
QueryPowersParams::All(true)
2027-
} else {
2028-
match capability {
2029-
Some(c) => match Capability::from_str(&c) {
2030-
Ok(c) => QueryPowersParams::Capability(c),
2031-
Err(_) => QueryPowersParams::Capability(Capability::Mining),
2032-
},
2033-
None => QueryPowersParams::Capability(Capability::Mining),
2034-
}
2024+
2025+
let mut params = QueryStakingPowers::default();
2026+
params.distinct = Some(distinct);
2027+
params.order_by = match capability {
2028+
Some(c) => match Capability::from_str(&c) {
2029+
Ok(c) => c,
2030+
Err(_) => Capability::Mining,
2031+
},
2032+
None => Capability::Mining,
20352033
};
20362034

20372035
let response = send_request(
@@ -2042,42 +2040,22 @@ pub fn query_powers(
20422040
),
20432041
)?;
20442042

2045-
let mut powers: Vec<QueryPowersRecord> = parse_response(&response)?;
2046-
powers.sort_by_key(|power| Reverse(power.powers[0]));
2043+
let records: Vec<QueryStakingPowersRecord> = parse_response(&response)?;
20472044

20482045
let mut powers_table = Table::new();
20492046
powers_table.set_format(*prettytable::format::consts::FORMAT_NO_BORDER_LINE_SEPARATOR);
2050-
if all {
2051-
let mut header = vec![
2052-
Cell::new("Validator").style_spec("c"),
2053-
Cell::new("Withdrawer").style_spec("c"),
2054-
];
2055-
for capability in ALL_CAPABILITIES {
2056-
let capability_str: &'static str = capability.into();
2057-
header.push(Cell::new(capability_str).style_spec("c"));
2058-
}
2059-
powers_table.set_titles(Row::new(header));
2060-
for power in powers.iter() {
2061-
let mut row = vec![
2062-
Cell::new(&power.validator.to_string()),
2063-
Cell::new(&power.withdrawer.to_string()),
2064-
];
2065-
for p in &power.powers {
2066-
row.push(Cell::new(&p.to_formatted_string(&Locale::en)).style_spec("r"));
2067-
}
2068-
powers_table.add_row(Row::new(row));
2069-
}
2070-
} else {
2071-
let capability_str: &'static str = params.into();
2072-
powers_table.set_titles(row![c->"Validator", c->"Withdrawer", c->capability_str]);
2073-
for power in powers.iter() {
2074-
powers_table.add_row(row![
2075-
power.validator,
2076-
power.withdrawer,
2077-
r->(power.powers[0]).to_formatted_string(&Locale::en),
2078-
]);
2079-
}
2047+
2048+
let capability_str: &'static str = params.order_by.into();
2049+
powers_table.set_titles(row![c->"Ranking", c->"Validator", c->"Withdrawer", c->capability_str]);
2050+
for record in records.iter() {
2051+
powers_table.add_row(row![
2052+
record.ranking,
2053+
record.validator,
2054+
record.withdrawer,
2055+
record.power.to_formatted_string(&Locale::en),
2056+
]);
20802057
}
2058+
20812059
powers_table.printstd();
20822060
println!();
20832061

src/cli/node/with_node.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -300,8 +300,8 @@ pub fn exec_cmd(
300300
Command::QueryPowers {
301301
node,
302302
capability,
303-
all,
304-
} => rpc::query_powers(node.unwrap_or(default_jsonrpc), capability, all),
303+
distinct,
304+
} => rpc::query_powers(node.unwrap_or(default_jsonrpc), capability, distinct),
305305
Command::Unstake {
306306
node,
307307
operator,
@@ -848,8 +848,8 @@ pub enum Command {
848848
node: Option<SocketAddr>,
849849
#[structopt(short = "c", long = "capability")]
850850
capability: Option<String>,
851-
#[structopt(short = "a", long = "all")]
852-
all: bool,
851+
#[structopt(short = "d", long = "distinct")]
852+
distinct: bool,
853853
},
854854
#[structopt(name = "unstake", about = "Create an unstake transaction")]
855855
Unstake {

0 commit comments

Comments
 (0)