Skip to content

Commit

Permalink
Refactor validator inclusion endpoint
Browse files Browse the repository at this point in the history
  • Loading branch information
paulhauner committed Jun 25, 2021
1 parent f0696af commit 4fa189f
Show file tree
Hide file tree
Showing 5 changed files with 129 additions and 68 deletions.
95 changes: 51 additions & 44 deletions beacon_node/http_api/src/validator_inclusion.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,35 +4,46 @@ use eth2::{
lighthouse::{GlobalValidatorInclusionData, ValidatorInclusionData},
types::ValidatorId,
};
use state_processing::per_epoch_processing::ValidatorStatuses;
use types::{Epoch, EthSpec};
use state_processing::per_epoch_processing::{process_epoch, EpochProcessingSummary};
use types::{BeaconState, ChainSpec, Epoch, EthSpec};

fn end_of_epoch_state<T: BeaconChainTypes>(
epoch: Epoch,
chain: &BeaconChain<T>,
) -> Result<BeaconState<T::EthSpec>, warp::reject::Rejection> {
let target_slot = epoch.end_slot(T::EthSpec::slots_per_epoch());
StateId::slot(target_slot).state(chain)
}

fn get_epoch_processing_summary<T: EthSpec>(
state: &mut BeaconState<T>,
spec: &ChainSpec,
) -> Result<EpochProcessingSummary, warp::reject::Rejection> {
process_epoch(state, spec)
.map_err(|e| warp_utils::reject::custom_server_error(format!("{:?}", e)))
}

/// Returns information about *all validators* (i.e., global) and how they performed during a given
/// epoch.
pub fn global_validator_inclusion_data<T: BeaconChainTypes>(
epoch: Epoch,
chain: &BeaconChain<T>,
) -> Result<GlobalValidatorInclusionData, warp::Rejection> {
let target_slot = epoch.end_slot(T::EthSpec::slots_per_epoch());

let state = StateId::slot(target_slot).state(chain)?;

let mut validator_statuses = ValidatorStatuses::new(&state, &chain.spec)
.map_err(warp_utils::reject::beacon_state_error)?;
validator_statuses
.process_attestations(&state)
.map_err(warp_utils::reject::beacon_state_error)?;

let totals = validator_statuses.total_balances;
let mut state = end_of_epoch_state(epoch, chain)?;
let summary = get_epoch_processing_summary(&mut state, &chain.spec)?;

Ok(GlobalValidatorInclusionData {
current_epoch_active_gwei: totals.current_epoch(),
previous_epoch_active_gwei: totals.previous_epoch(),
current_epoch_attesting_gwei: totals.current_epoch_attesters(),
current_epoch_target_attesting_gwei: totals.current_epoch_target_attesters(),
previous_epoch_attesting_gwei: totals.previous_epoch_attesters(),
previous_epoch_target_attesting_gwei: totals.previous_epoch_target_attesters(),
previous_epoch_head_attesting_gwei: totals.previous_epoch_head_attesters(),
current_epoch_active_gwei: summary.current_epoch_total_active_balance(),
previous_epoch_active_gwei: summary.previous_epoch_total_active_balance(),
current_epoch_target_attesting_gwei: summary
.current_epoch_target_attesting_balance()
.map_err(|e| warp_utils::reject::custom_server_error(format!("{:?}", e)))?,
previous_epoch_target_attesting_gwei: summary
.previous_epoch_target_attesting_balance()
.map_err(|e| warp_utils::reject::custom_server_error(format!("{:?}", e)))?,
previous_epoch_head_attesting_gwei: summary
.previous_epoch_head_attesting_balance()
.map_err(|e| warp_utils::reject::custom_server_error(format!("{:?}", e)))?,
})
}

Expand All @@ -42,15 +53,7 @@ pub fn validator_inclusion_data<T: BeaconChainTypes>(
validator_id: &ValidatorId,
chain: &BeaconChain<T>,
) -> Result<Option<ValidatorInclusionData>, warp::Rejection> {
let target_slot = epoch.end_slot(T::EthSpec::slots_per_epoch());

let mut state = StateId::slot(target_slot).state(chain)?;

let mut validator_statuses = ValidatorStatuses::new(&state, &chain.spec)
.map_err(warp_utils::reject::beacon_state_error)?;
validator_statuses
.process_attestations(&state)
.map_err(warp_utils::reject::beacon_state_error)?;
let mut state = end_of_epoch_state(epoch, chain)?;

state
.update_pubkey_cache()
Expand All @@ -70,19 +73,23 @@ pub fn validator_inclusion_data<T: BeaconChainTypes>(
}
};

