diff --git a/consensus/state_processing/src/common/mod.rs b/consensus/state_processing/src/common/mod.rs index 513bc2553..f799d4303 100644 --- a/consensus/state_processing/src/common/mod.rs +++ b/consensus/state_processing/src/common/mod.rs @@ -3,6 +3,7 @@ mod get_attestation_participation; mod get_attesting_indices; mod get_indexed_attestation; mod initiate_validator_exit; +mod pulse; mod slash_validator; pub mod altair; @@ -17,14 +18,19 @@ pub use initiate_validator_exit::initiate_validator_exit; pub use slash_validator::slash_validator; use safe_arith::SafeArith; -use types::{BeaconState, BeaconStateError, EthSpec}; +use types::{BeaconState, BeaconStateError, ChainSpec, EthSpec}; /// Increase the balance of a validator, upon overflow set the balance to u64 MAX. pub fn increase_balance( state: &mut BeaconState, index: usize, - delta: u64, + mut delta: u64, + spec: &ChainSpec, + apply_burn: bool, ) -> Result<(), BeaconStateError> { + if apply_burn { + delta = pulse::apply_burn(delta, spec) + } let balance = state.get_balance_mut(index)?; if let Err(_) = balance.safe_add_assign(delta) { *balance = u64::MAX; diff --git a/consensus/state_processing/src/common/pulse.rs b/consensus/state_processing/src/common/pulse.rs new file mode 100644 index 000000000..59f985e58 --- /dev/null +++ b/consensus/state_processing/src/common/pulse.rs @@ -0,0 +1,36 @@ +use types::ChainSpec; + +pub fn apply_burn(base_reward: u64, spec: &ChainSpec) -> u64 { + let seconds_per_slot = spec.seconds_per_slot; + + // First we compensate for the increased block frequency. + let after_burn = base_reward * seconds_per_slot / 12; + + // Then we burn an additional 25%. + after_burn * 3 / 4 +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_apply_burn() { + let before_burn: u64 = 1000000; + let mut spec = ChainSpec::mainnet(); + + // Default 12 second slots => 25% general burn. + let after_burn = apply_burn(before_burn, &spec); + assert_eq!(after_burn, 750000); + + // 6 second slots => 50% burn then 25% general burn. + spec.seconds_per_slot = 6; + let after_burn = apply_burn(before_burn, &spec); + assert_eq!(after_burn, 375000); + + // 3 second slots => 75% burn then 25% general burn. + spec.seconds_per_slot = 3; + let after_burn = apply_burn(before_burn, &spec); + assert_eq!(after_burn, 187500); + } +} diff --git a/consensus/state_processing/src/common/slash_validator.rs b/consensus/state_processing/src/common/slash_validator.rs index d8b1c1a10..c7751020d 100644 --- a/consensus/state_processing/src/common/slash_validator.rs +++ b/consensus/state_processing/src/common/slash_validator.rs @@ -66,11 +66,14 @@ pub fn slash_validator( return Err(BeaconStateError::UnknownValidator(whistleblower_index).into()); } - increase_balance(state, proposer_index, proposer_reward)?; + // Do not apply burn to slashing rewards. + increase_balance(state, proposer_index, proposer_reward, spec, false)?; increase_balance( state, whistleblower_index, whistleblower_reward.safe_sub(proposer_reward)?, + spec, + false, )?; Ok(()) diff --git a/consensus/state_processing/src/per_block_processing/altair/sync_committee.rs b/consensus/state_processing/src/per_block_processing/altair/sync_committee.rs index aca640714..fb92bffc4 100644 --- a/consensus/state_processing/src/per_block_processing/altair/sync_committee.rs +++ b/consensus/state_processing/src/per_block_processing/altair/sync_committee.rs @@ -52,8 +52,8 @@ pub fn process_sync_aggregate( .zip(aggregate.sync_committee_bits.iter()) { if participation_bit { - increase_balance(state, participant_index, participant_reward)?; - increase_balance(state, proposer_index as usize, proposer_reward)?; + increase_balance(state, participant_index, participant_reward, spec, true)?; + increase_balance(state, proposer_index as usize, proposer_reward, spec, true)?; } else { decrease_balance(state, participant_index, participant_reward)?; } diff --git a/consensus/state_processing/src/per_block_processing/process_operations.rs b/consensus/state_processing/src/per_block_processing/process_operations.rs index 33e30bfb2..6769c697d 100644 --- a/consensus/state_processing/src/per_block_processing/process_operations.rs +++ b/consensus/state_processing/src/per_block_processing/process_operations.rs @@ -181,7 +181,7 @@ pub mod altair_deneb { .safe_mul(WEIGHT_DENOMINATOR)? .safe_div(PROPOSER_WEIGHT)?; let proposer_reward = proposer_reward_numerator.safe_div(proposer_reward_denominator)?; - increase_balance(state, proposer_index as usize, proposer_reward)?; + increase_balance(state, proposer_index as usize, proposer_reward, spec, true)?; Ok(()) } } @@ -391,7 +391,8 @@ pub fn process_deposit( if let Some(index) = validator_index { // Update the existing validator balance. - increase_balance(state, index as usize, amount)?; + // Do not apply burn to deposits. + increase_balance(state, index as usize, amount, spec, false)?; } else { // The signature should be checked for new validators. Return early for a bad // signature. diff --git a/consensus/state_processing/src/per_epoch_processing/altair/rewards_and_penalties.rs b/consensus/state_processing/src/per_epoch_processing/altair/rewards_and_penalties.rs index 69379599f..285d49f68 100644 --- a/consensus/state_processing/src/per_epoch_processing/altair/rewards_and_penalties.rs +++ b/consensus/state_processing/src/per_epoch_processing/altair/rewards_and_penalties.rs @@ -44,7 +44,7 @@ pub fn process_rewards_and_penalties( // Apply the deltas, erroring on overflow above but not on overflow below (saturating at 0 // instead). for (i, delta) in deltas.into_iter().enumerate() { - increase_balance(state, i, delta.rewards as u64)?; + increase_balance(state, i, delta.rewards as u64, spec, true)?; decrease_balance(state, i, delta.penalties as u64)?; } diff --git a/consensus/state_processing/src/per_epoch_processing/base/rewards_and_penalties.rs b/consensus/state_processing/src/per_epoch_processing/base/rewards_and_penalties.rs index 4971499b7..fb1dda3a4 100644 --- a/consensus/state_processing/src/per_epoch_processing/base/rewards_and_penalties.rs +++ b/consensus/state_processing/src/per_epoch_processing/base/rewards_and_penalties.rs @@ -65,7 +65,7 @@ pub fn process_rewards_and_penalties( // instead). for (i, delta) in deltas.into_iter().enumerate() { let combined_delta = delta.flatten()?; - increase_balance(state, i, combined_delta.rewards as u64)?; + increase_balance(state, i, combined_delta.rewards as u64, spec, true)?; decrease_balance(state, i, combined_delta.penalties as u64)?; }