From 7d048ce783fc1d2c4b4b4302f9b95434b80199e9 Mon Sep 17 00:00:00 2001 From: tersec Date: Fri, 20 Aug 2021 14:41:32 +0000 Subject: [PATCH] avoid repeated `integer_squareroot`s for 20% faster Altair epoch processing (#2797) * avoid repeated integer_squareroots for 20% faster altair epoch processing * the square root of a Gwei isn't a Gwei --- beacon_chain/spec/state_transition_epoch.nim | 107 ++++++++++--------- 1 file changed, 54 insertions(+), 53 deletions(-) diff --git a/beacon_chain/spec/state_transition_epoch.nim b/beacon_chain/spec/state_transition_epoch.nim index 78ded6392..6d2b80a19 100644 --- a/beacon_chain/spec/state_transition_epoch.nim +++ b/beacon_chain/spec/state_transition_epoch.nim @@ -6,7 +6,8 @@ # at your option. This file may not be copied, modified, or distributed except according to those terms. # State transition - epoch processing, as described in -# https://github.com/ethereum/eth2.0-specs/blob/master/specs/core/0_beacon-chain.md#beacon-chain-state-transition-function +# https://github.com/ethereum/consensus-specs/blob/v1.1.0-beta.2/specs/phase0/beacon-chain.md#epoch-processing and +# https://github.com/ethereum/consensus-specs/blob/v1.1.0-beta.2/specs/altair/beacon-chain.md#epoch-processing # # The entry point is `process_epoch`, which is at the bottom of this file. # @@ -35,7 +36,7 @@ export extras, phase0, altair logScope: topics = "consens" # Accessors that implement the max condition in `get_total_balance`: -# https://github.com/ethereum/eth2.0-specs/blob/v1.0.1/specs/phase0/beacon-chain.md#get_total_balance +# https://github.com/ethereum/consensus-specs/blob/v1.0.1/specs/phase0/beacon-chain.md#get_total_balance template current_epoch*(v: TotalBalances): Gwei = max(EFFECTIVE_BALANCE_INCREMENT, v.current_epoch_raw) template previous_epoch*(v: TotalBalances): Gwei = @@ -158,7 +159,7 @@ func is_eligible_validator*(validator: RewardStatus): bool = # Spec # -------------------------------------------------------- -# https://github.com/ethereum/eth2.0-specs/blob/v1.1.0-alpha.6/specs/altair/beacon-chain.md#get_unslashed_participating_indices +# https://github.com/ethereum/consensus-specs/blob/v1.1.0-beta.2/specs/altair/beacon-chain.md#get_unslashed_participating_indices func get_unslashed_participating_indices( state: altair.BeaconState, flag_index: int, epoch: Epoch): HashSet[ValidatorIndex] = @@ -182,7 +183,7 @@ func get_unslashed_participating_indices( res.incl validator_index res -# https://github.com/ethereum/eth2.0-specs/blob/v1.0.1/specs/phase0/beacon-chain.md#justification-and-finalization +# https://github.com/ethereum/consensus-specs/blob/v1.0.1/specs/phase0/beacon-chain.md#justification-and-finalization proc process_justification_and_finalization*(state: var phase0.BeaconState, total_balances: TotalBalances, flags: UpdateFlags = {}) {.nbench.} = # Initial FFG checkpoint values have a `0x00` stub for `root`. @@ -204,7 +205,7 @@ proc process_justification_and_finalization*(state: var phase0.BeaconState, ## state.justification_bits[1:] = state.justification_bits[:-1] ## state.justification_bits[0] = 0b0 - # https://github.com/ethereum/eth2.0-specs/blob/v1.0.1/specs/phase0/beacon-chain.md#constants + # https://github.com/ethereum/consensus-specs/blob/v1.0.1/specs/phase0/beacon-chain.md#constants const JUSTIFICATION_BITS_LENGTH = 4 state.justification_bits = (state.justification_bits shl 1) and @@ -279,8 +280,8 @@ proc process_justification_and_finalization*(state: var phase0.BeaconState, current_epoch = current_epoch, checkpoint = shortLog(state.finalized_checkpoint) -# https://github.com/ethereum/eth2.0-specs/blob/v1.1.0-alpha.7/specs/altair/beacon-chain.md#justification-and-finalization -# https://github.com/ethereum/eth2.0-specs/blob/v1.1.0-alpha.7/specs/phase0/beacon-chain.md#justification-and-finalization +# https://github.com/ethereum/consensus-specs/blob/v1.1.0-alpha.7/specs/altair/beacon-chain.md#justification-and-finalization +# https://github.com/ethereum/consensus-specs/blob/v1.1.0-alpha.7/specs/phase0/beacon-chain.md#justification-and-finalization # TODO merge these things -- effectively, the phase0 process_justification_and_finalization is mostly a stub in this world proc weigh_justification_and_finalization(state: var altair.BeaconState, total_active_balance: Gwei, @@ -300,7 +301,7 @@ proc weigh_justification_and_finalization(state: var altair.BeaconState, ## state.justification_bits[1:] = state.justification_bits[:-1] ## state.justification_bits[0] = 0b0 - # https://github.com/ethereum/eth2.0-specs/blob/v1.0.1/specs/phase0/beacon-chain.md#constants + # https://github.com/ethereum/consensus-specs/blob/v1.0.1/specs/phase0/beacon-chain.md#constants const JUSTIFICATION_BITS_LENGTH = 4 state.justification_bits = (state.justification_bits shl 1) and @@ -384,7 +385,7 @@ proc process_justification_and_finalization*(state: var altair.BeaconState, return let # these ultimately differ from phase0 only in these lines - # https://github.com/ethereum/eth2.0-specs/blob/v1.1.0-alpha.8/specs/phase0/beacon-chain.md#justification-and-finalization + # https://github.com/ethereum/consensus-specs/blob/v1.1.0-beta.2/specs/phase0/beacon-chain.md#justification-and-finalization previous_indices = get_unslashed_participating_indices( state, TIMELY_TARGET_FLAG_INDEX, get_previous_epoch(state)) current_indices = get_unslashed_participating_indices( @@ -395,7 +396,7 @@ proc process_justification_and_finalization*(state: var altair.BeaconState, state, total_active_balance, previous_target_balance, current_target_balance, flags) -# https://github.com/ethereum/eth2.0-specs/blob/v1.0.1/specs/phase0/beacon-chain.md#helpers +# https://github.com/ethereum/consensus-specs/blob/v1.0.1/specs/phase0/beacon-chain.md#helpers func get_base_reward_sqrt*(state: phase0.BeaconState, index: ValidatorIndex, total_balance_sqrt: auto): Gwei = # Spec function recalculates total_balance every time, which creates an @@ -414,7 +415,7 @@ func is_in_inactivity_leak(finality_delay: uint64): bool = func get_finality_delay(state: SomeBeaconState): uint64 = get_previous_epoch(state) - state.finalized_checkpoint.epoch -# https://github.com/ethereum/eth2.0-specs/blob/v1.1.0-alpha.8/specs/phase0/beacon-chain.md#rewards-and-penalties-1 +# https://github.com/ethereum/consensus-specs/blob/v1.1.0-alpha.8/specs/phase0/beacon-chain.md#rewards-and-penalties-1 func is_in_inactivity_leak(state: altair.BeaconState): bool = # TODO remove this, see above get_finality_delay(state) > MIN_EPOCHS_TO_INACTIVITY_PENALTY @@ -439,7 +440,7 @@ func get_attestation_component_delta(is_unslashed_attester: bool, else: RewardDelta(penalties: base_reward) -# https://github.com/ethereum/eth2.0-specs/blob/v1.0.1/specs/phase0/beacon-chain.md#components-of-attestation-deltas +# https://github.com/ethereum/consensus-specs/blob/v1.0.1/specs/phase0/beacon-chain.md#components-of-attestation-deltas func get_source_delta*(validator: RewardStatus, base_reward: uint64, total_balances: TotalBalances, @@ -517,7 +518,7 @@ func get_inactivity_penalty_delta*(validator: RewardStatus, delta -# https://github.com/ethereum/eth2.0-specs/blob/v1.0.1/specs/phase0/beacon-chain.md#get_attestation_deltas +# https://github.com/ethereum/consensus-specs/blob/v1.0.1/specs/phase0/beacon-chain.md#get_attestation_deltas func get_attestation_deltas(state: phase0.BeaconState, rewards: var RewardInfo) = ## Update rewards with attestation reward/penalty deltas for each validator. @@ -561,27 +562,25 @@ func get_attestation_deltas(state: phase0.BeaconState, rewards: var RewardInfo) rewards.statuses[proposer_index].delta.add( proposer_delta.get()[1]) -# https://github.com/ethereum/eth2.0-specs/blob/v1.1.0-alpha.8/specs/altair/beacon-chain.md#get_base_reward_per_increment +# https://github.com/ethereum/consensus-specs/blob/v1.1.0-beta.2/specs/altair/beacon-chain.md#get_base_reward_per_increment func get_base_reward_per_increment( - state: altair.BeaconState, total_active_balance: Gwei): Gwei = - # TODO hoist this integer_squareroot, as with phase 0 - EFFECTIVE_BALANCE_INCREMENT * BASE_REWARD_FACTOR div - integer_squareroot(total_active_balance) + state: altair.BeaconState, total_active_balance_sqrt: uint64): Gwei = + EFFECTIVE_BALANCE_INCREMENT * BASE_REWARD_FACTOR div total_active_balance_sqrt -# https://github.com/ethereum/eth2.0-specs/blob/v1.1.0-alpha.8/specs/altair/beacon-chain.md#get_base_reward +# https://github.com/ethereum/consensus-specs/blob/v1.1.0-beta.2/specs/altair/beacon-chain.md#get_base_reward func get_base_reward( - state: altair.BeaconState, index: ValidatorIndex, total_active_balance: Gwei): - Gwei = + state: altair.BeaconState, index: ValidatorIndex, + total_active_balance_sqrt: uint64): Gwei = ## Return the base reward for the validator defined by ``index`` with respect ## to the current ``state``. let increments = state.validators[index].effective_balance div EFFECTIVE_BALANCE_INCREMENT - increments * get_base_reward_per_increment(state, total_active_balance) + increments * get_base_reward_per_increment(state, total_active_balance_sqrt) -# https://github.com/ethereum/eth2.0-specs/blob/v1.1.0-alpha.6/specs/altair/beacon-chain.md#get_flag_index_deltas +# https://github.com/ethereum/consensus-specs/blob/v1.1.0-beta.2/specs/altair/beacon-chain.md#get_flag_index_deltas iterator get_flag_index_deltas( - state: altair.BeaconState, flag_index: int, total_active_balance: Gwei): - (ValidatorIndex, Gwei, Gwei) = + state: altair.BeaconState, flag_index: int, total_active_balance: Gwei, + total_active_balance_sqrt: uint64): (ValidatorIndex, Gwei, Gwei) = ## Return the deltas for a given ``flag_index`` by scanning through the ## participation flags. let @@ -603,7 +602,7 @@ iterator get_flag_index_deltas( continue template vidx: ValidatorIndex = index.ValidatorIndex - let base_reward = get_base_reward(state, vidx, total_active_balance) + let base_reward = get_base_reward(state, vidx, total_active_balance_sqrt) yield if vidx in unslashed_participating_indices: if not is_in_inactivity_leak(state): @@ -617,7 +616,7 @@ iterator get_flag_index_deltas( else: (vidx, 0.Gwei, 0.Gwei) -# https://github.com/ethereum/eth2.0-specs/blob/v1.1.0-alpha.7/specs/altair/beacon-chain.md#modified-get_inactivity_penalty_deltas +# https://github.com/ethereum/consensus-specs/blob/v1.1.0-beta.2/specs/altair/beacon-chain.md#modified-get_inactivity_penalty_deltas iterator get_inactivity_penalty_deltas(cfg: RuntimeConfig, state: altair.BeaconState): (ValidatorIndex, Gwei) = ## Return the inactivity penalty deltas by considering timely target @@ -643,7 +642,7 @@ iterator get_inactivity_penalty_deltas(cfg: RuntimeConfig, state: altair.BeaconS state.inactivity_scores[index] yield (vidx, Gwei(penalty_numerator div penalty_denominator)) -# https://github.com/ethereum/eth2.0-specs/blob/v1.0.1/specs/phase0/beacon-chain.md#process_rewards_and_penalties +# https://github.com/ethereum/consensus-specs/blob/v1.1.0-beta.2/specs/altair/beacon-chain.md#rewards-and-penalties func process_rewards_and_penalties( state: var phase0.BeaconState, rewards: var RewardInfo) {.nbench.} = # No rewards are applied at the end of `GENESIS_EPOCH` because rewards are @@ -664,7 +663,7 @@ func process_rewards_and_penalties( increase_balance(state.balances.asSeq()[idx], v.delta.rewards) decrease_balance(state.balances.asSeq()[idx], v.delta.penalties) -# https://github.com/ethereum/eth2.0-specs/blob/v1.1.0-alpha.8/specs/altair/beacon-chain.md#rewards-and-penalties +# https://github.com/ethereum/consensus-specs/blob/v1.1.0-beta.2/specs/altair/beacon-chain.md#rewards-and-penalties func process_rewards_and_penalties( cfg: RuntimeConfig, state: var altair.BeaconState, total_active_balance: Gwei) {.nbench.} = if get_current_epoch(state) == GENESIS_EPOCH: @@ -680,9 +679,11 @@ func process_rewards_and_penalties( rewards = newSeq[Gwei](state.validators.len) penalties = newSeq[Gwei](state.validators.len) + let total_active_balance_sqrt = integer_squareroot(total_active_balance) + for flag_index in 0 ..< PARTICIPATION_FLAG_WEIGHTS.len: for validator_index, reward, penalty in get_flag_index_deltas( - state, flag_index, total_active_balance): + state, flag_index, total_active_balance, total_active_balance_sqrt): rewards[validator_index] += reward penalties[validator_index] += penalty @@ -693,8 +694,8 @@ func process_rewards_and_penalties( increase_balance(state, ValidatorIndex(index), rewards[index]) decrease_balance(state, ValidatorIndex(index), penalties[index]) -# https://github.com/ethereum/eth2.0-specs/blob/v1.0.1/specs/phase0/beacon-chain.md#slashings -# https://github.com/ethereum/eth2.0-specs/blob/v1.1.0-alpha.8/specs/altair/beacon-chain.md#slashings +# https://github.com/ethereum/consensus-specs/blob/v1.0.1/specs/phase0/beacon-chain.md#slashings +# https://github.com/ethereum/consensus-specs/blob/v1.1.0-beta.2/specs/altair/beacon-chain.md#slashings func process_slashings*(state: var SomeBeaconState, total_balance: Gwei) {.nbench.}= let epoch = get_current_epoch(state) @@ -722,7 +723,7 @@ func process_slashings*(state: var SomeBeaconState, total_balance: Gwei) {.nbenc let penalty = penalty_numerator div total_balance * increment decrease_balance(state, index.ValidatorIndex, penalty) -# https://github.com/ethereum/eth2.0-specs/blob/34cea67b91/specs/phase0/beacon-chain.md#eth1-data-votes-updates +# https://github.com/ethereum/consensus-specs/blob/34cea67b91/specs/phase0/beacon-chain.md#eth1-data-votes-updates func process_eth1_data_reset*(state: var SomeBeaconState) {.nbench.} = let next_epoch = get_current_epoch(state) + 1 @@ -730,7 +731,7 @@ func process_eth1_data_reset*(state: var SomeBeaconState) {.nbench.} = if next_epoch mod EPOCHS_PER_ETH1_VOTING_PERIOD == 0: state.eth1_data_votes = default(type state.eth1_data_votes) -# https://github.com/ethereum/eth2.0-specs/blob/34cea67b91/specs/phase0/beacon-chain.md#effective-balances-updates +# https://github.com/ethereum/consensus-specs/blob/34cea67b91/specs/phase0/beacon-chain.md#effective-balances-updates func process_effective_balance_updates*(state: var SomeBeaconState) {.nbench.} = # Update effective balances with hysteresis for index in 0..= currentEpoch - # https://github.com/ethereum/eth2.0-specs/blob/v1.0.1/specs/phase0/beacon-chain.md#rewards-and-penalties-1 + # https://github.com/ethereum/consensus-specs/blob/v1.0.1/specs/phase0/beacon-chain.md#rewards-and-penalties-1 process_rewards_and_penalties(state, rewards) - # https://github.com/ethereum/eth2.0-specs/blob/v1.0.1/specs/phase0/beacon-chain.md#registry-updates + # https://github.com/ethereum/consensus-specs/blob/v1.0.1/specs/phase0/beacon-chain.md#registry-updates process_registry_updates(cfg, state, cache) - # https://github.com/ethereum/eth2.0-specs/blob/v1.0.1/specs/phase0/beacon-chain.md#slashings + # https://github.com/ethereum/consensus-specs/blob/v1.0.1/specs/phase0/beacon-chain.md#slashings process_slashings(state, rewards.total_balances.current_epoch) - # https://github.com/ethereum/eth2.0-specs/blob/v1.0.1/specs/phase0/beacon-chain.md#final-updates + # https://github.com/ethereum/consensus-specs/blob/v1.0.1/specs/phase0/beacon-chain.md#final-updates process_eth1_data_reset(state) process_effective_balance_updates(state) process_slashings_reset(state) @@ -877,7 +878,7 @@ proc process_epoch*( process_historical_roots_update(state) process_participation_record_updates(state) -# https://github.com/ethereum/eth2.0-specs/blob/v1.1.0-alpha.7/specs/altair/beacon-chain.md#epoch-processing +# https://github.com/ethereum/consensus-specs/blob/v1.1.0-alpha.7/specs/altair/beacon-chain.md#epoch-processing proc process_epoch*( cfg: RuntimeConfig, state: var altair.BeaconState, flags: UpdateFlags, cache: var StateCache, rewards: var RewardInfo) {.nbench.} = @@ -890,7 +891,7 @@ proc process_epoch*( let total_active_balance = state.get_total_active_balance(cache) - # https://github.com/ethereum/eth2.0-specs/blob/v1.0.1/specs/phase0/beacon-chain.md#justification-and-finalization + # https://github.com/ethereum/consensus-specs/blob/v1.0.1/specs/phase0/beacon-chain.md#justification-and-finalization process_justification_and_finalization(state, total_active_balance, flags) # state.slot hasn't been incremented yet. @@ -905,13 +906,13 @@ proc process_epoch*( process_inactivity_updates(cfg, state) # [New in Altair] - # https://github.com/ethereum/eth2.0-specs/blob/v1.0.1/specs/phase0/beacon-chain.md#rewards-and-penalties-1 + # https://github.com/ethereum/consensus-specs/blob/v1.0.1/specs/phase0/beacon-chain.md#rewards-and-penalties-1 process_rewards_and_penalties(cfg, state, total_active_balance) - # https://github.com/ethereum/eth2.0-specs/blob/v1.0.1/specs/phase0/beacon-chain.md#registry-updates + # https://github.com/ethereum/consensus-specs/blob/v1.0.1/specs/phase0/beacon-chain.md#registry-updates process_registry_updates(cfg, state, cache) - # https://github.com/ethereum/eth2.0-specs/blob/v1.0.1/specs/phase0/beacon-chain.md#slashings + # https://github.com/ethereum/consensus-specs/blob/v1.0.1/specs/phase0/beacon-chain.md#slashings process_slashings(state, total_active_balance) process_eth1_data_reset(state)