# Equivalent Partition Analysis: `process_deposit_request` *Generated from test specification analysis* ## Overview This document identifies equivalence classes for testing the `process_deposit_request` function in the GLOAS fork. Equivalence partitioning divides the input space into classes where all values within a class should produce equivalent behavior. The GLOAS fork significantly modifies this function from Electra by adding **builder routing logic**: deposits can now be routed to either builders (applied immediately) or validators (queued in `pending_deposits`), based on pubkey existence and withdrawal credential prefix. ______________________________________________________________________ ## Input Parameters Summary | Parameter | Type | Description | | ----------------- | ---------------- | ----------------------------------------------- | | `deposit_request` | `DepositRequest` | Contains pubkey, withdrawal_credentials, amount, signature, index | | `state` | `BeaconState` | Current beacon state with builders and validators registries | ### `DepositRequest` Fields | Field | Type | Value Space | | ------------------------ | -------------- | ------------------------------------------------ | | `pubkey` | `BLSPubkey` | `Bytes48` - identifies target builder/validator | | `withdrawal_credentials` | `Bytes32` | First byte: `0x00`=BLS, `0x01`=ETH1, `0x02`=compounding, `0x03`=Builder | | `amount` | `Gwei` | `uint64` in [0, 2^64-1] | | `signature` | `BLSSignature` | `Bytes96` - proof of possession (required for new builders only) | | `index` | `uint64` | Deposit contract index (unused in GLOAS routing) | ______________________________________________________________________ ## Equivalence Partitions ### P1: Pubkey Existence - Builder Registry | Partition ID | Class | Effect | Description | | ------------ | ---------------------- | ------------------------ | ------------------------------------------ | | P1.1 | Pubkey exists in builders | Builder path (top-up) | `deposit_request.pubkey in builder_pubkeys` | | P1.2 | Pubkey not in builders | Check other conditions | `deposit_request.pubkey not in builder_pubkeys` | **Boundary Values:** | Boundary ID | Partition | Boundary Condition | Description | | ----------- | --------- | ----------------------------- | ------------------------------------ | | P1.1B1 | P1.1 | `len(state.builders) == 1` | Single builder in registry | | P1.1B2 | P1.1 | Builder at index 0 | First builder in registry | | P1.1B3 | P1.1 | Builder at last index | Last builder in registry | **Test Coverage:** | Partition | Test(s) | Covered | | --------- | ---------------------------------------------------------------- | ------- | | P1.1 | `test_process_deposit_request__builder_top_up`, `test_process_deposit_request__builder_top_up_large`, `test_process_deposit_request__routing__builder_pubkey_validator_credentials` | ✅ | | P1.2 | `test_process_deposit_request__new_builder`, routing tests | ✅ | ______________________________________________________________________ ### P2: Pubkey Existence - Validator Registry | Partition ID | Class | Effect | Description | | ------------ | ------------------------- | ----------------------------- | -------------------------------------------- | | P2.1 | Pubkey exists in validators | Validator path (queued) | `deposit_request.pubkey in validator_pubkeys` | | P2.2 | Pubkey not in validators | Check credential prefix | `deposit_request.pubkey not in validator_pubkeys` | **Test Coverage:** | Partition | Test(s) | Covered | | --------- | ------------------------------------------------------------------------------------------ | ------- | | P2.1 | `test_process_deposit_request__routing__validator_pubkey_builder_credentials`, `test_process_deposit_request__routing__validator_pubkey_validator_credentials` | ✅ | | P2.2 | `test_process_deposit_request__new_builder`, `test_process_deposit_request__routing__new_pubkey_validator_credentials` | ✅ | ______________________________________________________________________ ### P3: Withdrawal Credential Prefix | Partition ID | Class | Effect | Description | | ------------ | ---------------------- | --------------------- | ----------------------------------- | | P3.1 | Builder prefix (0x03) | Builder path eligible | `is_builder_withdrawal_credential() == True` | | P3.2 | BLS prefix (0x00) | Validator path | BLS withdrawal credentials | | P3.3 | ETH1 prefix (0x01) | Validator path | ETH1 address withdrawal credentials | | P3.4 | Compounding prefix (0x02) | Validator path | Compounding withdrawal credentials | **Test Coverage:** | Partition | Test(s) | Covered | | --------- | ---------------------------------------------------------------- | ------- | | P3.1 | `test_process_deposit_request__new_builder`, `test_process_deposit_request__routing__validator_pubkey_builder_credentials` | ✅ | | P3.2 | `test_process_deposit_request__routing__builder_pubkey_validator_credentials` (uses BLS prefix) | ✅ | | P3.3 | (not explicitly tested - assumed equivalent to P3.2) | ⚠️ Implicit | | P3.4 | (not explicitly tested - assumed equivalent to P3.2) | ⚠️ Implicit | ______________________________________________________________________ ### P4: Routing Decision (Composite) This partition represents the combined routing logic: ```python if is_builder or (is_builder_prefix and not is_validator): # Builder path else: # Validator path ``` | Partition ID | Pubkey Status | Credential Prefix | Route | Description | | ------------ | ------------------ | ----------------- | -------------- | ------------------------------- | | P4.1 | Existing builder | Any | Builder (top-up) | Builder pubkey wins regardless of credentials | | P4.2 | Existing validator | Any (incl 0x03) | Validator (queue) | Validator pubkey wins over builder credentials | | P4.3 | New pubkey | 0x03 (Builder) | Builder (new) | New builder created | | P4.4 | New pubkey | 0x00/0x01/0x02 | Validator (queue) | New validator queued | **Test Coverage:** | Partition | Test(s) | Covered | | --------- | -------------------------------------------------------------------------------- | ------- | | P4.1 | `test_process_deposit_request__builder_top_up`, `test_process_deposit_request__routing__builder_pubkey_validator_credentials` | ✅ | | P4.2 | `test_process_deposit_request__routing__validator_pubkey_builder_credentials` | ✅ | | P4.3 | `test_process_deposit_request__new_builder` | ✅ | | P4.4 | `test_process_deposit_request__routing__new_pubkey_validator_credentials`, `test_process_deposit_request__routing__validator_pubkey_validator_credentials` | ✅ | ______________________________________________________________________ ### P5: Deposit Amount | Partition ID | Class | Valid | Description | | ------------ | ---------------------- | ---------- | --------------------------------------- | | P5.1 | Minimum deposit | ✅ Valid | `amount == MIN_DEPOSIT_AMOUNT` | | P5.2 | Typical deposit | ✅ Valid | `MIN_DEPOSIT_AMOUNT < amount < MAX_EFFECTIVE_BALANCE` | | P5.3 | At max effective | ✅ Valid | `amount == MAX_EFFECTIVE_BALANCE` | | P5.4 | Above max effective | ✅ Valid | `amount > MAX_EFFECTIVE_BALANCE` | | P5.5 | Zero amount | ⚠️ Edge | `amount == 0` | | P5.6 | Below minimum | ❓ Unknown | `0 < amount < MIN_DEPOSIT_AMOUNT` | | P5.7 | Non-round amount | ✅ Valid | Amount with extra gwei (not whole ETH) | **Boundary Values:** Standard BVA requires testing at, just below, and just above each boundary point. | Boundary ID | Partition | Boundary Condition | Description | | ----------- | --------- | ------------------------------------- | ------------------------------------- | | P5.1B1 | P5.1 | `amount == MIN_DEPOSIT_AMOUNT` | At minimum valid deposit | | P5.2B1 | P5.2 | `amount == MIN_DEPOSIT_AMOUNT + 1` | Just above minimum (first typical) | | P5.2B2 | P5.2 | `amount == MAX_EFFECTIVE_BALANCE - 1` | Just below max (last typical) | | P5.3B1 | P5.3 | `amount == MAX_EFFECTIVE_BALANCE` | At maximum effective balance | | P5.4B1 | P5.4 | `amount == MAX_EFFECTIVE_BALANCE + 1` | Just above max effective | | P5.5B1 | P5.5 | `amount == 0` | Zero deposit edge case | | P5.6B1 | P5.6 | `amount == 1` | Minimum positive amount (1 gwei) | | P5.6B2 | P5.6 | `amount == MIN_DEPOSIT_AMOUNT - 1` | Just below minimum (max for P5.6) | **Test Coverage:** | Partition | Test(s) | Covered | | --------- | ---------------------------------------------------------------- | ------- | | P5.1 | `test_process_deposit_request__new_builder`, `test_process_deposit_request__builder_top_up` | ✅ | | P5.2 | `test_...__new_builder_large_amount`, `test_...__builder_top_up_large` (GLOAS) | ✅ | | P5.3 | `test_process_deposit_request_max_effective_balance_compounding` (Electra) | ✅ | | P5.4 | `test_process_deposit_request_greater_than_max_effective_balance_compounding` (Electra) | ✅ | | P5.5 | (not tested - zero amount) | ❌ Gap | | P5.6 | (not tested - below minimum amount) | ❌ Gap | | P5.7 | `test_process_deposit_request__new_builder_extra_gwei` | ✅ | ______________________________________________________________________ ### P6: Signature Validity (New Builder Only) Signature is only checked for **new** builder deposits (not for top-ups or validator deposits). | Partition ID | Class | Valid | Description | | ------------ | ------------------ | ---------- | ------------------------------------- | | P6.1 | Valid signature | ✅ Valid | `is_valid_deposit_signature() == True` | | P6.2 | Invalid signature | ❌ Invalid | `is_valid_deposit_signature() == False` (for new builder) | | P6.3 | Signature skipped | N/A | Top-up or validator deposit (signature not verified) | **Test Coverage:** | Partition | Test(s) | Covered | | --------- | ---------------------------------------------------------------- | ------- | | P6.1 | `test_process_deposit_request__new_builder` | ✅ | | P6.2 | `test_process_deposit_request__new_builder_invalid_sig` | ✅ | | P6.3 | `test_process_deposit_request__builder_top_up_invalid_sig` (proves signature skipped for top-up) | ✅ | ______________________________________________________________________ ### P7: Builder Index Allocation (New Builder) | Partition ID | Class | Effect | Description | | ------------ | ------------------------ | ----------------------- | ---------------------------------------------- | | P7.1 | Reusable slot exists | Slot reused | `builder.withdrawable_epoch <= current_epoch AND builder.balance == 0` | | P7.2 | No reusable slot | Append to registry | New index = `len(state.builders)` | | P7.3 | Multiple reusable slots | First slot reused | First matching slot in iteration order | **Boundary Values:** Reusability requires BOTH conditions: `withdrawable_epoch <= current_epoch AND balance == 0` *Epoch dimension:* | Boundary ID | Partition | Boundary Condition | Description | | ----------- | --------- | ---------------------------------------------- | --------------------------------- | | P7.1B1 | P7.1 | `withdrawable_epoch == current_epoch` | At boundary (just became reusable)| | P7.1B2 | P7.1 | `withdrawable_epoch == current_epoch - 1` | Below boundary (clearly reusable) | | P7.2B1 | P7.2 | `withdrawable_epoch == current_epoch + 1` | Above boundary (not yet reusable) | | P7.2B2 | P7.2 | `withdrawable_epoch == FAR_FUTURE_EPOCH` | Sentinel value (active builder) | *Balance dimension:* | Boundary ID | Partition | Boundary Condition | Description | | ----------- | --------- | ---------------------------------------------- | --------------------------------- | | P7.1B3 | P7.1 | `balance == 0` | At boundary (reusable) | | P7.2B3 | P7.2 | `balance == 1` | Just above zero (blocks reuse) | | P7.2B4 | P7.2 | `balance > 0` (typical) | Non-zero balance blocks reuse | **Test Coverage:** | Partition | Test(s) | Covered | | --------- | ---------------------------------------------------------------- | ------- | | P7.1 | `test_process_deposit_request__reuses_exited_builder_slot` | ✅ | | P7.2 | `test_process_deposit_request__new_builder` (appends to registry) | ✅ | | P7.3 | (not tested - multiple reusable slots scenario) | ❌ Gap | ______________________________________________________________________ ### P8: Builder Registry State | Partition ID | Class | Effect | Description | | ------------ | -------------------------- | ------------------- | ---------------------------------- | | P8.1 | Empty builders registry | New builder appended | `len(state.builders) == 0` | | P8.2 | Single builder in registry | Various | `len(state.builders) == 1` | | P8.3 | Multiple builders | Various | `len(state.builders) > 1` | **Boundary Values:** | Boundary ID | Partition | Boundary Condition | Description | | ----------- | --------- | -------------------------------------------- | ---------------------------------- | | P8.1B1 | P8.1 | `len(state.builders) == 0` | Empty registry | | P8.2B1 | P8.2 | `len(state.builders) == 1` | Single builder (boundary) | | P8.3B1 | P8.3 | `len(state.builders) == BUILDER_REGISTRY_LIMIT - 1` | Near limit | | P8.3B2 | P8.3 | `len(state.builders) == BUILDER_REGISTRY_LIMIT` | At limit (full registry) | **Test Coverage:** | Partition | Test(s) | Covered | | --------- | ---------------------------------------------------------------- | ---------- | | P8.1 | (not explicitly tested - state fixture includes builders) | ❌ Gap | | P8.2 | (not explicitly tested) | ⚠️ Implicit | | P8.3 | Most tests (state fixture includes multiple builders) | ✅ | ______________________________________________________________________ ### P9: Pending Deposits State (Validator Path) | Partition ID | Class | Effect | Description | | ------------ | ------------------------------ | ---------------------- | ------------------------------------- | | P9.1 | Empty pending_deposits | First deposit appended | `len(state.pending_deposits) == 0` | | P9.2 | Non-empty pending_deposits | Deposit appended | `len(state.pending_deposits) > 0` | | P9.3 | Near limit pending_deposits | Deposit appended | `len(state.pending_deposits) == PENDING_DEPOSITS_LIMIT - 1` | | P9.4 | At limit pending_deposits | Overflow? | `len(state.pending_deposits) == PENDING_DEPOSITS_LIMIT` | **Boundary Values:** | Boundary ID | Partition | Boundary Condition | Description | | ----------- | --------- | -------------------------------------------- | ------------------------------ | | P9.1B1 | P9.1 | `len == 0` | Empty (first deposit) | | P9.2B1 | P9.2 | `len == 1` | Single existing deposit | | P9.3B1 | P9.3 | `len == PENDING_DEPOSITS_LIMIT - 1` | One slot remaining | | P9.4B1 | P9.4 | `len == PENDING_DEPOSITS_LIMIT` | At limit (full) | **Test Coverage:** | Partition | Test(s) | Covered | | --------- | ---------------------------------------------------------------- | ---------- | | P9.1 | (not explicitly tested) | ⚠️ Implicit | | P9.2 | Validator routing tests | ✅ | | P9.3 | (not tested - near limit scenario) | ❌ Gap | | P9.4 | (not tested - at limit/overflow scenario) | ❌ Gap | ______________________________________________________________________ ## Inherited Partitions (from Electra) These partitions cover behavior inherited from Electra that applies to the **validator deposit path** in GLOAS. ### P10: Validator Deposit Type | Partition ID | Class | Effect | Description | | ------------ | ---------------------- | ------------------------- | -------------------------------------------- | | P10.1 | New validator | Added to pending_deposits | `pubkey not in validator_pubkeys` | | P10.2 | Existing validator | Top-up queued | `pubkey in validator_pubkeys` (balance added later) | **Test Coverage:** | Partition | Test(s) | Covered | | --------- | ---------------------------------------------------------------- | ------- | | P10.1 | `test_process_deposit_request_min_activation` (Electra), `test_...__routing__new_pubkey_validator_credentials` (GLOAS) | ✅ | | P10.2 | `test_process_deposit_request_top_up_min_activation` (Electra), `test_...__routing__validator_pubkey_validator_credentials` (GLOAS) | ✅ | ______________________________________________________________________ ### P11: PendingDeposit Field Correctness Verifies all fields are correctly copied from `DepositRequest` to `PendingDeposit`. | Partition ID | Field | Expectation | Description | | ------------ | ------------------------ | ---------------------------------------- | ------------------------------------- | | P11.1 | `pubkey` | `pending.pubkey == request.pubkey` | Pubkey copied correctly | | P11.2 | `withdrawal_credentials` | `pending.withdrawal_credentials == request.withdrawal_credentials` | Credentials copied correctly | | P11.3 | `amount` | `pending.amount == request.amount` | Amount copied correctly | | P11.4 | `signature` | `pending.signature == request.signature` | Signature stored (not verified here) | | P11.5 | `slot` | `pending.slot == state.slot` | Slot bound to current state slot | **Test Coverage:** | Partition | Test(s) | Covered | | --------- | ---------------------------------------------------------------- | ------- | | P11.1 | `test_process_deposit_request_min_activation` (Electra), `run_deposit_request_processing` helper verifies | ✅ | | P11.2 | `test_process_deposit_request_max_effective_balance_compounding` (Electra) | ✅ | | P11.3 | `test_process_deposit_request_extra_gwei` (Electra) - asserts exact amount | ✅ | | P11.4 | `test_process_deposit_request_invalid_sig` (Electra) - invalid sig still stored | ✅ | | P11.5 | `run_deposit_request_processing` helper (implicit in all validator path tests) | ⚠️ Implicit | ______________________________________________________________________ ### P12: Signature Verification (Validator Path) In Electra/GLOAS, signatures are **not verified** during `process_deposit_request`. They are stored and verified later during `process_pending_deposits`. | Partition ID | Class | Effect | Description | | ------------ | ------------------ | ------------------------- | ---------------------------------------- | | P12.1 | Valid signature | Deposit queued | Signature valid (verified later) | | P12.2 | Invalid signature | Deposit queued anyway | Signature stored, rejected during processing | **Test Coverage:** | Partition | Test(s) | Covered | | --------- | ---------------------------------------------------------------- | ------- | | P12.1 | `test_process_deposit_request_min_activation` (Electra) | ✅ | | P12.2 | `test_process_deposit_request_invalid_sig`, `test_process_deposit_request_top_up_invalid_sig` (Electra) | ✅ | ______________________________________________________________________ ### P13: Withdrawal Credential Types (Validator Path) | Partition ID | Class | Effect | Description | | ------------ | ------------------------- | --------------- | ---------------------------------------- | | P13.1 | BLS credentials (0x00) | Deposit queued | BLS withdrawal credentials | | P13.2 | ETH1 credentials (0x01) | Deposit queued | ETH1 address withdrawal credentials | | P13.3 | Compounding credentials (0x02) | Deposit queued | Compounding withdrawal credentials | **Test Coverage:** | Partition | Test(s) | Covered | | --------- | ---------------------------------------------------------------- | ------- | | P13.1 | `test_process_deposit_request_min_activation` (Electra - uses default BLS) | ✅ | | P13.2 | (not explicitly tested in Electra tests) | ❌ Gap | | P13.3 | `test_process_deposit_request_max_effective_balance_compounding`, `test_process_deposit_request_top_up_max_effective_balance_compounding` (Electra) | ✅ | ______________________________________________________________________ ### P14: Deposit Amount Boundaries (Validator Path) | Partition ID | Class | Effect | Description | | ------------ | ------------------------------- | --------------- | ---------------------------------------- | | P14.1 | Minimum activation balance | Deposit queued | `amount == MIN_ACTIVATION_BALANCE` | | P14.2 | Below minimum activation | Deposit queued | `amount < MIN_ACTIVATION_BALANCE` | | P14.3 | Maximum effective balance | Deposit queued | `amount == MAX_EFFECTIVE_BALANCE_ELECTRA` | | P14.4 | Above maximum effective balance | Deposit queued | `amount > MAX_EFFECTIVE_BALANCE_ELECTRA` | | P14.5 | Non-round gwei amount | Deposit queued | Amount not multiple of ETH | **Test Coverage:** | Partition | Test(s) | Covered | | --------- | ---------------------------------------------------------------- | ------- | | P14.1 | `test_process_deposit_request_min_activation` (Electra) | ✅ | | P14.2 | `test_process_deposit_request_top_up_still_less_than_min_activation` (Electra) | ✅ | | P14.3 | `test_process_deposit_request_max_effective_balance_compounding` (Electra) | ✅ | | P14.4 | `test_process_deposit_request_greater_than_max_effective_balance_compounding` (Electra) | ✅ | | P14.5 | `test_process_deposit_request_extra_gwei` (Electra) | ✅ | ______________________________________________________________________ ### P15: Deposit Requests Start Index (Electra Only) **Note:** This behavior was **removed in GLOAS**. Tests use `@with_all_phases_from_to(ELECTRA, GLOAS)` to exclude GLOAS. | Partition ID | Class | Effect | Description | | ------------ | ------------------------ | ----------------------------------- | ---------------------------------------- | | P15.1 | First deposit request | `start_index` set to `request.index` | `deposit_requests_start_index == UNSET` | | P15.2 | Subsequent deposit | `start_index` unchanged | `deposit_requests_start_index != UNSET` | **Test Coverage:** | Partition | Test(s) | Covered | | --------- | ---------------------------------------------------------------- | ------- | | P15.1 | `test_process_deposit_request_set_start_index` (Electra only) | ✅ | | P15.2 | `test_process_deposit_request_set_start_index_only_once` (Electra) | ✅ | ______________________________________________________________________ ## GLOAS-Specific Partitions ### P16: Builder vs Validator Priority This partition captures the GLOAS-specific routing priority rules. | Partition ID | Scenario | Priority Winner | Description | | ------------ | ------------------------------------- | --------------- | ------------------------------ | | P16.1 | Builder pubkey + Builder credentials | Builder | Builder pubkey takes precedence | | P16.2 | Builder pubkey + Validator credentials | Builder | Builder pubkey ignores credentials | | P16.3 | Validator pubkey + Builder credentials | Validator | Validator pubkey blocks new builder creation | | P16.4 | Validator pubkey + Validator credentials | Validator | Normal validator deposit | | P16.5 | New pubkey + Builder credentials | Builder | Create new builder | | P16.6 | New pubkey + Validator credentials | Validator | Queue new validator | **Test Coverage:** | Partition | Test(s) | Covered | | --------- | -------------------------------------------------------------------------------- | ------- | | P16.1 | (implicit - builder top-up with builder credentials is default) | ⚠️ Implicit | | P16.2 | `test_process_deposit_request__routing__builder_pubkey_validator_credentials` | ✅ | | P16.3 | `test_process_deposit_request__routing__validator_pubkey_builder_credentials` | ✅ | | P16.4 | `test_process_deposit_request__routing__validator_pubkey_validator_credentials` | ✅ | | P16.5 | `test_process_deposit_request__new_builder` | ✅ | | P16.6 | `test_process_deposit_request__routing__new_pubkey_validator_credentials` | ✅ | ______________________________________________________________________ ### P17: Execution Address Extraction (New Builder) The `Builder` container extracts `execution_address` from `withdrawal_credentials[12:]`. | Partition ID | Class | Effect | Description | | ------------ | ---------------------------- | ------------------------ | ------------------------------------- | | P17.1 | Valid 0x03 prefix format | Address extracted | `credentials[:1] == 0x03`, `credentials[1:12] == 0x00*11` | | P17.2 | Non-standard padding | Address extracted anyway | `credentials[1:12] != 0x00*11` but still processed | **Test Coverage:** | Partition | Test(s) | Covered | | --------- | ---------------------------------------------------------------- | ---------- | | P17.1 | `test_process_deposit_request__new_builder` | ✅ | | P17.2 | (not tested - non-standard padding) | ❌ Gap | ______________________________________________________________________ ## Coverage Gap Analysis ### Identified Gaps | Gap ID | Partition/Boundary | Description | Priority | Status | | ------ | ------------------ | --------------------------------------------------------- | -------- | ------ | | G1 | P5.5 | Zero amount deposit not tested | Medium | ✅ Covered | | G2 | P5.6 | Below minimum amount (`0 < amount < MIN_DEPOSIT_AMOUNT`) not tested | Medium | ✅ Covered | | G3 | P5.2B1 | `MIN_DEPOSIT_AMOUNT + 1` boundary not tested | Low | ✅ Covered | | G4 | P5.2B2 | `MAX_EFFECTIVE_BALANCE - 1` boundary not tested | Low | ✅ Covered | | G5 | P7.3 | Multiple reusable builder slots scenario not tested | Low | ✅ Covered | | G6 | P8.1 | Empty builders registry not explicitly tested | Low | ✅ Covered | | G7 | P9.3, P9.4 | Near-limit and at-limit pending_deposits not tested | Low | ⏭️ Skipped | | G8 | P3.3, P3.4 | ETH1 and Compounding prefixes not explicitly tested (GLOAS routing) | Low | ✅ Covered | | G9 | P17.2 | Non-standard withdrawal credential padding not tested | Low | ✅ Covered | | G10 | P7.1B1 | `withdrawable_epoch == current_epoch` boundary not explicit | Low | ✅ Covered | | G11 | P7.2B1 | `withdrawable_epoch == current_epoch + 1` not tested | Low | ✅ Covered | | G12 | P7.2B3 | `balance == 1` (minimum non-zero) not tested | Low | ✅ Covered | | G13 | P8.3B1, P8.3B2 | Near-limit and at-limit builder registry not tested | Low | ⏭️ Skipped | | G14 | P16.1 | Builder pubkey + builder credentials combination implicit | Low | ✅ Covered | | G15 | P13.2 | ETH1 credentials (0x01) not tested in validator path | Low | ✅ Covered | | G16 | P11.5 | Slot binding (`pending.slot == state.slot`) not explicitly verified | Low | ✅ Covered | | G17 | P1.1B1 | Single builder in registry boundary not tested | Low | ✅ Covered | | G18 | P1.1B3 | Builder at last index (top-up target) not tested | Low | ✅ Covered | ### Tests Implemented 17 tests were implemented covering 16 gaps (G7 and G13 skipped due to impractical limits). #### GLOAS Tests (`test/gloas/block_processing/test_process_deposit_request.py`) | Gap | Test Name | Description | |-----|-----------|-------------| | G1 | `test_process_deposit_request__new_builder_zero_amount` | Zero amount deposit creates builder with zero balance | | G2 | `test_process_deposit_request__new_builder_below_minimum` | Amount below MIN_DEPOSIT_AMOUNT accepted for builders | | G3 | `test_process_deposit_request__new_builder_extra_gwei` | Amount = MIN_DEPOSIT_AMOUNT + 1 (non-round amount) | | G4 | `test_process_deposit_request__new_builder_max_minus_one` | Amount = MAX_EFFECTIVE_BALANCE - 1 boundary | | G5 | `test_process_deposit_request__reuses_first_of_multiple_exited_slots` | First reusable slot selected when multiple available | | G6 | `test_process_deposit_request__new_builder_empty_registry` | New builder when registry is empty | | G8a | `test_process_deposit_request__routing__new_pubkey_eth1_credentials` | ETH1 prefix (0x01) routes to validator queue | | G8b | `test_process_deposit_request__routing__new_pubkey_compounding_credentials` | Compounding prefix (0x02) routes to validator queue | | G9 | `test_process_deposit_request__nonstandard_credential_padding` | Non-zero bytes in credentials[1:12] handled correctly | | G10 | `test_process_deposit_request__reuses_slot_at_current_epoch` | Slot reusable when withdrawable_epoch == current_epoch | | G11 | `test_process_deposit_request__no_reuse_future_epoch` | Slot NOT reusable when withdrawable_epoch == current_epoch + 1 | | G12 | `test_process_deposit_request__no_reuse_nonzero_balance` | Slot NOT reusable when balance == 1 (minimum non-zero) | | G14 | `test_process_deposit_request__builder_top_up_builder_credentials` | Builder pubkey + builder credentials routes to builder | | G17 | `test_process_deposit_request__builder_top_up_single_builder` | Top-up with single builder in registry | | G18 | `test_process_deposit_request__builder_top_up_last_index` | Top-up targeting last builder in registry | #### Electra Tests (`test/electra/block_processing/test_process_deposit_request.py`) | Gap | Test Name | Description | |-----|-----------|-------------| | G15 | `test_process_deposit_request_eth1_credentials` | ETH1 credentials (0x01) in validator path | | G16 | `test_process_deposit_request_pending_deposit_slot_binding` | Verify pending_deposit.slot == state.slot | #### Skipped Gaps | Gap | Reason | |-----|--------| | G7 | Testing PENDING_DEPOSITS_LIMIT (134217728) is impractical | | G13 | Testing BUILDER_REGISTRY_LIMIT is impractical (limit too large) | ### Recommendations (Historical) Each gap (G1-G18) had a corresponding recommendation: | Rec # | Gap ID | Recommendation | |-------|--------|----------------| | 1 | G1 | **Add P5.5 test**: Test zero amount deposit behavior | | 2 | G2 | **Add P5.6 test**: Test below-minimum amount (`0 < amount < MIN_DEPOSIT_AMOUNT`) | | 3 | G3 | **Add P5.2B1 boundary test**: Test `amount == MIN_DEPOSIT_AMOUNT + 1` | | 4 | G4 | **Add P5.2B2 boundary test**: Test `amount == MAX_EFFECTIVE_BALANCE - 1` | | 5 | G5 | **Add P7.3 test**: Test with multiple exited builders to verify first reusable slot is selected | | 6 | G6 | **Add P8.1 test**: Test new builder deposit when `state.builders` is empty | | 7 | G7 | **Add P9.3/P9.4 tests**: Test near-limit and at-limit pending_deposits | | 8 | G8 | **Add P3.3/P3.4 tests**: Explicitly test ETH1 and compounding credential prefixes route to validator queue | | 9 | G9 | **Add P17.2 test**: Test non-standard withdrawal credential padding (non-zero bytes in `credentials[1:12]`) | | 10 | G10 | **Add P7.1B1 boundary test**: Test `withdrawable_epoch == current_epoch` (exactly at boundary) | | 11 | G11 | **Add P7.2B1 boundary test**: Test `withdrawable_epoch == current_epoch + 1` (just above boundary) | | 12 | G12 | **Add P7.2B3 boundary test**: Test `balance == 1` (minimum non-zero balance blocks reuse) | | 13 | G13 | **Add P8.3 boundary tests**: Test near-limit and at-limit builder registry | | 14 | G14 | **Add P16.1 explicit test**: Test builder top-up with builder credentials (verify credentials ignored) | | 15 | G15 | **Add P13.2 test**: Test ETH1 credentials (0x01) explicitly in validator path | | 16 | G16 | **Add P11.5 test**: Explicitly verify `pending_deposit.slot == state.slot` | | 17 | G17 | **Add P1.1B1 boundary test**: Test with single builder in registry | | 18 | G18 | **Add P1.1B3 boundary test**: Test top-up targeting last builder in registry | ______________________________________________________________________ ## Complete Boundary Combination Matrix ### Legend - ✅ Explicit - Test specifically sets up this boundary condition - ⚠️ Implicit - Boundary may be exercised but not explicitly targeted - ❌ Not covered - No test targets this boundary ______________________________________________________________________ ### P1: Builder Pubkey Existence Boundaries | Boundary ID | Boundary Condition | Partition | Covered | Test | Coverage Details | | ----------- | -------------------------- | --------- | ----------- | --------------------------------------- | ----------------------------------------- | | P1.1B1 | `len(state.builders) == 1` | P1.1 | ❌ | - | State fixture has multiple builders; never tested with single builder | | P1.1B2 | Builder at index 0 | P1.1 | ✅ Explicit | `test_process_deposit_request__builder_top_up` | Uses `state.builders[0].pubkey` | | P1.1B3 | Builder at last index | P1.1 | ❌ | - | All top-up tests use `state.builders[0]` | ______________________________________________________________________ ### P5: Deposit Amount Boundaries | Boundary ID | Boundary Condition | Partition | Covered | Test | Coverage Details | | ----------- | ------------------------------------- | --------- | ----------- | ------------------------------------------------- | ------------------------------------------------ | | P5.1B1 | `amount == MIN_DEPOSIT_AMOUNT` | P5.1 | ✅ Explicit | `test_process_deposit_request__new_builder` | Uses `spec.MIN_DEPOSIT_AMOUNT` | | P5.2B1 | `amount == MIN_DEPOSIT_AMOUNT + 1` | P5.2 | ❌ | - | Just above minimum not explicitly tested | | P5.2B2 | `amount == MAX_EFFECTIVE_BALANCE - 1` | P5.2 | ❌ | - | Just below max not explicitly tested | | P5.3B1 | `amount == MAX_EFFECTIVE_BALANCE` | P5.3 | ✅ Explicit | `test_process_deposit_request_max_effective_balance_compounding` (Electra) | Uses `spec.MAX_EFFECTIVE_BALANCE_ELECTRA` | | P5.4B1 | `amount == MAX_EFFECTIVE_BALANCE + 1` | P5.4 | ✅ Explicit | `test_process_deposit_request_greater_than_max_effective_balance_compounding` (Electra) | Uses `MAX_EFFECTIVE_BALANCE_ELECTRA + EFFECTIVE_BALANCE_INCREMENT` | | P5.5B1 | `amount == 0` | P5.5 | ❌ | - | Zero amount not tested | | P5.6B1 | `amount == 1` | P5.6 | ❌ | - | Minimum positive amount (1 gwei) not tested | | P5.6B2 | `amount == MIN_DEPOSIT_AMOUNT - 1` | P5.6 | ❌ | - | Just below minimum not tested | ______________________________________________________________________ ### P7: Builder Index Allocation Boundaries Reusability requires BOTH: `withdrawable_epoch <= current_epoch AND balance == 0` *Epoch dimension:* | Boundary ID | Boundary Condition | Partition | Covered | Test | Coverage Details | | ----------- | ----------------------------------------- | --------- | ----------- | ------------------------------------------------------- | ----------------------------------------------------- | | P7.1B1 | `withdrawable_epoch == current_epoch` | P7.1 | ⚠️ Implicit | `test_...__reuses_exited_builder_slot` | Test uses `current_epoch - 1`; boundary not explicitly tested | | P7.1B2 | `withdrawable_epoch == current_epoch - 1` | P7.1 | ✅ Explicit | `test_process_deposit_request__reuses_exited_builder_slot` | Sets `withdrawable_epoch = current_epoch - 1` | | P7.2B1 | `withdrawable_epoch == current_epoch + 1` | P7.2 | ❌ | - | Just above boundary not tested | | P7.2B2 | `withdrawable_epoch == FAR_FUTURE_EPOCH` | P7.2 | ✅ Explicit | `test_process_deposit_request__new_builder` | Default active builder has FAR_FUTURE_EPOCH | *Balance dimension:* | Boundary ID | Boundary Condition | Partition | Covered | Test | Coverage Details | | ----------- | ----------------------------------------- | --------- | ----------- | ------------------------------------------------------- | ----------------------------------------------------- | | P7.1B3 | `balance == 0` | P7.1 | ✅ Explicit | `test_...__reuses_exited_builder_slot` | Sets `balance = 0` for reusability | | P7.2B3 | `balance == 1` | P7.2 | ❌ | - | Minimum non-zero (just above boundary) not tested | | P7.2B4 | `balance > 0` (typical) | P7.2 | ⚠️ Implicit | `test_process_deposit_request__new_builder` | Default builders have non-zero balance | ______________________________________________________________________ ### P8: Builder Registry State Boundaries | Boundary ID | Boundary Condition | Partition | Covered | Test | Coverage Details | | ----------- | ----------------------------------------------- | --------- | ----------- | ------------------------------------------------------- | ----------------------------------------------------- | | P8.1B1 | `len(state.builders) == 0` | P8.1 | ❌ | - | Empty registry not tested | | P8.2B1 | `len(state.builders) == 1` | P8.2 | ⚠️ Implicit | - | State fixture has multiple builders | | P8.3B1 | `len == BUILDER_REGISTRY_LIMIT - 1` | P8.3 | ❌ | - | Near limit not tested | | P8.3B2 | `len == BUILDER_REGISTRY_LIMIT` | P8.3 | ❌ | - | At limit not tested | ______________________________________________________________________ ### P9: Pending Deposits State Boundaries | Boundary ID | Boundary Condition | Partition | Covered | Test | Coverage Details | | ----------- | ----------------------------------------------- | --------- | ----------- | ------------------------------------------------------- | ----------------------------------------------------- | | P9.1B1 | `len(state.pending_deposits) == 0` | P9.1 | ⚠️ Implicit | Most tests | Initial state typically has empty pending_deposits | | P9.2B1 | `len(state.pending_deposits) == 1` | P9.2 | ⚠️ Implicit | - | Not explicitly tested | | P9.3B1 | `len == PENDING_DEPOSITS_LIMIT - 1` | P9.3 | ❌ | - | Near limit not tested | | P9.4B1 | `len == PENDING_DEPOSITS_LIMIT` | P9.4 | ❌ | - | At limit (overflow behavior) not tested | ______________________________________________________________________ ### Boundary Coverage Summary | Category | Total | Covered (✅) | Implicit (⚠️) | Not Covered (❌) | | ---------------------------- | ------ | ------------ | ------------- | ---------------- | | P1: Builder Pubkey | 3 | 1 | 0 | 2 | | P5: Deposit Amount | 8 | 3 | 0 | 5 | | P7: Builder Index Allocation | 7 | 3 | 2 | 2 | | P8: Builder Registry State | 4 | 0 | 1 | 3 | | P9: Pending Deposits State | 4 | 0 | 2 | 2 | | **Total** | **26** | **7** | **5** | **14** | **Explicit Boundary Coverage: 27% (7/26)** **Including Implicit: 46% (12/26)** ______________________________________________________________________ ## Complete Partition Combination Matrix ### Legend - ✅ Covered - Test exists for this combination - ❌ Not covered - No test exists - N/A - Combination not applicable ______________________________________________________________________ ### Core Routing Partitions (P1, P2, P3) These partitions determine the routing decision (builder vs validator path). #### Builder Path Combinations | # | P1 (Builder) | P2 (Validator) | P3 (Credential) | Route | Covered | Test | | --- | ------------ | -------------- | --------------- | -------- | ------- | ------------------------------------------------------------- | | 1 | P1.1 (exists) | Any | Any | Builder | ✅ | `test_process_deposit_request__builder_top_up` | | 2 | P1.1 (exists) | Any | P3.2 (BLS) | Builder | ✅ | `test_process_deposit_request__routing__builder_pubkey_validator_credentials` | | 3 | P1.2 (not) | P2.2 (not) | P3.1 (0x03) | Builder | ✅ | `test_process_deposit_request__new_builder` | #### Validator Path Combinations | # | P1 (Builder) | P2 (Validator) | P3 (Credential) | Route | Covered | Test | | --- | ------------ | -------------- | --------------- | --------- | ------- | ------------------------------------------------------------- | | 4 | P1.2 (not) | P2.1 (exists) | P3.1 (0x03) | Validator | ✅ | `test_process_deposit_request__routing__validator_pubkey_builder_credentials` | | 5 | P1.2 (not) | P2.1 (exists) | P3.2 (BLS) | Validator | ✅ | `test_process_deposit_request__routing__validator_pubkey_validator_credentials` | | 6 | P1.2 (not) | P2.2 (not) | P3.2 (BLS) | Validator | ✅ | `test_process_deposit_request__routing__new_pubkey_validator_credentials` | | 7 | P1.2 (not) | P2.2 (not) | P3.3 (ETH1) | Validator | ❌ | - | | 8 | P1.2 (not) | P2.2 (not) | P3.4 (Compound) | Validator | ❌ | - | ______________________________________________________________________ ### Builder Deposit Outcome Partitions #### New Builder Creation (P6 × P7) | # | P6 (Signature) | P7 (Index) | Outcome | Covered | Test | | --- | -------------- | -------------------- | ----------------- | ------- | ------------------------------------------------------- | | 9 | P6.1 (valid) | P7.2 (append) | Builder created | ✅ | `test_process_deposit_request__new_builder` | | 10 | P6.1 (valid) | P7.1 (reuse) | Slot reused | ✅ | `test_process_deposit_request__reuses_exited_builder_slot` | | 11 | P6.2 (invalid) | N/A | Rejected (no change) | ✅ | `test_process_deposit_request__new_builder_invalid_sig` | | 12 | P6.1 (valid) | P7.3 (multi-reuse) | First slot reused | ❌ | - | #### Builder Top-up (P6 × P5) | # | P6 (Signature) | P5 (Amount) | Outcome | Covered | Test | | --- | --------------- | ---------------- | ---------------- | ------- | ------------------------------------------------------- | | 13 | P6.3 (skipped) | P5.1 (minimum) | Balance increased | ✅ | `test_process_deposit_request__builder_top_up` | | 14 | P6.3 (skipped) | P5.3 (large) | Balance increased | ✅ | `test_process_deposit_request__builder_top_up_large` | | 15 | P6.3 (skipped) | P5.5 (zero) | No change? | ❌ | - | | 16 | P6.2 (invalid) | P5.1 (minimum) | Balance increased | ✅ | `test_process_deposit_request__builder_top_up_invalid_sig` | ______________________________________________________________________ ### Amount Variations (P5) | # | P5 (Amount) | Route | Covered | Test | | --- | ------------------------ | ------- | ------- | ------------------------------------------------------- | | 17 | P5.1 (minimum) | Builder | ✅ | `test_process_deposit_request__new_builder` | | 18 | P5.2 (typical) | Builder | ✅ | `test_...__new_builder_large_amount`, `test_...__builder_top_up_large` | | 19 | P5.3 (at max effective) | Builder | ⚠️ | `test_process_deposit_request_max_effective_balance_compounding` (Electra, validator path) | | 20 | P5.4 (above max) | Builder | ⚠️ | `test_..._greater_than_max_effective_balance_compounding` (Electra, validator path) | | 21 | P5.5 (zero) | Builder | ❌ | - | | 22 | P5.6 (below minimum) | Builder | ❌ | - | | 23 | P5.7 (non-round) | Builder | ✅ | `test_process_deposit_request__new_builder_extra_gwei` | ______________________________________________________________________ ### Summary: Complete Coverage Table | Combination # | Description | Covered | Test | | ------------- | ------------------------------------------------- | ------- | ------------------------------------------------------- | | 1 | Builder top-up (default credentials) | ✅ | `test_process_deposit_request__builder_top_up` | | 2 | Builder top-up (validator credentials ignored) | ✅ | `test_...__routing__builder_pubkey_validator_credentials` | | 3 | New builder (builder credentials) | ✅ | `test_process_deposit_request__new_builder` | | 4 | Validator pubkey + builder credentials → queue | ✅ | `test_...__routing__validator_pubkey_builder_credentials` | | 5 | Existing validator (validator credentials) | ✅ | `test_...__routing__validator_pubkey_validator_credentials` | | 6 | New validator (BLS credentials) | ✅ | `test_...__routing__new_pubkey_validator_credentials` | | 7 | New validator (ETH1 credentials) | ❌ | - | | 8 | New validator (compounding credentials) | ❌ | - | | 9 | New builder appended | ✅ | `test_process_deposit_request__new_builder` | | 10 | New builder reuses slot | ✅ | `test_...__reuses_exited_builder_slot` | | 11 | New builder rejected (invalid signature) | ✅ | `test_...__new_builder_invalid_sig` | | 12 | New builder reuses first of multiple slots | ❌ | - | | 13 | Builder top-up minimum amount | ✅ | `test_process_deposit_request__builder_top_up` | | 14 | Builder top-up large amount | ✅ | `test_process_deposit_request__builder_top_up_large` | | 15 | Builder top-up zero amount | ❌ | - | | 16 | Builder top-up invalid sig (still succeeds) | ✅ | `test_...__builder_top_up_invalid_sig` | | 17-20 | Various amount sizes for new builder | ✅ | Multiple tests | | 21 | Zero amount new builder (P5.5) | ❌ | - | | 22 | Below minimum amount new builder (P5.6) | ❌ | - | | 23 | Non-round amount new builder (P5.7) | ✅ | `test_...__new_builder_extra_gwei` | ______________________________________________________________________ ### Coverage Statistics | Category | Total | Covered | Not Covered | | ---------------------------------- | ------ | ------- | ----------- | | Routing combinations (1-8) | 8 | 6 | 2 | | Builder creation outcomes (9-12) | 4 | 3 | 1 | | Builder top-up outcomes (13-16) | 4 | 3 | 1 | | Amount variations (17-23) | 7 | 5 | 2 | | **Total** | **23** | **17** | **6** | **Coverage Rate: 74% (17/23 meaningful combinations)** ______________________________________________________________________ ### Uncovered Combinations Requiring Tests | Priority | # | Description | Suggested Test Name | | -------- | --- | ---------------------------------------------- | -------------------------------------------------- | | Low | 7 | New validator with ETH1 credentials | `test_...__routing__new_pubkey_eth1_credentials` | | Low | 8 | New validator with compounding credentials | `test_...__routing__new_pubkey_compounding_credentials` | | Low | 12 | Multiple reusable slots (first selected) | `test_...__reuses_first_of_multiple_exited_slots` | | Medium | 15 | Zero amount top-up (P5.5) | `test_...__builder_top_up_zero_amount` | | Medium | 21 | Zero amount new builder (P5.5) | `test_...__new_builder_zero_amount` | | Medium | 22 | Below minimum amount new builder (P5.6) | `test_...__new_builder_below_minimum_amount` | ______________________________________________________________________ ## Summary Statistics ### Partition Coverage | Category | Total Partitions | Covered | Gaps | | ---------------------------------- | ---------------- | ------- | ----- | | Core Routing (P1-P4) | 11 | 9 | 2 | | Builder Logic (P5-P9) | 17 | 12 | 5 | | **Inherited from Electra (P10-P15)** | **19** | **17** | **2** | | GLOAS-Specific (P16-P17) | 8 | 6 | 2 | | **Total** | **55** | **44** | **11**| **Overall Partition Coverage: 80%** ### Boundary Coverage | Category | Total | Covered (✅) | Implicit (⚠️) | Not Covered (❌) | | ---------------------------- | ------ | ------------ | ------------- | ---------------- | | P1: Builder Pubkey | 3 | 1 | 0 | 2 | | P5: Deposit Amount | 8 | 3 | 0 | 5 | | P7: Builder Index Allocation | 7 | 3 | 2 | 2 | | P8: Builder Registry State | 4 | 0 | 1 | 3 | | P9: Pending Deposits State | 4 | 0 | 2 | 2 | | **Total** | **26** | **7** | **5** | **14** | **Explicit Boundary Coverage: 27% (7/26)** **Including Implicit: 46% (12/26)** --- The test suite provides good coverage of the main equivalence classes for `process_deposit_request`. Both the inherited Electra behavior (validator path) and the new GLOAS routing logic are well-tested. **Inherited Electra behavior (P10-P15):** - Validator deposit types (new vs top-up): ✅ Fully covered - PendingDeposit field correctness: ✅ Mostly covered (slot binding implicit) - Signature handling (stored, not verified): ✅ Fully covered - Withdrawal credential types: ⚠️ ETH1 (0x01) not explicitly tested - Amount boundaries: ✅ Fully covered - Deposit start index (Electra only): ✅ Fully covered **GLOAS-specific behavior (P16-P17):** - Builder vs validator priority routing: ✅ Well covered - Execution address extraction: ⚠️ Non-standard padding not tested **Identified partition gaps:** 1. **Zero amount deposits (P5.5)** - edge case behavior unclear 2. **Below minimum amount deposits (P5.6)** - not tested 3. **Alternative credential prefixes (P3.3, P3.4)** - not tested in GLOAS routing 4. **Multiple reusable slots (P7.3)** - tests only single reusable slot scenario 5. **Empty/limit registry scenarios (P8.1, P9.3, P9.4)** - state fixtures don't test boundaries **Identified boundary gaps:** 1. **P1.1B1, P1.1B3** - single builder registry and last index boundaries 2. **P5.2B1, P5.2B2** - `MIN_DEPOSIT_AMOUNT + 1` and `MAX_EFFECTIVE_BALANCE - 1` 3. **P7.1B1, P7.2B1, P7.2B3** - epoch and balance boundaries for reusability 4. **P8.3B1, P8.3B2** - near-limit and at-limit builder registry size 5. **P9.3B1, P9.4B1** - near-limit and at-limit pending_deposits size The routing priority tests (`test_...__routing__*`) provide excellent coverage of the GLOAS-specific builder vs validator routing decision logic.