## Issue Addressed #4512 Which issue # does this PR address? ## Proposed Changes Add inactivity calculation for Altair Please list or describe the changes introduced by this PR. Add inactivity calculation for Altair ## Additional Info Please provide any additional information. For example, future considerations or information useful for reviewers. Co-authored-by: Jimmy Chen <jchen.tc@gmail.com>
This commit is contained in:
parent
90f78d141f
commit
b11988223f
@ -5,6 +5,7 @@ use participation_cache::ParticipationCache;
|
||||
use safe_arith::SafeArith;
|
||||
use serde_utils::quoted_u64::Quoted;
|
||||
use slog::debug;
|
||||
use state_processing::per_epoch_processing::altair::process_inactivity_updates;
|
||||
use state_processing::{
|
||||
common::altair::BaseRewardPerIncrement,
|
||||
per_epoch_processing::altair::{participation_cache, rewards_and_penalties::get_flag_weight},
|
||||
@ -124,6 +125,7 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
|
||||
|
||||
// Calculate ideal_rewards
|
||||
let participation_cache = ParticipationCache::new(&state, spec)?;
|
||||
process_inactivity_updates(&mut state, &participation_cache, spec)?;
|
||||
|
||||
let previous_epoch = state.previous_epoch();
|
||||
|
||||
@ -190,6 +192,7 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
|
||||
let mut head_reward = 0i64;
|
||||
let mut target_reward = 0i64;
|
||||
let mut source_reward = 0i64;
|
||||
let mut inactivity_penalty = 0i64;
|
||||
|
||||
if eligible {
|
||||
let effective_balance = state.get_effective_balance(*validator_index)?;
|
||||
@ -215,6 +218,14 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
|
||||
head_reward = 0;
|
||||
} else if flag_index == TIMELY_TARGET_FLAG_INDEX {
|
||||
target_reward = *penalty;
|
||||
|
||||
let penalty_numerator = effective_balance
|
||||
.safe_mul(state.get_inactivity_score(*validator_index)?)?;
|
||||
let penalty_denominator = spec
|
||||
.inactivity_score_bias
|
||||
.safe_mul(spec.inactivity_penalty_quotient_for_state(&state))?;
|
||||
inactivity_penalty =
|
||||
-(penalty_numerator.safe_div(penalty_denominator)? as i64);
|
||||
} else if flag_index == TIMELY_SOURCE_FLAG_INDEX {
|
||||
source_reward = *penalty;
|
||||
}
|
||||
@ -226,8 +237,7 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
|
||||
target: target_reward,
|
||||
source: source_reward,
|
||||
inclusion_delay: None,
|
||||
// TODO: altair calculation logic needs to be updated to include inactivity penalty
|
||||
inactivity: 0,
|
||||
inactivity: inactivity_penalty,
|
||||
});
|
||||
}
|
||||
|
||||
@ -250,7 +260,6 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
|
||||
target: 0,
|
||||
source: 0,
|
||||
inclusion_delay: None,
|
||||
// TODO: altair calculation logic needs to be updated to include inactivity penalty
|
||||
inactivity: 0,
|
||||
});
|
||||
match *flag_index {
|
||||
|
@ -2350,6 +2350,29 @@ where
|
||||
.await
|
||||
}
|
||||
|
||||
/// Uses `Self::extend_chain` to `num_slots` blocks.
|
||||
///
|
||||
/// Utilizes:
|
||||
///
|
||||
/// - BlockStrategy::OnCanonicalHead,
|
||||
/// - AttestationStrategy::SomeValidators(validators),
|
||||
pub async fn extend_slots_some_validators(
|
||||
&self,
|
||||
num_slots: usize,
|
||||
validators: Vec<usize>,
|
||||
) -> Hash256 {
|
||||
if self.chain.slot().unwrap() == self.chain.canonical_head.cached_head().head_slot() {
|
||||
self.advance_slot();
|
||||
}
|
||||
|
||||
self.extend_chain(
|
||||
num_slots,
|
||||
BlockStrategy::OnCanonicalHead,
|
||||
AttestationStrategy::SomeValidators(validators),
|
||||
)
|
||||
.await
|
||||
}
|
||||
|
||||
/// Extend the `BeaconChain` with some blocks and attestations. Returns the root of the
|
||||
/// last-produced block (the head of the chain).
|
||||
///
|
||||
|
@ -14,7 +14,7 @@ use eth2::lighthouse::StandardAttestationRewards;
|
||||
use eth2::types::ValidatorId;
|
||||
use lazy_static::lazy_static;
|
||||
use types::beacon_state::Error as BeaconStateError;
|
||||
use types::{BeaconState, ChainSpec};
|
||||
use types::{BeaconState, ChainSpec, ForkName, Slot};
|
||||
|
||||
pub const VALIDATOR_COUNT: usize = 64;
|
||||
|
||||
@ -219,6 +219,100 @@ async fn test_verify_attestation_rewards_base_inactivity_leak() {
|
||||
assert_eq!(expected_balances, balances);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_verify_attestation_rewards_altair_inactivity_leak() {
|
||||
let spec = ForkName::Altair.make_genesis_spec(E::default_spec());
|
||||
let harness = get_harness(spec.clone());
|
||||
|
||||
let half = VALIDATOR_COUNT / 2;
|
||||
let half_validators: Vec<usize> = (0..half).collect();
|
||||
// target epoch is the epoch where the chain enters inactivity leak
|
||||
let target_epoch = &spec.min_epochs_to_inactivity_penalty + 1;
|
||||
|
||||
// advance until beginning of epoch N + 1 and get balances
|
||||
harness
|
||||
.extend_slots_some_validators(
|
||||
(E::slots_per_epoch() * (target_epoch + 1)) as usize,
|
||||
half_validators.clone(),
|
||||
)
|
||||
.await;
|
||||
let initial_balances: Vec<u64> = harness.get_current_state().balances().clone().into();
|
||||
|
||||
// advance until epoch N + 2 and build proposal rewards map
|
||||
let mut proposal_rewards_map: HashMap<u64, u64> = HashMap::new();
|
||||
let mut sync_committee_rewards_map: HashMap<u64, i64> = HashMap::new();
|
||||
for _ in 0..E::slots_per_epoch() {
|
||||
let state = harness.get_current_state();
|
||||
let slot = state.slot() + Slot::new(1);
|
||||
|
||||
// calculate beacon block rewards / penalties
|
||||
let ((signed_block, _maybe_blob_sidecars), mut state) =
|
||||
harness.make_block_return_pre_state(state, slot).await;
|
||||
let beacon_block_reward = harness
|
||||
.chain
|
||||
.compute_beacon_block_reward(
|
||||
signed_block.message(),
|
||||
signed_block.canonical_root(),
|
||||
&mut state,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let total_proposer_reward = proposal_rewards_map
|
||||
.get(&beacon_block_reward.proposer_index)
|
||||
.unwrap_or(&0u64)
|
||||
+ beacon_block_reward.total;
|
||||
|
||||
proposal_rewards_map.insert(beacon_block_reward.proposer_index, total_proposer_reward);
|
||||
|
||||
// calculate sync committee rewards / penalties
|
||||
let reward_payload = harness
|
||||
.chain
|
||||
.compute_sync_committee_rewards(signed_block.message(), &mut state)
|
||||
.unwrap();
|
||||
|
||||
reward_payload.iter().for_each(|reward| {
|
||||
let mut amount = *sync_committee_rewards_map
|
||||
.get(&reward.validator_index)
|
||||
.unwrap_or(&0);
|
||||
amount += reward.reward;
|
||||
sync_committee_rewards_map.insert(reward.validator_index, amount);
|
||||
});
|
||||
|
||||
harness
|
||||
.extend_slots_some_validators(1, half_validators.clone())
|
||||
.await;
|
||||
}
|
||||
|
||||
// compute reward deltas for all validators in epoch N
|
||||
let StandardAttestationRewards {
|
||||
ideal_rewards,
|
||||
total_rewards,
|
||||
} = harness
|
||||
.chain
|
||||
.compute_attestation_rewards(Epoch::new(target_epoch), vec![])
|
||||
.unwrap();
|
||||
|
||||
// assert inactivity penalty for both ideal rewards and individual validators
|
||||
assert!(ideal_rewards.iter().all(|reward| reward.inactivity == 0));
|
||||
assert!(total_rewards[..half]
|
||||
.iter()
|
||||
.all(|reward| reward.inactivity == 0));
|
||||
assert!(total_rewards[half..]
|
||||
.iter()
|
||||
.all(|reward| reward.inactivity < 0));
|
||||
|
||||
// apply attestation, proposal, and sync committee rewards and penalties to initial balances
|
||||
let expected_balances = apply_attestation_rewards(&initial_balances, total_rewards);
|
||||
let expected_balances = apply_beacon_block_rewards(&proposal_rewards_map, expected_balances);
|
||||
let expected_balances =
|
||||
apply_sync_committee_rewards(&sync_committee_rewards_map, expected_balances);
|
||||
|
||||
// verify expected balances against actual balances
|
||||
let balances: Vec<u64> = harness.get_current_state().balances().clone().into();
|
||||
|
||||
assert_eq!(expected_balances, balances);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_verify_attestation_rewards_base_subset_only() {
|
||||
let harness = get_harness(E::default_spec());
|
||||
@ -297,3 +391,32 @@ fn get_validator_balances(state: BeaconState<E>, validators: &[usize]) -> Vec<u6
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
||||
fn apply_beacon_block_rewards(
|
||||
proposal_rewards_map: &HashMap<u64, u64>,
|
||||
expected_balances: Vec<u64>,
|
||||
) -> Vec<u64> {
|
||||
let calculated_balances = expected_balances
|
||||
.iter()
|
||||
.enumerate()
|
||||
.map(|(i, balance)| balance + proposal_rewards_map.get(&(i as u64)).unwrap_or(&0u64))
|
||||
.collect();
|
||||
|
||||
calculated_balances
|
||||
}
|
||||
|
||||
fn apply_sync_committee_rewards(
|
||||
sync_committee_rewards_map: &HashMap<u64, i64>,
|
||||
expected_balances: Vec<u64>,
|
||||
) -> Vec<u64> {
|
||||
let calculated_balances = expected_balances
|
||||
.iter()
|
||||
.enumerate()
|
||||
.map(|(i, balance)| {
|
||||
(*balance as i64 + sync_committee_rewards_map.get(&(i as u64)).unwrap_or(&0i64))
|
||||
.unsigned_abs()
|
||||
})
|
||||
.collect();
|
||||
|
||||
calculated_balances
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user