bb5a6d2cca
## Issue Addressed #3031 ## Proposed Changes Updates the following API endpoints to conform with https://github.com/ethereum/beacon-APIs/pull/190 and https://github.com/ethereum/beacon-APIs/pull/196 - [x] `beacon/states/{state_id}/root` - [x] `beacon/states/{state_id}/fork` - [x] `beacon/states/{state_id}/finality_checkpoints` - [x] `beacon/states/{state_id}/validators` - [x] `beacon/states/{state_id}/validators/{validator_id}` - [x] `beacon/states/{state_id}/validator_balances` - [x] `beacon/states/{state_id}/committees` - [x] `beacon/states/{state_id}/sync_committees` - [x] `beacon/headers` - [x] `beacon/headers/{block_id}` - [x] `beacon/blocks/{block_id}` - [x] `beacon/blocks/{block_id}/root` - [x] `beacon/blocks/{block_id}/attestations` - [x] `debug/beacon/states/{state_id}` - [x] `debug/beacon/heads` - [x] `validator/duties/attester/{epoch}` - [x] `validator/duties/proposer/{epoch}` - [x] `validator/duties/sync/{epoch}` Updates the following Server-Sent Events: - [x] `events?topics=head` - [x] `events?topics=block` - [x] `events?topics=finalized_checkpoint` - [x] `events?topics=chain_reorg` ## Backwards Incompatible There is a very minor breaking change with the way the API now handles requests to `beacon/blocks/{block_id}/root` and `beacon/states/{state_id}/root` when `block_id` or `state_id` is the `Root` variant of `BlockId` and `StateId` respectively. Previously a request to a non-existent root would simply echo the root back to the requester: ``` curl "http://localhost:5052/eth/v1/beacon/states/0xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/root" {"data":{"root":"0xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"}} ``` Now it will return a `404`: ``` curl "http://localhost:5052/eth/v1/beacon/blocks/0xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/root" {"code":404,"message":"NOT_FOUND: beacon block with root 0xaaaa…aaaa","stacktraces":[]} ``` In addition to this is the block root `0x0000000000000000000000000000000000000000000000000000000000000000` previously would return the genesis block. It will now return a `404`: ``` curl "http://localhost:5052/eth/v1/beacon/blocks/0x0000000000000000000000000000000000000000000000000000000000000000" {"code":404,"message":"NOT_FOUND: beacon block with root 0x0000…0000","stacktraces":[]} ``` ## Additional Info - `execution_optimistic` is always set, and will return `false` pre-Bellatrix. I am also open to the idea of doing something like `#[serde(skip_serializing_if = "Option::is_none")]`. - The value of `execution_optimistic` is set to `false` where possible. Any computation that is reliant on the `head` will simply use the `ExecutionStatus` of the head (unless the head block is pre-Bellatrix). Co-authored-by: Paul Hauner <paul@paulhauner.com>
120 lines
4.6 KiB
Rust
120 lines
4.6 KiB
Rust
use crate::state_id::StateId;
|
|
use beacon_chain::{BeaconChain, BeaconChainTypes};
|
|
use eth2::{
|
|
lighthouse::{GlobalValidatorInclusionData, ValidatorInclusionData},
|
|
types::ValidatorId,
|
|
};
|
|
use state_processing::per_epoch_processing::{
|
|
altair::participation_cache::Error as ParticipationCacheError, process_epoch,
|
|
EpochProcessingSummary,
|
|
};
|
|
use types::{BeaconState, ChainSpec, Epoch, EthSpec};
|
|
|
|
/// Returns the state in the last slot of `epoch`.
|
|
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());
|
|
// The execution status is not returned, any functions which rely upon this method might return
|
|
// optimistic information without explicitly declaring so.
|
|
let (state, _execution_status) = StateId::from_slot(target_slot).state(chain)?;
|
|
Ok(state)
|
|
}
|
|
|
|
/// Generate an `EpochProcessingSummary` for `state`.
|
|
///
|
|
/// ## Notes
|
|
///
|
|
/// Will mutate `state`, transitioning it to the next epoch.
|
|
fn get_epoch_processing_summary<T: EthSpec>(
|
|
state: &mut BeaconState<T>,
|
|
spec: &ChainSpec,
|
|
) -> Result<EpochProcessingSummary<T>, warp::reject::Rejection> {
|
|
process_epoch(state, spec)
|
|
.map_err(|e| warp_utils::reject::custom_server_error(format!("{:?}", e)))
|
|
}
|
|
|
|
fn convert_cache_error(error: ParticipationCacheError) -> warp::reject::Rejection {
|
|
warp_utils::reject::custom_server_error(format!("{:?}", error))
|
|
}
|
|
|
|
/// 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 mut state = end_of_epoch_state(epoch, chain)?;
|
|
let summary = get_epoch_processing_summary(&mut state, &chain.spec)?;
|
|
|
|
Ok(GlobalValidatorInclusionData {
|
|
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(convert_cache_error)?,
|
|
previous_epoch_target_attesting_gwei: summary
|
|
.previous_epoch_target_attesting_balance()
|
|
.map_err(convert_cache_error)?,
|
|
previous_epoch_head_attesting_gwei: summary
|
|
.previous_epoch_head_attesting_balance()
|
|
.map_err(convert_cache_error)?,
|
|
})
|
|
}
|
|
|
|
/// Returns information about a single validator and how it performed during a given epoch.
|
|
pub fn validator_inclusion_data<T: BeaconChainTypes>(
|
|
epoch: Epoch,
|
|
validator_id: &ValidatorId,
|
|
chain: &BeaconChain<T>,
|
|
) -> Result<Option<ValidatorInclusionData>, warp::Rejection> {
|
|
let mut state = end_of_epoch_state(epoch, chain)?;
|
|
|
|
state
|
|
.update_pubkey_cache()
|
|
.map_err(warp_utils::reject::beacon_state_error)?;
|
|
|
|
let validator_index = match validator_id {
|
|
ValidatorId::Index(index) => *index as usize,
|
|
ValidatorId::PublicKey(pubkey) => {
|
|
if let Some(index) = state
|
|
.get_validator_index(pubkey)
|
|
.map_err(warp_utils::reject::beacon_state_error)?
|
|
{
|
|
index
|
|
} else {
|
|
return Ok(None);
|
|
}
|
|
}
|
|
};
|
|
|
|
// Obtain the validator *before* transitioning the state into the next epoch.
|
|
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_unslashed_in_current_epoch: summary
|
|
.is_active_unslashed_in_current_epoch(validator_index),
|
|
is_active_unslashed_in_previous_epoch: summary
|
|
.is_active_unslashed_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)
|
|
.map_err(convert_cache_error)?,
|
|
is_previous_epoch_target_attester: summary
|
|
.is_previous_epoch_target_attester(validator_index)
|
|
.map_err(convert_cache_error)?,
|
|
is_previous_epoch_head_attester: summary
|
|
.is_previous_epoch_head_attester(validator_index)
|
|
.map_err(convert_cache_error)?,
|
|
}))
|
|
}
|