# 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.