From f53271eaaac829cb53539af601107bb8a1b56776 Mon Sep 17 00:00:00 2001 From: tersec Date: Wed, 24 Apr 2024 12:28:47 +0000 Subject: [PATCH] add rest of EF consensus spec test Electra epoch transition fixture(s) (#6232) --- ConsensusSpecPreset-mainnet.md | 35 +++- ConsensusSpecPreset-minimal.md | 42 ++++- beacon_chain/spec/beaconstate.nim | 135 +++++++++++++++- beacon_chain/spec/presets.nim | 20 ++- beacon_chain/spec/state_transition_epoch.nim | 149 ++++++++++++++++-- .../test_fixture_state_transition_epoch.nim | 26 ++- 6 files changed, 375 insertions(+), 32 deletions(-) diff --git a/ConsensusSpecPreset-mainnet.md b/ConsensusSpecPreset-mainnet.md index 4dd84b8e8..ca86c38ad 100644 --- a/ConsensusSpecPreset-mainnet.md +++ b/ConsensusSpecPreset-mainnet.md @@ -2465,11 +2465,44 @@ OK: 10/10 Fail: 0/10 Skip: 0/10 + Participation flag updates - random_genesis [Preset: mainnet] OK ``` OK: 10/10 Fail: 0/10 Skip: 0/10 +## EF - Electra - Epoch Processing - Pending balance deposits [Preset: mainnet] +```diff ++ Pending balance deposits - multiple_pending_deposits_above_churn [Preset: mainnet] OK ++ Pending balance deposits - multiple_pending_deposits_below_churn [Preset: mainnet] OK ++ Pending balance deposits - pending_deposit_balance_above_churn [Preset: mainnet] OK ++ Pending balance deposits - pending_deposit_balance_equal_churn [Preset: mainnet] OK ++ Pending balance deposits - pending_deposit_min_activation_balance [Preset: mainnet] OK ++ Pending balance deposits - pending_deposit_preexisting_churn [Preset: mainnet] OK +``` +OK: 6/6 Fail: 0/6 Skip: 0/6 +## EF - Electra - Epoch Processing - Pending consolidations [Preset: mainnet] +```diff ++ Pending consolidations - all_consolidation_cases_together [Preset: mainnet] OK ++ Pending consolidations - basic_pending_consolidation [Preset: mainnet] OK ++ Pending consolidations - consolidation_not_yet_withdrawable_validator [Preset: mainnet] OK ++ Pending consolidations - skip_consolidation_when_source_slashed [Preset: mainnet] OK +``` +OK: 4/4 Fail: 0/4 Skip: 0/4 ## EF - Electra - Epoch Processing - RANDAO mixes reset [Preset: mainnet] ```diff + RANDAO mixes reset - updated_randao_mixes [Preset: mainnet] OK ``` OK: 1/1 Fail: 0/1 Skip: 0/1 +## EF - Electra - Epoch Processing - Registry updates [Preset: mainnet] +```diff ++ Registry updates - activation_queue_activation_and_ejection__1 [Preset: mainnet] OK ++ Registry updates - activation_queue_activation_and_ejection__churn_limit [Preset: mainnet] OK ++ Registry updates - activation_queue_activation_and_ejection__exceed_churn_limit [Preset: m OK ++ Registry updates - activation_queue_efficiency_min [Preset: mainnet] OK ++ Registry updates - activation_queue_no_activation_no_finality [Preset: mainnet] OK ++ Registry updates - activation_queue_sorting [Preset: mainnet] OK ++ Registry updates - activation_queue_to_activated_if_finalized [Preset: mainnet] OK ++ Registry updates - add_to_activation_queue [Preset: mainnet] OK ++ Registry updates - ejection [Preset: mainnet] OK ++ Registry updates - ejection_past_churn_limit_min [Preset: mainnet] OK ++ Registry updates - invalid_large_withdrawable_epoch [Preset: mainnet] OK +``` +OK: 11/11 Fail: 0/11 Skip: 0/11 ## EF - Electra - Epoch Processing - Rewards and penalties [Preset: mainnet] ```diff + Rewards and penalties - almost_empty_attestations [Preset: mainnet] OK @@ -3250,4 +3283,4 @@ OK: 69/88 Fail: 0/88 Skip: 19/88 OK: 3/3 Fail: 0/3 Skip: 0/3 ---TOTAL--- -OK: 2601/2620 Fail: 0/2620 Skip: 19/2620 +OK: 2622/2641 Fail: 0/2641 Skip: 19/2641 diff --git a/ConsensusSpecPreset-minimal.md b/ConsensusSpecPreset-minimal.md index 3cd0641b2..5200f217e 100644 --- a/ConsensusSpecPreset-minimal.md +++ b/ConsensusSpecPreset-minimal.md @@ -2576,11 +2576,51 @@ OK: 10/10 Fail: 0/10 Skip: 0/10 + Participation flag updates - slightly_larger_random [Preset: minimal] OK ``` OK: 12/12 Fail: 0/12 Skip: 0/12 +## EF - Electra - Epoch Processing - Pending balance deposits [Preset: minimal] +```diff ++ Pending balance deposits - multiple_pending_deposits_above_churn [Preset: minimal] OK ++ Pending balance deposits - multiple_pending_deposits_below_churn [Preset: minimal] OK ++ Pending balance deposits - pending_deposit_balance_above_churn [Preset: minimal] OK ++ Pending balance deposits - pending_deposit_balance_equal_churn [Preset: minimal] OK ++ Pending balance deposits - pending_deposit_min_activation_balance [Preset: minimal] OK ++ Pending balance deposits - pending_deposit_preexisting_churn [Preset: minimal] OK +``` +OK: 6/6 Fail: 0/6 Skip: 0/6 +## EF - Electra - Epoch Processing - Pending consolidations [Preset: minimal] +```diff ++ Pending consolidations - all_consolidation_cases_together [Preset: minimal] OK ++ Pending consolidations - basic_pending_consolidation [Preset: minimal] OK ++ Pending consolidations - consolidation_not_yet_withdrawable_validator [Preset: minimal] OK ++ Pending consolidations - skip_consolidation_when_source_slashed [Preset: minimal] OK +``` +OK: 4/4 Fail: 0/4 Skip: 0/4 ## EF - Electra - Epoch Processing - RANDAO mixes reset [Preset: minimal] ```diff + RANDAO mixes reset - updated_randao_mixes [Preset: minimal] OK ``` OK: 1/1 Fail: 0/1 Skip: 0/1 +## EF - Electra - Epoch Processing - Registry updates [Preset: minimal] +```diff ++ Registry updates - activation_churn_limit__equal_to_activation_limit [Preset: minimal] OK ++ Registry updates - activation_churn_limit__greater_than_activation_limit [Preset: minimal] OK ++ Registry updates - activation_churn_limit__less_than_activation_limit [Preset: minimal] OK ++ Registry updates - activation_queue_activation_and_ejection__1 [Preset: minimal] OK ++ Registry updates - activation_queue_activation_and_ejection__churn_limit [Preset: minimal] OK ++ Registry updates - activation_queue_activation_and_ejection__exceed_churn_limit [Preset: m OK ++ Registry updates - activation_queue_activation_and_ejection__exceed_scaled_churn_limit [Pr OK ++ Registry updates - activation_queue_activation_and_ejection__scaled_churn_limit [Preset: m OK ++ Registry updates - activation_queue_efficiency_min [Preset: minimal] OK ++ Registry updates - activation_queue_efficiency_scaled [Preset: minimal] OK ++ Registry updates - activation_queue_no_activation_no_finality [Preset: minimal] OK ++ Registry updates - activation_queue_sorting [Preset: minimal] OK ++ Registry updates - activation_queue_to_activated_if_finalized [Preset: minimal] OK ++ Registry updates - add_to_activation_queue [Preset: minimal] OK ++ Registry updates - ejection [Preset: minimal] OK ++ Registry updates - ejection_past_churn_limit_min [Preset: minimal] OK ++ Registry updates - ejection_past_churn_limit_scaled [Preset: minimal] OK ++ Registry updates - invalid_large_withdrawable_epoch [Preset: minimal] OK +``` +OK: 18/18 Fail: 0/18 Skip: 0/18 ## EF - Electra - Epoch Processing - Rewards and penalties [Preset: minimal] ```diff + Rewards and penalties - almost_empty_attestations [Preset: minimal] OK @@ -3530,4 +3570,4 @@ OK: 185/207 Fail: 0/207 Skip: 22/207 OK: 3/3 Fail: 0/3 Skip: 0/3 ---TOTAL--- -OK: 2850/2872 Fail: 0/2872 Skip: 22/2872 +OK: 2878/2900 Fail: 0/2900 Skip: 22/2900 diff --git a/beacon_chain/spec/beaconstate.nim b/beacon_chain/spec/beaconstate.nim index 2037fc9bf..f47d6f542 100644 --- a/beacon_chain/spec/beaconstate.nim +++ b/beacon_chain/spec/beaconstate.nim @@ -91,7 +91,9 @@ func get_validator_activation_churn_limit*( get_validator_churn_limit(cfg, state, cache)) # https://github.com/ethereum/consensus-specs/blob/v1.4.0/specs/phase0/beacon-chain.md#initiate_validator_exit -func get_state_exit_queue_info*(state: ForkyBeaconState): ExitQueueInfo = +func get_state_exit_queue_info*( + state: phase0.BeaconState | altair.BeaconState | bellatrix.BeaconState | + capella.BeaconState | deneb.BeaconState): ExitQueueInfo = var exit_queue_epoch = compute_activation_exit_epoch(get_current_epoch(state)) exit_queue_churn: uint64 @@ -118,11 +120,19 @@ func get_state_exit_queue_info*(state: ForkyBeaconState): ExitQueueInfo = ExitQueueInfo( exit_queue_epoch: exit_queue_epoch, exit_queue_churn: exit_queue_churn) +func get_state_exit_queue_info*(state: electra.BeaconState): ExitQueueInfo = + # Electra initiate_validator_exit doesn't have same quadratic aspect given + # StateCache balance caching + default(ExitQueueInfo) + # https://github.com/ethereum/consensus-specs/blob/v1.4.0/specs/phase0/beacon-chain.md#initiate_validator_exit func initiate_validator_exit*( - cfg: RuntimeConfig, state: var ForkyBeaconState, - index: ValidatorIndex, exit_queue_info: ExitQueueInfo, cache: var StateCache): - Result[ExitQueueInfo, cstring] = + cfg: RuntimeConfig, + state: var (phase0.BeaconState | altair.BeaconState | + bellatrix.BeaconState | capella.BeaconState | + deneb.BeaconState), + index: ValidatorIndex, exit_queue_info: ExitQueueInfo, + cache: var StateCache): Result[ExitQueueInfo, cstring] = ## Initiate the exit of the validator with index ``index``. if state.validators.item(index).exit_epoch != FAR_FUTURE_EPOCH: @@ -156,6 +166,85 @@ func initiate_validator_exit*( ok(ExitQueueInfo( exit_queue_epoch: exit_queue_epoch, exit_queue_churn: exit_queue_churn)) +func get_total_active_balance*(state: ForkyBeaconState, cache: var StateCache): Gwei + +# https://github.com/ethereum/consensus-specs/blob/v1.5.0-alpha.0/specs/electra/beacon-chain.md#new-get_balance_churn_limit +func get_balance_churn_limit( + cfg: RuntimeConfig, state: electra.BeaconState, + cache: var StateCache): Gwei = + ## Return the churn limit for the current epoch. + let churn = max( + cfg.MIN_PER_EPOCH_CHURN_LIMIT_ELECTRA.Gwei, + get_total_active_balance(state, cache) div cfg.CHURN_LIMIT_QUOTIENT + ) + churn - churn mod EFFECTIVE_BALANCE_INCREMENT.Gwei + +# https://github.com/ethereum/consensus-specs/blob/v1.5.0-alpha.0/specs/electra/beacon-chain.md#new-get_activation_exit_churn_limit +func get_activation_exit_churn_limit*( + cfg: RuntimeConfig, state: electra.BeaconState, cache: var StateCache): + Gwei = + ## Return the churn limit for the current epoch dedicated to activations and + ## exits. + min( + cfg.MAX_PER_EPOCH_ACTIVATION_EXIT_CHURN_LIMIT.Gwei, + get_balance_churn_limit(cfg, state, cache)) + +# https://github.com/ethereum/consensus-specs/blob/v1.5.0-alpha.0/specs/electra/beacon-chain.md#new-compute_exit_epoch_and_update_churn +func compute_exit_epoch_and_update_churn( + cfg: RuntimeConfig, state: var electra.BeaconState, exit_balance: Gwei, + cache: var StateCache): Epoch = + var earliest_exit_epoch = max(state.earliest_exit_epoch, + compute_activation_exit_epoch(get_current_epoch(state))) + let per_epoch_churn = get_activation_exit_churn_limit(cfg, state, cache) + + # New epoch for exits. + var exit_balance_to_consume = + if state.earliest_exit_epoch < earliest_exit_epoch: + per_epoch_churn + else: + state.exit_balance_to_consume + + # Exit doesn't fit in the current earliest epoch. + if exit_balance > exit_balance_to_consume: + let + balance_to_process = exit_balance - exit_balance_to_consume + additional_epochs = (balance_to_process - 1.Gwei) div per_epoch_churn + 1 + earliest_exit_epoch += additional_epochs + exit_balance_to_consume += additional_epochs * per_epoch_churn + + # Consume the balance and update state variables. + state.exit_balance_to_consume = exit_balance_to_consume - exit_balance + state.earliest_exit_epoch = earliest_exit_epoch + + state.earliest_exit_epoch + +# https://github.com/ethereum/consensus-specs/blob/v1.5.0-alpha.0/specs/electra/beacon-chain.md#updated--initiate_validator_exit +func initiate_validator_exit*( + cfg: RuntimeConfig, state: var electra.BeaconState, + index: ValidatorIndex, exit_queue_info: ExitQueueInfo, + cache: var StateCache): Result[ExitQueueInfo, cstring] = + ## Initiate the exit of the validator with index ``index``. + + # Return if validator already initiated exit + var validator = state.validators.item(index) + if validator.exit_epoch != FAR_FUTURE_EPOCH: + return + + # Compute exit queue epoch [Modified in Electra:EIP7251] + let exit_queue_epoch = compute_exit_epoch_and_update_churn( + cfg, state, validator.effective_balance, cache) + + # Set validator exit epoch and withdrawable epoch + validator.exit_epoch = exit_queue_epoch + validator.withdrawable_epoch = + Epoch(validator.exit_epoch + cfg.MIN_VALIDATOR_WITHDRAWABILITY_DELAY) + if validator.withdrawable_epoch < validator.exit_epoch: + return err("Invalid large withdrawable epoch") + state.validators.mitem(index) = validator + + # The Electra initiate_validator_exit() isn't accidentally quadratic; ignore + ok(static(default(ExitQueueInfo))) + from ./datatypes/deneb import BeaconState # https://github.com/ethereum/consensus-specs/blob/v1.4.0/specs/phase0/beacon-chain.md#slash_validator @@ -304,7 +393,8 @@ func get_initial_beacon_block*(state: deneb.HashedBeaconState): deneb.TrustedSignedBeaconBlock( message: message, root: hash_tree_root(message)) -from ./datatypes/electra import HashedBeaconState, TrustedSignedBeaconBlock +from ./datatypes/electra import + HashedBeaconState, PendingBalanceDeposit, TrustedSignedBeaconBlock # TODO spec link here when it exists func get_initial_beacon_block*(state: electra.HashedBeaconState): @@ -897,6 +987,41 @@ func has_execution_withdrawal_credential(validator: Validator): bool = has_compounding_withdrawal_credential(validator) or has_eth1_withdrawal_credential(validator) +# https://github.com/ethereum/consensus-specs/blob/v1.5.0-alpha.0/specs/electra/beacon-chain.md#get_validator_max_effective_balance +func get_validator_max_effective_balance(validator: Validator): Gwei = + ## Get max effective balance for ``validator``. + if has_compounding_withdrawal_credential(validator): + MAX_EFFECTIVE_BALANCE_ELECTRA.Gwei + else: + MIN_ACTIVATION_BALANCE.Gwei + +# https://github.com/ethereum/consensus-specs/blob/v1.5.0-alpha.0/specs/electra/beacon-chain.md#new-get_active_balance +func get_active_balance*( + state: electra.BeaconState, validator_index: ValidatorIndex): Gwei = + let max_effective_balance = + get_validator_max_effective_balance(state.validators[validator_index]) + min(state.balances[validator_index], max_effective_balance) + +# https://github.com/ethereum/consensus-specs/blob/v1.5.0-alpha.0/specs/electra/beacon-chain.md#new-queue_excess_active_balance +func queue_excess_active_balance( + state: var electra.BeaconState, index: ValidatorIndex) = + let balance = state.balances.item(index) + if balance > MIN_ACTIVATION_BALANCE.Gwei: + let excess_balance = balance - MIN_ACTIVATION_BALANCE.Gwei + state.balances.mitem(index) = MIN_ACTIVATION_BALANCE.Gwei + debugRaiseAssert "maybe check return value" + discard state.pending_balance_deposits.add( + PendingBalanceDeposit(index: index.uint64, amount: excess_balance) + ) + +# https://github.com/ethereum/consensus-specs/blob/v1.5.0-alpha.0/specs/electra/beacon-chain.md#new-switch_to_compounding_validator +func switch_to_compounding_validator*( + state: var electra.BeaconState, index: ValidatorIndex) = + let validator = addr state.validators.mitem(index) + if has_eth1_withdrawal_credential(validator[]): + validator.withdrawal_credentials.data[0] = COMPOUNDING_WITHDRAWAL_PREFIX + queue_excess_active_balance(state, index) + # https://github.com/ethereum/consensus-specs/blob/v1.4.0-beta.5/specs/capella/beacon-chain.md#new-get_expected_withdrawals func get_expected_withdrawals*( state: capella.BeaconState | deneb.BeaconState | electra.BeaconState): diff --git a/beacon_chain/spec/presets.nim b/beacon_chain/spec/presets.nim index a6db78d39..6b79b5e1a 100644 --- a/beacon_chain/spec/presets.nim +++ b/beacon_chain/spec/presets.nim @@ -77,6 +77,8 @@ type MIN_PER_EPOCH_CHURN_LIMIT*: uint64 CHURN_LIMIT_QUOTIENT*: uint64 MAX_PER_EPOCH_ACTIVATION_CHURN_LIMIT*: uint64 + MIN_PER_EPOCH_CHURN_LIMIT_ELECTRA*: uint64 + MAX_PER_EPOCH_ACTIVATION_EXIT_CHURN_LIMIT*: uint64 # Fork choice # TODO PROPOSER_SCORE_BOOST*: uint64 @@ -151,8 +153,6 @@ when const_preset == "mainnet": # Free-form short name of the network that this configuration applies to - known # canonical network names include: # * 'mainnet' - there can be only one - # * 'prater' - testnet - # * 'ropsten' - testnet # * 'sepolia' - testnet # * 'holesky' - testnet # Must match the regex: [a-z0-9\-] @@ -228,6 +228,10 @@ when const_preset == "mainnet": CHURN_LIMIT_QUOTIENT: 65536, # [New in Deneb:EIP7514] 2**3 (= 8) MAX_PER_EPOCH_ACTIVATION_CHURN_LIMIT: 8, + # [New in Electra:EIP7251] 2**7 * 10**9 (= 128,000,000,000) + MIN_PER_EPOCH_CHURN_LIMIT_ELECTRA: 128000000000'u64, + # [New in Electra:EIP7251] 2**8 * 10**9 (= 256,000,000,000) + MAX_PER_EPOCH_ACTIVATION_EXIT_CHURN_LIMIT: 256000000000'u64, # Deposit contract # --------------------------------------------------------------- @@ -298,8 +302,6 @@ elif const_preset == "gnosis": # Free-form short name of the network that this configuration applies to - known # canonical network names include: # * 'mainnet' - there can be only one - # * 'prater' - testnet - # * 'ropsten' - testnet # * 'sepolia' - testnet # * 'holesky' - testnet # Must match the regex: [a-z0-9\-] @@ -376,6 +378,10 @@ elif const_preset == "gnosis": CHURN_LIMIT_QUOTIENT: 4096, # [New in Deneb:EIP7514] 2**3 (= 8) MAX_PER_EPOCH_ACTIVATION_CHURN_LIMIT: 8, + # [New in Electra:EIP7251] 2**7 * 10**9 (= 128,000,000,000) (copied from EF mainnet) + MIN_PER_EPOCH_CHURN_LIMIT_ELECTRA: 128000000000'u64, + # [New in Electra:EIP7251] 2**8 * 10**9 (= 256,000,000,000) (copied from EF mainnet) + MAX_PER_EPOCH_ACTIVATION_EXIT_CHURN_LIMIT: 256000000000'u64, # Deposit contract # --------------------------------------------------------------- @@ -440,8 +446,6 @@ elif const_preset == "minimal": # Free-form short name of the network that this configuration applies to - known # canonical network names include: # * 'mainnet' - there can be only one - # * 'prater' - testnet - # * 'ropsten' - testnet # * 'sepolia' - testnet # * 'holesky' - testnet # Must match the regex: [a-z0-9\-] @@ -519,6 +523,10 @@ elif const_preset == "minimal": CHURN_LIMIT_QUOTIENT: 32, # [New in Deneb:EIP7514] [customized] MAX_PER_EPOCH_ACTIVATION_CHURN_LIMIT: 4, + # [New in Electra:EIP7251] 2**6 * 10**9 (= 64,000,000,000) + MIN_PER_EPOCH_CHURN_LIMIT_ELECTRA: 64000000000'u64, + # [New in Electra:EIP7251] 2**7 * 10**9 (= 128,000,000,000) + MAX_PER_EPOCH_ACTIVATION_EXIT_CHURN_LIMIT: 128000000000'u64, # Deposit contract diff --git a/beacon_chain/spec/state_transition_epoch.nim b/beacon_chain/spec/state_transition_epoch.nim index 87d8b6df3..f1a5e1110 100644 --- a/beacon_chain/spec/state_transition_epoch.nim +++ b/beacon_chain/spec/state_transition_epoch.nim @@ -867,19 +867,13 @@ from std/heapqueue import HeapQueue, `[]`, len, push, replace # https://github.com/ethereum/consensus-specs/blob/v1.4.0-beta.6/specs/phase0/beacon-chain.md#registry-updates func process_registry_updates*( - cfg: RuntimeConfig, state: var ForkyBeaconState, cache: var StateCache): - Result[void, cstring] = + cfg: RuntimeConfig, + state: var (phase0.BeaconState | altair.BeaconState | + bellatrix.BeaconState | capella.BeaconState | + deneb.BeaconState), + cache: var StateCache): Result[void, cstring] = ## Process activation eligibility and ejections - # Make visible, e.g., - # https://github.com/status-im/nimbus-eth2/pull/608 - # https://github.com/sigp/lighthouse/pull/657 - let epoch {.used.} = get_current_epoch(state) - trace "process_registry_updates validator balances", - balances=state.balances, - active_validator_indices=get_active_validator_indices(state, epoch), - epoch=epoch - # is_active_validator(...) is activation_epoch <= epoch < exit_epoch, # and changes here to either activation_epoch or exit_epoch only take # effect with a compute_activation_exit_epoch(...) delay of, based on @@ -939,6 +933,32 @@ func process_registry_updates*( ok() +# https://github.com/ethereum/consensus-specs/blob/v1.5.0-alpha.0/specs/electra/beacon-chain.md#updated--process_registry_updates +func process_registry_updates*( + cfg: RuntimeConfig, state: var electra.BeaconState, cache: var StateCache): + Result[void, cstring] = + # Process activation eligibility and ejections + for index in 0 ..< state.validators.len: + let validator = state.validators.item(index) + if is_eligible_for_activation_queue(validator): + # Usually not too many at once, so do this individually + state.validators.mitem(index).activation_eligibility_epoch = + get_current_epoch(state) + 1 + + if is_active_validator(validator, get_current_epoch(state)) and + distinctBase(validator.effective_balance) <= cfg.EJECTION_BALANCE: + discard ? initiate_validator_exit( + cfg, state, ValidatorIndex(index), static(default(ExitQueueInfo)), cache) + + # Activate all eligible validators + let activation_epoch = + compute_activation_exit_epoch(get_current_epoch(state)) + for index in 0 ..< state.validators.len: + if is_eligible_for_activation(state, state.validators.item(index)): + state.validators.mitem(index).activation_epoch = activation_epoch + + ok() + # https://github.com/ethereum/consensus-specs/blob/v1.4.0-beta.7/specs/phase0/beacon-chain.md#slashings # https://github.com/ethereum/consensus-specs/blob/v1.4.0/specs/altair/beacon-chain.md#slashings # https://github.com/ethereum/consensus-specs/blob/v1.4.0/specs/bellatrix/beacon-chain.md#slashings @@ -1166,6 +1186,66 @@ func process_historical_summaries_update*( ok() +# https://github.com/ethereum/consensus-specs/blob/v1.5.0-alpha.0/specs/electra/beacon-chain.md#new-process_pending_balance_deposits +func process_pending_balance_deposits*( + cfg: RuntimeConfig, state: var electra.BeaconState, + cache: var StateCache) = + let + available_for_processing = state.deposit_balance_to_consume + + get_activation_exit_churn_limit(cfg, state, cache) + var + processed_amount = 0.Gwei + next_deposit_index = 0.Gwei + + for deposit in state.pending_balance_deposits: + if processed_amount + deposit.amount > available_for_processing: + break + debugRaiseAssert "do this validatorindex check properly (it truncates)" + increase_balance(state, deposit.index.ValidatorIndex, deposit.amount) + processed_amount += deposit.amount + inc next_deposit_index + + state.pending_balance_deposits = + HashList[PendingBalanceDeposit, Limit PENDING_BALANCE_DEPOSITS_LIMIT].init( + state.pending_balance_deposits.asSeq[next_deposit_index..^1]) + + if len(state.pending_balance_deposits) == 0: + state.deposit_balance_to_consume = Gwei(0) + else: + state.deposit_balance_to_consume = + available_for_processing - processed_amount + +# https://github.com/ethereum/consensus-specs/blob/v1.5.0-alpha.0/specs/electra/beacon-chain.md#new-process_pending_consolidations +func process_pending_consolidations*(cfg: RuntimeConfig, state: var electra.BeaconState) = + var next_pending_consolidation = 0 + for pending_consolidation in state.pending_consolidations: + let source_validator = + state.validators.item(pending_consolidation.source_index) + if source_validator.slashed: + next_pending_consolidation += 1 + continue + if source_validator.withdrawable_epoch > get_current_epoch(state): + break + + # Churn any target excess active balance of target and raise its max + debugRaiseAssert "truncating integer conversion" + switch_to_compounding_validator( + state, pending_consolidation.target_index.ValidatorIndex) + + # Move active balance to target. Excess balance is withdrawable. + debugRaiseAssert "Truncating" + let active_balance = get_active_balance( + state, pending_consolidation.source_index.ValidatorIndex) + decrease_balance( + state, pending_consolidation.source_index.ValidatorIndex, active_balance) + increase_balance( + state, pending_consolidation.target_index.ValidatorIndex, active_balance) + inc next_pending_consolidation + + state.pending_consolidations = + HashList[PendingConsolidation, Limit PENDING_CONSOLIDATIONS_LIMIT].init( + state.pending_consolidations.asSeq[next_pending_consolidation..^1]) + # https://github.com/ethereum/consensus-specs/blob/v1.4.0/specs/phase0/beacon-chain.md#epoch-processing proc process_epoch*( cfg: RuntimeConfig, state: var phase0.BeaconState, flags: UpdateFlags, @@ -1273,7 +1353,52 @@ proc process_epoch*( # https://github.com/ethereum/consensus-specs/blob/v1.4.0-beta.5/specs/capella/beacon-chain.md#epoch-processing proc process_epoch*( cfg: RuntimeConfig, - state: var (capella.BeaconState | deneb.BeaconState | electra.BeaconState), + state: var (capella.BeaconState | deneb.BeaconState), + flags: UpdateFlags, cache: var StateCache, info: var altair.EpochInfo): + Result[void, cstring] = + let epoch = get_current_epoch(state) + trace "process_epoch", epoch + + info.init(state) + + # https://github.com/ethereum/consensus-specs/blob/v1.4.0/specs/altair/beacon-chain.md#justification-and-finalization + process_justification_and_finalization(state, info.balances, flags) + + # state.slot hasn't been incremented yet. + if strictVerification in flags: + # Rule 2/3/4 finalization results in the most pessimal case. The other + # three finalization rules finalize more quickly as long as the any of + # the finalization rules triggered. + if (epoch >= 2 and state.current_justified_checkpoint.epoch + 2 < epoch) or + (epoch >= 3 and state.finalized_checkpoint.epoch + 3 < epoch): + fatal "The network did not finalize", + epoch, finalizedEpoch = state.finalized_checkpoint.epoch + quit 1 + + process_inactivity_updates(cfg, state, info) + + # https://github.com/ethereum/consensus-specs/blob/v1.4.0/specs/altair/beacon-chain.md#rewards-and-penalties + process_rewards_and_penalties(cfg, state, info) + + # https://github.com/ethereum/consensus-specs/blob/v1.4.0-beta.6/specs/phase0/beacon-chain.md#registry-updates + ? process_registry_updates(cfg, state, cache) + + # https://github.com/ethereum/consensus-specs/blob/v1.4.0/specs/altair/beacon-chain.md#slashings + process_slashings(state, info.balances.current_epoch) + + process_eth1_data_reset(state) + process_effective_balance_updates(state) + process_slashings_reset(state) + process_randao_mixes_reset(state) + ? process_historical_summaries_update(state) # [Modified in Capella] + process_participation_flag_updates(state) + process_sync_committee_updates(state) + + ok() + +# https://github.com/ethereum/consensus-specs/blob/v1.4.0-beta.5/specs/capella/beacon-chain.md#epoch-processing +proc process_epoch*( + cfg: RuntimeConfig, state: var electra.BeaconState, flags: UpdateFlags, cache: var StateCache, info: var altair.EpochInfo): Result[void, cstring] = let epoch = get_current_epoch(state) diff --git a/tests/consensus_spec/electra/test_fixture_state_transition_epoch.nim b/tests/consensus_spec/electra/test_fixture_state_transition_epoch.nim index 98340d007..e9bd6bc15 100644 --- a/tests/consensus_spec/electra/test_fixture_state_transition_epoch.nim +++ b/tests/consensus_spec/electra/test_fixture_state_transition_epoch.nim @@ -38,15 +38,17 @@ const SyncCommitteeDir = RootDir/"sync_committee_updates" RewardsAndPenaltiesDir = RootDir/"rewards_and_penalties" HistoricalSummariesUpdateDir = RootDir/"historical_summaries_update" + PendingBalanceDepositsDir = RootDir/"pending_balance_deposits" + PendingConsolidationsDir = RootDir/"pending_consolidations" -debugRaiseAssert "check Electra state transition epoch subdirectories" -doAssert true or (toHashSet(mapIt(toSeq(walkDir(RootDir, relative = false)), it.path)) - +doAssert (toHashSet(mapIt(toSeq(walkDir(RootDir, relative = false)), it.path)) - toHashSet([SyncCommitteeDir])) == toHashSet([ JustificationFinalizationDir, InactivityDir, RegistryUpdatesDir, SlashingsDir, Eth1DataResetDir, EffectiveBalanceUpdatesDir, SlashingsResetDir, RandaoMixesResetDir, ParticipationFlagDir, - RewardsAndPenaltiesDir, HistoricalSummariesUpdateDir]) + RewardsAndPenaltiesDir, HistoricalSummariesUpdateDir, + PendingBalanceDepositsDir, PendingConsolidationsDir]) template runSuite( suiteDir, testName: string, transitionProc: untyped): untyped = @@ -95,10 +97,8 @@ runSuite(RewardsAndPenaltiesDir, "Rewards and penalties"): # Registry updates # --------------------------------------------------------------- -when false: - debugRaiseAssert "re-enable registry updates tests in Electra state transition epoch checks" - runSuite(RegistryUpdatesDir, "Registry updates"): - process_registry_updates(cfg, state, cache) +runSuite(RegistryUpdatesDir, "Registry updates"): + process_registry_updates(cfg, state, cache) # Slashings # --------------------------------------------------------------- @@ -142,6 +142,18 @@ runSuite(ParticipationFlagDir, "Participation flag updates"): process_participation_flag_updates(state) Result[void, cstring].ok() +# Pending balance deposits +# --------------------------------------------------------------- +runSuite(PendingBalanceDepositsDir, "Pending balance deposits"): + process_pending_balance_deposits(cfg, state, cache) + Result[void, cstring].ok() + +# Pending consolidations +# --------------------------------------------------------------- +runSuite(PendingConsolidationsDir, "Pending consolidations"): + process_pending_consolidations(cfg, state) + Result[void, cstring].ok() + # Sync committee updates # ---------------------------------------------------------------