Ok(validator_statuses
.statuses
.get(validator_index)
.map(|vote| ValidatorInclusionData {
is_slashed: vote.is_slashed,
is_withdrawable_in_current_epoch: vote.is_withdrawable_in_current_epoch,
is_active_in_current_epoch: vote.is_active_in_current_epoch,
is_active_in_previous_epoch: vote.is_active_in_previous_epoch,
current_epoch_effective_balance_gwei: vote.current_epoch_effective_balance,
is_current_epoch_attester: vote.is_current_epoch_attester,
is_current_epoch_target_attester: vote.is_current_epoch_target_attester,
is_previous_epoch_attester: vote.is_previous_epoch_attester,
is_previous_epoch_target_attester: vote.is_previous_epoch_target_attester,
is_previous_epoch_head_attester: vote.is_previous_epoch_head_attester,
}))
let validator = if let Ok(validator) = state.get_validator(validator_index) {
validator.clone()
} else {
return Ok(None);
};

let summary = get_epoch_processing_summary(&mut state, &chain.spec)?;

Ok(Some(ValidatorInclusionData {
is_slashed: validator.slashed,
is_withdrawable_in_current_epoch: validator.is_withdrawable_at(epoch),
is_active_in_current_epoch: summary.is_active_in_current_epoch(validator_index),
is_active_in_previous_epoch: summary.is_active_in_previous_epoch(validator_index),
current_epoch_effective_balance_gwei: validator.effective_balance,
is_current_epoch_target_attester: summary.is_current_epoch_target_attester(validator_index),
is_previous_epoch_target_attester: summary
.is_previous_epoch_target_attester(validator_index),
is_previous_epoch_head_attester: summary.is_previous_epoch_head_attester(validator_index),
}))
}
13 changes: 2 additions & 11 deletions book/src/validator-inclusion.md
Original file line number Diff line number Diff line change
Expand Up @@ -52,14 +52,9 @@ The following fields are returned:

