Skip to content

Commit feb531f

Browse files
Single-pass epoch processing and optimised block processing (#5279)
* Single-pass epoch processing (#4483, #4573) Co-authored-by: Michael Sproul <[email protected]> * Delete unused epoch processing code (#5170) * Delete unused epoch processing code * Compare total deltas * Remove unnecessary apply_pending * cargo fmt * Remove newline * Use epoch cache in block packing (#5223) * Remove progressive balances mode (#5224) * inline inactivity_penalty_quotient_for_state * drop previous_epoch_total_active_balance * fc lint * spec compliant process_sync_aggregate (#15) * spec compliant process_sync_aggregate * Update consensus/state_processing/src/per_block_processing/altair/sync_committee.rs Co-authored-by: Michael Sproul <[email protected]> --------- Co-authored-by: Michael Sproul <[email protected]> * Delete the participation cache (#16) * update help * Fix op_pool tests * Fix fork choice tests * Merge remote-tracking branch 'sigp/unstable' into epoch-single-pass * Simplify exit cache (#5280) * Fix clippy on exit cache * Clean up single-pass a bit (#5282) * Address Mark's review of single-pass (#5386) * Merge remote-tracking branch 'origin/unstable' into epoch-single-pass * Address Sean's review comments (#5414) * Address most of Sean's review comments * Simplify total balance cache building * Clean up unused junk * Merge remote-tracking branch 'origin/unstable' into epoch-single-pass * More self-review * Merge remote-tracking branch 'origin/unstable' into epoch-single-pass * Merge branch 'unstable' into epoch-single-pass * Fix imports for beta compiler * Fix tests, probably
1 parent f4cdcea commit feb531f

File tree

81 files changed

+2549
-1320
lines changed

Some content is hidden

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

81 files changed

+2549
-1320
lines changed

beacon_node/beacon_chain/src/attestation_rewards.rs

Lines changed: 83 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,14 @@
11
use crate::{BeaconChain, BeaconChainError, BeaconChainTypes};
22
use eth2::lighthouse::attestation_rewards::{IdealAttestationRewards, TotalAttestationRewards};
33
use eth2::lighthouse::StandardAttestationRewards;
4-
use participation_cache::ParticipationCache;
4+
use eth2::types::ValidatorId;
55
use safe_arith::SafeArith;
66
use serde_utils::quoted_u64::Quoted;
77
use slog::debug;
8+
use state_processing::common::base::{self, SqrtTotalActiveBalance};
89
use state_processing::per_epoch_processing::altair::{
9-
process_inactivity_updates, process_justification_and_finalization,
10-
};
11-
use state_processing::{
12-
common::altair::BaseRewardPerIncrement,
13-
per_epoch_processing::altair::{participation_cache, rewards_and_penalties::get_flag_weight},
14-
};
15-
use std::collections::HashMap;
16-
use store::consts::altair::{
17-
PARTICIPATION_FLAG_WEIGHTS, TIMELY_HEAD_FLAG_INDEX, TIMELY_SOURCE_FLAG_INDEX,
18-
TIMELY_TARGET_FLAG_INDEX,
10+
process_inactivity_updates_slow, process_justification_and_finalization,
1911
};
20-
use types::consts::altair::WEIGHT_DENOMINATOR;
21-
22-
use types::{BeaconState, Epoch, EthSpec};
23-
24-
use eth2::types::ValidatorId;
25-
use state_processing::common::base::get_base_reward_from_effective_balance;
2612
use state_processing::per_epoch_processing::base::rewards_and_penalties::{
2713
get_attestation_component_delta, get_attestation_deltas_all, get_attestation_deltas_subset,
2814
get_inactivity_penalty_delta, get_inclusion_delay_delta,
@@ -32,6 +18,19 @@ use state_processing::per_epoch_processing::base::{
3218
process_justification_and_finalization as process_justification_and_finalization_base,
3319
TotalBalances, ValidatorStatus, ValidatorStatuses,
3420
};
21+
use state_processing::{
22+
common::altair::BaseRewardPerIncrement,
23+
common::update_progressive_balances_cache::initialize_progressive_balances_cache,
24+
epoch_cache::initialize_epoch_cache,
25+
per_epoch_processing::altair::rewards_and_penalties::get_flag_weight,
26+
};
27+
use std::collections::HashMap;
28+
use store::consts::altair::{
29+
PARTICIPATION_FLAG_WEIGHTS, TIMELY_HEAD_FLAG_INDEX, TIMELY_SOURCE_FLAG_INDEX,
30+
TIMELY_TARGET_FLAG_INDEX,
31+
};
32+
use types::consts::altair::WEIGHT_DENOMINATOR;
33+
use types::{BeaconState, Epoch, EthSpec, RelativeEpoch};
3534

3635
impl<T: BeaconChainTypes> BeaconChain<T> {
3736
pub fn compute_attestation_rewards(
@@ -134,11 +133,16 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
134133
) -> Result<StandardAttestationRewards, BeaconChainError> {
135134
let spec = &self.spec;
136135

136+
// Build required caches.
137+
initialize_epoch_cache(&mut state, spec)?;
138+
initialize_progressive_balances_cache(&mut state, spec)?;
139+
state.build_exit_cache(spec)?;
140+
state.build_committee_cache(RelativeEpoch::Previous, spec)?;
141+
state.build_committee_cache(RelativeEpoch::Current, spec)?;
142+
137143
// Calculate ideal_rewards
138-
let participation_cache = ParticipationCache::new(&state, spec)?;
139-
process_justification_and_finalization(&state, &participation_cache)?
140-
.apply_changes_to_state(&mut state);
141-
process_inactivity_updates(&mut state, &participation_cache, spec)?;
144+
process_justification_and_finalization(&state)?.apply_changes_to_state(&mut state);
145+
process_inactivity_updates_slow(&mut state, spec)?;
142146

143147
let previous_epoch = state.previous_epoch();
144148

@@ -148,18 +152,14 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
148152
let weight = get_flag_weight(flag_index)
149153
.map_err(|_| BeaconChainError::AttestationRewardsError)?;
150154

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

159159
let unslashed_participating_increments =
160160
unslashed_participating_balance.safe_div(spec.effective_balance_increment)?;
161161

162-
let total_active_balance = participation_cache.current_epoch_total_active_balance();
162+
let total_active_balance = state.get_total_active_balance()?;
163163

164164
let active_increments =
165165
total_active_balance.safe_div(spec.effective_balance_increment)?;
@@ -195,30 +195,49 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
195195
let mut total_rewards: Vec<TotalAttestationRewards> = Vec::new();
196196

197197
let validators = if validators.is_empty() {
198-
participation_cache.eligible_validator_indices().to_vec()
198+
Self::all_eligible_validator_indices(&state, previous_epoch)?
199199
} else {
200200
Self::validators_ids_to_indices(&mut state, validators)?
201201
};
202202

203-
for validator_index in &validators {
204-
let eligible = state.is_eligible_validator(previous_epoch, *validator_index)?;
203+
for &validator_index in &validators {
204+
// Return 0s for unknown/inactive validator indices.
205+
let Ok(validator) = state.get_validator(validator_index) else {
206+
debug!(
207+
self.log,
208+
"No rewards for inactive/unknown validator";
209+
"index" => validator_index,
210+
"epoch" => previous_epoch
211+
);
212+
total_rewards.push(TotalAttestationRewards {
213+
validator_index: validator_index as u64,
214+
head: 0,
215+
target: 0,
216+
source: 0,
217+
inclusion_delay: None,
218+
inactivity: 0,
219+
});
220+
continue;
221+
};
222+
let previous_epoch_participation_flags = state
223+
.previous_epoch_participation()?
224+
.get(validator_index)
225+
.ok_or(BeaconChainError::AttestationRewardsError)?;
226+
let eligible = state.is_eligible_validator(previous_epoch, validator)?;
205227
let mut head_reward = 0i64;
206228
let mut target_reward = 0i64;
207229
let mut source_reward = 0i64;
208230
let mut inactivity_penalty = 0i64;
209231

210232
if eligible {
211-
let effective_balance = state.get_effective_balance(*validator_index)?;
233+
let effective_balance = validator.effective_balance;
212234

213235
for flag_index in 0..PARTICIPATION_FLAG_WEIGHTS.len() {
214236
let (ideal_reward, penalty) = ideal_rewards_hashmap
215237
.get(&(flag_index, effective_balance))
216238
.ok_or(BeaconChainError::AttestationRewardsError)?;
217-
let voted_correctly = participation_cache
218-
.get_unslashed_participating_indices(flag_index, previous_epoch)
219-
.map_err(|_| BeaconChainError::AttestationRewardsError)?
220-
.contains(*validator_index)
221-
.map_err(|_| BeaconChainError::AttestationRewardsError)?;
239+
let voted_correctly = !validator.slashed
240+
&& previous_epoch_participation_flags.has_flag(flag_index)?;
222241
if voted_correctly {
223242
if flag_index == TIMELY_HEAD_FLAG_INDEX {
224243
head_reward += *ideal_reward as i64;
@@ -233,10 +252,10 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
233252
target_reward = *penalty;
234253

235254
let penalty_numerator = effective_balance
236-
.safe_mul(state.get_inactivity_score(*validator_index)?)?;
237-
let penalty_denominator = spec
238-
.inactivity_score_bias
239-
.safe_mul(spec.inactivity_penalty_quotient_for_state(&state))?;
255+
.safe_mul(state.get_inactivity_score(validator_index)?)?;
256+
let penalty_denominator = spec.inactivity_score_bias.safe_mul(
257+
spec.inactivity_penalty_quotient_for_fork(state.fork_name_unchecked()),
258+
)?;
240259
inactivity_penalty =
241260
-(penalty_numerator.safe_div(penalty_denominator)? as i64);
242261
} else if flag_index == TIMELY_SOURCE_FLAG_INDEX {
@@ -245,7 +264,7 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
245264
}
246265
}
247266
total_rewards.push(TotalAttestationRewards {
248-
validator_index: *validator_index as u64,
267+
validator_index: validator_index as u64,
249268
head: head_reward,
250269
target: target_reward,
251270
source: source_reward,
@@ -302,6 +321,24 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
302321
Ok(max_steps)
303322
}
304323

324+
fn all_eligible_validator_indices(
325+
state: &BeaconState<T::EthSpec>,
326+
previous_epoch: Epoch,
327+
) -> Result<Vec<usize>, BeaconChainError> {
328+
state
329+
.validators()
330+
.iter()
331+
.enumerate()
332+
.filter_map(|(i, validator)| {
333+
state
334+
.is_eligible_validator(previous_epoch, validator)
335+
.map(|eligible| eligible.then_some(i))
336+
.map_err(BeaconChainError::BeaconStateError)
337+
.transpose()
338+
})
339+
.collect()
340+
}
341+
305342
fn validators_ids_to_indices(
306343
state: &mut BeaconState<T::EthSpec>,
307344
validators: Vec<ValidatorId>,
@@ -340,15 +377,12 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
340377
};
341378

342379
let mut ideal_attestation_rewards_list = Vec::new();
343-
380+
let sqrt_total_active_balance = SqrtTotalActiveBalance::new(total_balances.current_epoch());
344381
for effective_balance_step in 1..=self.max_effective_balance_increment_steps()? {
345382
let effective_balance =
346383
effective_balance_step.safe_mul(spec.effective_balance_increment)?;
347-
let base_reward = get_base_reward_from_effective_balance::<T::EthSpec>(
348-
effective_balance,
349-
total_balances.current_epoch(),
350-
spec,
351-
)?;
384+
let base_reward =
385+
base::get_base_reward(effective_balance, sqrt_total_active_balance, spec)?;
352386

353387
// compute ideal head rewards
354388
let head = get_attestation_component_delta(

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: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,7 @@ use slot_clock::SlotClock;
9595
use ssz::Encode;
9696
use state_processing::{
9797
common::get_attesting_indices_from_state,
98+
epoch_cache::initialize_epoch_cache,
9899
per_block_processing,
99100
per_block_processing::{
100101
errors::AttestationValidationError, get_expected_withdrawals,
@@ -3360,9 +3361,7 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
33603361
block_delay,
33613362
&state,
33623363
payload_verification_status,
3363-
self.config.progressive_balances_mode,
33643364
&self.spec,
3365-
&self.log,
33663365
)
33673366
.map_err(|e| BlockError::BeaconChainError(e.into()))?;
33683367
}
@@ -4981,6 +4980,10 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
49814980
let attestation_packing_timer =
49824981
metrics::start_timer(&metrics::BLOCK_PRODUCTION_ATTESTATION_TIMES);
49834982

4983+
// Epoch cache and total balance cache are required for op pool packing.
4984+
state.build_total_active_balance_cache(&self.spec)?;
4985+
initialize_epoch_cache(&mut state, &self.spec)?;
4986+
49844987
let mut prev_filter_cache = HashMap::new();
49854988
let prev_attestation_filter = |att: &AttestationRef<T::EthSpec>| {
49864989
self.filter_op_pool_attestation(&mut prev_filter_cache, att, &state)

beacon_node/beacon_chain/src/builder.rs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -775,8 +775,6 @@ where
775775
store.clone(),
776776
Some(current_slot),
777777
&self.spec,
778-
self.chain_config.progressive_balances_mode,
779-
&log,
780778
)?;
781779
}
782780

beacon_node/beacon_chain/src/chain_config.rs

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
pub use proto_array::{DisallowedReOrgOffsets, ReOrgThreshold};
22
use serde::{Deserialize, Serialize};
33
use std::time::Duration;
4-
use types::{Checkpoint, Epoch, ProgressiveBalancesMode};
4+
use types::{Checkpoint, Epoch};
55

66
pub const DEFAULT_RE_ORG_THRESHOLD: ReOrgThreshold = ReOrgThreshold(20);
77
pub const DEFAULT_RE_ORG_MAX_EPOCHS_SINCE_FINALIZATION: Epoch = Epoch::new(2);
@@ -81,8 +81,6 @@ pub struct ChainConfig {
8181
///
8282
/// This is useful for block builders and testing.
8383
pub always_prepare_payload: bool,
84-
/// Whether to use `ProgressiveBalancesCache` in unrealized FFG progression calculation.
85-
pub progressive_balances_mode: ProgressiveBalancesMode,
8684
/// Number of epochs between each migration of data from the hot database to the freezer.
8785
pub epochs_per_migration: u64,
8886
/// When set to true Light client server computes and caches state proofs for serving updates
@@ -117,7 +115,6 @@ impl Default for ChainConfig {
117115
snapshot_cache_size: crate::snapshot_cache::DEFAULT_SNAPSHOT_CACHE_SIZE,
118116
genesis_backfill: false,
119117
always_prepare_payload: false,
120-
progressive_balances_mode: ProgressiveBalancesMode::Fast,
121118
epochs_per_migration: crate::migrate::DEFAULT_EPOCHS_PER_MIGRATION,
122119
enable_light_client_server: false,
123120
}

beacon_node/beacon_chain/src/errors.rs

Lines changed: 4 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
easy_from_to!(LightClientError, BeaconChainError);
254256

255257
#[derive(Debug)]
@@ -259,6 +261,7 @@ pub enum BlockProductionError {
259261
UnableToProduceAtSlot(Slot),
260262
SlotProcessingError(SlotProcessingError),
261263
BlockProcessingError(BlockProcessingError),
264+
EpochCacheError(EpochCacheError),
262265
ForkChoiceError(ForkChoiceError),
263266
Eth1ChainError(Eth1ChainError),
264267
BeaconStateError(BeaconStateError),
@@ -298,3 +301,4 @@ easy_from_to!(SlotProcessingError, BlockProductionError);
298301
easy_from_to!(Eth1ChainError, BlockProductionError);
299302
easy_from_to!(StateAdvanceError, BlockProductionError);
300303
easy_from_to!(ForkChoiceError, BlockProductionError);
304+
easy_from_to!(EpochCacheError, BlockProductionError);

beacon_node/beacon_chain/src/fork_revert.rs

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,7 @@ use state_processing::{
1010
use std::sync::Arc;
1111
use std::time::Duration;
1212
use store::{iter::ParentRootBlockIterator, HotColdDB, ItemStore};
13-
use types::{
14-
BeaconState, ChainSpec, EthSpec, ForkName, Hash256, ProgressiveBalancesMode, SignedBeaconBlock,
15-
Slot,
16-
};
13+
use types::{BeaconState, ChainSpec, EthSpec, ForkName, Hash256, SignedBeaconBlock, Slot};
1714

1815
const CORRUPT_DB_MESSAGE: &str = "The database could be corrupt. Check its file permissions or \
1916
consider deleting it by running with the --purge-db flag.";
@@ -103,8 +100,6 @@ pub fn reset_fork_choice_to_finalization<E: EthSpec, Hot: ItemStore<E>, Cold: It
103100
store: Arc<HotColdDB<E, Hot, Cold>>,
104101
current_slot: Option<Slot>,
105102
spec: &ChainSpec,
106-
progressive_balances_mode: ProgressiveBalancesMode,
107-
log: &Logger,
108103
) -> Result<ForkChoice<BeaconForkChoiceStore<E, Hot, Cold>, E>, String> {
109104
// Fetch finalized block.
110105
let finalized_checkpoint = head_state.finalized_checkpoint();
@@ -202,9 +197,7 @@ pub fn reset_fork_choice_to_finalization<E: EthSpec, Hot: ItemStore<E>, Cold: It
202197
Duration::from_secs(0),
203198
&state,
204199
payload_verification_status,
205-
progressive_balances_mode,
206200
spec,
207-
log,
208201
)
209202
.map_err(|e| format!("Error applying replayed block to fork choice: {:?}", e))?;
210203
}

0 commit comments

Comments
 (0)