mirror of
https://github.com/sigp/lighthouse.git
synced 2026-03-14 18:32:42 +00:00
Implement sync_committee_rewards API (per-validator reward) (#3903)
[#3661](https://github.com/sigp/lighthouse/issues/3661) `/eth/v1/beacon/rewards/sync_committee/{block_id}` ``` { "execution_optimistic": false, "finalized": false, "data": [ { "validator_index": "0", "reward": "2000" } ] } ``` The issue contains the implementation of three per-validator reward APIs: * `sync_committee_rewards` * [`attestation_rewards`](https://github.com/sigp/lighthouse/pull/3822) * `block_rewards` This PR only implements the `sync_committe_rewards `. The endpoints can be viewed in the Ethereum Beacon nodes API browser: [https://ethereum.github.io/beacon-APIs/?urls.primaryName=dev#/Rewards](https://ethereum.github.io/beacon-APIs/?urls.primaryName=dev#/Rewards) The implementation of [consensus client reward APIs](https://github.com/eth-protocol-fellows/cohort-three/blob/master/projects/project-ideas.md#consensus-client-reward-apis) is part of the [EPF](https://github.com/eth-protocol-fellows/cohort-three). Co-authored-by: navie <naviechan@gmail.com> Co-authored-by: kevinbogner <kevbogner@gmail.com>
This commit is contained in:
@@ -162,6 +162,7 @@ pub enum BeaconChainError {
|
||||
BlockRewardSlotError,
|
||||
BlockRewardAttestationError,
|
||||
BlockRewardSyncError,
|
||||
SyncCommitteeRewardsSyncError,
|
||||
HeadMissingFromForkChoice(Hash256),
|
||||
FinalizedBlockMissingFromForkChoice(Hash256),
|
||||
HeadBlockMissingFromForkChoice(Hash256),
|
||||
|
||||
@@ -43,6 +43,7 @@ pub mod schema_change;
|
||||
mod shuffling_cache;
|
||||
mod snapshot_cache;
|
||||
pub mod state_advance_timer;
|
||||
pub mod sync_committee_rewards;
|
||||
pub mod sync_committee_verification;
|
||||
pub mod test_utils;
|
||||
mod timeout_rw_lock;
|
||||
|
||||
87
beacon_node/beacon_chain/src/sync_committee_rewards.rs
Normal file
87
beacon_node/beacon_chain/src/sync_committee_rewards.rs
Normal file
@@ -0,0 +1,87 @@
|
||||
use crate::{BeaconChain, BeaconChainError, BeaconChainTypes};
|
||||
|
||||
use eth2::lighthouse::SyncCommitteeReward;
|
||||
use safe_arith::SafeArith;
|
||||
use slog::error;
|
||||
use state_processing::per_block_processing::altair::sync_committee::compute_sync_aggregate_rewards;
|
||||
use std::collections::HashMap;
|
||||
use store::RelativeEpoch;
|
||||
use types::{BeaconBlockRef, BeaconState, ExecPayload};
|
||||
|
||||
impl<T: BeaconChainTypes> BeaconChain<T> {
|
||||
pub fn compute_sync_committee_rewards<Payload: ExecPayload<T::EthSpec>>(
|
||||
&self,
|
||||
block: BeaconBlockRef<'_, T::EthSpec, Payload>,
|
||||
state: &mut BeaconState<T::EthSpec>,
|
||||
) -> Result<Vec<SyncCommitteeReward>, BeaconChainError> {
|
||||
if block.slot() != state.slot() {
|
||||
return Err(BeaconChainError::BlockRewardSlotError);
|
||||
}
|
||||
|
||||
let spec = &self.spec;
|
||||
|
||||
state.build_committee_cache(RelativeEpoch::Current, spec)?;
|
||||
|
||||
let sync_aggregate = block.body().sync_aggregate()?;
|
||||
|
||||
let sync_committee = state.current_sync_committee()?.clone();
|
||||
|
||||
let sync_committee_indices = state.get_sync_committee_indices(&sync_committee)?;
|
||||
|
||||
let (participant_reward_value, proposer_reward_per_bit) =
|
||||
compute_sync_aggregate_rewards(state, spec).map_err(|e| {
|
||||
error!(
|
||||
self.log, "Error calculating sync aggregate rewards";
|
||||
"error" => ?e
|
||||
);
|
||||
BeaconChainError::SyncCommitteeRewardsSyncError
|
||||
})?;
|
||||
|
||||
let mut balances = HashMap::<usize, u64>::new();
|
||||
|
||||
let mut total_proposer_rewards = 0;
|
||||
let proposer_index = state.get_beacon_proposer_index(block.slot(), spec)?;
|
||||
|
||||
// Apply rewards to participant balances. Keep track of proposer rewards
|
||||
for (validator_index, participant_bit) in sync_committee_indices
|
||||
.iter()
|
||||
.zip(sync_aggregate.sync_committee_bits.iter())
|
||||
{
|
||||
let participant_balance = balances
|
||||
.entry(*validator_index)
|
||||
.or_insert_with(|| state.balances()[*validator_index]);
|
||||
|
||||
if participant_bit {
|
||||
participant_balance.safe_add_assign(participant_reward_value)?;
|
||||
|
||||
balances
|
||||
.entry(proposer_index)
|
||||
.or_insert_with(|| state.balances()[proposer_index])
|
||||
.safe_add_assign(proposer_reward_per_bit)?;
|
||||
|
||||
total_proposer_rewards.safe_add_assign(proposer_reward_per_bit)?;
|
||||
} else {
|
||||
*participant_balance = participant_balance.saturating_sub(participant_reward_value);
|
||||
}
|
||||
}
|
||||
|
||||
Ok(balances
|
||||
.iter()
|
||||
.filter_map(|(i, new_balance)| {
|
||||
let reward = if *i != proposer_index {
|
||||
*new_balance as i64 - state.balances()[*i] as i64
|
||||
} else if sync_committee_indices.contains(i) {
|
||||
*new_balance as i64
|
||||
- state.balances()[*i] as i64
|
||||
- total_proposer_rewards as i64
|
||||
} else {
|
||||
return None;
|
||||
};
|
||||
Some(SyncCommitteeReward {
|
||||
validator_index: *i as u64,
|
||||
reward,
|
||||
})
|
||||
})
|
||||
.collect())
|
||||
}
|
||||
}
|
||||
@@ -2,6 +2,7 @@ pub use crate::persisted_beacon_chain::PersistedBeaconChain;
|
||||
pub use crate::{
|
||||
beacon_chain::{BEACON_CHAIN_DB_KEY, ETH1_CACHE_DB_KEY, FORK_CHOICE_DB_KEY, OP_POOL_DB_KEY},
|
||||
migrate::MigratorConfig,
|
||||
sync_committee_verification::Error as SyncCommitteeError,
|
||||
validator_monitor::DEFAULT_INDIVIDUAL_TRACKING_THRESHOLD,
|
||||
BeaconChainError, NotifyExecutionLayer, ProduceBlockVerification,
|
||||
};
|
||||
@@ -2079,6 +2080,30 @@ where
|
||||
|
||||
(honest_head, faulty_head)
|
||||
}
|
||||
|
||||
pub fn process_sync_contributions(
|
||||
&self,
|
||||
sync_contributions: HarnessSyncContributions<E>,
|
||||
) -> Result<(), SyncCommitteeError> {
|
||||
let mut verified_contributions = Vec::with_capacity(sync_contributions.len());
|
||||
|
||||
for (_, contribution_and_proof) in sync_contributions {
|
||||
let signed_contribution_and_proof = contribution_and_proof.unwrap();
|
||||
|
||||
let verified_contribution = self
|
||||
.chain
|
||||
.verify_sync_contribution_for_gossip(signed_contribution_and_proof)?;
|
||||
|
||||
verified_contributions.push(verified_contribution);
|
||||
}
|
||||
|
||||
for verified_contribution in verified_contributions {
|
||||
self.chain
|
||||
.add_contribution_to_block_inclusion_pool(verified_contribution)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
// Junk `Debug` impl to satistfy certain trait bounds during testing.
|
||||
|
||||
Reference in New Issue
Block a user