Problem Statement / Feature Objective
The storage trie pruner removes stale state entries older than FINALIZED_EPOCH - PRUNE_DEPTH after each epoch finalization. When epoch finalization occurs faster than the pruner can process (burst finalization of 4+ epochs in one slot), the pruner's async task falls behind and the pruning cursor state becomes inconsistent. The pruner then halts permanently, causing unbounded storage growth.
Technical Invariants & Bounds
- PRUNE_DEPTH = 256 epochs (~27 hours of history).
- Storage growth rate: ~2 MB per epoch (state diff).
- Pruner throughput: ~500 entries per 100ms budget.
- Burst finalization: up to 8 epochs in a single slot (during sync).
- Unbounded growth can exhaust disk at ~1.5 GB/day if pruner stalls.
Codebase Navigation Guide
- src/storage/trie-pruner.rs - Pruner state machine, prune_old_epochs(), and cursor management.
- src/storage/state-db.rs - finalize_state() trigger for pruner.
- src/state/finalization.rs - handle_finalization_updates().
- tests/storage/pruner_burst_test.rs - burst finalization tests.
Implementation Blueprint
- In src/storage/trie-pruner.rs, convert the single-cursor model to a multi-cursor queue: each finalization enqueues a PruneJob(from_epoch, to_epoch).
- The pruner processes one PruneJob per invocation and records progress in a checkpoint.
- If a new finalization arrives while an earlier job is still processing, the jobs are merged into a single contiguous range to avoid redundant work.
- Add a backpressure mechanism: if the pending job queue exceeds 4 entries, block finalization until the pruner catches up (async channel with capacity 4).
- Write a test that simulates 8 sequential finalizations at once and verifies the pruner completes all pruning within the expected slot budget.
Problem Statement / Feature Objective
The storage trie pruner removes stale state entries older than FINALIZED_EPOCH - PRUNE_DEPTH after each epoch finalization. When epoch finalization occurs faster than the pruner can process (burst finalization of 4+ epochs in one slot), the pruner's async task falls behind and the pruning cursor state becomes inconsistent. The pruner then halts permanently, causing unbounded storage growth.
Technical Invariants & Bounds
Codebase Navigation Guide
Implementation Blueprint