ChainSafe / ChainSafe/lodestar
Interchange import is not atomic, a rejected file leaves partial slashing protection state
- Dominant language
- TypeScript
- Stars
- 1.4k
- Forks
- 483
- Avg merge
- 1d 18h
- Merged PRs (30d)
- 156
Description
`SlashingProtectionAttestationService.importAttestations` stores the attestation rows of the whole file, then inserts min-max spans one attestation at a time. If a later attestation is rejected by the span check, the rows of the file and the spans of the earlier attestations remain in the db.
Leftover spans can reject attestations that are safe against everything actually signed. Example from the review of #9999: after signing `(10,11)` and `(11,12)`, importing `[(12,13), (9,14)]` fails on `(9,14)` but leaves the min-span entry for source 11 from `(12,13)`, which then rejects `(11,14)`.
Intra-file conflicts are only detected while inserting spans, so validating without mutation needs either an in-memory span overlay, or a complete check of the file itself (sorted by target epoch, source epochs must be non-decreasing) plus a check of each attestation against existing history, followed by writing rows and spans in a single batch.
Related: the EIP-3076 harness in `packages/validator/test/spec/spec.test.ts` runs no assertions for steps with `contains_slashable_data`, so import rejection is currently untested.
Contributor guide
Research direction
Start at SlashingProtectionAttestationService.importAttestations and trace how attestation rows and min-max spans are written. Review packages/validator/test/spec/spec.test.ts, add assertions for contains_slashable_data steps, and verify that a rejected file leaves no rows or spans while valid imports remain usable.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- typescript
- Domain
- blockchain, testing
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 55/100