diff --git a/tests/checklists/eip7732.md b/tests/checklists/eip7732.md new file mode 100644 index 0000000000..57d051e5d6 --- /dev/null +++ b/tests/checklists/eip7732.md @@ -0,0 +1,1438 @@ +# EIP-7732 Test Checklist + +## Test Formats + +| Format | Handler | Test File | Tests | +| ------------------ | ------------------------- | ------------------------------------------- | ----- | +| `operations` | `execution_payload_bid` | `test_process_execution_payload_bid.py` | 19 | +| `operations` | `execution_payload` | `test_process_execution_payload.py` | 18 | +| `operations` | `payload_attestation` | `test_process_payload_attestation.py` | 8 | +| `operations` | `attestation` | `test_process_attestation.py` | 13 | +| `operations` | `proposer_slashing` | `test_process_proposer_slashing.py` | 3 | +| `epoch_processing` | `builder_pending_payments` | `test_process_builder_pending_payments.py` | 8 | +| `sanity` | `slots` | `test_slots.py` | 2 | + + + +- [Test Formats](#test-formats) +- [Operations Format Tests](#operations-format-tests) + - [Execution Payload Bid](#execution-payload-bid) + - [Execution Payload](#execution-payload) + - [Payload Attestation](#payload-attestation) + - [Attestation](#attestation) + - [Proposer Slashing](#proposer-slashing) +- [Epoch Processing Format Tests](#epoch-processing-format-tests) + - [Builder Pending Payments](#builder-pending-payments) +- [Sanity Format Tests](#sanity-format-tests) + - [Slots](#slots) + + + +## Operations Format Tests + +Tests from block processing operations that process individual block components. + +### Execution Payload Bid + +Handler: `execution_payload_bid` + +#### `test_process_execution_payload_bid_valid_self_build` + +##### Status + +Implemented ✅ + +##### Description + +Proposer can self-build by submitting a bid with their own validator index and +zero value. + +##### Scenario + +Proposer creates a valid execution payload bid with `builder_index` equal to +`proposer_index` and `value = 0`. + +##### Expectation + +Bid is accepted, `latest_execution_payload_bid` is updated in state, and no +pending payment is created since `value` is zero. + +#### `test_process_execution_payload_bid_valid_builder` + +##### Status + +Implemented ✅ + +##### Description + +Registered builder can submit a valid bid with non-zero value. + +##### Scenario + +A validator with builder withdrawal credentials (0x03) submits a bid with +sufficient balance to cover the bid value plus `MIN_ACTIVATION_BALANCE` and any +pending payments/withdrawals. + +##### Expectation + +Bid is accepted, `latest_execution_payload_bid` is updated, builder balance +remains unchanged, and a pending payment is created in the +`builder_pending_payments` queue with `weight = 0` and +`withdrawable_epoch = FAR_FUTURE_EPOCH`. + +#### `test_process_execution_payload_bid_valid_builder_zero_value` + +##### Status + +Implemented ✅ + +##### Description + +Registered builder can submit a bid with zero value. + +##### Scenario + +A validator with builder withdrawal credentials submits a bid with `value = 0`. + +##### Expectation + +Bid is accepted and `latest_execution_payload_bid` is updated. No pending +payment is created since `value` is zero. + +#### `test_process_execution_payload_bid_invalid_signature` + +##### Status + +Implemented ✅ + +##### Description + +Bid with invalid signature is rejected. + +##### Scenario + +Submit a bid with an invalid BLS signature. + +##### Expectation + +Processing fails with assertion error. + +#### `test_process_execution_payload_bid_inactive_builder` + +##### Status + +Implemented ✅ + +##### Description + +Inactive builder cannot submit bids. + +##### Scenario + +Builder with `exit_epoch <= current_epoch` attempts to submit a bid. + +##### Expectation + +Processing fails because builder is not active. + +#### `test_process_execution_payload_bid_slashed_builder` + +##### Status + +Implemented ✅ + +##### Description + +Slashed builder cannot submit bids. + +##### Scenario + +Builder with `slashed = True` attempts to submit a bid. + +##### Expectation + +Processing fails because builder is slashed. + +#### `test_process_execution_payload_bid_self_build_non_zero_value` + +##### Status + +Implemented ✅ + +##### Description + +Self-build scenario with non-zero value is invalid. + +##### Scenario + +Proposer attempts to submit a bid where `builder_index` equals `proposer_index` +but `value > 0`. + +##### Expectation + +Processing fails because self-builds must use zero value. + +#### `test_process_execution_payload_bid_non_builder_non_zero_value` + +##### Status + +Implemented ✅ + +##### Description + +Non-builder validator cannot submit non-zero value bids. + +##### Scenario + +Validator without builder withdrawal credentials attempts to submit a bid with +`value > 0`. + +##### Expectation + +Processing fails because only registered builders can submit non-zero bids. + +#### `test_process_execution_payload_bid_non_builder_wrong_proposer` + +##### Status + +Implemented ✅ + +##### Description + +Non-builder validator can only self-build as proposer. + +##### Scenario + +Non-builder validator (without 0x03 credentials) attempts to submit a bid where +`builder_index` is not the `proposer_index`. + +##### Expectation + +Processing fails because non-builders must be the proposer to submit bids. + +#### `test_process_execution_payload_bid_insufficient_balance` + +##### Status + +Implemented ✅ + +##### Description + +Builder must have sufficient balance to cover bid value. + +##### Scenario + +Builder attempts to submit a bid where +`balance < value + MIN_ACTIVATION_BALANCE + pending_payments + pending_withdrawals`. + +##### Expectation + +Processing fails due to insufficient balance. + +#### `test_process_execution_payload_bid_excess_balance` + +##### Status + +Implemented ✅ + +##### Description + +Builder with excess balance (above `MAX_EFFECTIVE_BALANCE`) can submit large +bids using their full balance. + +##### Scenario + +Builder with 2048.25 ETH balance and 2048 ETH effective balance submits a bid +for 2016.25 ETH. + +##### Expectation + +Bid is accepted because balance check uses actual balance, not effective +balance. Pending payment is created correctly. + +#### `test_process_execution_payload_bid_insufficient_balance_with_pending_payments` + +##### Status + +Implemented ✅ + +##### Description + +Builder balance must account for existing pending payments. + +##### Scenario + +Builder has balance just above `MIN_ACTIVATION_BALANCE`, has existing pending +payments, and attempts to submit a bid that would exceed available balance when +accounting for all obligations. + +##### Expectation + +Processing fails because total obligations (bid + existing pending payments + +`MIN_ACTIVATION_BALANCE`) exceed balance. + +#### `test_process_execution_payload_bid_sufficient_balance_with_pending_payments` + +##### Status + +Implemented ✅ + +##### Description + +Builder can submit multiple bids if balance is sufficient for all pending +payments. + +##### Scenario + +Builder with sufficient balance has existing pending payments and submits a new +bid. Total obligations are within balance limits. + +##### Expectation + +Bid is accepted, new pending payment is added, and existing pending payments +remain unchanged. + +#### `test_process_execution_payload_bid_insufficient_balance_with_pending_withdrawals` + +##### Status + +Implemented ✅ + +##### Description + +Builder balance must account for pending withdrawals. + +##### Scenario + +Builder has balance just above `MIN_ACTIVATION_BALANCE`, has existing pending +withdrawals, and attempts to submit a bid that would exceed available balance. + +##### Expectation + +Processing fails because total obligations (bid + pending withdrawals + +`MIN_ACTIVATION_BALANCE`) exceed balance. + +#### `test_process_execution_payload_bid_sufficient_balance_with_pending_withdrawals` + +##### Status + +Implemented ✅ + +##### Description + +Builder can submit bids if balance is sufficient for pending withdrawals. + +##### Scenario + +Builder with sufficient balance has existing pending withdrawals and submits a +new bid. + +##### Expectation + +Bid is accepted, pending payment is added, and existing pending withdrawals +remain unchanged. + +#### `test_process_execution_payload_bid_wrong_slot` + +##### Status + +Implemented ✅ + +##### Description + +Bid slot must match the block slot. + +##### Scenario + +Submit a bid where `bid.slot != state.slot`. + +##### Expectation + +Processing fails due to slot mismatch. + +#### `test_process_execution_payload_bid_wrong_parent_block_hash` + +##### Status + +Implemented ✅ + +##### Description + +Bid `parent_block_hash` must match state's `latest_block_hash`. + +##### Scenario + +Submit a bid with incorrect `parent_block_hash`. + +##### Expectation + +Processing fails due to parent hash mismatch. + +#### `test_process_execution_payload_bid_wrong_parent_block_root` + +##### Status + +Implemented ✅ + +##### Description + +Bid `parent_block_root` must match the block's `parent_root`. + +##### Scenario + +Submit a bid with incorrect `parent_block_root`. + +##### Expectation + +Processing fails due to parent root mismatch. + +#### `test_process_execution_payload_bid_wrong_prev_randao` + +##### Status + +Implemented ✅ + +##### Description + +Bid `prev_randao` must match `get_randao_mix` for the current epoch. + +##### Scenario + +Submit a bid with incorrect `prev_randao` value. + +##### Expectation + +Processing fails due to randao mismatch. + +### Execution Payload + +Handler: `execution_payload` + +#### `test_process_execution_payload_valid` + +##### Status + +Implemented ✅ + +##### Description + +Valid execution payload can be processed with separate builder and non-zero +payment. + +##### Scenario + +Process an execution payload envelope that matches the committed bid, with a +separate builder (not proposer) and non-zero payment value. + +##### Expectation + +Payload is accepted, `execution_payload_availability` bit is set, +`latest_block_hash` is updated, pending payment is converted to pending +withdrawal with correct `withdrawable_epoch`, and pending payment slot is +cleared. + +#### `test_process_execution_payload_self_build_zero_value` + +##### Status + +Implemented ✅ + +##### Description + +Valid self-build scenario with zero value payload. + +##### Scenario + +Proposer delivers their own payload (`builder_index` equals `proposer_index`) +with zero bid value. + +##### Expectation + +Payload is accepted, state is updated correctly, and no withdrawal is created +since value is zero. + +#### `test_process_execution_payload_large_payment_churn_impact` + +##### Status + +Implemented ✅ + +##### Description + +Large builder payments correctly impact exit churn tracking. + +##### Scenario + +Process a payload with a very large payment amount (500 ETH) that requires +multiple epochs to process through the exit queue. + +##### Expectation + +Payload is accepted, pending withdrawal is created with `withdrawable_epoch` +calculated based on churn limits, and exit churn state variables are updated +correctly. + +#### `test_process_execution_payload_with_blob_commitments` + +##### Status + +Implemented ✅ + +##### Description + +Payload with blob KZG commitments is validated correctly. + +##### Scenario + +Process a payload that includes `blob_kzg_commitments`, which must match the +`blob_kzg_commitments_root` in the committed bid. + +##### Expectation + +Payload is accepted when commitments match the bid, and builder payment is +processed correctly. + +#### `test_process_execution_payload_with_execution_requests` + +##### Status + +Implemented ✅ + +##### Description + +Payload with execution requests (deposits, withdrawals, consolidations) is +processed correctly. + +##### Scenario + +Process a payload that includes execution requests. Deposit requests should be +added to `pending_deposits`. + +##### Expectation + +Payload is accepted, execution requests are processed (deposits added to pending +queue), and builder payment is processed correctly. + +#### `test_process_execution_payload_invalid_signature` + +##### Status + +Implemented ✅ + +##### Description + +Payload envelope with invalid signature is rejected. + +##### Scenario + +Submit an execution payload envelope with an invalid BLS signature. + +##### Expectation + +Processing fails with assertion error. + +#### `test_process_execution_payload_wrong_beacon_block_root` + +##### Status + +Implemented ✅ + +##### Description + +Envelope `beacon_block_root` must match the block root. + +##### Scenario + +Submit an envelope with incorrect `beacon_block_root`. + +##### Expectation + +Processing fails due to beacon block root mismatch. + +#### `test_process_execution_payload_wrong_slot` + +##### Status + +Implemented ✅ + +##### Description + +Envelope slot must match `state.slot`. + +##### Scenario + +Submit an envelope with `envelope.slot != state.slot`. + +##### Expectation + +Processing fails due to slot mismatch. + +#### `test_process_execution_payload_wrong_builder_index` + +##### Status + +Implemented ✅ + +##### Description + +Envelope `builder_index` must match the committed bid's `builder_index`. + +##### Scenario + +Submit an envelope with a different `builder_index` than what was committed in +the bid. + +##### Expectation + +Processing fails due to builder index mismatch. + +#### `test_process_execution_payload_wrong_blob_commitments_root` + +##### Status + +Implemented ✅ + +##### Description + +Blob commitments must match the committed bid's `blob_kzg_commitments_root`. + +##### Scenario + +Submit an envelope with `blob_kzg_commitments` that produce a different hash +than `bid.blob_kzg_commitments_root`. + +##### Expectation + +Processing fails due to blob commitments mismatch. + +#### `test_process_execution_payload_wrong_gas_limit` + +##### Status + +Implemented ✅ + +##### Description + +Payload `gas_limit` must match the committed bid's `gas_limit`. + +##### Scenario + +Submit a payload with `gas_limit != bid.gas_limit`. + +##### Expectation + +Processing fails due to gas limit mismatch. + +#### `test_process_execution_payload_wrong_block_hash` + +##### Status + +Implemented ✅ + +##### Description + +Payload `block_hash` must match the committed bid's `block_hash`. + +##### Scenario + +Submit a payload with `block_hash != bid.block_hash`. + +##### Expectation + +Processing fails due to block hash mismatch. + +#### `test_process_execution_payload_wrong_parent_hash` + +##### Status + +Implemented ✅ + +##### Description + +Payload `parent_hash` must match `state.latest_block_hash`. + +##### Scenario + +Submit a payload with incorrect `parent_hash`. + +##### Expectation + +Processing fails due to parent hash mismatch. + +#### `test_process_execution_payload_wrong_prev_randao` + +##### Status + +Implemented ✅ + +##### Description + +Payload `prev_randao` must match the committed bid's `prev_randao`. + +##### Scenario + +Submit a payload with `prev_randao != bid.prev_randao`. + +##### Expectation + +Processing fails due to `prev_randao` mismatch. + +#### `test_process_execution_payload_bid_prev_randao_mismatch` + +##### Status + +Implemented ✅ + +##### Description + +Both committed bid `prev_randao` and payload `prev_randao` must match. + +##### Scenario + +Setup a bid with one `prev_randao` value, then submit a payload with a different +`prev_randao` value. + +##### Expectation + +Processing fails because `payload.prev_randao` must equal `bid.prev_randao`. + +#### `test_process_execution_payload_wrong_timestamp` + +##### Status + +Implemented ✅ + +##### Description + +Payload timestamp must match expected slot timestamp. + +##### Scenario + +Submit a payload with incorrect timestamp. + +##### Expectation + +Processing fails due to timestamp mismatch. + +#### `test_process_execution_payload_max_blob_commitments_valid` + +##### Status + +Implemented ✅ + +##### Description + +Payload with maximum allowed blob commitments is valid. + +##### Scenario + +Submit a payload with exactly `MAX_BLOBS_PER_BLOCK` commitments. + +##### Expectation + +Payload is accepted and builder payment is processed correctly. + +#### `test_process_execution_payload_execution_engine_invalid` + +##### Status + +Implemented ✅ + +##### Description + +Payload rejected by execution engine is invalid. + +##### Scenario + +Submit a payload that the execution engine's `verify_and_notify_new_payload` +returns `False` for. + +##### Expectation + +Processing fails because execution engine rejected the payload. + +### Payload Attestation + +Handler: `payload_attestation` + +#### `test_process_payload_attestation_payload_present` + +##### Status + +Implemented ✅ + +##### Description + +PTC members can attest that payload was present. + +##### Scenario + +PTC members submit a valid payload attestation with `payload_present = True`. + +##### Expectation + +Attestation is processed successfully. + +#### `test_process_payload_attestation_payload_not_present` + +##### Status + +Implemented ✅ + +##### Description + +PTC members can attest that payload was not present. + +##### Scenario + +PTC members submit a valid payload attestation with `payload_present = False`. + +##### Expectation + +Attestation is processed successfully. + +#### `test_process_payload_attestation_partial_participation` + +##### Status + +Implemented ✅ + +##### Description + +Payload attestation with partial PTC participation is valid. + +##### Scenario + +Only half of PTC members participate in the attestation. + +##### Expectation + +Attestation is processed successfully with partial participation. + +#### `test_process_payload_attestation_invalid_beacon_block_root` + +##### Status + +Implemented ✅ + +##### Description + +Payload attestation with wrong beacon block root is rejected. + +##### Scenario + +Submit a payload attestation with `beacon_block_root` that doesn't match the +expected block root. + +##### Expectation + +Processing fails due to beacon block root mismatch. + +#### `test_process_payload_attestation_future_slot` + +##### Status + +Implemented ✅ + +##### Description + +Payload attestation for future slot is invalid. + +##### Scenario + +Attempt to attest to current slot instead of previous slot. + +##### Expectation + +Processing fails because attestations must be for previous slot only. + +#### `test_process_payload_attestation_too_old_slot` + +##### Status + +Implemented ✅ + +##### Description + +Payload attestation for slot too far in the past is invalid. + +##### Scenario + +Attempt to attest to a slot more than 1 slot in the past. + +##### Expectation + +Processing fails because attestations must be for exactly the previous slot. + +#### `test_process_payload_attestation_invalid_signature` + +##### Status + +Implemented ✅ + +##### Description + +Payload attestation with invalid signature is rejected. + +##### Scenario + +Submit a payload attestation with invalid BLS signature. + +##### Expectation + +Processing fails due to signature verification failure. + +#### `test_process_payload_attestation_no_attesting_indices` + +##### Status + +Implemented ✅ + +##### Description + +Payload attestation with no attesting indices is invalid. + +##### Scenario + +Submit a payload attestation where no PTC members are attesting (empty +`aggregation_bits`). + +##### Expectation + +Processing fails because at least one PTC member must attest. + +### Attestation + +Handler: `attestation` + +#### `test_invalid_attestation_data_index_too_high` + +##### Status + +Implemented ✅ + +##### Description + +Attestation `data.index` must be 0 or 1 in Gloas. + +##### Scenario + +Submit an attestation with `data.index = 2` (or higher). + +##### Expectation + +Processing fails because only indices 0 and 1 are valid in Gloas. + +#### `test_valid_attestation_data_index_zero_previous_slot` + +##### Status + +Implemented ✅ + +##### Description + +Attestation with index = 0 is valid for previous slot attestations. + +##### Scenario + +Submit a previous-slot attestation with `data.index = 0`. + +##### Expectation + +Attestation is processed successfully. + +#### `test_valid_attestation_data_index_one_previous_slot_matching_blockroot` + +##### Status + +Implemented ✅ + +##### Description + +Attestation with index = 1 is valid when blockroot matches the slot. + +##### Scenario + +Attest to a missed slot (no block proposed) where the attestation inherits the +previous block's root. Set `data.index = 1`. + +##### Expectation + +Attestation is processed successfully because `is_matching_blockroot = True` and +`is_current_blockroot = False`. + +#### `test_valid_attestation_data_index_one_previous_slot_current_blockroot` + +##### Status + +Implemented ✅ + +##### Description + +Attestation with index = 1 is valid when blockroot is current (different from +parent). + +##### Scenario + +Submit an attestation with custom block root that differs from the previous +slot's block root. Set `data.index = 1`. + +##### Expectation + +Attestation is processed successfully because `is_current_blockroot = True`. + +#### `test_valid_same_slot_attestation_index_zero` + +##### Status + +Implemented ✅ + +##### Description + +Same-slot attestations must use index = 0. + +##### Scenario + +Submit a same-slot attestation with `data.index = 0`. + +##### Expectation + +Attestation is processed successfully. + +#### `test_invalid_same_slot_attestation_index_one` + +##### Status + +Implemented ✅ + +##### Description + +Same-slot attestations with index = 1 are invalid. + +##### Scenario + +Submit a same-slot attestation with `data.index = 1`. + +##### Expectation + +Processing fails because same-slot attestations must use index = 0. + +#### `test_builder_payment_weight_tracking` + +##### Status + +Implemented ✅ + +##### Description + +Same-slot attestations correctly accumulate weight for builder pending payments. + +##### Scenario + +Submit a same-slot attestation for a slot with a non-zero builder pending +payment. + +##### Expectation + +The pending payment's weight increases by the attesting validator's effective +balance. + +#### `test_builder_payment_weight_no_double_counting` + +##### Status + +Implemented ✅ + +##### Description + +Builder payment weights don't double count when validator already has +participation flags set. + +##### Scenario + +Submit two attestations from the same validator for the same slot. The second +attestation should not increase weight since participation flags are already +set. + +##### Expectation + +First attestation increases weight, second attestation does not increase weight +(no double counting). + +#### `test_matching_payload_true_same_slot` + +##### Status + +Implemented ✅ + +##### Description + +Same-slot attestations always have `is_matching_payload = True` regardless of +availability bit. + +##### Scenario + +Submit a same-slot attestation for a slot where `execution_payload_availability` +bit is 0. + +##### Expectation + +Attestation is processed successfully because same-slot always sets +`is_matching_payload = True`. + +#### `test_matching_payload_true_historical_slot` + +##### Status + +Implemented ✅ + +##### Description + +Historical slot attestations have `is_matching_payload = True` when `data.index` +matches the payload availability bit. + +##### Scenario + +Submit an attestation for a historical slot with `data.index = 1` and +`execution_payload_availability[slot] = 1`. + +##### Expectation + +Attestation is processed successfully and gets participation flags because +payload matches. + +#### `test_matching_payload_false_historical_slot` + +##### Status + +Implemented ✅ + +##### Description + +Historical slot attestations have `is_matching_payload = False` when +`data.index` doesn't match availability bit. + +##### Scenario + +Submit an attestation for a historical slot with `data.index = 1` but +`execution_payload_availability[slot] = 0`. + +##### Expectation + +Attestation is processed but does not get head flag due to mismatched payload. + +#### `test_matching_payload_gets_head_flag` + +##### Status + +Implemented ✅ + +##### Description + +Attestation gets `TIMELY_HEAD_FLAG` when both blockroot and payload match. + +##### Scenario + +Submit an attestation where `is_matching_blockroot = True` and +`is_matching_payload = True`. + +##### Expectation + +Attestation gets `TIMELY_HEAD_FLAG` because both conditions are met. + +#### `test_mismatched_payload_no_head_flag` + +##### Status + +Implemented ✅ + +##### Description + +Attestation does not get `TIMELY_HEAD_FLAG` when payload doesn't match, even if +blockroot matches. + +##### Scenario + +Submit an attestation where `is_matching_blockroot = True` but +`is_matching_payload = False`. + +##### Expectation + +Attestation does not get `TIMELY_HEAD_FLAG` because `is_matching_head` requires +both conditions. + +### Proposer Slashing + +Handler: `proposer_slashing` + +#### `test_builder_payment_deletion_current_epoch` + +##### Status + +Implemented ✅ + +##### Description + +Builder payment is deleted when proposer is slashed in the same epoch as the +proposal. + +##### Scenario + +Create a builder pending payment for a slot in the current epoch, then slash the +proposer for that slot. + +##### Expectation + +The builder pending payment is removed (replaced with empty payment) from the +queue. + +#### `test_builder_payment_deletion_previous_epoch` + +##### Status + +Implemented ✅ + +##### Description + +Builder payment is deleted when proposer is slashed in the epoch after the +proposal. + +##### Scenario + +Create a builder pending payment for a slot in the previous epoch, then slash +the proposer for that slot in the current epoch. + +##### Expectation + +The builder pending payment is removed from the queue. + +#### `test_builder_payment_deletion_too_late` + +##### Status + +Implemented ✅ + +##### Description + +Builder payment is NOT deleted when slashing comes more than two epochs after +the proposal. + +##### Scenario + +Create a builder pending payment, advance more than two epochs, then slash the +proposer. + +##### Expectation + +The builder pending payment is not affected because the slashing is too late +(outside the 2-epoch window). + +## Epoch Processing Format Tests + +Tests from epoch boundary processing that update state at the end of an epoch. + +### Builder Pending Payments + +Handler: `builder_pending_payments` + +#### `test_process_builder_pending_payments_empty_queue` + +##### Status + +Implemented ✅ + +##### Description + +Processing with no pending payments ready for withdrawal. + +##### Scenario + +Process epoch transition with pending payments in the queue but all below quorum +threshold. + +##### Expectation + +Queue is rotated, no withdrawals are added, and payments are moved but not +processed. + +#### `test_process_builder_pending_payments_below_quorum` + +##### Status + +Implemented ✅ + +##### Description + +Payments below quorum threshold are not processed. + +##### Scenario + +A pending payment has `weight < get_builder_payment_quorum_threshold`. + +##### Expectation + +Payment is rotated out of the first epoch's slots but no withdrawal is created. + +#### `test_process_builder_pending_payments_equal_quorum` + +##### Status + +Implemented ✅ + +##### Description + +Payments equal to quorum threshold are not processed (strict inequality). + +##### Scenario + +A pending payment has `weight` exactly equal to +`get_builder_payment_quorum_threshold()`. + +##### Expectation + +Payment is rotated out but no withdrawal is created because weight must be +strictly greater than quorum. + +#### `test_process_builder_pending_payments_above_quorum` + +##### Status + +Implemented ✅ + +##### Description + +Payments above quorum threshold are processed into withdrawals. + +##### Scenario + +A pending payment has `weight > get_builder_payment_quorum_threshold()`. + +##### Expectation + +Payment is converted to a withdrawal, added to `builder_pending_withdrawals` +with correct `withdrawable_epoch`, and removed from pending_payments queue. + +#### `test_process_builder_pending_payments_multiple_above_quorum` + +##### Status + +Implemented ✅ + +##### Description + +Multiple payments above quorum are all processed. + +##### Scenario + +Multiple pending payments all have weight > quorum threshold. + +##### Expectation + +All qualifying payments are converted to withdrawals with correct amounts and +withdrawable epochs. + +#### `test_process_builder_pending_payments_mixed_weights` + +##### Status + +Implemented ✅ + +##### Description + +Mix of payments above and below quorum are handled correctly. + +##### Scenario + +Process payments with varying weights: some below, some equal to, and some above +quorum threshold. + +##### Expectation + +Only payments with weight > quorum are processed into withdrawals. Others are +rotated out without withdrawal creation. + +#### `test_process_builder_pending_payments_queue_rotation` + +##### Status + +Implemented ✅ + +##### Description + +Payment queue is properly rotated after epoch processing. + +##### Scenario + +Both epochs of the queue (`2 * SLOTS_PER_EPOCH` entries) contain payments. + +##### Expectation + +After processing, the second epoch becomes the first epoch, and the new second +epoch is cleared (all zeros). + +#### `test_process_builder_pending_payments_large_amount_churn_impact` + +##### Status + +Implemented ✅ + +##### Description + +Large payment amounts correctly impact exit churn limits. + +##### Scenario + +Process a payment with `amount = MAX_EFFECTIVE_BALANCE_ELECTRA` that requires +multiple epochs to process through exit queue. + +##### Expectation + +Withdrawal is created with `withdrawable_epoch` calculated based on churn +limits, and `exit_balance_to_consume` is updated correctly. + +## Sanity Format Tests + +Tests from sanity checks that verify basic protocol invariants and state +transitions. + +### Slots + +Handler: `slots` + +#### `test_execution_payload_availability_reset_from_set` + +##### Status + +Implemented ✅ + +##### Description + +Slot processing correctly resets `execution_payload_availability` bit from 1 to +0 for the next slot. + +##### Scenario + +Set the next slot's availability bit to 1, then process one slot. + +##### Expectation + +The next slot's availability bit is reset to 0 during slot processing. + +#### `test_execution_payload_availability_reset_from_unset` + +##### Status + +Implemented ✅ + +##### Description + +Slot processing correctly keeps `execution_payload_availability` bit at 0 when +already unset. + +##### Scenario + +Set the next slot's availability bit to 0, then process one slot. + +##### Expectation + +The next slot's availability bit remains 0 (no change needed).