From b0f58a58b6a3af0e2c7a315241534f5b670bc4b0 Mon Sep 17 00:00:00 2001 From: tersec Date: Thu, 25 Apr 2024 18:50:54 +0000 Subject: [PATCH] add EF consensus spec test Electra consolidation operations fixture (#6235) --- ConsensusSpecPreset-mainnet.md | 17 +++- ConsensusSpecPreset-minimal.md | 26 ++++++- beacon_chain/spec/beaconstate.nim | 37 +++++++++ beacon_chain/spec/state_transition_block.nim | 78 +++++++++++++++++++ .../electra/test_fixture_operations.nim | 21 ++++- 5 files changed, 176 insertions(+), 3 deletions(-) diff --git a/ConsensusSpecPreset-mainnet.md b/ConsensusSpecPreset-mainnet.md index 4b846c7f9..471bd916e 100644 --- a/ConsensusSpecPreset-mainnet.md +++ b/ConsensusSpecPreset-mainnet.md @@ -2598,6 +2598,21 @@ OK: 14/14 Fail: 0/14 Skip: 0/14 + [Valid] EF - Electra - Operations - Block Header - basic_block_header OK ``` OK: 6/6 Fail: 0/6 Skip: 0/6 +## EF - Electra - Operations - Consolidation [Preset: mainnet] +```diff ++ [Invalid] EF - Electra - Operations - Consolidation - invalid_before_specified_epoch OK ++ [Invalid] EF - Electra - Operations - Consolidation - invalid_different_credentials OK ++ [Invalid] EF - Electra - Operations - Consolidation - invalid_exited_source OK ++ [Invalid] EF - Electra - Operations - Consolidation - invalid_exited_target OK ++ [Invalid] EF - Electra - Operations - Consolidation - invalid_inactive_source OK ++ [Invalid] EF - Electra - Operations - Consolidation - invalid_inactive_target OK ++ [Invalid] EF - Electra - Operations - Consolidation - invalid_no_execution_withdrawal_cred OK ++ [Invalid] EF - Electra - Operations - Consolidation - invalid_not_enough_consolidation_chu OK ++ [Invalid] EF - Electra - Operations - Consolidation - invalid_source_equals_target OK ++ [Invalid] EF - Electra - Operations - Consolidation - invalid_source_signature OK ++ [Invalid] EF - Electra - Operations - Consolidation - invalid_target_signature OK +``` +OK: 11/11 Fail: 0/11 Skip: 0/11 ## EF - Electra - Operations - Execution Layer Withdrawal Request [Preset: mainnet] ```diff + [Valid] EF - Electra - Operations - Execution Layer Withdrawal Request - activation_epoc OK @@ -3382,4 +3397,4 @@ OK: 69/88 Fail: 0/88 Skip: 19/88 OK: 3/3 Fail: 0/3 Skip: 0/3 ---TOTAL--- -OK: 2705/2724 Fail: 0/2724 Skip: 19/2724 +OK: 2716/2735 Fail: 0/2735 Skip: 19/2735 diff --git a/ConsensusSpecPreset-minimal.md b/ConsensusSpecPreset-minimal.md index 501541a4c..c94fd7894 100644 --- a/ConsensusSpecPreset-minimal.md +++ b/ConsensusSpecPreset-minimal.md @@ -2725,6 +2725,30 @@ OK: 14/14 Fail: 0/14 Skip: 0/14 + [Valid] EF - Electra - Operations - Block Header - basic_block_header OK ``` OK: 6/6 Fail: 0/6 Skip: 0/6 +## EF - Electra - Operations - Consolidation [Preset: minimal] +```diff ++ [Invalid] EF - Electra - Operations - Consolidation - invalid_before_specified_epoch OK ++ [Invalid] EF - Electra - Operations - Consolidation - invalid_different_credentials OK ++ [Invalid] EF - Electra - Operations - Consolidation - invalid_exited_source OK ++ [Invalid] EF - Electra - Operations - Consolidation - invalid_exited_target OK ++ [Invalid] EF - Electra - Operations - Consolidation - invalid_inactive_source OK ++ [Invalid] EF - Electra - Operations - Consolidation - invalid_inactive_target OK ++ [Invalid] EF - Electra - Operations - Consolidation - invalid_no_execution_withdrawal_cred OK ++ [Invalid] EF - Electra - Operations - Consolidation - invalid_not_enough_consolidation_chu OK ++ [Invalid] EF - Electra - Operations - Consolidation - invalid_source_equals_target OK ++ [Invalid] EF - Electra - Operations - Consolidation - invalid_source_signature OK ++ [Invalid] EF - Electra - Operations - Consolidation - invalid_target_signature OK ++ [Valid] EF - Electra - Operations - Consolidation - basic_consolidation_in_current_conso OK ++ [Valid] EF - Electra - Operations - Consolidation - basic_consolidation_in_new_consolida OK ++ [Valid] EF - Electra - Operations - Consolidation - basic_consolidation_with_compounding OK ++ [Valid] EF - Electra - Operations - Consolidation - basic_consolidation_with_insufficien OK ++ [Valid] EF - Electra - Operations - Consolidation - basic_consolidation_with_preexisting OK ++ [Valid] EF - Electra - Operations - Consolidation - consolidation_balance_larger_than_ch OK ++ [Valid] EF - Electra - Operations - Consolidation - consolidation_balance_through_two_ch OK ++ [Valid] EF - Electra - Operations - Consolidation - consolidation_churn_limit_balance OK ++ [Valid] EF - Electra - Operations - Consolidation - multiple_consolidations_above_churn OK +``` +OK: 20/20 Fail: 0/20 Skip: 0/20 ## EF - Electra - Operations - Execution Layer Withdrawal Request [Preset: minimal] ```diff + [Valid] EF - Electra - Operations - Execution Layer Withdrawal Request - activation_epoc OK @@ -3675,4 +3699,4 @@ OK: 185/207 Fail: 0/207 Skip: 22/207 OK: 3/3 Fail: 0/3 Skip: 0/3 ---TOTAL--- -OK: 2967/2989 Fail: 0/2989 Skip: 22/2989 +OK: 2987/3009 Fail: 0/3009 Skip: 22/3009 diff --git a/beacon_chain/spec/beaconstate.nim b/beacon_chain/spec/beaconstate.nim index 018bfa0f8..2c23a3a58 100644 --- a/beacon_chain/spec/beaconstate.nim +++ b/beacon_chain/spec/beaconstate.nim @@ -189,6 +189,13 @@ func get_activation_exit_churn_limit*( 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-get_consolidation_churn_limit +func get_consolidation_churn_limit*( + cfg: RuntimeConfig, state: electra.BeaconState, cache: var StateCache): + Gwei = + get_balance_churn_limit(cfg, state, cache) - + get_activation_exit_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, @@ -218,6 +225,36 @@ func compute_exit_epoch_and_update_churn*( state.earliest_exit_epoch +# https://github.com/ethereum/consensus-specs/blob/v1.5.0-alpha.0/specs/electra/beacon-chain.md#new-compute_consolidation_epoch_and_update_churn +func compute_consolidation_epoch_and_update_churn*( + cfg: RuntimeConfig, state: var electra.BeaconState, + consolidation_balance: Gwei, cache: var StateCache): Epoch = + var earliest_consolidation_epoch = max(state.earliest_consolidation_epoch, + compute_activation_exit_epoch(get_current_epoch(state))) + let per_epoch_consolidation_churn = + get_consolidation_churn_limit(cfg, state, cache) + + # New epoch for consolidations. + var consolidation_balance_to_consume = + if state.earliest_consolidation_epoch < earliest_consolidation_epoch: + per_epoch_consolidation_churn + else: + state.consolidation_balance_to_consume + + # Consolidation doesn't fit in the current earliest epoch. + if consolidation_balance > consolidation_balance_to_consume: + let + balance_to_process = consolidation_balance - consolidation_balance_to_consume + additional_epochs = (balance_to_process - 1.Gwei) div per_epoch_consolidation_churn + 1 + earliest_consolidation_epoch += additional_epochs + consolidation_balance_to_consume += additional_epochs * per_epoch_consolidation_churn + + # Consume the balance and update state variables. + state.consolidation_balance_to_consume = consolidation_balance_to_consume - consolidation_balance + state.earliest_consolidation_epoch = earliest_consolidation_epoch + + state.earliest_consolidation_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, diff --git a/beacon_chain/spec/state_transition_block.nim b/beacon_chain/spec/state_transition_block.nim index 113cf0bb9..ea30a4dc2 100644 --- a/beacon_chain/spec/state_transition_block.nim +++ b/beacon_chain/spec/state_transition_block.nim @@ -962,6 +962,84 @@ func process_execution_layer_withdrawal_request*( withdrawable_epoch: withdrawable_epoch, )) +# https://github.com/ethereum/consensus-specs/blob/v1.5.0-alpha.0/specs/electra/beacon-chain.md#consolidations +func process_consolidation*( + cfg: RuntimeConfig, state: var electra.BeaconState, + signed_consolidation: SignedConsolidation, cache: var StateCache): + Result[void, cstring] = + # If the pending consolidations queue is full, no consolidations are allowed + # in the block + if not(lenu64(state.pending_consolidations) < PENDING_CONSOLIDATIONS_LIMIT): + return err("Consolidation: too many pending consolidations already") + + # If there is too little available consolidation churn limit, no + # consolidations are allowed in the block + if not (get_consolidation_churn_limit(cfg, state, cache) > + static(MIN_ACTIVATION_BALANCE.Gwei)): + return err("Consolidation: insufficient available consolidation churn limit") + + let consolidation = signed_consolidation.message + + # Verify that source != target, so a consolidation cannot be used as an exit. + if not(consolidation.source_index != consolidation.target_index): + return err("Consolidation: a consolidation cannot be used as an exit") + + let + source_validator = addr state.validators.mitem(consolidation.source_index) + target_validator = state.validators.item(consolidation.target_index) + + # Verify the source and the target are active + let current_epoch = get_current_epoch(state) + + if not is_active_validator(source_validator[], current_epoch): + return err("Consolidation: source validator not active") + if not is_active_validator(target_validator, current_epoch): + return err("Consolidation: target validator not active") + + # Verify exits for source and target have not been initiated + if not (source_validator[].exit_epoch == FAR_FUTURE_EPOCH): + return err("Consolidation: exit for source validator already initiated") + if not (target_validator.exit_epoch == FAR_FUTURE_EPOCH): + return err("Consolidation: exit for target validator already initiated") + + # Consolidations must specify an epoch when they become valid; they are not + # valid before then + if not (current_epoch >= consolidation.epoch): + return err("Consolidation: consolidation not valid before specified epoch") + + # Verify the source and the target have Execution layer withdrawal credentials + if not has_execution_withdrawal_credential(source_validator[]): + return err("Consolidation: source doesn't have execution layer withdrawal credentials") + if not has_execution_withdrawal_credential(target_validator): + return err("Consolidation: target doesn't have execution layer withdrawal credentials") + + # Verify the same withdrawal address + if not (source_validator[].withdrawal_credentials.data.toOpenArray(12, 31) == + target_validator.withdrawal_credentials.data.toOpenArray(12, 31)): + return err("Consolidation: source and target don't have same withdrawal address") + + debugRaiseAssert "add signature checking for process_consolidation, which oddly isn't tested" + # Verify consolidation is signed by the source and the target + #let + # domain = compute_domain( + # DOMAIN_CONSOLIDATION, genesis_validators_root=state.genesis_validators_root) + # signing_root = compute_signing_root(consolidation, domain) + # pubkeys = [source_validator.pubkey, target_validator.pubkey] + #assert bls.FastAggregateVerify(pubkeys, signing_root, signed_consolidation.signature) + + # Initiate source validator exit and append pending consolidation + source_validator[].exit_epoch = compute_consolidation_epoch_and_update_churn( + cfg, state, source_validator[].effective_balance, cache) + source_validator[].withdrawable_epoch = + source_validator[].exit_epoch + cfg.MIN_VALIDATOR_WITHDRAWABILITY_DELAY + debugRaiseAssert "check HashList add return value" + discard state.pending_consolidations.add(PendingConsolidation( + source_index: consolidation.source_index, + target_index: consolidation.target_index + )) + + ok() + # https://github.com/ethereum/consensus-specs/blob/v1.4.0/specs/deneb/beacon-chain.md#kzg_commitment_to_versioned_hash func kzg_commitment_to_versioned_hash*( kzg_commitment: KzgCommitment): VersionedHash = diff --git a/tests/consensus_spec/electra/test_fixture_operations.nim b/tests/consensus_spec/electra/test_fixture_operations.nim index 7a829e3c3..7f864214b 100644 --- a/tests/consensus_spec/electra/test_fixture_operations.nim +++ b/tests/consensus_spec/electra/test_fixture_operations.nim @@ -148,7 +148,26 @@ suite baseDescription & "BLS to execution change " & preset(): OpBlsToExecutionChangeDir, suiteName, "BLS to execution change", "address_change", applyBlsToExecutionChange, path) -debugRaiseAssert "consolidations tests" +suite baseDescription & "Consolidation " & preset(): + proc applyConsolidation( + preState: var electra.BeaconState, + signed_consolidation: SignedConsolidation): + Result[void, cstring] = + var cache: StateCache + process_consolidation( + defaultRuntimeConfig, preState, signed_consolidation, cache) + + for path in walkTests(OpConsolidationDir): + if path in [ + "multiple_consolidations_below_churn", # missing consolidation.ssz + "multiple_consolidations_equal_churn", # missing consolidation.ssz + "multiple_consolidations_equal_twice_churn", # missing consolidation.ssz + "invalid_exceed_pending_consolidations_limit", # apparently invalid prestate SSZ + ]: + continue + runTest[SignedConsolidation, typeof applyConsolidation]( + OpConsolidationDir, suiteName, "Consolidation", "consolidation", + applyConsolidation, path) when false: from ".."/".."/".."/beacon_chain/bloomfilter import constructBloomFilter