From ce0e751df42fe0f07ff39d2370e5986c63f49115 Mon Sep 17 00:00:00 2001 From: bengtlofgren Date: Tue, 4 Jul 2023 11:31:47 +0200 Subject: [PATCH 1/5] query bonded-stake and order --- apps/src/lib/client/rpc.rs | 17 ++++++++++++++--- wasm/checksums.json | 2 +- 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/apps/src/lib/client/rpc.rs b/apps/src/lib/client/rpc.rs index 44955967d0..fb1dbd6c33 100644 --- a/apps/src/lib/client/rpc.rs +++ b/apps/src/lib/client/rpc.rs @@ -10,7 +10,7 @@ use std::str::FromStr; use borsh::{BorshDeserialize, BorshSerialize}; use data_encoding::HEXLOWER; -use itertools::Either; +use itertools::{Either, Itertools}; use masp_primitives::asset_type::AssetType; use masp_primitives::merkle_tree::MerklePath; use masp_primitives::sapling::{Node, ViewingKey}; @@ -1580,13 +1580,19 @@ pub async fn query_bonded_stake( .below_capacity_validator_set(client, &Some(epoch)) .await, ); + + let sorted_consensus = consensus.into_iter(). + sorted_by_key(|v| + -(i128::try_from(v.bonded_stake.change())) + .expect("Failed to sort consensus validators") + ); // Iterate all validators let stdout = io::stdout(); let mut w = stdout.lock(); writeln!(w, "Consensus validators:").unwrap(); - for val in consensus { + for val in sorted_consensus { writeln!( w, " {}: {}", @@ -1596,8 +1602,13 @@ pub async fn query_bonded_stake( .unwrap(); } if !below_capacity.is_empty() { + let sorted_below_capacity = below_capacity.into_iter(). + sorted_by_key(|v| + -(i128::try_from(v.bonded_stake.change())) + .expect("Failed to sort consensus validators") + ); writeln!(w, "Below capacity validators:").unwrap(); - for val in &below_capacity { + for val in sorted_below_capacity { writeln!( w, " {}: {}", diff --git a/wasm/checksums.json b/wasm/checksums.json index 8397ffb0d6..c2d3d7e014 100644 --- a/wasm/checksums.json +++ b/wasm/checksums.json @@ -19,4 +19,4 @@ "vp_token.wasm": "vp_token.ec4f3914d074168f7ecbd43d5587e014381d409b3df4db4f63eaf73d3a56cdd6.wasm", "vp_user.wasm": "vp_user.fd9810232a2ec79ff3f9f8fc70a6427ce9d07a9ef51c1468a785247a9b08b337.wasm", "vp_validator.wasm": "vp_validator.8ce4c52a53aa451459e37ec560aa56ac4083d8829b0c29168c448e1e9d764c22.wasm" -} \ No newline at end of file +} From cb48c5133f527e3180a97082c45e52db0d440dc4 Mon Sep 17 00:00:00 2001 From: brentstone Date: Tue, 4 Jul 2023 14:18:33 +0200 Subject: [PATCH 2/5] CLI query a validator's state --- apps/src/bin/namada-client/cli.rs | 16 ++++++ apps/src/lib/cli.rs | 68 ++++++++++++++++++++++++-- apps/src/lib/client/rpc.rs | 75 ++++++++++++++++++++++++----- shared/src/ledger/args.rs | 11 +++++ shared/src/ledger/queries/vp/pos.rs | 26 +++++++++- 5 files changed, 179 insertions(+), 17 deletions(-) diff --git a/apps/src/bin/namada-client/cli.rs b/apps/src/bin/namada-client/cli.rs index 609588045d..be77d2b982 100644 --- a/apps/src/bin/namada-client/cli.rs +++ b/apps/src/bin/namada-client/cli.rs @@ -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, diff --git a/apps/src/lib/cli.rs b/apps/src/lib/cli.rs index 06d6f3f406..a7a1e83350 100644 --- a/apps/src/lib/cli.rs +++ b/apps/src/lib/cli.rs @@ -381,6 +381,7 @@ pub mod cmds { QueryProposal(QueryProposal), QueryProposalResult(QueryProposalResult), QueryProtocolParameters(QueryProtocolParameters), + QueryValidatorState(QueryValidatorState), } #[allow(clippy::large_enum_variant)] @@ -1453,6 +1454,27 @@ pub mod cmds { } } + #[derive(Clone, Debug)] + pub struct QueryValidatorState( + pub args::QueryValidatorState, + ); + + impl SubCmd for QueryValidatorState { + const CMD: &'static str = "validator-state"; + + fn parse(matches: &ArgMatches) -> Option { + 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::>() + } + } + #[derive(Clone, Debug)] pub struct QueryTransfers(pub args::QueryTransfers); @@ -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::>() } } @@ -4016,8 +4038,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> for QueryValidatorState { + fn to_sdk(self, ctx: &mut Context) -> QueryValidatorState { + QueryValidatorState:: { + query: self.query.to_sdk(ctx), + validator: ctx.get(&self.validator), + epoch: self.epoch, + } + } + } + + impl Args for QueryValidatorState { + 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::>() + .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).", )) } } @@ -4127,8 +4185,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).", )) } } diff --git a/apps/src/lib/client/rpc.rs b/apps/src/lib/client/rpc.rs index fb1dbd6c33..81d9d71009 100644 --- a/apps/src/lib/client/rpc.rs +++ b/apps/src/lib/client/rpc.rs @@ -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::{ @@ -1580,12 +1580,11 @@ pub async fn query_bonded_stake( .below_capacity_validator_set(client, &Some(epoch)) .await, ); - - let sorted_consensus = consensus.into_iter(). - sorted_by_key(|v| + + let sorted_consensus = consensus.into_iter().sorted_by_key(|v| { -(i128::try_from(v.bonded_stake.change())) - .expect("Failed to sort consensus validators") - ); + .expect("Failed to sort consensus validators") + }); // Iterate all validators let stdout = io::stdout(); @@ -1602,11 +1601,11 @@ pub async fn query_bonded_stake( .unwrap(); } if !below_capacity.is_empty() { - let sorted_below_capacity = below_capacity.into_iter(). - sorted_by_key(|v| - -(i128::try_from(v.bonded_stake.change())) - .expect("Failed to sort consensus validators") - ); + let sorted_below_capacity = + below_capacity.into_iter().sorted_by_key(|v| { + -(i128::try_from(v.bonded_stake.change())) + .expect("Failed to sort consensus validators") + }); writeln!(w, "Below capacity validators:").unwrap(); for val in sorted_below_capacity { writeln!( @@ -1645,6 +1644,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, +) -> Option { + unwrap_client_response::>( + 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, + args: args::QueryValidatorState, +) { + let validator = args.validator; + let state: Option = + 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, diff --git a/shared/src/ledger/args.rs b/shared/src/ledger/args.rs index 35081d3283..47117ba594 100644 --- a/shared/src/ledger/args.rs +++ b/shared/src/ledger/args.rs @@ -356,6 +356,17 @@ pub struct QueryBondedStake { pub epoch: Option, } +/// Query the state of a validator (its validator set or if it is jailed) +#[derive(Clone, Debug)] +pub struct QueryValidatorState { + /// Common query args + pub query: Query, + /// Address of a validator + pub validator: C::Address, + /// Epoch in which to find the validator state + pub epoch: Option, +} + #[derive(Clone, Debug)] /// Commission rate change args pub struct CommissionRateChange { diff --git a/shared/src/ledger/queries/vp/pos.rs b/shared/src/ledger/queries/vp/pos.rs index d872aa5002..9934a71271 100644 --- a/shared/src/ledger/queries/vp/pos.rs +++ b/shared/src/ledger/queries/vp/pos.rs @@ -7,7 +7,7 @@ use namada_core::ledger::storage_api::collections::lazy_map; use namada_core::ledger::storage_api::OptionExt; use namada_proof_of_stake::types::{ BondId, BondsAndUnbondsDetail, BondsAndUnbondsDetails, CommissionPair, - Slash, WeightedValidator, + Slash, ValidatorState, WeightedValidator, }; use namada_proof_of_stake::{ self, below_capacity_validator_set_handle, bond_amount, bond_handle, @@ -16,6 +16,7 @@ use namada_proof_of_stake::{ read_pos_params, read_total_stake, read_validator_max_commission_rate_change, read_validator_stake, unbond_handle, validator_commission_rate_handle, validator_slashes_handle, + validator_state_handle, }; use crate::ledger::queries::types::RequestCtx; @@ -43,6 +44,9 @@ router! {POS, ( "commission" / [validator: Address] / [epoch: opt Epoch] ) -> Option = validator_commission, + + ( "state" / [validator: Address] / [epoch: opt Epoch] ) + -> Option = validator_state, }, ( "validator_set" ) = { @@ -203,6 +207,26 @@ where } } +/// Get the validator state +fn validator_state( + ctx: RequestCtx<'_, D, H>, + validator: Address, + epoch: Option, +) -> storage_api::Result> +where + D: 'static + DB + for<'iter> DBIter<'iter> + Sync, + H: 'static + StorageHasher + Sync, +{ + let epoch = epoch.unwrap_or(ctx.wl_storage.storage.last_epoch); + let params = read_pos_params(ctx.wl_storage)?; + let state = validator_state_handle(&validator).get( + ctx.wl_storage, + epoch, + ¶ms, + )?; + Ok(state) +} + /// Get the total stake of a validator at the given epoch or current when /// `None`. The total stake is a sum of validator's self-bonds and delegations /// to their address. From 23a78b224fea2e0b20eca1a991bab4a156eaeade Mon Sep 17 00:00:00 2001 From: brentstone Date: Thu, 6 Jul 2023 11:59:19 +0200 Subject: [PATCH 3/5] Expanding and fixing slashes query --- apps/src/lib/client/rpc.rs | 92 +++++++++++++++++++++++++---- proof_of_stake/src/lib.rs | 36 +++++++++++ shared/src/ledger/queries/vp/pos.rs | 25 ++++++-- 3 files changed, 135 insertions(+), 18 deletions(-) diff --git a/apps/src/lib/client/rpc.rs b/apps/src/lib/client/rpc.rs index 81d9d71009..626c946f3d 100644 --- a/apps/src/lib/client/rpc.rs +++ b/apps/src/lib/client/rpc.rs @@ -1,7 +1,7 @@ //! Client RPC queries use std::cmp::Ordering; -use std::collections::{HashMap, HashSet}; +use std::collections::{BTreeMap, HashMap, HashSet}; use std::fs::File; use std::io::{self, Write}; use std::iter::Iterator; @@ -1738,11 +1738,6 @@ pub async fn query_slashes( _wallet: &mut Wallet, args: args::QuerySlashes, ) { - let params_key = pos::params_key(); - let params = query_storage_value::(client, ¶ms_key) - .await - .expect("Parameter should be defined."); - match args.validator { Some(validator) => { let validator = validator; @@ -1751,18 +1746,54 @@ pub async fn query_slashes( 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>, + > = unwrap_client_response::< + C, + HashMap>>, + >(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 => { @@ -1774,15 +1805,16 @@ pub async fn query_slashes( 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(¶ms), + slash.rate, slash.r#type, validator, ) @@ -1790,7 +1822,41 @@ pub async fn query_slashes( } } } 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>, + > = unwrap_client_response::< + C, + HashMap>>, + >(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") } } } diff --git a/proof_of_stake/src/lib.rs b/proof_of_stake/src/lib.rs index 7f7265be91..050334debc 100644 --- a/proof_of_stake/src/lib.rs +++ b/proof_of_stake/src/lib.rs @@ -2753,6 +2753,42 @@ where } } +/// Collect the details of all of the enqueued slashes to be processed in future +/// epochs into a nested map +pub fn find_all_enqueued_slashes( + storage: &S, + epoch: Epoch, +) -> storage_api::Result>>> +where + S: StorageRead, +{ + let mut enqueued = HashMap::>>::new(); + for res in enqueued_slashes_handle().get_data_handler().iter(storage)? { + let ( + NestedSubKey::Data { + key: processing_epoch, + nested_sub_key: + NestedSubKey::Data { + key: address, + nested_sub_key: _, + }, + }, + slash, + ) = res?; + if processing_epoch <= epoch { + continue; + } + + let slashes = enqueued + .entry(address) + .or_default() + .entry(processing_epoch) + .or_default(); + slashes.push(slash); + } + Ok(enqueued) +} + /// Find all slashes and the associated validators in the PoS system pub fn find_all_slashes( storage: &S, diff --git a/shared/src/ledger/queries/vp/pos.rs b/shared/src/ledger/queries/vp/pos.rs index 9934a71271..94c93f6a54 100644 --- a/shared/src/ledger/queries/vp/pos.rs +++ b/shared/src/ledger/queries/vp/pos.rs @@ -1,6 +1,6 @@ //! Queries router and handlers for PoS validity predicate -use std::collections::{HashMap, HashSet}; +use std::collections::{BTreeMap, HashMap, HashSet}; use borsh::{BorshDeserialize, BorshSchema, BorshSerialize}; use namada_core::ledger::storage_api::collections::lazy_map; @@ -11,9 +11,9 @@ use namada_proof_of_stake::types::{ }; use namada_proof_of_stake::{ self, below_capacity_validator_set_handle, bond_amount, bond_handle, - consensus_validator_set_handle, find_all_slashes, - find_delegation_validators, find_delegations, read_all_validator_addresses, - read_pos_params, read_total_stake, + consensus_validator_set_handle, find_all_enqueued_slashes, + find_all_slashes, find_delegation_validators, find_delegations, + read_all_validator_addresses, read_pos_params, read_total_stake, read_validator_max_commission_rate_change, read_validator_stake, unbond_handle, validator_commission_rate_handle, validator_slashes_handle, validator_state_handle, @@ -86,6 +86,9 @@ router! {POS, ( "bonds_and_unbonds" / [source: opt Address] / [validator: opt Address] ) -> BondsAndUnbondsDetails = bonds_and_unbonds, + ( "enqueued_slashes" ) + -> HashMap>> = enqueued_slashes, + ( "all_slashes" ) -> HashMap> = slashes, ( "is_delegator" / [addr: Address ] / [epoch: opt Epoch] ) -> bool = is_delegator, @@ -520,7 +523,19 @@ where find_all_slashes(ctx.wl_storage) } -/// All slashes +/// Enqueued slashes +fn enqueued_slashes( + ctx: RequestCtx<'_, D, H>, +) -> storage_api::Result>>> +where + D: 'static + DB + for<'iter> DBIter<'iter> + Sync, + H: 'static + StorageHasher + Sync, +{ + let current_epoch = ctx.wl_storage.storage.last_epoch; + find_all_enqueued_slashes(ctx.wl_storage, current_epoch) +} + +/// Native validator address by looking up the Tendermint address fn validator_by_tm_addr( ctx: RequestCtx<'_, D, H>, tm_addr: String, From b3b1f261049f03cf1a70da7f378e806c47204500 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Zemanovi=C4=8D?= Date: Tue, 11 Jul 2023 09:25:19 +0100 Subject: [PATCH 4/5] pos: return sorted validator sets and code re-use for queries --- apps/src/lib/client/rpc.rs | 22 +++------- proof_of_stake/src/lib.rs | 4 +- shared/src/ledger/queries/vp/pos.rs | 68 ++++++++--------------------- wasm/wasm_source/src/tx_bond.rs | 6 +-- wasm/wasm_source/src/tx_unbond.rs | 4 +- 5 files changed, 30 insertions(+), 74 deletions(-) diff --git a/apps/src/lib/client/rpc.rs b/apps/src/lib/client/rpc.rs index 626c946f3d..2895238071 100644 --- a/apps/src/lib/client/rpc.rs +++ b/apps/src/lib/client/rpc.rs @@ -1,7 +1,7 @@ //! Client RPC queries use std::cmp::Ordering; -use std::collections::{BTreeMap, HashMap, HashSet}; +use std::collections::{BTreeMap, BTreeSet, HashMap, HashSet}; use std::fs::File; use std::io::{self, Write}; use std::iter::Iterator; @@ -10,7 +10,7 @@ use std::str::FromStr; use borsh::{BorshDeserialize, BorshSerialize}; use data_encoding::HEXLOWER; -use itertools::{Either, Itertools}; +use itertools::Either; use masp_primitives::asset_type::AssetType; use masp_primitives::merkle_tree::MerklePath; use masp_primitives::sapling::{Node, ViewingKey}; @@ -1567,31 +1567,26 @@ pub async fn query_bonded_stake( } None => { let consensus = - unwrap_client_response::>( + unwrap_client_response::>( RPC.vp() .pos() .consensus_validator_set(client, &Some(epoch)) .await, ); let below_capacity = - unwrap_client_response::>( + unwrap_client_response::>( RPC.vp() .pos() .below_capacity_validator_set(client, &Some(epoch)) .await, ); - let sorted_consensus = consensus.into_iter().sorted_by_key(|v| { - -(i128::try_from(v.bonded_stake.change())) - .expect("Failed to sort consensus validators") - }); - // Iterate all validators let stdout = io::stdout(); let mut w = stdout.lock(); writeln!(w, "Consensus validators:").unwrap(); - for val in sorted_consensus { + for val in consensus.into_iter().rev() { writeln!( w, " {}: {}", @@ -1601,13 +1596,8 @@ pub async fn query_bonded_stake( .unwrap(); } if !below_capacity.is_empty() { - let sorted_below_capacity = - below_capacity.into_iter().sorted_by_key(|v| { - -(i128::try_from(v.bonded_stake.change())) - .expect("Failed to sort consensus validators") - }); writeln!(w, "Below capacity validators:").unwrap(); - for val in sorted_below_capacity { + for val in below_capacity.into_iter().rev() { writeln!( w, " {}: {}", diff --git a/proof_of_stake/src/lib.rs b/proof_of_stake/src/lib.rs index 050334debc..4022d49ffc 100644 --- a/proof_of_stake/src/lib.rs +++ b/proof_of_stake/src/lib.rs @@ -748,7 +748,7 @@ where pub fn read_consensus_validator_set_addresses_with_stake( storage: &S, epoch: namada_core::types::storage::Epoch, -) -> storage_api::Result> +) -> storage_api::Result> where S: StorageRead, { @@ -792,7 +792,7 @@ where pub fn read_below_capacity_validator_set_addresses_with_stake( storage: &S, epoch: namada_core::types::storage::Epoch, -) -> storage_api::Result> +) -> storage_api::Result> where S: StorageRead, { diff --git a/shared/src/ledger/queries/vp/pos.rs b/shared/src/ledger/queries/vp/pos.rs index 94c93f6a54..177b31ed87 100644 --- a/shared/src/ledger/queries/vp/pos.rs +++ b/shared/src/ledger/queries/vp/pos.rs @@ -1,6 +1,6 @@ //! Queries router and handlers for PoS validity predicate -use std::collections::{BTreeMap, HashMap, HashSet}; +use std::collections::{BTreeMap, BTreeSet, HashMap, HashSet}; use borsh::{BorshDeserialize, BorshSchema, BorshSerialize}; use namada_core::ledger::storage_api::collections::lazy_map; @@ -10,13 +10,14 @@ use namada_proof_of_stake::types::{ Slash, ValidatorState, WeightedValidator, }; use namada_proof_of_stake::{ - self, below_capacity_validator_set_handle, bond_amount, bond_handle, - consensus_validator_set_handle, find_all_enqueued_slashes, + self, bond_amount, bond_handle, find_all_enqueued_slashes, find_all_slashes, find_delegation_validators, find_delegations, - read_all_validator_addresses, read_pos_params, read_total_stake, - read_validator_max_commission_rate_change, read_validator_stake, - unbond_handle, validator_commission_rate_handle, validator_slashes_handle, - validator_state_handle, + read_all_validator_addresses, + read_below_capacity_validator_set_addresses_with_stake, + read_consensus_validator_set_addresses_with_stake, read_pos_params, + read_total_stake, read_validator_max_commission_rate_change, + read_validator_stake, unbond_handle, validator_commission_rate_handle, + validator_slashes_handle, validator_state_handle, }; use crate::ledger::queries::types::RequestCtx; @@ -51,10 +52,10 @@ router! {POS, ( "validator_set" ) = { ( "consensus" / [epoch: opt Epoch] ) - -> HashSet = consensus_validator_set, + -> BTreeSet = consensus_validator_set, ( "below_capacity" / [epoch: opt Epoch] ) - -> HashSet = below_capacity_validator_set, + -> BTreeSet = below_capacity_validator_set, // TODO: add "below_threshold" }, @@ -253,64 +254,29 @@ where fn consensus_validator_set( ctx: RequestCtx<'_, D, H>, epoch: Option, -) -> storage_api::Result> +) -> storage_api::Result> where D: 'static + DB + for<'iter> DBIter<'iter> + Sync, H: 'static + StorageHasher + Sync, { let epoch = epoch.unwrap_or(ctx.wl_storage.storage.last_epoch); - consensus_validator_set_handle() - .at(&epoch) - .iter(ctx.wl_storage)? - .map(|next_result| { - next_result.map( - |( - lazy_map::NestedSubKey::Data { - key: bonded_stake, - nested_sub_key: _position, - }, - address, - )| { - WeightedValidator { - bonded_stake, - address, - } - }, - ) - }) - .collect() + read_consensus_validator_set_addresses_with_stake(ctx.wl_storage, epoch) } /// Get all the validator in the below-capacity set with their bonded stake. fn below_capacity_validator_set( ctx: RequestCtx<'_, D, H>, epoch: Option, -) -> storage_api::Result> +) -> storage_api::Result> where D: 'static + DB + for<'iter> DBIter<'iter> + Sync, H: 'static + StorageHasher + Sync, { let epoch = epoch.unwrap_or(ctx.wl_storage.storage.last_epoch); - below_capacity_validator_set_handle() - .at(&epoch) - .iter(ctx.wl_storage)? - .map(|next_result| { - next_result.map( - |( - lazy_map::NestedSubKey::Data { - key: bonded_stake, - nested_sub_key: _position, - }, - address, - )| { - WeightedValidator { - bonded_stake: bonded_stake.into(), - address, - } - }, - ) - }) - .collect() + read_below_capacity_validator_set_addresses_with_stake( + ctx.wl_storage, + epoch, + ) } /// Get the total stake in PoS system at the given epoch or current when `None`. diff --git a/wasm/wasm_source/src/tx_bond.rs b/wasm/wasm_source/src/tx_bond.rs index df55270ceb..9340592bb0 100644 --- a/wasm/wasm_source/src/tx_bond.rs +++ b/wasm/wasm_source/src/tx_bond.rs @@ -15,7 +15,7 @@ fn apply_tx(ctx: &mut Ctx, tx_data: Tx) -> TxResult { #[cfg(test)] mod tests { - use std::collections::HashSet; + use std::collections::BTreeSet; use namada::ledger::pos::{GenesisValidator, PosParams, PosVP}; use namada::proof_of_stake::{ @@ -132,7 +132,7 @@ mod tests { // Read some data before the tx is executed let mut epoched_total_stake_pre: Vec = Vec::new(); let mut epoched_validator_stake_pre: Vec = Vec::new(); - let mut epoched_validator_set_pre: Vec> = + let mut epoched_validator_set_pre: Vec> = Vec::new(); for epoch in 0..=pos_params.unbonding_len { @@ -163,7 +163,7 @@ mod tests { // Read the data after the tx is executed. let mut epoched_total_stake_post: Vec = Vec::new(); let mut epoched_validator_stake_post: Vec = Vec::new(); - let mut epoched_validator_set_post: Vec> = + let mut epoched_validator_set_post: Vec> = Vec::new(); println!("\nFILLING POST STATE\n"); diff --git a/wasm/wasm_source/src/tx_unbond.rs b/wasm/wasm_source/src/tx_unbond.rs index 7fb1de8f4f..fc69294b2b 100644 --- a/wasm/wasm_source/src/tx_unbond.rs +++ b/wasm/wasm_source/src/tx_unbond.rs @@ -15,7 +15,7 @@ fn apply_tx(ctx: &mut Ctx, tx_data: Tx) -> TxResult { #[cfg(test)] mod tests { - use std::collections::HashSet; + use std::collections::BTreeSet; use namada::ledger::pos::{GenesisValidator, PosParams, PosVP}; use namada::proof_of_stake::types::WeightedValidator; @@ -164,7 +164,7 @@ mod tests { let mut epoched_total_stake_pre: Vec = Vec::new(); let mut epoched_validator_stake_pre: Vec = Vec::new(); let mut epoched_bonds_pre: Vec> = Vec::new(); - let mut epoched_validator_set_pre: Vec> = + let mut epoched_validator_set_pre: Vec> = Vec::new(); for epoch in 0..=pos_params.unbonding_len { From 9702dd90f89bc6a8de129c15746fe57e335af89a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Zemanovi=C4=8D?= Date: Tue, 11 Jul 2023 12:16:11 +0100 Subject: [PATCH 5/5] changelog: add #1656 --- .changelog/unreleased/improvements/1656-pos-cli-queries.md | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 .changelog/unreleased/improvements/1656-pos-cli-queries.md diff --git a/.changelog/unreleased/improvements/1656-pos-cli-queries.md b/.changelog/unreleased/improvements/1656-pos-cli-queries.md new file mode 100644 index 0000000000..a114c6f2f6 --- /dev/null +++ b/.changelog/unreleased/improvements/1656-pos-cli-queries.md @@ -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)) \ No newline at end of file