Skip to content

Commit

Permalink
Merge branch 'brent/fix-liveness' (#2246)
Browse files Browse the repository at this point in the history
* origin/brent/fix-liveness:
  changelog: add #2246
  only call jail if validator is not already jailed
  fix unjail tx from client to consider liveness jailing
  • Loading branch information
tzemanovic committed Dec 7, 2023
2 parents b1d5c9b + 56b5384 commit ce8167c
Show file tree
Hide file tree
Showing 5 changed files with 53 additions and 27 deletions.
3 changes: 3 additions & 0 deletions .changelog/unreleased/improvements/2246-fix-liveness.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
- Fix bug in client to allow for unjailing a validator
that was jailed for missing liveness requirements
([\#2246](https://github.com/anoma/namada/pull/2246))
6 changes: 6 additions & 0 deletions proof_of_stake/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5840,6 +5840,12 @@ where
.collect::<HashSet<_>>();

for validator in &validators_to_jail {
let state_jail_epoch = validator_state_handle(validator)
.get(storage, jail_epoch, params)?
.expect("Validator should have a state for the jail epoch");
if state_jail_epoch == ValidatorState::Jailed {
continue;
}
tracing::info!(
"Jailing validator {} starting in epoch {} for missing too many \
votes to ensure liveness",
Expand Down
23 changes: 19 additions & 4 deletions sdk/src/queries/vp/pos.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,10 @@ use namada_proof_of_stake::{
read_consensus_validator_set_addresses_with_stake, read_pos_params,
read_total_stake, read_validator_description,
read_validator_discord_handle, read_validator_email,
read_validator_max_commission_rate_change, read_validator_stake,
read_validator_website, unbond_handle, validator_commission_rate_handle,
validator_incoming_redelegations_handle, validator_slashes_handle,
validator_state_handle,
read_validator_last_slash_epoch, read_validator_max_commission_rate_change,
read_validator_stake, read_validator_website, unbond_handle,
validator_commission_rate_handle, validator_incoming_redelegations_handle,
validator_slashes_handle, validator_state_handle,
};

use crate::queries::types::RequestCtx;
Expand Down Expand Up @@ -57,6 +57,9 @@ router! {POS,

( "incoming_redelegation" / [src_validator: Address] / [delegator: Address] )
-> Option<Epoch> = validator_incoming_redelegation,

( "last_infraction_epoch" / [validator: Address] )
-> Option<Epoch> = validator_last_infraction_epoch,
},

( "validator_set" ) = {
Expand Down Expand Up @@ -291,6 +294,18 @@ where
Ok(state)
}

/// Get the validator state
fn validator_last_infraction_epoch<D, H, V, T>(
ctx: RequestCtx<'_, D, H, V, T>,
validator: Address,
) -> storage_api::Result<Option<Epoch>>
where
D: 'static + DB + for<'iter> DBIter<'iter> + Sync,
H: 'static + StorageHasher + Sync,
{
read_validator_last_slash_epoch(ctx.wl_storage, &validator)
}

/// 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.
Expand Down
13 changes: 13 additions & 0 deletions sdk/src/rpc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -815,6 +815,19 @@ pub async fn query_bond<C: crate::queries::Client + Sync>(
)
}

/// Query a validator's bonds for a given epoch
pub async fn query_last_infraction_epoch<C: crate::queries::Client + Sync>(
client: &C,
validator: &Address,
) -> Result<Option<Epoch>, error::Error> {
convert_response::<C, _>(
RPC.vp()
.pos()
.validator_last_infraction_epoch(client, validator)
.await,
)
}

/// Query the accunt substorage space of an address
pub async fn get_account_info<C: crate::queries::Client + Sync>(
client: &C,
Expand Down
35 changes: 12 additions & 23 deletions sdk/src/tx.rs
Original file line number Diff line number Diff line change
Expand Up @@ -897,23 +897,20 @@ pub async fn build_unjail_validator(
}
}

let last_slash_epoch_key =
namada_proof_of_stake::storage::validator_last_slash_key(validator);
let last_slash_epoch = rpc::query_storage_value::<_, Epoch>(
context.client(),
&last_slash_epoch_key,
)
.await;
let last_slash_epoch =
rpc::query_last_infraction_epoch(context.client(), validator).await;
match last_slash_epoch {
Ok(last_slash_epoch) => {
Ok(Some(last_slash_epoch)) => {
// Jailed due to slashing
let eligible_epoch =
last_slash_epoch + params.slash_processing_epoch_offset();
if current_epoch < eligible_epoch {
edisplay_line!(
context.io(),
"The given validator address {} is currently frozen and \
not yet eligible to be unjailed.",
&validator
will be eligible to be unjailed starting at epoch {}.",
&validator,
eligible_epoch
);
if !tx_args.force {
return Err(Error::from(
Expand All @@ -924,22 +921,14 @@ pub async fn build_unjail_validator(
}
}
}
Err(Error::Query(
QueryError::NoSuchKey(_) | QueryError::General(_),
)) => {
edisplay_line!(
context.io(),
"The given validator address {} is currently frozen and not \
yet eligible to be unjailed.",
&validator
);
Ok(None) => {
// Jailed due to liveness only. No checks needed.
}
Err(err) => {
if !tx_args.force {
return Err(Error::from(
TxError::ValidatorFrozenFromUnjailing(validator.clone()),
));
return Err(err);
}
}
Err(err) => return Err(err),
}

build(
Expand Down

0 comments on commit ce8167c

Please sign in to comment.