Skip to content

Commit

Permalink
Merge branch 'bengt/pos-cli-queries' (#1656)
Browse files Browse the repository at this point in the history
* bengt/pos-cli-queries:
  changelog: add #1656
  pos: return sorted validator sets and code re-use for queries
  Expanding and fixing slashes query
  CLI query a validator's state
  query bonded-stake and order
  • Loading branch information
tzemanovic committed Jul 11, 2023
2 parents 119210b + 9702dd9 commit 3dd7245
Show file tree
Hide file tree
Showing 10 changed files with 332 additions and 84 deletions.
2 changes: 2 additions & 0 deletions .changelog/unreleased/improvements/1656-pos-cli-queries.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
- Added a client query for `validator-state` and improved the slashes query to
show more info. ([\#1656](https://github.com/anoma/namada/pull/1656))
16 changes: 16 additions & 0 deletions apps/src/bin/namada-client/cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -325,6 +325,22 @@ pub async fn main() -> Result<()> {
let args = args.to_sdk(&mut ctx);
rpc::query_bonded_stake(&client, args).await;
}
Sub::QueryValidatorState(QueryValidatorState(mut args)) => {
let client = HttpClient::new(utils::take_config_address(
&mut args.query.ledger_address,
))
.unwrap();
wait_until_node_is_synched(&client)
.await
.proceed_or_else(error)?;
let args = args.to_sdk(&mut ctx);
rpc::query_and_print_validator_state(
&client,
&mut ctx.wallet,
args,
)
.await;
}
Sub::QueryCommissionRate(QueryCommissionRate(mut args)) => {
let client = HttpClient::new(utils::take_config_address(
&mut args.query.ledger_address,
Expand Down
68 changes: 63 additions & 5 deletions apps/src/lib/cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -381,6 +381,7 @@ pub mod cmds {
QueryProposal(QueryProposal),
QueryProposalResult(QueryProposalResult),
QueryProtocolParameters(QueryProtocolParameters),
QueryValidatorState(QueryValidatorState),
}

#[allow(clippy::large_enum_variant)]
Expand Down Expand Up @@ -1453,6 +1454,27 @@ pub mod cmds {
}
}

#[derive(Clone, Debug)]
pub struct QueryValidatorState(
pub args::QueryValidatorState<args::CliTypes>,
);

impl SubCmd for QueryValidatorState {
const CMD: &'static str = "validator-state";

fn parse(matches: &ArgMatches) -> Option<Self> {
matches.subcommand_matches(Self::CMD).map(|matches| {
QueryValidatorState(args::QueryValidatorState::parse(matches))
})
}

fn def() -> App {
App::new(Self::CMD)
.about("Query the state of a PoS validator.")
.add_args::<args::QueryValidatorState<args::CliTypes>>()
}
}

#[derive(Clone, Debug)]
pub struct QueryTransfers(pub args::QueryTransfers<args::CliTypes>);

Expand Down Expand Up @@ -1488,7 +1510,7 @@ pub mod cmds {

fn def() -> App {
App::new(Self::CMD)
.about("Query commission rate.")
.about("Query a validator's commission rate.")
.add_args::<args::QueryCommissionRate<args::CliTypes>>()
}
}
Expand Down Expand Up @@ -4042,8 +4064,44 @@ pub mod args {
"The validator's address whose bonded stake to query.",
))
.arg(EPOCH.def().help(
"The epoch at which to query (last committed, if not \
specified).",
"The epoch at which to query (corresponding to the last \
committed block, if not specified).",
))
}
}

impl CliToSdk<QueryValidatorState<SdkTypes>> for QueryValidatorState<CliTypes> {
fn to_sdk(self, ctx: &mut Context) -> QueryValidatorState<SdkTypes> {
QueryValidatorState::<SdkTypes> {
query: self.query.to_sdk(ctx),
validator: ctx.get(&self.validator),
epoch: self.epoch,
}
}
}

impl Args for QueryValidatorState<CliTypes> {
fn parse(matches: &ArgMatches) -> Self {
let query = Query::parse(matches);
let validator = VALIDATOR.parse(matches);
let epoch = EPOCH.parse(matches);
Self {
query,
validator,
epoch,
}
}

fn def(app: App) -> App {
app.add_args::<Query<CliTypes>>()
.arg(
VALIDATOR.def().help(
"The validator's address whose state is queried.",
),
)
.arg(EPOCH.def().help(
"The epoch at which to query (corresponding to the last \
committed block, if not specified).",
))
}
}
Expand Down Expand Up @@ -4153,8 +4211,8 @@ pub mod args {
"The validator's address whose commission rate to query.",
))
.arg(EPOCH.def().help(
"The epoch at which to query (last committed, if not \
specified).",
"The epoch at which to query (corresponding to the last \
committed block, if not specified).",
))
}
}
Expand Down
156 changes: 138 additions & 18 deletions apps/src/lib/client/rpc.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
//! Client RPC queries

