#4512 inactivity calculation for Altair (#4807)

## 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:
Zackary Scott
2023-10-20 06:23:28 +00:00
parent 90f78d141f
commit b11988223f
3 changed files with 159 additions and 4 deletions

View File

@@ -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
}