Skip to content

Commit

Permalink
Merge branch 'bengt/add-unjail-validator' (#1654)
Browse files Browse the repository at this point in the history
* origin/bengt/add-unjail-validator:
  handle errors for unjail-validator tx in the client
  expand and fix e2e test `double_signing_gets_slashed`
  add unjail tx at CLI
  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
Fraccaman committed Jul 21, 2023
2 parents d8036f1 + a5d2237 commit 7a18295
Show file tree
Hide file tree
Showing 7 changed files with 282 additions and 23 deletions.
14 changes: 14 additions & 0 deletions apps/src/bin/namada-client/cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -234,6 +234,20 @@ pub async fn main() -> Result<()> {
sdk_tx::process_tx(&client, &mut ctx.wallet, &tx_args, tx)
.await?;
}
Sub::TxUnjailValidator(TxUnjailValidator(mut args)) => {
let client = HttpClient::new(utils::take_config_address(
&mut args.tx.ledger_address,
))
.unwrap();
wait_until_node_is_synched(&client)
.await
.proceed_or_else(error)?;
let args = args.to_sdk(&mut ctx);
tx::submit_unjail_validator::<HttpClient>(
&client, ctx, args,
)
.await?;
}
// Ledger queries
Sub::QueryEpoch(QueryEpoch(mut args)) => {
let client = HttpClient::new(utils::take_config_address(
Expand Down
37 changes: 29 additions & 8 deletions apps/src/lib/cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ const WALLET_CMD: &str = "wallet";
const RELAYER_CMD: &str = "relayer";

pub mod cmds {

use super::utils::*;
use super::{
args, ArgMatches, CLIENT_CMD, NODE_CMD, RELAYER_CMD, WALLET_CMD,
Expand Down Expand Up @@ -216,6 +217,7 @@ pub mod cmds {
.subcommand(TxVoteProposal::def().display_order(1))
// PoS transactions
.subcommand(TxInitValidator::def().display_order(2))
.subcommand(TxUnjailValidator::def().display_order(2))
.subcommand(Bond::def().display_order(2))
.subcommand(Unbond::def().display_order(2))
.subcommand(Withdraw::def().display_order(2))
Expand Down Expand Up @@ -252,6 +254,8 @@ pub mod cmds {
let tx_init_account = Self::parse_with_ctx(matches, TxInitAccount);
let tx_init_validator =
Self::parse_with_ctx(matches, TxInitValidator);
let tx_unjail_validator =
Self::parse_with_ctx(matches, TxUnjailValidator);
let tx_reveal_pk = Self::parse_with_ctx(matches, TxRevealPk);
let tx_init_proposal =
Self::parse_with_ctx(matches, TxInitProposal);
Expand Down Expand Up @@ -298,6 +302,7 @@ pub mod cmds {
.or(tx_vote_proposal)
.or(tx_init_validator)
.or(tx_commission_rate_change)
.or(tx_unjail_validator)
.or(bond)
.or(unbond)
.or(withdraw)
Expand Down Expand Up @@ -363,6 +368,7 @@ pub mod cmds {
TxInitAccount(TxInitAccount),
TxInitValidator(TxInitValidator),
TxCommissionRateChange(TxCommissionRateChange),
TxUnjailValidator(TxUnjailValidator),
TxInitProposal(TxInitProposal),
TxVoteProposal(TxVoteProposal),
TxRevealPk(TxRevealPk),
Expand Down Expand Up @@ -1287,6 +1293,27 @@ pub mod cmds {
}
}

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

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

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

fn def() -> App {
App::new(Self::CMD)
.about(
"Send a signed transaction to unjail a jailed validator.",
)
.add_args::<args::TxUnjailValidator<args::CliTypes>>()
}
}

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

Expand Down Expand Up @@ -4152,16 +4179,10 @@ pub mod args {

impl CliToSdk<TxUnjailValidator<SdkTypes>> for TxUnjailValidator<CliTypes> {
fn to_sdk(self, ctx: &mut Context) -> TxUnjailValidator<SdkTypes> {
TxUnjailValidator {
TxUnjailValidator::<SdkTypes> {
tx: self.tx.to_sdk(ctx),
validator: ctx.get(&self.validator),
tx_code_path: self
.tx_code_path
.as_path()
.to_str()
.unwrap()
.to_string()
.into_bytes(),
tx_code_path: self.tx_code_path.to_path_buf(),
}
}
}
Expand Down
2 changes: 1 addition & 1 deletion shared/src/ledger/args.rs
Original file line number Diff line number Diff line change
Expand Up @@ -388,7 +388,7 @@ pub struct TxUnjailValidator<C: NamadaTypes = SdkTypes> {
/// Validator address (should be self)
pub validator: C::Address,
/// Path to the TX WASM code file
pub tx_code_path: C::Data,
pub tx_code_path: PathBuf,
}

/// Query PoS commission rate
Expand Down
12 changes: 12 additions & 0 deletions shared/src/ledger/queries/vp/pos.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ use std::collections::{BTreeMap, BTreeSet, HashMap, HashSet};
use borsh::{BorshDeserialize, BorshSchema, BorshSerialize};
use namada_core::ledger::storage_api::collections::lazy_map;
use namada_core::ledger::storage_api::OptionExt;
use namada_proof_of_stake::parameters::PosParams;
use namada_proof_of_stake::types::{
BondId, BondsAndUnbondsDetail, BondsAndUnbondsDetails, CommissionPair,
Slash, ValidatorState, WeightedValidator,
Expand Down Expand Up @@ -60,6 +61,8 @@ router! {POS,
// TODO: add "below_threshold"
},

( "pos_params") -> PosParams = pos_params,

( "total_stake" / [epoch: opt Epoch] )
-> token::Amount = total_stake,

Expand Down Expand Up @@ -141,6 +144,15 @@ impl<T> Enriched<T> {

// Handlers that implement the functions via `trait StorageRead`:

/// Get the PoS parameters
fn pos_params<D, H>(ctx: RequestCtx<'_, D, H>) -> storage_api::Result<PosParams>
where
D: 'static + DB + for<'iter> DBIter<'iter> + Sync,
H: 'static + StorageHasher + Sync,
{
read_pos_params(ctx.wl_storage)
}

/// Find if the given address belongs to a validator account.
fn is_validator<D, H>(
ctx: RequestCtx<'_, D, H>,
Expand Down
26 changes: 25 additions & 1 deletion shared/src/ledger/rpc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,10 @@ use namada_core::types::storage::Key;
use namada_core::types::token::{
Amount, DenominatedAmount, Denomination, MaspDenom, TokenAddress,
};
use namada_proof_of_stake::types::{BondsAndUnbondsDetails, CommissionPair};
use namada_proof_of_stake::parameters::PosParams;
use namada_proof_of_stake::types::{
BondsAndUnbondsDetails, CommissionPair, ValidatorState,
};
use serde::Serialize;

use crate::ledger::args::InputAmount;
Expand Down Expand Up @@ -696,6 +699,13 @@ pub async fn get_proposal_votes<C: crate::ledger::queries::Client + Sync>(
}
}

/// Get the PoS parameters
pub async fn get_pos_params<C: crate::ledger::queries::Client + Sync>(
client: &C,
) -> PosParams {
unwrap_client_response::<C, _>(RPC.vp().pos().pos_params(client).await)
}

/// Get all validators in the given epoch
pub async fn get_all_validators<C: crate::ledger::queries::Client + Sync>(
client: &C,
Expand Down Expand Up @@ -736,6 +746,20 @@ pub async fn get_validator_stake<C: crate::ledger::queries::Client + Sync>(
.unwrap_or_default()
}

/// Query and return a validator's state
pub async fn get_validator_state<C: crate::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,
)
}

/// Get the delegator's delegation
pub async fn get_delegators_delegation<
C: crate::ledger::queries::Client + Sync,
Expand Down
73 changes: 63 additions & 10 deletions shared/src/ledger/tx.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ use namada_core::types::dec::Dec;
use namada_core::types::storage::Key;
use namada_core::types::token::MaspDenom;
use namada_proof_of_stake::parameters::PosParams;
use namada_proof_of_stake::types::CommissionPair;
use namada_proof_of_stake::types::{CommissionPair, ValidatorState};
use prost::EncodeError;
use thiserror::Error;

Expand Down Expand Up @@ -110,6 +110,18 @@ pub enum Error {
/// Invalid validator address
#[error("The address {0} doesn't belong to any known validator account.")]
InvalidValidatorAddress(Address),
/// Not jailed at pipeline epoch
#[error(
"The validator address {0} is not jailed at epoch when it would be \
restored."
)]
ValidatorNotCurrentlyJailed(Address),
/// Validator still frozen and ineligible to be unjailed
#[error(
"The validator address {0} is currently frozen and ineligible to be \
unjailed."
)]
ValidatorFrozenFromUnjailing(Address),
/// Rate of epoch change too large for current epoch
#[error(
"New rate, {0}, is too large of a change with respect to the \
Expand Down Expand Up @@ -631,11 +643,7 @@ pub async fn build_validator_commission_change<
.await
.unwrap();

// TODO: put following two let statements in its own function
let params_key = crate::ledger::pos::params_key();
let params = rpc::query_storage_value::<C, PosParams>(client, &params_key)
.await
.expect("Parameter should be defined.");
let params: PosParams = rpc::get_pos_params(client).await;

let validator = args.validator.clone();
if rpc::is_validator(client, &validator).await {
Expand Down Expand Up @@ -725,9 +733,10 @@ pub async fn build_unjail_validator<
}
}

let tx_code_path = String::from_utf8(args.tx_code_path).unwrap();
let tx_code_hash =
query_wasm_code_hash(client, tx_code_path).await.unwrap();
query_wasm_code_hash(client, args.tx_code_path.to_str().unwrap())
.await
.unwrap();

let data = args
.validator
Expand Down Expand Up @@ -770,9 +779,53 @@ pub async fn submit_unjail_validator<
}
}

let tx_code_path = String::from_utf8(args.tx_code_path).unwrap();
let params: PosParams = rpc::get_pos_params(client).await;
let current_epoch = rpc::query_epoch(client).await;
let pipeline_epoch = current_epoch + params.pipeline_len;

let validator_state_at_pipeline =
rpc::get_validator_state(client, &args.validator, Some(pipeline_epoch))
.await
.expect("Validator state should be defined.");
if validator_state_at_pipeline != ValidatorState::Jailed {
eprintln!(
"The given validator address {} is not jailed at the pipeline \
epoch when it would be restored to one of the validator sets.",
&args.validator
);
if !args.tx.force {
return Err(Error::ValidatorNotCurrentlyJailed(
args.validator.clone(),
));
}
}

let last_slash_epoch_key =
crate::ledger::pos::validator_last_slash_key(&args.validator);
let last_slash_epoch =
rpc::query_storage_value::<C, Epoch>(client, &last_slash_epoch_key)
.await;
if let Some(last_slash_epoch) = last_slash_epoch {
let eligible_epoch =
last_slash_epoch + params.slash_processing_epoch_offset();
if current_epoch < eligible_epoch {
eprintln!(
"The given validator address {} is currently frozen and not \
yet eligible to be unjailed.",
&args.validator
);
if !args.tx.force {
return Err(Error::ValidatorNotCurrentlyJailed(
args.validator.clone(),
));
}
}
}

let tx_code_hash =
query_wasm_code_hash(client, tx_code_path).await.unwrap();
query_wasm_code_hash(client, args.tx_code_path.to_str().unwrap())
.await
.unwrap();

let data = args
.validator
Expand Down
Loading

0 comments on commit 7a18295

Please sign in to comment.