From 178a40aaf97f70b7f37a9c4c3a66f3f45d16d946 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Zemanovi=C4=8D?= Date: Fri, 5 Jan 2024 17:26:34 +0000 Subject: [PATCH] look-up validator by native address and query consensus key --- apps/src/lib/cli.rs | 28 +++++++++---- apps/src/lib/client/rpc.rs | 74 +++++++++++++++++++++++++---------- proof_of_stake/src/storage.rs | 13 ++++++ sdk/src/args.rs | 4 +- sdk/src/queries/vp/pos.rs | 19 +++++++++ 5 files changed, 109 insertions(+), 29 deletions(-) diff --git a/apps/src/lib/cli.rs b/apps/src/lib/cli.rs index fca330ec48..77af7f1f3d 100644 --- a/apps/src/lib/cli.rs +++ b/apps/src/lib/cli.rs @@ -3031,7 +3031,7 @@ pub mod args { pub const TEMPLATES_PATH: Arg = arg("templates-path"); pub const TIMEOUT_HEIGHT: ArgOpt = arg_opt("timeout-height"); pub const TIMEOUT_SEC_OFFSET: ArgOpt = arg_opt("timeout-sec-offset"); - pub const TM_ADDRESS: Arg = arg("tm-address"); + pub const TM_ADDRESS: ArgOpt = arg_opt("tm-address"); pub const TOKEN_OPT: ArgOpt = TOKEN.opt(); pub const TOKEN: Arg = arg("token"); pub const TOKEN_STR: Arg = arg("token"); @@ -5733,15 +5733,26 @@ pub mod args { fn parse(matches: &ArgMatches) -> Self { let query = Query::parse(matches); let tm_addr = TM_ADDRESS.parse(matches); - Self { query, tm_addr } + let validator_addr = VALIDATOR_OPT.parse(matches); + Self { + query, + tm_addr, + validator_addr, + } } fn def(app: App) -> App { - app.add_args::>().arg( - TM_ADDRESS - .def() - .help("The address of the validator in Tendermint."), - ) + app.add_args::>() + .arg( + TM_ADDRESS + .def() + .help("The address of the validator in Tendermint."), + ) + .arg( + VALIDATOR_OPT + .def() + .help("The native address of the validator."), + ) } } @@ -5750,6 +5761,9 @@ pub mod args { QueryFindValidator:: { query: self.query.to_sdk(ctx), tm_addr: self.tm_addr, + validator_addr: self + .validator_addr + .map(|x| ctx.borrow_chain_or_exit().get(&x)), } } } diff --git a/apps/src/lib/client/rpc.rs b/apps/src/lib/client/rpc.rs index bc57f58f14..d41917b1dc 100644 --- a/apps/src/lib/client/rpc.rs +++ b/apps/src/lib/client/rpc.rs @@ -2245,33 +2245,65 @@ pub async fn query_find_validator( context: &N, args: args::QueryFindValidator, ) { - let args::QueryFindValidator { query: _, tm_addr } = args; - if tm_addr.len() != 40 { - edisplay_line!( - context.io(), - "Expected 40 characters in Tendermint address, got {}", - tm_addr.len() + let args::QueryFindValidator { + query: _, + tm_addr, + mut validator_addr, + } = args; + if let Some(tm_addr) = tm_addr { + if tm_addr.len() != 40 { + edisplay_line!( + context.io(), + "Expected 40 characters in Tendermint address, got {}", + tm_addr.len() + ); + cli::safe_exit(1); + } + let tm_addr = tm_addr.to_ascii_uppercase(); + let validator = unwrap_client_response::( + RPC.vp() + .pos() + .validator_by_tm_addr(context.client(), &tm_addr) + .await, ); - cli::safe_exit(1); + match validator { + Some(address) => { + display_line!( + context.io(), + "Found validator address \"{address}\"." + ); + if validator_addr.is_none() { + validator_addr = Some(address); + } + } + None => { + display_line!( + context.io(), + "No validator with Tendermint address {tm_addr} found." + ) + } + } } - let tm_addr = tm_addr.to_ascii_uppercase(); - let validator = unwrap_client_response::( - RPC.vp() - .pos() - .validator_by_tm_addr(context.client(), &tm_addr) - .await, - ); - match validator { - Some(address) => { + if let Some(validator_addr) = validator_addr { + if let Some(consensus_key) = unwrap_client_response::( + RPC.vp() + .pos() + .consensus_key(context.client(), &validator_addr) + .await, + ) { + let pkh: PublicKeyHash = (&consensus_key).into(); + display_line!(context.io(), "Consensus key: {consensus_key}"); display_line!( context.io(), - "Found validator address \"{address}\"." - ) - } - None => { + "Tendermint key: {}", + tm_consensus_key_raw_hash(&consensus_key) + ); + display_line!(context.io(), "Consensus key hash: {}", pkh); + } else { display_line!( context.io(), - "No validator with Tendermint address {tm_addr} found." + "Consensus key for validator {validator_addr} could not be \ + found." ) } } diff --git a/proof_of_stake/src/storage.rs b/proof_of_stake/src/storage.rs index bab677b3a0..94fa374461 100644 --- a/proof_of_stake/src/storage.rs +++ b/proof_of_stake/src/storage.rs @@ -846,3 +846,16 @@ where let handle = LazySet::open(key); handle.contains(storage, consensus_key) } + +/// Find a consensus key of a validator account. +pub fn get_consensus_key( + storage: &S, + addr: &Address, + epoch: Epoch, +) -> storage_api::Result> +where + S: StorageRead, +{ + let params = read_pos_params(storage)?; + validator_consensus_key_handle(addr).get(storage, epoch, ¶ms) +} diff --git a/sdk/src/args.rs b/sdk/src/args.rs index c12ecdf537..d754ff8332 100644 --- a/sdk/src/args.rs +++ b/sdk/src/args.rs @@ -1812,7 +1812,9 @@ pub struct QueryFindValidator { /// Common query args pub query: Query, /// Tendermint address - pub tm_addr: String, + pub tm_addr: Option, + /// Native validator address + pub validator_addr: Option, } /// Query the raw bytes of given storage key diff --git a/sdk/src/queries/vp/pos.rs b/sdk/src/queries/vp/pos.rs index ff1b073dc4..91f8d10cd9 100644 --- a/sdk/src/queries/vp/pos.rs +++ b/sdk/src/queries/vp/pos.rs @@ -42,6 +42,8 @@ router! {POS, ( "validator" ) = { ( "is_validator" / [addr: Address] ) -> bool = is_validator, + ( "consensus_key" / [addr: Address] ) -> Option = consensus_key, + ( "addresses" / [epoch: opt Epoch] ) -> HashSet
= validator_addresses, @@ -194,6 +196,23 @@ where namada_proof_of_stake::is_validator(ctx.wl_storage, &addr) } +/// Find a consensus key of a validator account. +fn consensus_key( + ctx: RequestCtx<'_, D, H, V, T>, + addr: Address, +) -> 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; + namada_proof_of_stake::storage::get_consensus_key( + ctx.wl_storage, + &addr, + current_epoch, + ) +} + /// Find if the given address is a delegator fn is_delegator( ctx: RequestCtx<'_, D, H, V, T>,