Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

look-up validator by native address and query consensus key #2368

Merged
merged 4 commits into from
Jan 13, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
- Added validator's consensus key look-up to `client find-validator`
command, which now also accepts a native validator address.
([\#2368](https://github.com/anoma/namada/pull/2368))
33 changes: 25 additions & 8 deletions apps/src/lib/cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1757,7 +1757,10 @@ pub mod cmds {

fn def() -> App {
App::new(Self::CMD)
.about("Find a PoS validator by its Tendermint address.")
.about(
"Find a PoS validator and its consensus key by its native \
address or Tendermint address.",
)
.add_args::<args::QueryFindValidator<args::CliTypes>>()
}
}
Expand Down Expand Up @@ -3031,7 +3034,7 @@ pub mod args {
pub const TEMPLATES_PATH: Arg<PathBuf> = arg("templates-path");
pub const TIMEOUT_HEIGHT: ArgOpt<u64> = arg_opt("timeout-height");
pub const TIMEOUT_SEC_OFFSET: ArgOpt<u64> = arg_opt("timeout-sec-offset");
pub const TM_ADDRESS: Arg<String> = arg("tm-address");
pub const TM_ADDRESS: ArgOpt<String> = arg_opt("tm-address");
pub const TOKEN_OPT: ArgOpt<WalletAddress> = TOKEN.opt();
pub const TOKEN: Arg<WalletAddress> = arg("token");
pub const TOKEN_STR: Arg<String> = arg("token");
Expand Down Expand Up @@ -5733,15 +5736,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::<Query<CliTypes>>().arg(
TM_ADDRESS
.def()
.help("The address of the validator in Tendermint."),
)
app.add_args::<Query<CliTypes>>()
.arg(
TM_ADDRESS
.def()
.help("The address of the validator in Tendermint."),
)
.arg(
VALIDATOR_OPT
.def()
.help("The native address of the validator."),
)
}
}

Expand All @@ -5750,6 +5764,9 @@ pub mod args {
QueryFindValidator::<SdkTypes> {
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)),
}
}
}
Expand Down
74 changes: 53 additions & 21 deletions apps/src/lib/client/rpc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2245,33 +2245,65 @@ pub async fn query_find_validator<N: Namada>(
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::<N::Client, _>(
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::<N::Client, _>(
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::<N::Client, _>(
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."
)
}
}
Expand Down
13 changes: 13 additions & 0 deletions proof_of_stake/src/storage.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<S>(
storage: &S,
addr: &Address,
epoch: Epoch,
) -> storage_api::Result<Option<common::PublicKey>>
where
S: StorageRead,
{
let params = read_pos_params(storage)?;
validator_consensus_key_handle(addr).get(storage, epoch, &params)
}
4 changes: 3 additions & 1 deletion sdk/src/args.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1812,7 +1812,9 @@ pub struct QueryFindValidator<C: NamadaTypes = SdkTypes> {
/// Common query args
pub query: Query<C>,
/// Tendermint address
pub tm_addr: String,
pub tm_addr: Option<String>,
/// Native validator address
pub validator_addr: Option<C::Address>,
}

/// Query the raw bytes of given storage key
Expand Down
19 changes: 19 additions & 0 deletions sdk/src/queries/vp/pos.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,8 @@ router! {POS,
( "validator" ) = {
( "is_validator" / [addr: Address] ) -> bool = is_validator,

( "consensus_key" / [addr: Address] ) -> Option<common::PublicKey> = consensus_key,

( "addresses" / [epoch: opt Epoch] )
-> HashSet<Address> = validator_addresses,

Expand Down Expand Up @@ -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<D, H, V, T>(
ctx: RequestCtx<'_, D, H, V, T>,
addr: Address,
) -> storage_api::Result<Option<common::PublicKey>>
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<D, H, V, T>(
ctx: RequestCtx<'_, D, H, V, T>,
Expand Down
22 changes: 22 additions & 0 deletions sdk/src/rpc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ use namada_core::ledger::governance::utils::Vote;
use namada_core::ledger::ibc::storage::{
ibc_denom_key, ibc_denom_key_prefix, is_ibc_denom_key,
};
use namada_core::ledger::pgf::storage::steward::StewardDetail;
use namada_core::ledger::storage::LastBlock;
use namada_core::types::account::Account;
use namada_core::types::address::{Address, InternalAddress};
Expand Down Expand Up @@ -223,6 +224,27 @@ pub async fn has_bonds<C: crate::queries::Client + Sync>(
convert_response::<C, bool>(RPC.vp().pos().has_bonds(client, source).await)
}

/// Get the set of pgf stewards
pub async fn query_pgf_stewards<C: crate::queries::Client + Sync>(
client: &C,
) -> Result<Vec<StewardDetail>, error::Error> {
convert_response::<C, Vec<StewardDetail>>(
RPC.vp().pgf().stewards(client).await,
)
}

/// Query the consensus key by validator address
pub async fn query_validator_consensus_keys<
C: crate::queries::Client + Sync,
>(
client: &C,
address: &Address,
) -> Result<Option<common::PublicKey>, error::Error> {
convert_response::<C, Option<common::PublicKey>>(
RPC.vp().pos().consensus_key(client, address).await,
)
}

/// Get the set of consensus keys registered in the network
pub async fn get_consensus_keys<C: crate::queries::Client + Sync>(
client: &C,
Expand Down
Loading