Update ValidatorStatus to match the v1 API (#2149)

## Issue Addressed

N/A

## Proposed Changes

We are currently a bit off of the standard API spec because we have [this](https://hackmd.io/bQxMDRt1RbS1TLno8K4NPg?view) proposal implemented for validator status.  Based on discussion [here](https://github.com/ethereum/eth2.0-APIs/pull/94), it looks like this won't be added to the spec until v2, so this PR implements [this](https://hackmd.io/ofFJ5gOmQpu1jjHilHbdQQ) validator status logic instead

## Additional Info

N/A


Co-authored-by: realbigsean <seananderson33@gmail.com>
This commit is contained in:
realbigsean 2021-02-24 04:15:13 +00:00
parent a764c3b247
commit 5bc93869c8
3 changed files with 113 additions and 97 deletions

View File

@ -498,7 +498,6 @@ pub fn serve<T: BeaconChainTypes>(
state_id
.map_state(&chain, |state| {
let epoch = state.current_epoch();
let finalized_epoch = state.finalized_checkpoint.epoch;
let far_future_epoch = chain.spec.far_future_epoch;
Ok(state
@ -522,17 +521,18 @@ pub fn serve<T: BeaconChainTypes>(
// filter by status(es) if provided and map the result
.filter_map(|(index, (validator, balance))| {
let status = api_types::ValidatorStatus::from_validator(
Some(validator),
validator,
epoch,
finalized_epoch,
far_future_epoch,
);
if query
.status
.as_ref()
.map_or(true, |statuses| statuses.0.contains(&status))
{
let status_matches =
query.status.as_ref().map_or(true, |statuses| {
statuses.0.contains(&status)
|| statuses.0.contains(&status.superstatus())
});
if status_matches {
Some(api_types::ValidatorData {
index: index as u64,
balance: *balance,
@ -577,16 +577,14 @@ pub fn serve<T: BeaconChainTypes>(
let validator = state.validators.get(index)?;
let balance = *state.balances.get(index)?;
let epoch = state.current_epoch();
let finalized_epoch = state.finalized_checkpoint.epoch;
let far_future_epoch = chain.spec.far_future_epoch;
Some(api_types::ValidatorData {
index: index as u64,
balance,
status: api_types::ValidatorStatus::from_validator(
Some(validator),
validator,
epoch,
finalized_epoch,
far_future_epoch,
),
validator: validator.clone(),

View File

@ -638,7 +638,6 @@ impl ApiTester {
let expected = state_opt.map(|state| {
let epoch = state.current_epoch();
let finalized_epoch = state.finalized_checkpoint.epoch;
let far_future_epoch = self.chain.spec.far_future_epoch;
let mut validators = Vec::with_capacity(validator_indices.len());
@ -649,12 +648,14 @@ impl ApiTester {
}
let validator = state.validators[i as usize].clone();
let status = ValidatorStatus::from_validator(
Some(&validator),
&validator,
epoch,
finalized_epoch,
far_future_epoch,
);
if statuses.contains(&status) || statuses.is_empty() {
if statuses.contains(&status)
|| statuses.is_empty()
|| statuses.contains(&status.superstatus())
{
validators.push(ValidatorData {
index: i as u64,
balance: state.balances[i as usize],
@ -706,16 +707,14 @@ impl ApiTester {
let expected = {
let epoch = state.current_epoch();
let finalized_epoch = state.finalized_checkpoint.epoch;
let far_future_epoch = self.chain.spec.far_future_epoch;
ValidatorData {
index: i as u64,
balance: state.balances[i],
status: ValidatorStatus::from_validator(
Some(&validator),
&validator,
epoch,
finalized_epoch,
far_future_epoch,
),
validator: validator.clone(),
@ -1444,18 +1443,19 @@ impl ApiTester {
vec![],
vec![ValidatorStatus::Active],
vec![
ValidatorStatus::Unknown,
ValidatorStatus::WaitingForEligibility,
ValidatorStatus::WaitingForFinality,
ValidatorStatus::WaitingInQueue,
ValidatorStatus::StandbyForActive,
ValidatorStatus::Active,
ValidatorStatus::ActiveAwaitingVoluntaryExit,
ValidatorStatus::ActiveAwaitingSlashedExit,
ValidatorStatus::ExitedVoluntarily,
ValidatorStatus::PendingInitialized,
ValidatorStatus::PendingQueued,
ValidatorStatus::ActiveOngoing,
ValidatorStatus::ActiveExiting,
ValidatorStatus::ActiveSlashed,
ValidatorStatus::ExitedUnslashed,
ValidatorStatus::ExitedSlashed,
ValidatorStatus::Withdrawable,
ValidatorStatus::Withdrawn,
ValidatorStatus::WithdrawalPossible,
ValidatorStatus::WithdrawalDone,
ValidatorStatus::Active,
ValidatorStatus::Pending,
ValidatorStatus::Exited,
ValidatorStatus::Withdrawal,
],
];
interesting

View File

@ -246,66 +246,84 @@ pub struct ValidatorBalanceData {
pub balance: u64,
}
// TODO: This does not currently match the spec, but I'm going to try and change the spec using
// Implemented according to what is described here:
//
// https://hackmd.io/ofFJ5gOmQpu1jjHilHbdQQ
//
// We expect this to be updated in v2 of the standard api to
// this proposal:
//
// https://hackmd.io/bQxMDRt1RbS1TLno8K4NPg?view
#[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum ValidatorStatus {
Unknown,
WaitingForEligibility,
WaitingForFinality,
WaitingInQueue,
StandbyForActive,
Active,
ActiveAwaitingVoluntaryExit,
ActiveAwaitingSlashedExit,
ExitedVoluntarily,
PendingInitialized,
PendingQueued,
ActiveOngoing,
ActiveExiting,
ActiveSlashed,
ExitedUnslashed,
ExitedSlashed,
Withdrawable,
Withdrawn,
WithdrawalPossible,
WithdrawalDone,
Active,
Pending,
Exited,
Withdrawal,
}
impl ValidatorStatus {
pub fn from_validator(
validator_opt: Option<&Validator>,
epoch: Epoch,
finalized_epoch: Epoch,
far_future_epoch: Epoch,
) -> Self {
if let Some(validator) = validator_opt {
pub fn from_validator(validator: &Validator, epoch: Epoch, far_future_epoch: Epoch) -> Self {
if validator.is_withdrawable_at(epoch) {
ValidatorStatus::Withdrawable
} else if validator.is_exited_at(epoch) {
if validator.effective_balance == 0 {
ValidatorStatus::WithdrawalDone
} else {
ValidatorStatus::WithdrawalPossible
}
} else if validator.is_exited_at(epoch) && epoch < validator.withdrawable_epoch {
if validator.slashed {
ValidatorStatus::ExitedSlashed
} else {
ValidatorStatus::ExitedVoluntarily
ValidatorStatus::ExitedUnslashed
}
} else if validator.is_active_at(epoch) {
if validator.exit_epoch < far_future_epoch {
if validator.slashed {
ValidatorStatus::ActiveAwaitingSlashedExit
ValidatorStatus::ActiveSlashed
} else {
ValidatorStatus::ActiveAwaitingVoluntaryExit
ValidatorStatus::ActiveExiting
}
} else {
ValidatorStatus::ActiveOngoing
}
// `pending` statuses are specified as validators where `validator.activation_epoch > current_epoch`.
// If this code is reached, this criteria must have been met because `validator.is_active_at(epoch)`,
// `validator.is_exited_at(epoch)`, and `validator.is_withdrawable_at(epoch)` all returned false.
} else if validator.activation_eligibility_epoch == far_future_epoch {
ValidatorStatus::PendingInitialized
} else {
ValidatorStatus::PendingQueued
}
}
pub fn superstatus(&self) -> Self {
match self {
ValidatorStatus::PendingInitialized | ValidatorStatus::PendingQueued => {
ValidatorStatus::Pending
}
ValidatorStatus::ActiveOngoing
| ValidatorStatus::ActiveExiting
| ValidatorStatus::ActiveSlashed => ValidatorStatus::Active,
ValidatorStatus::ExitedUnslashed | ValidatorStatus::ExitedSlashed => {
ValidatorStatus::Exited
}
ValidatorStatus::WithdrawalPossible | ValidatorStatus::WithdrawalDone => {
ValidatorStatus::Withdrawal
}
ValidatorStatus::Active
}
} else if validator.activation_epoch < far_future_epoch {
ValidatorStatus::StandbyForActive
} else if validator.activation_eligibility_epoch < far_future_epoch {
if finalized_epoch < validator.activation_eligibility_epoch {
ValidatorStatus::WaitingForFinality
} else {
ValidatorStatus::WaitingInQueue
}
} else {
ValidatorStatus::WaitingForEligibility
}
} else {
ValidatorStatus::Unknown
| ValidatorStatus::Pending
| ValidatorStatus::Exited
| ValidatorStatus::Withdrawal => *self,
}
}
}
@ -315,18 +333,19 @@ impl FromStr for ValidatorStatus {
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s {
"unknown" => Ok(ValidatorStatus::Unknown),
"waiting_for_eligibility" => Ok(ValidatorStatus::WaitingForEligibility),
"waiting_for_finality" => Ok(ValidatorStatus::WaitingForFinality),
"waiting_in_queue" => Ok(ValidatorStatus::WaitingInQueue),
"standby_for_active" => Ok(ValidatorStatus::StandbyForActive),
"active" => Ok(ValidatorStatus::Active),
"active_awaiting_voluntary_exit" => Ok(ValidatorStatus::ActiveAwaitingVoluntaryExit),
"active_awaiting_slashed_exit" => Ok(ValidatorStatus::ActiveAwaitingSlashedExit),
"exited_voluntarily" => Ok(ValidatorStatus::ExitedVoluntarily),
"pending_initialized" => Ok(ValidatorStatus::PendingInitialized),
"pending_queued" => Ok(ValidatorStatus::PendingQueued),
"active_ongoing" => Ok(ValidatorStatus::ActiveOngoing),
"active_exiting" => Ok(ValidatorStatus::ActiveExiting),
"active_slashed" => Ok(ValidatorStatus::ActiveSlashed),
"exited_unslashed" => Ok(ValidatorStatus::ExitedUnslashed),
"exited_slashed" => Ok(ValidatorStatus::ExitedSlashed),
"withdrawable" => Ok(ValidatorStatus::Withdrawable),
"withdrawn" => Ok(ValidatorStatus::Withdrawn),
"withdrawal_possible" => Ok(ValidatorStatus::WithdrawalPossible),
"withdrawal_done" => Ok(ValidatorStatus::WithdrawalDone),
"active" => Ok(ValidatorStatus::Active),
"pending" => Ok(ValidatorStatus::Pending),
"exited" => Ok(ValidatorStatus::Exited),
"withdrawal" => Ok(ValidatorStatus::Withdrawal),
_ => Err(format!("{} cannot be parsed as a validator status.", s)),
}
}
@ -335,20 +354,19 @@ impl FromStr for ValidatorStatus {
impl fmt::Display for ValidatorStatus {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
ValidatorStatus::Unknown => write!(f, "unknown"),
ValidatorStatus::WaitingForEligibility => write!(f, "waiting_for_eligibility"),
ValidatorStatus::WaitingForFinality => write!(f, "waiting_for_finality"),
ValidatorStatus::WaitingInQueue => write!(f, "waiting_in_queue"),
ValidatorStatus::StandbyForActive => write!(f, "standby_for_active"),
ValidatorStatus::Active => write!(f, "active"),
ValidatorStatus::ActiveAwaitingVoluntaryExit => {
write!(f, "active_awaiting_voluntary_exit")
}
ValidatorStatus::ActiveAwaitingSlashedExit => write!(f, "active_awaiting_slashed_exit"),
ValidatorStatus::ExitedVoluntarily => write!(f, "exited_voluntarily"),
ValidatorStatus::PendingInitialized => write!(f, "pending_initialized"),
ValidatorStatus::PendingQueued => write!(f, "pending_queued"),
ValidatorStatus::ActiveOngoing => write!(f, "active_ongoing"),
ValidatorStatus::ActiveExiting => write!(f, "active_exiting"),
ValidatorStatus::ActiveSlashed => write!(f, "active_slashed"),
ValidatorStatus::ExitedUnslashed => write!(f, "exited_unslashed"),
ValidatorStatus::ExitedSlashed => write!(f, "exited_slashed"),
ValidatorStatus::Withdrawable => write!(f, "withdrawable"),
ValidatorStatus::Withdrawn => write!(f, "withdrawn"),
ValidatorStatus::WithdrawalPossible => write!(f, "withdrawal_possible"),
ValidatorStatus::WithdrawalDone => write!(f, "withdrawal_done"),
ValidatorStatus::Active => write!(f, "active"),
ValidatorStatus::Pending => write!(f, "pending"),
ValidatorStatus::Exited => write!(f, "exited"),
ValidatorStatus::Withdrawal => write!(f, "withdrawal"),
}
}
}