use std::cmp::Ordering;
use std::collections::{HashMap, HashSet};
use std::collections::{BTreeMap, BTreeSet, HashMap, HashSet};
use std::fs::File;
use std::io::{self, Write};
use std::iter::Iterator;
Expand Down Expand Up @@ -36,7 +36,7 @@ use namada::ledger::rpc::{
};
use namada::ledger::storage::ConversionState;
use namada::ledger::wallet::{AddressVpType, Wallet};
use namada::proof_of_stake::types::WeightedValidator;
use namada::proof_of_stake::types::{ValidatorState, WeightedValidator};
use namada::types::address::{masp, Address};
use namada::types::control_flow::ProceedOrElse;
use namada::types::governance::{
Expand Down Expand Up @@ -1567,14 +1567,14 @@ pub async fn query_bonded_stake<C: namada::ledger::queries::Client + Sync>(
}
None => {
let consensus =
unwrap_client_response::<C, HashSet<WeightedValidator>>(
unwrap_client_response::<C, BTreeSet<WeightedValidator>>(
RPC.vp()
.pos()
.consensus_validator_set(client, &Some(epoch))
.await,
);
let below_capacity =
unwrap_client_response::<C, HashSet<WeightedValidator>>(
unwrap_client_response::<C, BTreeSet<WeightedValidator>>(
RPC.vp()
.pos()
.below_capacity_validator_set(client, &Some(epoch))
Expand All @@ -1586,7 +1586,7 @@ pub async fn query_bonded_stake<C: namada::ledger::queries::Client + Sync>(
let mut w = stdout.lock();

writeln!(w, "Consensus validators:").unwrap();
for val in consensus {
for val in consensus.into_iter().rev() {
writeln!(
w,
" {}: {}",
Expand All @@ -1597,7 +1597,7 @@ pub async fn query_bonded_stake<C: namada::ledger::queries::Client + Sync>(
}
if !below_capacity.is_empty() {
writeln!(w, "Below capacity validators:").unwrap();
for val in &below_capacity {
for val in below_capacity.into_iter().rev() {
writeln!(
w,
" {}: {}",
Expand Down Expand Up @@ -1634,6 +1634,60 @@ pub async fn query_commission_rate<
)
}

/// Query and return validator's state
pub async fn query_validator_state<
C: namada::ledger::queries::Client + Sync,
>(
client: &C,
validator: &Address,
epoch: Option<Epoch>,
) -> Option<ValidatorState> {
unwrap_client_response::<C, Option<ValidatorState>>(
RPC.vp()
.pos()
.validator_state(client, validator, &epoch)
.await,
)
}

/// Query a validator's state information
pub async fn query_and_print_validator_state<
C: namada::ledger::queries::Client + Sync,
>(
client: &C,
_wallet: &mut Wallet<CliWalletUtils>,
args: args::QueryValidatorState,
) {
let validator = args.validator;
let state: Option<ValidatorState> =
query_validator_state(client, &validator, args.epoch).await;

match state {
Some(state) => match state {
ValidatorState::Consensus => {
println!("Validator {validator} is in the consensus set")
}
ValidatorState::BelowCapacity => {
println!("Validator {validator} is in the below-capacity set")
}
ValidatorState::BelowThreshold => {
println!("Validator {validator} is in the below-threshold set")
}
ValidatorState::Inactive => {
println!("Validator {validator} is inactive")
}
ValidatorState::Jailed => {
println!("Validator {validator} is jailed")
}
},
None => println!(
"Validator {validator} is either not a validator, or an epoch \
before the current epoch has been queried (and the validator \
state information is no longer stored)"
),
}
}

/// Query PoS validator's commission rate information
pub async fn query_and_print_commission_rate<
C: namada::ledger::queries::Client + Sync,
Expand Down Expand Up @@ -1674,11 +1728,6 @@ pub async fn query_slashes<C: namada::ledger::queries::Client + Sync>(
_wallet: &mut Wallet<CliWalletUtils>,
args: args::QuerySlashes,
) {
let params_key = pos::params_key();
let params = query_storage_value::<C, PosParams>(client, &params_key)
.await
.expect("Parameter should be defined.");

match args.validator {
Some(validator) => {
let validator = validator;
Expand All @@ -1687,18 +1736,54 @@ pub async fn query_slashes<C: namada::ledger::queries::Client + Sync>(
RPC.vp().pos().validator_slashes(client, &validator).await,
);
if !slashes.is_empty() {
println!("Processed slashes:");
let stdout = io::stdout();
let mut w = stdout.lock();
for slash in slashes {
writeln!(
w,
"Slash epoch {}, type {}, rate {}",
slash.epoch, slash.r#type, slash.rate
"Infraction epoch {}, block height {}, type {}, rate \
{}",
slash.epoch,
slash.block_height,
slash.r#type,
slash.rate
)
.unwrap();
}
} else {
println!("No slashes found for {}", validator.encode())
println!(
"No processed slashes found for {}",
validator.encode()
)
}
// Find enqueued slashes to be processed in the future for the given
// validator
let enqueued_slashes: HashMap<
Address,
BTreeMap<Epoch, Vec<Slash>>,
> = unwrap_client_response::<
C,
HashMap<Address, BTreeMap<Epoch, Vec<Slash>>>,
>(RPC.vp().pos().enqueued_slashes(client).await);
let enqueued_slashes = enqueued_slashes.get(&validator).cloned();
if let Some(enqueued) = enqueued_slashes {
println!("\nEnqueued slashes for future processing");
for (epoch, slashes) in enqueued {
println!("To be processed in epoch {}", epoch);
for slash in slashes {
let stdout = io::stdout();
let mut w = stdout.lock();
writeln!(
w,
"Infraction epoch {}, block height {}, type {}",
slash.epoch, slash.block_height, slash.r#type,
)
.unwrap();
}
}
} else {
println!("No enqueued slashes found for {}", validator.encode())
}
}
None => {
Expand All @@ -1710,23 +1795,58 @@ pub async fn query_slashes<C: namada::ledger::queries::Client + Sync>(
if !all_slashes.is_empty() {
let stdout = io::stdout();
let mut w = stdout.lock();
println!("Processed slashes:");
for (validator, slashes) in all_slashes.into_iter() {
for slash in slashes {
writeln!(
w,
"Slash epoch {}, block height {}, rate {}, type \
{}, validator {}",
"Infraction epoch {}, block height {}, rate {}, \
type {}, validator {}",
slash.epoch,
slash.block_height,
slash.r#type.get_slash_rate(&params),
slash.rate,
slash.r#type,
validator,
)
.unwrap();
}
}
} else {
println!("No slashes found")
println!("No processed slashes found")
}

// Find enqueued slashes to be processed in the future for the given
// validator
let enqueued_slashes: HashMap<
Address,
BTreeMap<Epoch, Vec<Slash>>,
> = unwrap_client_response::<
C,
HashMap<Address, BTreeMap<Epoch, Vec<Slash>>>,
>(RPC.vp().pos().enqueued_slashes(client).await);
if !enqueued_slashes.is_empty() {
println!("\nEnqueued slashes for future processing");
for (validator, slashes_by_epoch) in enqueued_slashes {
for (epoch, slashes) in slashes_by_epoch {
println!("\nTo be processed in epoch {}", epoch);
for slash in slashes {
let stdout = io::stdout();
let mut w = stdout.lock();
writeln!(
w,
"Infraction epoch {}, block height {}, type \
{}, validator {}",
slash.epoch,
slash.block_height,
slash.r#type,
validator
)
.unwrap();
}
}
}
} else {
println!("\nNo enqueued slashes found for future processing")
}
}
}
Expand Down
Loading

0 comments on commit 3dd7245

Please sign in to comment.