- `current_epoch_active_gwei`: the total staked gwei that was active (i.e.,
able to vote) during the current epoch.
- `current_epoch_attesting_gwei`: the total staked gwei that had one or more
attestations included in a block during the current epoch (multiple
attestations by the same validator do not increase this figure).
- `current_epoch_target_attesting_gwei`: the total staked gwei that attested to
the majority-elected Casper FFG target epoch during the current epoch. This
figure must be equal to or less than `current_epoch_attesting_gwei`.
- `previous_epoch_active_gwei`: as above, but during the previous epoch.
- `previous_epoch_attesting_gwei`: see `current_epoch_attesting_gwei`.
the majority-elected Casper FFG target epoch during the current epoch.
- `previous_epoch_active_gwei`: as per `current_epoch_active_gwei`, but during the previous epoch.
- `previous_epoch_target_attesting_gwei`: see `current_epoch_target_attesting_gwei`.
- `previous_epoch_head_attesting_gwei`: the total staked gwei that attested to a
head beacon block that is in the canonical chain.
Expand Down Expand Up @@ -91,9 +86,7 @@ curl -X GET "http://localhost:5052/lighthouse/validator_inclusion/0/global" -H
"data": {
"current_epoch_active_gwei": 642688000000000,
"previous_epoch_active_gwei": 642688000000000,
"current_epoch_attesting_gwei": 366208000000000,
"current_epoch_target_attesting_gwei": 366208000000000,
"previous_epoch_attesting_gwei": 1000000000,
"previous_epoch_target_attesting_gwei": 1000000000,
"previous_epoch_head_attesting_gwei": 1000000000
}
Expand Down Expand Up @@ -124,9 +117,7 @@ curl -X GET "http://localhost:5052/lighthouse/validator_inclusion/0/42" -H "acc
"is_active_in_current_epoch": true,
"is_active_in_previous_epoch": true,
"current_epoch_effective_balance_gwei": 32000000000,
"is_current_epoch_attester": false,
"is_current_epoch_target_attester": false,
"is_previous_epoch_attester": false,
"is_previous_epoch_target_attester": false,
"is_previous_epoch_head_attester": false
}
Expand Down
8 changes: 0 additions & 8 deletions common/eth2/src/lighthouse.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,13 +32,9 @@ pub struct GlobalValidatorInclusionData {
pub current_epoch_active_gwei: u64,
/// The total effective balance of all active validators during the _previous_ epoch.
pub previous_epoch_active_gwei: u64,
/// The total effective balance of all validators who attested during the _current_ epoch.
pub current_epoch_attesting_gwei: u64,
/// The total effective balance of all validators who attested during the _current_ epoch and
/// agreed with the state about the beacon block at the first slot of the _current_ epoch.
pub current_epoch_target_attesting_gwei: u64,
/// The total effective balance of all validators who attested during the _previous_ epoch.
pub previous_epoch_attesting_gwei: u64,
/// The total effective balance of all validators who attested during the _previous_ epoch and
/// agreed with the state about the beacon block at the first slot of the _previous_ epoch.
pub previous_epoch_target_attesting_gwei: u64,
Expand All @@ -59,13 +55,9 @@ pub struct ValidatorInclusionData {
pub is_active_in_previous_epoch: bool,
/// The validator's effective balance in the _current_ epoch.
pub current_epoch_effective_balance_gwei: u64,
/// True if the validator had an attestation included in the _current_ epoch.
pub is_current_epoch_attester: bool,
/// True if the validator's beacon block root attestation for the first slot of the _current_
/// epoch matches the block root known to the state.
pub is_current_epoch_target_attester: bool,
/// True if the validator had an attestation included in the _previous_ epoch.
pub is_previous_epoch_attester: bool,
/// True if the validator's beacon block root attestation for the first slot of the _previous_
/// epoch matches the block root known to the state.
pub is_previous_epoch_target_attester: bool,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -226,6 +226,22 @@ impl ParticipationCache {
&self.eligible_indices
}

pub fn current_epoch_total_active_balance(&self) -> u64 {
self.current_epoch_participation.total_active_balance.get()
}

fn current_epoch_flag_attesting_balance(&self, flag_index: usize) -> Result<u64, ArithError> {
self.current_epoch_participation
.total_flag_balances
.get(flag_index)
.map(Balance::get)
.ok_or(ArithError::Overflow)
}

pub fn current_epoch_target_attesting_balance(&self) -> Result<u64, ArithError> {
self.current_epoch_flag_attesting_balance(TIMELY_TARGET_FLAG_INDEX)
}

pub fn previous_epoch_total_active_balance(&self) -> u64 {
self.previous_epoch_participation.total_active_balance.get()
}
Expand All @@ -246,10 +262,6 @@ impl ParticipationCache {
self.previous_epoch_flag_attesting_balance(TIMELY_HEAD_FLAG_INDEX)
}

pub fn current_epoch_total_active_balance(&self) -> u64 {
self.current_epoch_participation.total_active_balance.get()
}

/// Equivalent to the `get_unslashed_participating_indices` function in the specification.
pub fn get_unslashed_participating_indices(
&self,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,29 @@ pub enum EpochProcessingSummary {
}

impl EpochProcessingSummary {
/// Returns the sum of the effective balance of all validators in the current epoch.
pub fn current_epoch_total_active_balance(&self) -> u64 {
match self {
EpochProcessingSummary::Base { total_balances, .. } => total_balances.current_epoch(),
EpochProcessingSummary::Altair {
participation_cache,
} => participation_cache.current_epoch_total_active_balance(),
}
}

/// Returns the sum of the effective balance of all validators in the current epoch who
/// included an attestation that matched the target.
pub fn current_epoch_target_attesting_balance(&self) -> Result<u64, ArithError> {
match self {
EpochProcessingSummary::Base { total_balances, .. } => {
Ok(total_balances.current_epoch_target_attesters())
}
EpochProcessingSummary::Altair {
participation_cache,
} => participation_cache.current_epoch_target_attesting_balance(),
}
}

/// Returns the sum of the effective balance of all validators in the previous epoch.
pub fn previous_epoch_total_active_balance(&self) -> u64 {
match self {
Expand All @@ -28,6 +51,42 @@ impl EpochProcessingSummary {
}
}

/// Returns `true` if `val_index` was included in the active validator indices in the current
/// epoch.
///
/// ## Notes
///
/// Always returns `false` for an unknown `val_index`.
pub fn is_active_in_current_epoch(&self, val_index: usize) -> bool {
match self {
EpochProcessingSummary::Base { statuses, .. } => statuses
.get(val_index)
.map_or(false, |s| s.is_current_epoch_target_attester),
EpochProcessingSummary::Altair {
participation_cache,
..
} => participation_cache.is_active_in_current_epoch(val_index),
}
}

/// Returns `true` if `val_index` had a target-matching attestation included on chain in the
/// current epoch.
///
/// ## Notes
///
/// Always returns `false` for an unknown `val_index`.
pub fn is_current_epoch_target_attester(&self, val_index: usize) -> bool {
match self {
EpochProcessingSummary::Base { statuses, .. } => statuses
.get(val_index)
.map_or(false, |s| s.is_current_epoch_target_attester),
EpochProcessingSummary::Altair {
participation_cache,
..
} => participation_cache.is_current_epoch_timely_target_attester(val_index),
}
}

/// Returns the sum of the effective balance of all validators in the previous epoch who
/// included an attestation that matched the target.
pub fn previous_epoch_target_attesting_balance(&self) -> Result<u64, ArithError> {
Expand Down Expand Up @@ -69,7 +128,7 @@ impl EpochProcessingSummary {
match self {
EpochProcessingSummary::Base { statuses, .. } => statuses
.get(val_index)
.map_or(false, |s| s.is_previous_epoch_target_attester),
.map_or(false, |s| s.is_active_in_previous_epoch),
EpochProcessingSummary::Altair {
participation_cache,
..
Expand Down

0 comments on commit 4fa189f

Please sign in to comment.