From aae3f5416c31d39c200b10d60b85e05a9c21fa2d Mon Sep 17 00:00:00 2001 From: brentstone Date: Thu, 6 Jul 2023 11:59:19 +0200 Subject: [PATCH] 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,