# Equivalent Partition Analysis: `process_proposer_slashing`
*Generated from test specification analysis*
## Overview
This document identifies equivalence classes for testing the
`process_proposer_slashing` function in the GLOAS fork. Equivalence partitioning
divides the input space into classes where all values within a class should
produce equivalent behavior.
______________________________________________________________________
## Input Parameters Summary
| Parameter | Type | Description |
| ----------------- | ------------------------- | -------------------------------------- |
| `signed_header_1` | `SignedBeaconBlockHeader` | First conflicting signed block header |
| `signed_header_2` | `SignedBeaconBlockHeader` | Second conflicting signed block header |
| `state` | `BeaconState` | Current beacon state |
______________________________________________________________________
## Equivalence Partitions
### P1: Header Slot Relationship
| Partition ID | Class | Valid | Description |
| ------------ | ---------------------------------- | ---------- | -------------------------------- |
| P1.1 | Slots equal | ✅ Valid | `header_1.slot == header_2.slot` |
| P1.2 | Slots different (same epoch) | ❌ Invalid | Slots differ but in same epoch |
| P1.3 | Slots different (different epochs) | ❌ Invalid | Slots in different epochs |
**Boundary Values:**
| Boundary ID | Partition | Boundary Condition | Description |
| ----------- | --------- | -------------------------- | ------------------------------------------ |
| P1.1B1 | P1.1 | `slot == epoch_start_slot` | Slot at epoch boundary (slot 0 of epoch N) |
| P1.1B2 | P1.1 | `slot == epoch_end_slot` | Slot at end of epoch (SLOTS_PER_EPOCH-1) |
| P1.1B3 | P1.1 | `header.slot > state.slot` | Future slot relative to state.slot |
**Test Coverage:**
| Partition | Test(s) | Covered |
| --------- | ----------------------------------------------------------------------------------------------------------------------------------------------------- | ---------- |
| P1.1 | `test_basic`, `test_block_header_from_future` | ✅ |
| P1.2 | `test_invalid_slots_of_different_epochs` (same validation path: `header_1.slot == header_2.slot` check rejects any slot mismatch regardless of epoch) | ⚠️ Partial |
| P1.3 | `test_invalid_slots_of_different_epochs` | ✅ |
______________________________________________________________________
### P2: Proposer Index Relationship
| Partition ID | Class | Valid | Description |
| ------------ | ----------------------- | ---------- | ------------------------------------------ |
| P2.1 | Indices equal and valid | ✅ Valid | Both headers reference same valid proposer |
| P2.2 | Indices different | ❌ Invalid | Headers reference different proposers |
| P2.3 | Index out of bounds | ❌ Invalid | `proposer_index >= len(validators)` |
**Boundary Values:**
| Boundary ID | Partition | Boundary Condition | Description |
| ----------- | --------- | --------------------------------------- | ------------------------------------ |
| P2.1B1 | P2.1 | `proposer_index == 0` | Minimum valid index |
| P2.1B2 | P2.1 | `proposer_index == len(validators) - 1` | Maximum valid index |
| P2.3B1 | P2.3 | `proposer_index == len(validators)` | Minimum invalid (just out of bounds) |
**Test Coverage:**
| Partition | Test(s) | Covered |
| --------- | ----------------------------------------- | ------- |
| P2.1 | `test_basic` | ✅ |
| P2.2 | `test_invalid_different_proposer_indices` | ✅ |
| P2.3 | `test_invalid_incorrect_proposer_index` | ✅ |
______________________________________________________________________
### P3: Header Content Distinction
| Partition ID | Class | Valid | Description |
| ------------ | ---------------------------------- | ---------- | ------------------------------------------ |
| P3.1 | Headers different | ✅ Valid | At least one root field differs |
| P3.2 | Headers identical (same sigs) | ❌ Invalid | All fields including signatures match |
| P3.3 | Headers identical (different sigs) | ❌ Invalid | Same message content, different signatures |
**Boundary Values:**
| Boundary ID | Partition | Boundary Condition | Description |
| ----------- | --------- | --------------------------- | -------------------------- |
| P3.1B1 | P3.1 | Only `parent_root` differs | Single field difference |
| P3.1B2 | P3.1 | Only `state_root` differs | Single field difference |
| P3.1B3 | P3.1 | Only `body_root` differs | Single field difference |
| P3.1B4 | P3.1 | Multiple root fields differ | Multiple field differences |
**Test Coverage:**
| Partition | Test(s) | Covered |
| --------- | -------------------------------------------------- | ------- |
| P3.1 | `test_basic` | ✅ |
| P3.2 | `test_invalid_headers_are_same_sigs_are_same` | ✅ |
| P3.3 | `test_invalid_headers_are_same_sigs_are_different` | ✅ |
______________________________________________________________________
### P4: Signature Validity (Header 1)
| Partition ID | Class | Valid | Description |
| ------------ | ------------------- | ---------- | ------------------------------ |
| P4.1 | Signature 1 valid | ✅ Valid | BLS verify passes for header 1 |
| P4.2 | Signature 1 invalid | ❌ Invalid | BLS verify fails for header 1 |
**Test Coverage:**
| Partition | Test(s) | Covered |
| --------- | ------------------------------ | ------- |
| P4.1 | `test_basic` | ✅ |
| P4.2 | `test_invalid_incorrect_sig_1` | ✅ |
______________________________________________________________________
### P5: Signature Validity (Header 2)
| Partition ID | Class | Valid | Description |
| ------------ | ------------------- | ---------- | ------------------------------ |
| P5.1 | Signature 2 valid | ✅ Valid | BLS verify passes for header 2 |
| P5.2 | Signature 2 invalid | ❌ Invalid | BLS verify fails for header 2 |
**Test Coverage:**
| Partition | Test(s) | Covered |
| --------- | ------------------------------ | ------- |
| P5.1 | `test_basic` | ✅ |
| P5.2 | `test_invalid_incorrect_sig_2` | ✅ |
______________________________________________________________________
### P6: Combined Signature States
| Partition ID | Class | Valid | Description |
| ------------ | ------------------ | ---------- | ------------------------------------- |
| P6.1 | Both valid | ✅ Valid | Both signatures pass verification |
| P6.2 | Both invalid | ❌ Invalid | Both signatures fail verification |
| P6.3 | Sig 1 invalid only | ❌ Invalid | Only signature 1 fails |
| P6.4 | Sig 2 invalid only | ❌ Invalid | Only signature 2 fails |
| P6.5 | Signatures swapped | ❌ Invalid | Valid signatures but on wrong headers |
**Test Coverage:**
| Partition | Test(s) | Covered |
| --------- | ----------------------------------------- | ------- |
| P6.1 | `test_basic` | ✅ |
| P6.2 | `test_invalid_incorrect_sig_1_and_2` | ✅ |
| P6.3 | `test_invalid_incorrect_sig_1` | ✅ |
| P6.4 | `test_invalid_incorrect_sig_2` | ✅ |
| P6.5 | `test_invalid_incorrect_sig_1_and_2_swap` | ✅ |
______________________________________________________________________
### P7: Validator Activation Status
| Partition ID | Class | Valid | Description |
| ------------ | ----------------- | ---------- | ----------------------------------- |
| P7.1 | Activated | ✅ Valid | `activation_epoch <= current_epoch` |
| P7.2 | Not yet activated | ❌ Invalid | `activation_epoch > current_epoch` |
**Boundary Values:**
| Boundary ID | Partition | Boundary Condition | Description |
| ----------- | --------- | --------------------------------------- | -------------------------------------- |
| P7.1B1 | P7.1 | `activation_epoch == current_epoch` | Just activated this epoch |
| P7.2B1 | P7.2 | `activation_epoch == current_epoch + 1` | Activates next epoch (minimum invalid) |
**Test Coverage:**
| Partition | Test(s) | Covered |
| --------- | ---------------------------------------- | ------- |
| P7.1 | `test_basic` | ✅ |
| P7.2 | `test_invalid_proposer_is_not_activated` | ✅ |
______________________________________________________________________
### P8: Validator Slashed Status
| Partition ID | Class | Valid | Description |
| ------------ | --------------- | ---------- | ------------------ |
| P8.1 | Not slashed | ✅ Valid | `slashed == False` |
| P8.2 | Already slashed | ❌ Invalid | `slashed == True` |
**Test Coverage:**
| Partition | Test(s) | Covered |
| --------- | ---------------------------------- | ------- |
| P8.1 | `test_basic` | ✅ |
| P8.2 | `test_invalid_proposer_is_slashed` | ✅ |
______________________________________________________________________
### P9: Validator Withdrawable Status
| Partition ID | Class | Valid | Description |
| ------------ | -------------------- | ---------- | ------------------------------------- |
| P9.1 | Not withdrawable | ✅ Valid | `withdrawable_epoch > current_epoch` |
| P9.2 | Already withdrawable | ❌ Invalid | `withdrawable_epoch <= current_epoch` |
**Boundary Values:**
| Boundary ID | Partition | Boundary Condition | Description |
| ----------- | --------- | ----------------------------------------- | ------------------------------------------ |
| P9.1B1 | P9.1 | `withdrawable_epoch == current_epoch + 1` | Withdrawable next epoch (minimum valid) |
| P9.1B2 | P9.1 | `withdrawable_epoch == FAR_FUTURE_EPOCH` | Never set (sentinel value) |
| P9.2B1 | P9.2 | `withdrawable_epoch == current_epoch` | Just became withdrawable (minimum invalid) |
| P9.2B2 | P9.2 | `withdrawable_epoch == current_epoch - 1` | Withdrawn in past |
**Test Coverage:**
| Partition | Test(s) | Covered |
| --------- | ------------------------------------ | ------- |
| P9.1 | `test_basic` | ✅ |
| P9.2 | `test_invalid_proposer_is_withdrawn` | ✅ |
______________________________________________________________________
### P10: Slasher Identity (Special Case)
| Partition ID | Class | Valid | Description |
| ------------ | ------------------------------ | -------- | ---------------------------------- |
| P10.1 | Slasher is different validator | ✅ Valid | Block proposer != slashed proposer |
| P10.2 | Slasher is same validator | ✅ Valid | Block proposer slashes themselves |
**Test Coverage:**
| Partition | Test(s) | Covered |
| --------- | ------------------------------------------ | ------- |
| P10.1 | `test_basic` | ✅ |
| P10.2 | `test_slashed_and_proposer_index_the_same` | ✅ |
______________________________________________________________________
### P11: Header Slot Timing (Relative to State)
| Partition ID | Class | Valid | Description |
| ------------ | ------------ | -------- | --------------------------- |
| P11.1 | Past slot | ✅ Valid | `header.slot < state.slot` |
| P11.2 | Current slot | ✅ Valid | `header.slot == state.slot` |
| P11.3 | Future slot | ✅ Valid | `header.slot > state.slot` |
**Test Coverage:**
| Partition | Test(s) | Covered |
| --------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------- |
| P11.1 | Not explicitly tested; `get_valid_proposer_slashing` defaults to `slot=state.slot` (current slot). Past slot would require `slot < state.slot` which no test sets up. | ⚠️ Partial |
| P11.2 | `test_basic` | ✅ |
| P11.3 | `test_block_header_from_future` | ✅ |
______________________________________________________________________
## GLOAS-Specific Partitions
### P12: Builder Payment Deletion Timing
| Partition ID | Class | Effect | Description |
| ------------ | ------------------- | --------------- | ---------------------------------- |
| P12.1 | Current epoch | Payment deleted | `proposal_epoch == current_epoch` |
| P12.2 | Previous epoch | Payment deleted | `proposal_epoch == previous_epoch` |
| P12.3 | Older than 2 epochs | No deletion | `proposal_epoch < previous_epoch` |
**Boundary Values:**
| Boundary ID | Partition | Boundary Condition | Description |
| ----------- | --------- | ---------------------------------- | ------------------------------- |
| P12.1B1 | P12.1 | `slot == current_epoch_start` | First slot of current epoch |
| P12.1B2 | P12.1 | `slot == current_epoch_end` | Last slot of current epoch |
| P12.2B1 | P12.2 | `slot == previous_epoch_start` | First slot of previous epoch |
| P12.2B2 | P12.2 | `slot == previous_epoch_end` | Last slot of previous epoch |
| P12.3B1 | P12.3 | `slot == previous_epoch_start - 1` | Last slot before 2-epoch window |
**Test Coverage:**
| Partition | Test(s) | Covered |
| --------- | ---------------------------------------------- | ------- |
| P12.1 | `test_builder_payment_deletion_current_epoch` | ✅ |
| P12.2 | `test_builder_payment_deletion_previous_epoch` | ✅ |
| P12.3 | `test_builder_payment_deletion_too_late` | ✅ |
______________________________________________________________________
### P13: Builder Payment State
| Partition ID | Class | Effect | Description |
| ------------ | -------------- | --------------- | ------------------------------- |
| P13.1 | Payment exists | Payment cleared | Non-empty payment at slot index |
| P13.2 | Payment empty | No change | Already empty payment |
**Test Coverage:**
| Partition | Test(s) | Covered |
| --------- | --------------------------------------------- | ------- |
| P13.1 | `test_builder_payment_deletion_current_epoch` | ✅ |
| P13.2 | (not explicitly tested) | ❌ Gap |
______________________________________________________________________
## Coverage Gap Analysis
### Identified Gaps
| Gap ID | Partition/Boundary | Description | Priority |
| ------ | ------------------ | ---------------------------------------------------------------------------------------------------------------------------------------- | -------- |
| G1 | P1.2 | Slots different but same epoch not explicitly tested | Low |
| G2 | P3.1B2-B4 | Only `state_root` or `body_root` differs not tested; multiple fields differ not tested (P3.1B1 `parent_root` IS covered by `test_basic`) | Low |
| G3 | P13.2 | Empty payment slot slashing not tested | Low |
| G4 | P7.1B1 | `activation_epoch == current_epoch` boundary not explicit | Low |
| G5 | P9.1B1 | `withdrawable_epoch == current_epoch + 1` boundary | Low |
### Recommendations
1. **Add boundary test for P7.1B1**: Test when
`activation_epoch == current_epoch` (validator just activated this epoch)
2. **Add boundary test for P9.1B1**: Test when
`withdrawable_epoch == current_epoch + 1` (withdrawable next epoch)
3. **Add P13.2 test**: Verify slashing works when no builder payment exists at
slot
4. **Consider P3.1B2-B4 variations**: Test `state_root` and `body_root`
single-field differences (P3.1B1 `parent_root` already covered by
`test_basic` via helper)
______________________________________________________________________
## 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: Header Slot Relationship Boundaries
| Boundary ID | Boundary Condition | Partition | Covered | Test | Coverage Details |
| ----------- | -------------------------- | --------- | ----------- | ------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------- |
| P1.1B1 | `slot == epoch_start_slot` | P1.1 | ⚠️ Implicit | `test_basic` | `get_valid_proposer_slashing` uses `slot=state.slot`; if state happens to be at epoch start, this boundary is hit. Not explicitly controlled. |
| P1.1B2 | `slot == epoch_end_slot` | P1.1 | ⚠️ Implicit | `test_basic` | Same as P1.1B1; if state happens to be at epoch end (slot % SLOTS_PER_EPOCH == 31), this boundary is hit. Not explicitly controlled. |
| P1.1B3 | `header.slot > state.slot` | P1.1 | ✅ Explicit | `test_block_header_from_future` | Test sets `header.slot = state.slot + 1` to verify future slots are accepted |
______________________________________________________________________
### P2: Proposer Index Relationship Boundaries
| Boundary ID | Boundary Condition | Partition | Covered | Test | Coverage Details |
| ----------- | --------------------------------------- | --------- | ----------- | --------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------- |
| P2.1B1 | `proposer_index == 0` | P2.1 | ⚠️ Implicit | - | `get_valid_proposer_slashing` uses `get_active_validator_indices(state, current_epoch)[-1]` (last active validator). Index 0 never explicitly targeted. |
| P2.1B2 | `proposer_index == len(validators) - 1` | P2.1 | ⚠️ Implicit | `test_basic` | Helper uses last active validator index which is typically close to `len(validators)-1` in minimal preset but not guaranteed to be exactly that value. |
| P2.3B1 | `proposer_index == len(validators)` | P2.3 | ✅ Explicit | `test_invalid_incorrect_proposer_index` | Test sets `proposer_index = len(state.validators)` to verify out-of-bounds rejection |
______________________________________________________________________
### P3: Header Content Distinction Boundaries
| Boundary ID | Boundary Condition | Partition | Covered | Test | Coverage Details |
| ----------- | --------------------------- | --------- | ----------- | ------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------- |
| P3.1B1 | Only `parent_root` differs | P3.1 | ✅ Explicit | `test_basic` | `get_valid_proposer_slashing` creates `header_2 = header_1.copy()` then sets only `header_2.parent_root = random_root`. This IS the default behavior. |
| P3.1B2 | Only `state_root` differs | P3.1 | ❌ | - | No test isolates state_root difference; would require modifying helper or custom setup |
| P3.1B3 | Only `body_root` differs | P3.1 | ❌ | - | No test isolates body_root difference; helper only changes parent_root |
| P3.1B4 | Multiple root fields differ | P3.1 | ❌ | - | Helper only changes parent_root; no test sets up multiple differing fields |
______________________________________________________________________
### P7: Validator Activation Status Boundaries
| Boundary ID | Boundary Condition | Partition | Covered | Test | Coverage Details |
| ----------- | --------------------------------------- | --------- | ----------- | ---------------------------------------- | ---------------------------------------------------------------------------------------------------------------- |
| P7.1B1 | `activation_epoch == current_epoch` | P7.1 | ❌ | - | No test uses validator activated in current epoch |
| P7.2B1 | `activation_epoch == current_epoch + 1` | P7.2 | ✅ Explicit | `test_invalid_proposer_is_not_activated` | Test sets `activation_epoch = current_epoch + 1` (line 196). This is exactly the minimum invalid boundary value. |
______________________________________________________________________
### P9: Validator Withdrawable Status Boundaries
| Boundary ID | Boundary Condition | Partition | Covered | Test | Coverage Details |
| ----------- | ----------------------------------------- | --------- | ----------- | ------------------------------------ | ----------------------------------------------------------------------------------------------------------------------------- |
| P9.1B1 | `withdrawable_epoch == current_epoch + 1` | P9.1 | ❌ | - | No test uses withdrawable_epoch just after current |
| P9.1B2 | `withdrawable_epoch == FAR_FUTURE_EPOCH` | P9.1 | ⚠️ Implicit | `test_basic` | Default validator state has `withdrawable_epoch = FAR_FUTURE_EPOCH`. All tests using default validators implicitly test this. |
| P9.2B1 | `withdrawable_epoch == current_epoch` | P9.2 | ⚠️ Implicit | - | No test sets `withdrawable_epoch == current_epoch` exactly. See P9.2B2. |
| P9.2B2 | `withdrawable_epoch == current_epoch - 1` | P9.2 | ✅ Explicit | `test_invalid_proposer_is_withdrawn` | Test sets `withdrawable_epoch = current_epoch - 1` (line 223) after advancing one epoch (line 219). |
______________________________________________________________________
### P12: Builder Payment Deletion Timing Boundaries (GLOAS-Specific)
| Boundary ID | Boundary Condition | Partition | Covered | Test | Coverage Details |
| ----------- | ---------------------------------- | --------- | ----------- | ---------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------ |
| P12.1B1 | `slot == current_epoch_start` | P12.1 | ⚠️ Implicit | `test_builder_payment_deletion_current_epoch` | Test uses `random.randrange(SLOTS_PER_EPOCH)` (line 26). Boundary slots (0, 31) have ~3% chance each of being selected. Not explicitly targeted. |
| P12.1B2 | `slot == current_epoch_end` | P12.1 | ⚠️ Implicit | `test_builder_payment_deletion_current_epoch` | Same as P12.1B1; last slot of epoch has ~3% chance of being randomly selected. |
| P12.2B1 | `slot == previous_epoch_start` | P12.2 | ⚠️ Implicit | `test_builder_payment_deletion_previous_epoch` | Test uses `random.randrange(SLOTS_PER_EPOCH)` (line 61). Boundary slots have ~3% chance each. |
| P12.2B2 | `slot == previous_epoch_end` | P12.2 | ⚠️ Implicit | `test_builder_payment_deletion_previous_epoch` | Same as P12.2B1; last slot of previous epoch has ~3% chance of being randomly selected. |
| P12.3B1 | `slot == previous_epoch_start - 1` | P12.3 | ✅ Explicit | `test_builder_payment_deletion_too_late` | Test sets header slot to epoch before previous to verify payment not deleted |
______________________________________________________________________
### Boundary Coverage Summary
| Category | Total | Covered (✅) | Implicit (⚠️) | Not Covered (❌) |
| --------------------------- | ------ | ------------ | ------------- | ---------------- |
| P1: Slot Relationship | 3 | 1 | 2 | 0 |
| P2: Proposer Index | 3 | 1 | 2 | 0 |
| P3: Header Content | 4 | 1 | 0 | 3 |
| P7: Activation Status | 2 | 1 | 0 | 1 |
| P9: Withdrawable Status | 4 | 1 | 2 | 1 |
| P12: Builder Payment Timing | 5 | 1 | 4 | 0 |
| **Total** | **21** | **6** | **10** | **5** |
**Explicit Boundary Coverage: 29% (6/21)** **Including Implicit: 76% (16/21)**
______________________________________________________________________
## Complete Partition Combination Matrix
### Legend
- ✅ Covered - Test exists for this combination
- ❌ Not covered - No test exists
- N/A - Combination not applicable (e.g., GLOAS partitions only apply to valid
slashings)
______________________________________________________________________
### Core Validation Partitions (P1-P9)
These partitions determine whether the slashing operation succeeds or fails.
#### All Valid Combinations (Happy Path)
| # | P1 | P2 | P3 | P6 | P7 | P8 | P9 | P10 | P11 | Covered | Test |
| --- | ---- | ---- | ---- | ---- | ---- | ---- | ---- | ----- | ----- | ------- | ------------------------------------------ |
| 1 | P1.1 | P2.1 | P3.1 | P6.1 | P7.1 | P8.1 | P9.1 | P10.1 | P11.1 | ❌ | (past slot, different slasher) |
| 2 | P1.1 | P2.1 | P3.1 | P6.1 | P7.1 | P8.1 | P9.1 | P10.1 | P11.2 | ✅ | `test_basic` |
| 3 | P1.1 | P2.1 | P3.1 | P6.1 | P7.1 | P8.1 | P9.1 | P10.1 | P11.3 | ✅ | `test_block_header_from_future` |
| 4 | P1.1 | P2.1 | P3.1 | P6.1 | P7.1 | P8.1 | P9.1 | P10.2 | P11.1 | ❌ | (past slot, self-slashing) |
| 5 | P1.1 | P2.1 | P3.1 | P6.1 | P7.1 | P8.1 | P9.1 | P10.2 | P11.2 | ✅ | `test_slashed_and_proposer_index_the_same` |
| 6 | P1.1 | P2.1 | P3.1 | P6.1 | P7.1 | P8.1 | P9.1 | P10.2 | P11.3 | ❌ | (future slot, self-slashing) |
#### P1: Header Slot Relationship (Invalid Combinations)
| # | P1 | P2 | P3 | P6 | P7 | P8 | P9 | Valid | Covered | Test |
| --- | -------- | ---- | ---- | ---- | ---- | ---- | ---- | ----- | ------- | ---------------------------------------- |
| 7 | **P1.2** | P2.1 | P3.1 | P6.1 | P7.1 | P8.1 | P9.1 | ❌ | ❌ | (slots differ, same epoch) |
| 8 | **P1.3** | P2.1 | P3.1 | P6.1 | P7.1 | P8.1 | P9.1 | ❌ | ✅ | `test_invalid_slots_of_different_epochs` |
#### P2: Proposer Index Relationship (Invalid Combinations)
| # | P1 | P2 | P3 | P6 | P7 | P8 | P9 | Valid | Covered | Test |
| --- | ---- | -------- | ---- | ---- | ---- | ---- | ---- | ----- | ------- | ----------------------------------------- |
| 9 | P1.1 | **P2.2** | P3.1 | P6.1 | P7.1 | P8.1 | P9.1 | ❌ | ✅ | `test_invalid_different_proposer_indices` |
| 10 | P1.1 | **P2.3** | P3.1 | P6.1 | P7.1 | P8.1 | P9.1 | ❌ | ✅ | `test_invalid_incorrect_proposer_index` |
#### P3: Header Content Distinction (Invalid Combinations)
| # | P1 | P2 | P3 | P6 | P7 | P8 | P9 | Valid | Covered | Test |
| --- | ---- | ---- | -------- | ---- | ---- | ---- | ---- | ----- | ------- | -------------------------------------------------- |
| 11 | P1.1 | P2.1 | **P3.2** | P6.1 | P7.1 | P8.1 | P9.1 | ❌ | ✅ | `test_invalid_headers_are_same_sigs_are_same` |
| 12 | P1.1 | P2.1 | **P3.3** | P6.1 | P7.1 | P8.1 | P9.1 | ❌ | ✅ | `test_invalid_headers_are_same_sigs_are_different` |
#### P4/P5/P6: Signature Validity (Invalid Combinations)
| # | P1 | P2 | P3 | P4 | P5 | P6 | P7 | P8 | P9 | Valid | Covered | Test |
| --- | ---- | ---- | ---- | -------- | -------- | ---- | ---- | ---- | ---- | ----- | ------- | ----------------------------------------- |
| 13 | P1.1 | P2.1 | P3.1 | **P4.2** | P5.1 | P6.3 | P7.1 | P8.1 | P9.1 | ❌ | ✅ | `test_invalid_incorrect_sig_1` |
| 14 | P1.1 | P2.1 | P3.1 | P4.1 | **P5.2** | P6.4 | P7.1 | P8.1 | P9.1 | ❌ | ✅ | `test_invalid_incorrect_sig_2` |
| 15 | P1.1 | P2.1 | P3.1 | **P4.2** | **P5.2** | P6.2 | P7.1 | P8.1 | P9.1 | ❌ | ✅ | `test_invalid_incorrect_sig_1_and_2` |
| 16 | P1.1 | P2.1 | P3.1 | **P4.2** | **P5.2** | P6.5 | P7.1 | P8.1 | P9.1 | ❌ | ✅ | `test_invalid_incorrect_sig_1_and_2_swap` |
#### P7: Validator Activation Status (Invalid Combinations)
| # | P1 | P2 | P3 | P6 | P7 | P8 | P9 | Valid | Covered | Test |
| --- | ---- | ---- | ---- | ---- | -------- | ---- | ---- | ----- | ------- | ---------------------------------------- |
| 17 | P1.1 | P2.1 | P3.1 | P6.1 | **P7.2** | P8.1 | P9.1 | ❌ | ✅ | `test_invalid_proposer_is_not_activated` |
#### P8: Validator Slashed Status (Invalid Combinations)
| # | P1 | P2 | P3 | P6 | P7 | P8 | P9 | Valid | Covered | Test |
| --- | ---- | ---- | ---- | ---- | ---- | -------- | ---- | ----- | ------- | ---------------------------------- |
| 18 | P1.1 | P2.1 | P3.1 | P6.1 | P7.1 | **P8.2** | P9.1 | ❌ | ✅ | `test_invalid_proposer_is_slashed` |
#### P9: Validator Withdrawable Status (Invalid Combinations)
| # | P1 | P2 | P3 | P6 | P7 | P8 | P9 | Valid | Covered | Test |
| --- | ---- | ---- | ---- | ---- | ---- | ---- | -------- | ----- | ------- | ------------------------------------ |
| 19 | P1.1 | P2.1 | P3.1 | P6.1 | P7.1 | P8.1 | **P9.2** | ❌ | ✅ | `test_invalid_proposer_is_withdrawn` |
______________________________________________________________________
### GLOAS-Specific Partitions (P12-P13)
These only apply when the core slashing is valid (all P1-P9 are valid).
#### P12 × P13: Builder Payment Combinations
| # | P12 (Timing) | P13 (Payment State) | Effect | Covered | Test |
| --- | ---------------------- | ---------------------- | ----------- | ------- | ---------------------------------------------- |
| 20 | P12.1 (current epoch) | P13.1 (payment exists) | Deleted | ✅ | `test_builder_payment_deletion_current_epoch` |
| 21 | P12.1 (current epoch) | P13.2 (payment empty) | No change | ❌ | - |
| 22 | P12.2 (previous epoch) | P13.1 (payment exists) | Deleted | ✅ | `test_builder_payment_deletion_previous_epoch` |
| 23 | P12.2 (previous epoch) | P13.2 (payment empty) | No change | ❌ | - |
| 24 | P12.3 (older) | P13.1 (payment exists) | No deletion | ✅ | `test_builder_payment_deletion_too_late` |
| 25 | P12.3 (older) | P13.2 (payment empty) | No change | ❌ | - |
______________________________________________________________________
### Multiple Invalid Partitions (Compound Failures)
These combinations have multiple invalid partitions. Generally not tested as
they fail on the first check.
| # | Invalid Partitions | Covered | Test | Notes |
| --- | ------------------ | ------- | ---- | ------------------------------------- |
| 26 | P1.3 + P2.2 | ❌ | - | Different slots AND different indices |
| 27 | P1.3 + P3.2 | ❌ | - | Different slots AND same headers |
| 28 | P2.2 + P3.2 | ❌ | - | Different indices AND same headers |
| 29 | P6.3 + P7.2 | ❌ | - | Invalid sig1 AND not activated |
| 30 | P6.4 + P8.2 | ❌ | - | Invalid sig2 AND already slashed |
| 31 | P7.2 + P8.2 | ❌ | - | Not activated AND already slashed |
| 32 | P7.2 + P9.2 | ❌ | - | Not activated AND withdrawn |
| 33 | P8.2 + P9.2 | ❌ | - | Already slashed AND withdrawn |
*Note: Testing compound failures is generally low priority as they fail on the
first validation check.*
______________________________________________________________________
### Summary: Complete Coverage Table
| Combination # | Description | Covered | Test |
| ------------- | ---------------------------------------- | ------- | -------------------------------------------------- |
| 1 | Valid + past slot + different slasher | ❌ | - |
| 2 | Valid + current slot + different slasher | ✅ | `test_basic` |
| 3 | Valid + future slot + different slasher | ✅ | `test_block_header_from_future` |
| 4 | Valid + past slot + self-slashing | ❌ | - |
| 5 | Valid + current slot + self-slashing | ✅ | `test_slashed_and_proposer_index_the_same` |
| 6 | Valid + future slot + self-slashing | ❌ | - |
| 7 | Invalid: slots differ (same epoch) | ❌ | - |
| 8 | Invalid: slots differ (different epochs) | ✅ | `test_invalid_slots_of_different_epochs` |
| 9 | Invalid: different proposer indices | ✅ | `test_invalid_different_proposer_indices` |
| 10 | Invalid: proposer index out of bounds | ✅ | `test_invalid_incorrect_proposer_index` |
| 11 | Invalid: identical headers (same sigs) | ✅ | `test_invalid_headers_are_same_sigs_are_same` |
| 12 | Invalid: identical headers (diff sigs) | ✅ | `test_invalid_headers_are_same_sigs_are_different` |
| 13 | Invalid: signature 1 invalid | ✅ | `test_invalid_incorrect_sig_1` |
| 14 | Invalid: signature 2 invalid | ✅ | `test_invalid_incorrect_sig_2` |
| 15 | Invalid: both signatures invalid | ✅ | `test_invalid_incorrect_sig_1_and_2` |
| 16 | Invalid: signatures swapped | ✅ | `test_invalid_incorrect_sig_1_and_2_swap` |
| 17 | Invalid: proposer not activated | ✅ | `test_invalid_proposer_is_not_activated` |
| 18 | Invalid: proposer already slashed | ✅ | `test_invalid_proposer_is_slashed` |
| 19 | Invalid: proposer already withdrawn | ✅ | `test_invalid_proposer_is_withdrawn` |
| 20 | GLOAS: current epoch + payment exists | ✅ | `test_builder_payment_deletion_current_epoch` |
| 21 | GLOAS: current epoch + payment empty | ❌ | - |
| 22 | GLOAS: previous epoch + payment exists | ✅ | `test_builder_payment_deletion_previous_epoch` |
| 23 | GLOAS: previous epoch + payment empty | ❌ | - |
| 24 | GLOAS: older epoch + payment exists | ✅ | `test_builder_payment_deletion_too_late` |
| 25 | GLOAS: older epoch + payment empty | ❌ | - |
| 26-33 | Compound failures (multiple invalid) | ❌ | (low priority) |
______________________________________________________________________
### Coverage Statistics
| Category | Total | Covered | Not Covered |
| --------------------------------- | ------ | ------- | ----------- |
| Valid slashing combinations (1-6) | 6 | 3 | 3 |
| Single invalid partition (7-19) | 13 | 12 | 1 |
| GLOAS combinations (20-25) | 6 | 3 | 3 |
| Compound failures (26-33) | 8 | 0 | 8 |
| **Total (excluding compound)** | **25** | **18** | **7** |
**Coverage Rate: 72% (18/25 meaningful combinations)**
______________________________________________________________________
### Uncovered Combinations Requiring Tests
| Priority | # | Description | Suggested Test Name |
| -------- | --- | ------------------------------------- | ---------------------------------------------- |
| Medium | 1 | Valid slashing with past slot header | `test_block_header_from_past` |
| Low | 4 | Self-slashing with past slot header | `test_self_slashing_past_slot` |
| Low | 6 | Self-slashing with future slot header | `test_self_slashing_future_slot` |
| Medium | 7 | Slots differ but same epoch | `test_invalid_slots_same_epoch_different_slot` |
| Low | 21 | Current epoch, empty payment slot | `test_builder_payment_empty_current_epoch` |
| Low | 23 | Previous epoch, empty payment slot | `test_builder_payment_empty_previous_epoch` |
| Low | 25 | Older epoch, empty payment slot | `test_builder_payment_empty_old_epoch` |
______________________________________________________________________
## Summary Statistics
| Category | Total Partitions | Covered | Gaps |
| --------------- | ---------------- | ------- | ----- |
| Core Validation | 22 | 20 | 2 |
| GLOAS-Specific | 5 | 4 | 1 |
| **Total** | **27** | **24** | **3** |
**Overall Coverage: 89%**
The test suite provides excellent coverage of the main equivalence classes. The
identified gaps are primarily edge cases and boundary conditions that have lower
risk due to implicit coverage through helper functions.