Remove /lighthouse/analysis/block_rewards APIs (#8935)

Mark pointed out that these APIs will require updates for Gloas, so I figured we may as well get rid of them. As far as I know, blockprint was the only use case and it is now defunct. The consensus block value is included in getBlock API responses, so there's no reason for VCs to use the `POST` API, and there is now a standard API for the rewards of canonical blocks. The SSE event was non-standard, and likely only used by blockprint as well.


Co-Authored-By: Michael Sproul <michael@sigmaprime.io>
This commit is contained in:
Michael Sproul
2026-03-09 11:35:52 +11:00
committed by GitHub
parent efe43f7699
commit 537c2ba8b3
11 changed files with 4 additions and 541 deletions

View File

@@ -1,140 +0,0 @@
use crate::{BeaconChain, BeaconChainError, BeaconChainTypes};
use eth2::lighthouse::{AttestationRewards, BlockReward, BlockRewardMeta};
use operation_pool::{
AttMaxCover, MaxCover, PROPOSER_REWARD_DENOMINATOR, RewardCache, SplitAttestation,
};
use state_processing::{
common::get_attesting_indices_from_state,
per_block_processing::altair::sync_committee::compute_sync_aggregate_rewards,
};
use types::{AbstractExecPayload, BeaconBlockRef, BeaconState, EthSpec, Hash256};
impl<T: BeaconChainTypes> BeaconChain<T> {
pub fn compute_block_reward<Payload: AbstractExecPayload<T::EthSpec>>(
&self,
block: BeaconBlockRef<'_, T::EthSpec, Payload>,
block_root: Hash256,
state: &BeaconState<T::EthSpec>,
reward_cache: &mut RewardCache,
include_attestations: bool,
) -> Result<BlockReward, BeaconChainError> {
if block.slot() != state.slot() {
return Err(BeaconChainError::BlockRewardSlotError);
}
reward_cache.update(state)?;
let total_active_balance = state.get_total_active_balance()?;
let split_attestations = block
.body()
.attestations()
.map(|att| {
let attesting_indices = get_attesting_indices_from_state(state, att)?;
Ok(SplitAttestation::new(
att.clone_as_attestation(),
attesting_indices,
))
})
.collect::<Result<Vec<_>, BeaconChainError>>()?;
let mut per_attestation_rewards = split_attestations
.iter()
.map(|att| {
AttMaxCover::new(
att.as_ref(),
state,
reward_cache,
total_active_balance,
&self.spec,
)
.ok_or(BeaconChainError::BlockRewardAttestationError)
})
.collect::<Result<Vec<_>, _>>()?;
// Update the attestation rewards for each previous attestation included.
// This is O(n^2) in the number of attestations n.
for i in 0..per_attestation_rewards.len() {
let (updated, to_update) = per_attestation_rewards.split_at_mut(i + 1);
let latest_att = &updated[i];
for att in to_update {
att.update_covering_set(latest_att.intermediate(), latest_att.covering_set());
}
}
let mut prev_epoch_total = 0;
let mut curr_epoch_total = 0;
for cover in &per_attestation_rewards {
if cover.att.data.slot.epoch(T::EthSpec::slots_per_epoch()) == state.current_epoch() {
curr_epoch_total += cover.score() as u64;
} else {
prev_epoch_total += cover.score() as u64;
}
}
let attestation_total = prev_epoch_total + curr_epoch_total;
// Drop the covers.
let per_attestation_rewards = per_attestation_rewards
.into_iter()
.map(|cover| {
// Divide each reward numerator by the denominator. This can lead to the total being
// less than the sum of the individual rewards due to the fact that integer division
// does not distribute over addition.
let mut rewards = cover.fresh_validators_rewards;
rewards
.values_mut()
.for_each(|reward| *reward /= PROPOSER_REWARD_DENOMINATOR);
rewards
})
.collect();
// Add the attestation data if desired.
let attestations = if include_attestations {
block
.body()
.attestations()
.map(|a| a.data().clone())
.collect()
} else {
vec![]
};
let attestation_rewards = AttestationRewards {
total: attestation_total,
prev_epoch_total,
curr_epoch_total,
per_attestation_rewards,
attestations,
};
// Sync committee rewards.
let sync_committee_rewards = if let Ok(sync_aggregate) = block.body().sync_aggregate() {
let (_, proposer_reward_per_bit) = compute_sync_aggregate_rewards(state, &self.spec)
.map_err(|_| BeaconChainError::BlockRewardSyncError)?;
sync_aggregate.sync_committee_bits.num_set_bits() as u64 * proposer_reward_per_bit
} else {
0
};
// Total, metadata
let total = attestation_total + sync_committee_rewards;
let meta = BlockRewardMeta {
slot: block.slot(),
parent_slot: state.latest_block_header().slot,
proposer_index: block.proposer_index(),
graffiti: block.body().graffiti().as_utf8_lossy(),
};
Ok(BlockReward {
total,
block_root,
meta,
attestation_rewards,
sync_committee_rewards,
})
}
}

View File

@@ -1571,24 +1571,6 @@ impl<T: BeaconChainTypes> ExecutionPendingBlock<T> {
metrics::stop_timer(committee_timer);
/*
* If we have block reward listeners, compute the block reward and push it to the
* event handler.
*/
if let Some(ref event_handler) = chain.event_handler
&& event_handler.has_block_reward_subscribers()
{
let mut reward_cache = Default::default();
let block_reward = chain.compute_block_reward(
block.message(),
block_root,
&state,
&mut reward_cache,
true,
)?;
event_handler.register(EventKind::BlockReward(block_reward));
}
/*
* Perform `per_block_processing` on the block and state, returning early if the block is
* invalid.

View File

@@ -21,7 +21,6 @@ pub struct ServerSentEventHandler<E: EthSpec> {
late_head: Sender<EventKind<E>>,
light_client_finality_update_tx: Sender<EventKind<E>>,
light_client_optimistic_update_tx: Sender<EventKind<E>>,
block_reward_tx: Sender<EventKind<E>>,
proposer_slashing_tx: Sender<EventKind<E>>,
attester_slashing_tx: Sender<EventKind<E>>,
bls_to_execution_change_tx: Sender<EventKind<E>>,
@@ -48,7 +47,6 @@ impl<E: EthSpec> ServerSentEventHandler<E> {
let (late_head, _) = broadcast::channel(capacity);
let (light_client_finality_update_tx, _) = broadcast::channel(capacity);
let (light_client_optimistic_update_tx, _) = broadcast::channel(capacity);
let (block_reward_tx, _) = broadcast::channel(capacity);
let (proposer_slashing_tx, _) = broadcast::channel(capacity);
let (attester_slashing_tx, _) = broadcast::channel(capacity);
let (bls_to_execution_change_tx, _) = broadcast::channel(capacity);
@@ -69,7 +67,6 @@ impl<E: EthSpec> ServerSentEventHandler<E> {
late_head,
light_client_finality_update_tx,
light_client_optimistic_update_tx,
block_reward_tx,
proposer_slashing_tx,
attester_slashing_tx,
bls_to_execution_change_tx,
@@ -142,10 +139,6 @@ impl<E: EthSpec> ServerSentEventHandler<E> {
.light_client_optimistic_update_tx
.send(kind)
.map(|count| log_count("light client optimistic update", count)),
EventKind::BlockReward(_) => self
.block_reward_tx
.send(kind)
.map(|count| log_count("block reward", count)),
EventKind::ProposerSlashing(_) => self
.proposer_slashing_tx
.send(kind)
@@ -224,10 +217,6 @@ impl<E: EthSpec> ServerSentEventHandler<E> {
self.light_client_optimistic_update_tx.subscribe()
}
pub fn subscribe_block_reward(&self) -> Receiver<EventKind<E>> {
self.block_reward_tx.subscribe()
}
pub fn subscribe_attester_slashing(&self) -> Receiver<EventKind<E>> {
self.attester_slashing_tx.subscribe()
}
@@ -292,10 +281,6 @@ impl<E: EthSpec> ServerSentEventHandler<E> {
self.late_head.receiver_count() > 0
}
pub fn has_block_reward_subscribers(&self) -> bool {
self.block_reward_tx.receiver_count() > 0
}
pub fn has_proposer_slashing_subscribers(&self) -> bool {
self.proposer_slashing_tx.receiver_count() > 0
}

View File

@@ -10,7 +10,6 @@ mod beacon_snapshot;
pub mod bellatrix_readiness;
pub mod blob_verification;
mod block_production;
pub mod block_reward;
mod block_times_cache;
mod block_verification;
pub mod block_verification_types;

View File

@@ -1,178 +0,0 @@
use beacon_chain::{BeaconChain, BeaconChainError, BeaconChainTypes, WhenSlotSkipped};
use eth2::lighthouse::{BlockReward, BlockRewardsQuery};
use lru::LruCache;
use state_processing::BlockReplayer;
use std::num::NonZeroUsize;
use std::sync::Arc;
use tracing::{debug, warn};
use types::block::BlindedBeaconBlock;
use types::new_non_zero_usize;
use warp_utils::reject::{beacon_state_error, custom_bad_request, unhandled_error};
const STATE_CACHE_SIZE: NonZeroUsize = new_non_zero_usize(2);
/// Fetch block rewards for blocks from the canonical chain.
pub fn get_block_rewards<T: BeaconChainTypes>(
query: BlockRewardsQuery,
chain: Arc<BeaconChain<T>>,
) -> Result<Vec<BlockReward>, warp::Rejection> {
let start_slot = query.start_slot;
let end_slot = query.end_slot;
let prior_slot = start_slot - 1;
if start_slot > end_slot || start_slot == 0 {
return Err(custom_bad_request(format!(
"invalid start and end: {}, {}",
start_slot, end_slot
)));
}
let end_block_root = chain
.block_root_at_slot(end_slot, WhenSlotSkipped::Prev)
.map_err(unhandled_error)?
.ok_or_else(|| custom_bad_request(format!("block at end slot {} unknown", end_slot)))?;
let blocks = chain
.store
.load_blocks_to_replay(start_slot, end_slot, end_block_root)
.map_err(|e| unhandled_error(BeaconChainError::from(e)))?;
let state_root = chain
.state_root_at_slot(prior_slot)
.map_err(unhandled_error)?
.ok_or_else(|| custom_bad_request(format!("prior state at slot {} unknown", prior_slot)))?;
// This branch is reached from the HTTP API. We assume the user wants
// to cache states so that future calls are faster.
let mut state = chain
.get_state(&state_root, Some(prior_slot), true)
.and_then(|maybe_state| maybe_state.ok_or(BeaconChainError::MissingBeaconState(state_root)))
.map_err(unhandled_error)?;
state
.build_caches(&chain.spec)
.map_err(beacon_state_error)?;
let mut reward_cache = Default::default();
let mut block_rewards = Vec::with_capacity(blocks.len());
let block_replayer = BlockReplayer::new(state, &chain.spec)
.pre_block_hook(Box::new(|state, block| {
state.build_all_committee_caches(&chain.spec)?;
// Compute block reward.
let block_reward = chain.compute_block_reward(
block.message(),
block.canonical_root(),
state,
&mut reward_cache,
query.include_attestations,
)?;
block_rewards.push(block_reward);
Ok(())
}))
.state_root_iter(
chain
.forwards_iter_state_roots_until(prior_slot, end_slot)
.map_err(unhandled_error)?,
)
.no_signature_verification()
.minimal_block_root_verification()
.apply_blocks(blocks, None)
.map_err(unhandled_error)?;
if block_replayer.state_root_miss() {
warn!(%start_slot, %end_slot, "Block reward state root miss");
}
drop(block_replayer);
Ok(block_rewards)
}
/// Compute block rewards for blocks passed in as input.
pub fn compute_block_rewards<T: BeaconChainTypes>(
blocks: Vec<BlindedBeaconBlock<T::EthSpec>>,
chain: Arc<BeaconChain<T>>,
) -> Result<Vec<BlockReward>, warp::Rejection> {
let mut block_rewards = Vec::with_capacity(blocks.len());
let mut state_cache = LruCache::new(STATE_CACHE_SIZE);
let mut reward_cache = Default::default();
for block in blocks {
let parent_root = block.parent_root();
// Check LRU cache for a constructed state from a previous iteration.
let state = if let Some(state) = state_cache.get(&(parent_root, block.slot())) {
debug!(
?parent_root,
slot = %block.slot(),
"Re-using cached state for block rewards"
);
state
} else {
debug!(
?parent_root,
slot = %block.slot(),
"Fetching state for block rewards"
);
let parent_block = chain
.get_blinded_block(&parent_root)
.map_err(unhandled_error)?
.ok_or_else(|| {
custom_bad_request(format!(
"parent block not known or not canonical: {:?}",
parent_root
))
})?;
// This branch is reached from the HTTP API. We assume the user wants
// to cache states so that future calls are faster.
let parent_state = chain
.get_state(&parent_block.state_root(), Some(parent_block.slot()), true)
.map_err(unhandled_error)?
.ok_or_else(|| {
custom_bad_request(format!(
"no state known for parent block: {:?}",
parent_root
))
})?;
let block_replayer = BlockReplayer::new(parent_state, &chain.spec)
.no_signature_verification()
.state_root_iter([Ok((parent_block.state_root(), parent_block.slot()))].into_iter())
.minimal_block_root_verification()
.apply_blocks(vec![], Some(block.slot()))
.map_err(unhandled_error::<BeaconChainError>)?;
if block_replayer.state_root_miss() {
warn!(
parent_slot = %parent_block.slot(),
slot = %block.slot(),
"Block reward state root miss"
);
}
let mut state = block_replayer.into_state();
state
.build_all_committee_caches(&chain.spec)
.map_err(beacon_state_error)?;
state_cache.get_or_insert((parent_root, block.slot()), || state)
};
// Compute block reward.
let block_reward = chain
.compute_block_reward(
block.to_ref(),
block.canonical_root(),
state,
&mut reward_cache,
true,
)
.map_err(unhandled_error)?;
block_rewards.push(block_reward);
}
Ok(block_rewards)
}

View File

@@ -12,7 +12,6 @@ mod attester_duties;
mod beacon;
mod block_id;
mod block_packing_efficiency;
mod block_rewards;
mod build_block_contents;
mod builder_states;
mod custody;
@@ -3066,34 +3065,6 @@ pub fn serve<T: BeaconChainTypes>(
},
);
// GET lighthouse/analysis/block_rewards
let get_lighthouse_block_rewards = warp::path("lighthouse")
.and(warp::path("analysis"))
.and(warp::path("block_rewards"))
.and(warp::query::<eth2::lighthouse::BlockRewardsQuery>())
.and(warp::path::end())
.and(task_spawner_filter.clone())
.and(chain_filter.clone())
.then(|query, task_spawner: TaskSpawner<T::EthSpec>, chain| {
task_spawner.blocking_json_task(Priority::P1, move || {
block_rewards::get_block_rewards(query, chain)
})
});
// POST lighthouse/analysis/block_rewards
let post_lighthouse_block_rewards = warp::path("lighthouse")
.and(warp::path("analysis"))
.and(warp::path("block_rewards"))
.and(warp_utils::json::json())
.and(warp::path::end())
.and(task_spawner_filter.clone())
.and(chain_filter.clone())
.then(|blocks, task_spawner: TaskSpawner<T::EthSpec>, chain| {
task_spawner.blocking_json_task(Priority::P1, move || {
block_rewards::compute_block_rewards(blocks, chain)
})
});
// GET lighthouse/analysis/attestation_performance/{index}
let get_lighthouse_attestation_performance = warp::path("lighthouse")
.and(warp::path("analysis"))
@@ -3184,9 +3155,6 @@ pub fn serve<T: BeaconChainTypes>(
api_types::EventTopic::LightClientOptimisticUpdate => {
event_handler.subscribe_light_client_optimistic_update()
}
api_types::EventTopic::BlockReward => {
event_handler.subscribe_block_reward()
}
api_types::EventTopic::AttesterSlashing => {
event_handler.subscribe_attester_slashing()
}
@@ -3363,7 +3331,6 @@ pub fn serve<T: BeaconChainTypes>(
.uor(get_lighthouse_staking)
.uor(get_lighthouse_database_info)
.uor(get_lighthouse_custody_info)
.uor(get_lighthouse_block_rewards)
.uor(get_lighthouse_attestation_performance)
.uor(get_beacon_light_client_optimistic_update)
.uor(get_beacon_light_client_finality_update)
@@ -3414,7 +3381,6 @@ pub fn serve<T: BeaconChainTypes>(
.uor(post_validator_liveness_epoch)
.uor(post_lighthouse_liveness)
.uor(post_lighthouse_database_reconstruct)
.uor(post_lighthouse_block_rewards)
.uor(post_lighthouse_ui_validator_metrics)
.uor(post_lighthouse_ui_validator_info)
.uor(post_lighthouse_finalize)