Skip to content

test(fc): block with duplicate AttestationData entries rejected #574

@tcoratger

Description

@tcoratger

Context

`Store.on_block` validates that a block does not contain duplicate `AttestationData` entries. Two attestations with the same (source, target, head) triple are duplicates and must be rejected.

The check in `on_block`:
```python
assert len(set(...attestation_data...)) == len(attestation_data_list)
```

This prevents a malicious proposer from padding a block with redundant attestations.

No spec test filler currently tests this rejection.

What to test

Write a fork choice filler that:

  1. Builds a chain
  2. Constructs a block containing two `AggregatedAttestationSpec` entries with identical attestation data (same source, target, and head)
  3. Attempts to process this block
  4. Verifies the block is rejected

Key assertions

  • The `BlockStep` has `valid=False`
  • The error relates to duplicate attestation data

Where to add the test

Add to: `tests/consensus/devnet/fc/test_block_processing_edge_cases.py` (new file)

Code skeleton

"""Block processing edge case tests."""

from consensus_testing import (
    AggregatedAttestationSpec,
    BlockSpec,
    BlockStep,
    ForkChoiceTestFiller,
    StoreChecks,
)
from lean_spec.subspecs.containers.slot import Slot
from lean_spec.subspecs.containers.validator import ValidatorIndex


def test_block_with_duplicate_attestation_data_rejected(
    fork_choice_test: ForkChoiceTestFiller,
) -> None:
    """Block containing duplicate AttestationData entries is rejected."""
    fork_choice_test(
        steps=[
            BlockStep(block=BlockSpec(slot=Slot(1), label="block_1")),
            BlockStep(
                block=BlockSpec(
                    slot=Slot(2),
                    attestations=[
                        # Two attestations with identical data
                        AggregatedAttestationSpec(
                            validator_ids=[ValidatorIndex(0)],
                            slot=Slot(2),
                            target_slot=Slot(1),
                            target_root_label="block_1",
                        ),
                        AggregatedAttestationSpec(
                            validator_ids=[ValidatorIndex(1)],
                            slot=Slot(2),
                            target_slot=Slot(1),
                            target_root_label="block_1",
                            # Same target/source/head = duplicate AttestationData
                        ),
                    ],
                ),
                valid=False,
                expected_error="duplicate",  # Or whatever the assertion says
            ),
        ],
    )

Note: Two `AggregatedAttestationSpec` with the same `target_slot` and `target_root_label` may produce the same `AttestationData`. Verify this by checking what fields determine `AttestationData` equality in `src/lean_spec/subspecs/containers/attestation/`.

How to run

uv run fill --fork=devnet --clean -n auto -k test_block_with_duplicate

References

  • `Store.on_block`: `src/lean_spec/subspecs/forkchoice/store.py` — duplicate check assertion
  • `AttestationData`: `src/lean_spec/subspecs/containers/attestation/attestation.py`

Metadata

Metadata

Assignees

Labels

good first issueGood for newcomerstestsScope: Changes to the spec tests

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions