Skip to content

Commit 3682028

Browse files
Single-pass epoch processing (sigp#4483, sigp#4573)
Co-authored-by: Michael Sproul <michael@sigmaprime.io>
1 parent 8530427 commit 3682028

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

64 files changed

+2494
-1063
lines changed

beacon_node/beacon_chain/src/attestation_rewards.rs

Lines changed: 34 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ use safe_arith::SafeArith;
66
use serde_utils::quoted_u64::Quoted;
77
use slog::debug;
88
use state_processing::per_epoch_processing::altair::{
9-
process_inactivity_updates, process_justification_and_finalization,
9+
process_inactivity_updates_slow, process_justification_and_finalization,
1010
};
1111
use state_processing::{
1212
common::altair::BaseRewardPerIncrement,
@@ -134,10 +134,10 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
134134
let spec = &self.spec;
135135

136136
// Calculate ideal_rewards
137-
let participation_cache = ParticipationCache::new(&state, spec)?;
138-
process_justification_and_finalization(&state, &participation_cache)?
139-
.apply_changes_to_state(&mut state);
140-
process_inactivity_updates(&mut state, &participation_cache, spec)?;
137+
let participation_cache = ParticipationCache::new(&state, spec)
138+
.map_err(|_| BeaconChainError::AttestationRewardsError)?;
139+
process_justification_and_finalization(&state)?.apply_changes_to_state(&mut state);
140+
process_inactivity_updates_slow(&mut state, spec)?;
141141

142142
let previous_epoch = state.previous_epoch();
143143

@@ -147,13 +147,9 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
147147
let weight = get_flag_weight(flag_index)
148148
.map_err(|_| BeaconChainError::AttestationRewardsError)?;
149149

150-
let unslashed_participating_indices = participation_cache
151-
.get_unslashed_participating_indices(flag_index, previous_epoch)?;
152-
153-
let unslashed_participating_balance =
154-
unslashed_participating_indices
155-
.total_balance()
156-
.map_err(|_| BeaconChainError::AttestationRewardsError)?;
150+
let unslashed_participating_balance = participation_cache
151+
.previous_epoch_flag_attesting_balance(flag_index)
152+
.map_err(|_| BeaconChainError::AttestationRewardsError)?;
157153

158154
let unslashed_participating_increments =
159155
unslashed_participating_balance.safe_div(spec.effective_balance_increment)?;
@@ -199,24 +195,41 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
199195
Self::validators_ids_to_indices(&mut state, validators)?
200196
};
201197

202-
for validator_index in &validators {
203-
let eligible = state.is_eligible_validator(previous_epoch, *validator_index)?;
198+
for &validator_index in &validators {
199+
// Return 0s for unknown/inactive validator indices. This is a bit different from stable
200+
// where we error for unknown pubkeys.
201+
let Ok(validator) = participation_cache.get_validator(validator_index) else {
202+
debug!(
203+
self.log,
204+
"No rewards for inactive/unknown validator";
205+
"index" => validator_index,
206+
"epoch" => previous_epoch
207+
);
208+
total_rewards.push(TotalAttestationRewards {
209+
validator_index: validator_index as u64,
210+
head: 0,
211+
target: 0,
212+
source: 0,
213+
inclusion_delay: None,
214+
inactivity: 0,
215+
});
216+
continue;
217+
};
218+
let eligible = validator.is_eligible;
204219
let mut head_reward = 0i64;
205220
let mut target_reward = 0i64;
206221
let mut source_reward = 0i64;
207222
let mut inactivity_penalty = 0i64;
208223

209224
if eligible {
210-
let effective_balance = state.get_effective_balance(*validator_index)?;
225+
let effective_balance = validator.effective_balance;
211226

212227
for flag_index in 0..PARTICIPATION_FLAG_WEIGHTS.len() {
213228
let (ideal_reward, penalty) = ideal_rewards_hashmap
214229
.get(&(flag_index, effective_balance))
215230
.ok_or(BeaconChainError::AttestationRewardsError)?;
216-
let voted_correctly = participation_cache
217-
.get_unslashed_participating_indices(flag_index, previous_epoch)
218-
.map_err(|_| BeaconChainError::AttestationRewardsError)?
219-
.contains(*validator_index)
231+
let voted_correctly = validator
232+
.is_unslashed_participating_index(flag_index)
220233
.map_err(|_| BeaconChainError::AttestationRewardsError)?;
221234
if voted_correctly {
222235
if flag_index == TIMELY_HEAD_FLAG_INDEX {
@@ -232,7 +245,7 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
232245
target_reward = *penalty;
233246

234247
let penalty_numerator = effective_balance
235-
.safe_mul(state.get_inactivity_score(*validator_index)?)?;
248+
.safe_mul(state.get_inactivity_score(validator_index)?)?;
236249
let penalty_denominator = spec
237250
.inactivity_score_bias
238251
.safe_mul(spec.inactivity_penalty_quotient_for_state(&state))?;
@@ -244,7 +257,7 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
244257
}
245258
}
246259
total_rewards.push(TotalAttestationRewards {
247-
validator_index: *validator_index as u64,
260+
validator_index: validator_index as u64,
248261
head: head_reward,
249262
target: target_reward,
250263
source: source_reward,

beacon_node/beacon_chain/src/beacon_block_reward.rs

Lines changed: 5 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,8 @@ use operation_pool::RewardCache;
44
use safe_arith::SafeArith;
55
use slog::error;
66
use state_processing::{
7-
common::{
8-
altair, get_attestation_participation_flag_indices, get_attesting_indices_from_state,
9-
},
7+
common::{get_attestation_participation_flag_indices, get_attesting_indices_from_state},
8+
epoch_cache::initialize_epoch_cache,
109
per_block_processing::{
1110
altair::sync_committee::compute_sync_aggregate_rewards, get_slashable_indices,
1211
},
@@ -32,6 +31,7 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
3231

3332
state.build_committee_cache(RelativeEpoch::Previous, &self.spec)?;
3433
state.build_committee_cache(RelativeEpoch::Current, &self.spec)?;
34+
initialize_epoch_cache(state, &self.spec)?;
3535

3636
self.compute_beacon_block_reward_with_cache(block, block_root, state)
3737
}
@@ -191,10 +191,6 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
191191
block: BeaconBlockRef<'_, T::EthSpec, Payload>,
192192
state: &BeaconState<T::EthSpec>,
193193
) -> Result<BeaconBlockSubRewardValue, BeaconChainError> {
194-
let total_active_balance = state.get_total_active_balance()?;
195-
let base_reward_per_increment =
196-
altair::BaseRewardPerIncrement::new(total_active_balance, &self.spec)?;
197-
198194
let mut total_proposer_reward = 0;
199195

200196
let proposer_reward_denominator = WEIGHT_DENOMINATOR
@@ -235,15 +231,8 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
235231
&& !validator_participation.has_flag(flag_index)?
236232
{
237233
validator_participation.add_flag(flag_index)?;
238-
proposer_reward_numerator.safe_add_assign(
239-
altair::get_base_reward(
240-
state,
241-
index,
242-
base_reward_per_increment,
243-
&self.spec,
244-
)?
245-
.safe_mul(weight)?,
246-
)?;
234+
proposer_reward_numerator
235+
.safe_add_assign(state.get_base_reward(index)?.safe_mul(weight)?)?;
247236
}
248237
}
249238
}

beacon_node/beacon_chain/src/beacon_chain.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4967,6 +4967,7 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
49674967
let attestation_packing_timer =
49684968
metrics::start_timer(&metrics::BLOCK_PRODUCTION_ATTESTATION_TIMES);
49694969

4970+
state.build_total_active_balance_cache_at(state.current_epoch(), &self.spec)?;
49704971
let mut prev_filter_cache = HashMap::new();
49714972
let prev_attestation_filter = |att: &AttestationRef<T::EthSpec>| {
49724973
self.filter_op_pool_attestation(&mut prev_filter_cache, att, &state)

beacon_node/beacon_chain/src/errors.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ pub enum BeaconChainError {
5555
SlotClockDidNotStart,
5656
NoStateForSlot(Slot),
5757
BeaconStateError(BeaconStateError),
58+
EpochCacheError(EpochCacheError),
5859
DBInconsistent(String),
5960
DBError(store::Error),
6061
ForkChoiceError(ForkChoiceError),
@@ -250,6 +251,7 @@ easy_from_to!(StateAdvanceError, BeaconChainError);
250251
easy_from_to!(BlockReplayError, BeaconChainError);
251252
easy_from_to!(InconsistentFork, BeaconChainError);
252253
easy_from_to!(AvailabilityCheckError, BeaconChainError);
254+
easy_from_to!(EpochCacheError, BeaconChainError);
253255

254256
#[derive(Debug)]
255257
pub enum BlockProductionError {

beacon_node/beacon_chain/tests/tests.rs

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,7 @@ use beacon_chain::{
1010
};
1111
use lazy_static::lazy_static;
1212
use operation_pool::PersistedOperationPool;
13-
use state_processing::{
14-
per_slot_processing, per_slot_processing::Error as SlotProcessingError, EpochProcessingError,
15-
};
13+
use state_processing::{per_slot_processing, per_slot_processing::Error as SlotProcessingError};
1614
use types::{
1715
BeaconState, BeaconStateError, EthSpec, Hash256, Keypair, MinimalEthSpec, RelativeEpoch, Slot,
1816
};
@@ -59,9 +57,7 @@ fn massive_skips() {
5957
assert!(state.slot() > 1, "the state should skip at least one slot");
6058
assert_eq!(
6159
error,
62-
SlotProcessingError::EpochProcessingError(EpochProcessingError::BeaconStateError(
63-
BeaconStateError::InsufficientValidators
64-
)),
60+
SlotProcessingError::BeaconStateError(BeaconStateError::InsufficientValidators),
6561
"should return error indicating that validators have been slashed out"
6662
)
6763
}

beacon_node/genesis/src/interop.rs

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -178,13 +178,14 @@ mod test {
178178
}
179179

180180
for v in state.validators() {
181-
let creds = v.withdrawal_credentials.as_bytes();
181+
let creds = v.withdrawal_credentials;
182182
assert_eq!(
183-
creds[0], spec.bls_withdrawal_prefix_byte,
183+
creds.as_bytes()[0],
184+
spec.bls_withdrawal_prefix_byte,
184185
"first byte of withdrawal creds should be bls prefix"
185186
);
186187
assert_eq!(
187-
&creds[1..],
188+
&creds.as_bytes()[1..],
188189
&hash(&v.pubkey.as_ssz_bytes())[1..],
189190
"rest of withdrawal creds should be pubkey hash"
190191
)
@@ -240,7 +241,8 @@ mod test {
240241
}
241242

242243
for (index, v) in state.validators().iter().enumerate() {
243-
let creds = v.withdrawal_credentials.as_bytes();
244+
let withdrawal_credientials = v.withdrawal_credentials;
245+
let creds = withdrawal_credientials.as_bytes();
244246
if index % 2 == 0 {
245247
assert_eq!(
246248
creds[0], spec.bls_withdrawal_prefix_byte,

beacon_node/http_api/src/validator_inclusion.rs

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,8 @@ use eth2::{
44
lighthouse::{GlobalValidatorInclusionData, ValidatorInclusionData},
55
types::ValidatorId,
66
};
7-
use state_processing::per_epoch_processing::{
8-
altair::participation_cache::Error as ParticipationCacheError, process_epoch,
9-
EpochProcessingSummary,
10-
};
11-
use types::{BeaconState, ChainSpec, Epoch, EthSpec};
7+
use state_processing::per_epoch_processing::{process_epoch, EpochProcessingSummary};
8+
use types::{BeaconState, BeaconStateError, ChainSpec, Epoch, EthSpec};
129

1310
/// Returns the state in the last slot of `epoch`.
1411
fn end_of_epoch_state<T: BeaconChainTypes>(
@@ -35,7 +32,7 @@ fn get_epoch_processing_summary<T: EthSpec>(
3532
.map_err(|e| warp_utils::reject::custom_server_error(format!("{:?}", e)))
3633
}
3734

38-
fn convert_cache_error(error: ParticipationCacheError) -> warp::reject::Rejection {
35+
fn convert_cache_error(error: BeaconStateError) -> warp::reject::Rejection {
3936
warp_utils::reject::custom_server_error(format!("{:?}", error))
4037
}
4138

beacon_node/operation_pool/src/attestation.rs

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -47,18 +47,17 @@ impl<'a, T: EthSpec> AttMaxCover<'a, T> {
4747
.get_beacon_committee(att.data.slot, att.data.index)
4848
.ok()?;
4949
let indices = get_attesting_indices::<T>(committee.committee, &fresh_validators).ok()?;
50+
let sqrt_total_active_balance = base::SqrtTotalActiveBalance::new(total_active_balance);
5051
let fresh_validators_rewards: HashMap<u64, u64> = indices
5152
.iter()
5253
.copied()
5354
.flat_map(|validator_index| {
54-
let reward = base::get_base_reward(
55-
state,
56-
validator_index as usize,
57-
total_active_balance,
58-
spec,
59-
)
60-
.ok()?
61-
.checked_div(spec.proposer_reward_quotient)?;
55+
let effective_balance =
56+
state.get_effective_balance(validator_index as usize).ok()?;
57+
let reward =
58+
base::get_base_reward(effective_balance, sqrt_total_active_balance, spec)
59+
.ok()?
60+
.checked_div(spec.proposer_reward_quotient)?;
6261
Some((validator_index, reward))
6362
})
6463
.collect();
@@ -99,8 +98,11 @@ impl<'a, T: EthSpec> AttMaxCover<'a, T> {
9998

10099
let mut proposer_reward_numerator = 0;
101100

101+
// FIXME(sproul): store base_reward in reward cache
102+
// let effective_balance = reward_cache.get_effective_balance(index)?;
103+
let effective_balance = state.get_effective_balance(index as usize).ok()?;
102104
let base_reward =
103-
altair::get_base_reward(state, index as usize, base_reward_per_increment, spec)
105+
altair::get_base_reward(effective_balance, base_reward_per_increment, spec)
104106
.ok()?;
105107

106108
for (flag_index, weight) in PARTICIPATION_FLAG_WEIGHTS.iter().enumerate() {

beacon_node/store/src/partial_beacon_state.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -399,6 +399,8 @@ macro_rules! impl_try_into_beacon_state {
399399
committee_caches: <_>::default(),
400400
pubkey_cache: <_>::default(),
401401
exit_cache: <_>::default(),
402+
slashings_cache: <_>::default(),
403+
epoch_cache: <_>::default(),
402404
tree_hash_cache: <_>::default(),
403405

404406
// Variant-specific fields

0 commit comments

Comments
 (0)