feat(flashblocks): Cache recent flashblocks#19786
Conversation
fdca217 to
0c51485
Compare
mattsse
left a comment
There was a problem hiding this comment.
cool,
all of this looks great
I only have last suggestion re the PreparedFlashblock, because we can cache all of the raw -> WithEncoded conversions of previous blocks, so that we only need to recover the new transactions per flashblock
| #[derive(Debug)] | ||
| struct PreparedFlashBlock<T> { | ||
| /// The prepared transactions, ready for execution | ||
| txs: Vec<WithEncoded<Recovered<T>>>, | ||
| /// The tracked flashblock | ||
| block: FlashBlock, | ||
| } |
There was a problem hiding this comment.
we should add this back because I believe rn we're re-recovering the entire block per flashblock in
recovery is fairly expensive and we can avoid doing all of this for the previous flashblocks in the block
There was a problem hiding this comment.
Done.
Chose to not revive PreparedFlashBlock and instead do recovery inside SequenceMananger.
After the caching change, we also need recovered transactions for FlashBlockCompleteSequence as well, so the choices are:
- Keep the original way of storing
PreparedFlashBlockin bothFlashBlockPendingSequenceandFlashBlockCompleteSequence, but any changes toFlashBlockCompleteSequencewould be breaking lots of interfaces likeFlashBlockListener,FlashBlockConsensClient, etc - Revert to the old way of just having
FlashBlockPendingSequenceusePreparedFlashBlock, however, it still leaves us caching the recovered txs inSequenceManager - Just have
SequenceManagerhandle it all.
Opting for 3 due to:
- Keeping
FlashBlockPendingSequencesimple to just be a data container - all the tx recovering, building related logic is handled by
SequenceManager, keep it consistent - Keep interfaces clean without unnecessary trait bounds
… more comprehensive tests
1. Use SequenceManager to manage pending and cached blocks 2. Remove Stream trait implementation and simplify loop logic 3. Remove CanonicalChainTip listening, it's not needed
0c51485 to
ccc6ef7
Compare
| // Batch process all other immediately available flashblocks | ||
| while let Some(result) = self.incoming_flashblock_rx.next().now_or_never().flatten() { |
Co-authored-by: Matthias Seitz <matthias.seitz@outlook.de>
* dev: chore: Update cargo deps (#65) feat(flashblock): Enable eth_getTransactionByHash support for flashblock (paradigmxyz#19954) feat(flashblocks): Cache recent flashblocks (paradigmxyz#19786) feat(flashblock): improve state root calculation condition (paradigmxyz#19667) feat(flashblocks): add metrics for current block and index (paradigmxyz#19712) refactor(flashblock): Move all flashblocks related data structure to op-alloy (paradigmxyz#19608) chore: add target: flashblock for all flashblock related traces (paradigmxyz#19656) feat(metrics): implement RAII-based block timing with Prometheus support (#60) Fix fmt (#62)
Co-authored-by: Matthias Seitz <matthias.seitz@outlook.de>
Co-authored-by: Matthias Seitz <matthias.seitz@outlook.de>
Co-authored-by: Matthias Seitz <matthias.seitz@outlook.de>
Rework FlashBlock: Introduce SequenceManager and Improve Architecture
Closes: #18373
Reviewer Notes:
Base Sepolia:

Unichain Sepolia:

Summary
This PR introduces a major refactoring of the flashblock system, implementing a
SequenceManagerto handlesequence caching and intelligent block building selection. The changes improve the system's ability to handle
both 1-second and 2-second block times, with and without sequencer-provided state roots.
Key Changes
1. Introduce SequenceManager (
cache.rs)Added
SequenceManagerto centralize sequence management with:compute_state_rootflag for different block timescenarios
build completion (with state_root)
Benefits:
2. Simplify FlashBlockPendingSequence (
sequence.rs)Removed
PreparedFlashblocktype and streamlined the pending sequence implementation:SequenceExecutionOutcometo store computed state_root and block_hash3. Rework FlashBlockService (
service.rs)Major improvements to the service loop:
Event Loop:
4. Rework FlashBlockConsensusClient (
consensus.rs)Simplified consensus client logic:
submit_new_payloadandsubmit_forkchoice_updateengine_newPayloadandengine_forkChoiceUpdatedengine_newPayload, only submit FCU with parent_hash5. Enhanced Test Infrastructure (
test_utils.rs)Improved
TestFlashBlockFactorywith:with_block_time())flashblock_after(),flashblock_for_next_block())Architecture Improvements
Before
FlashBlockService
├── Manual sequence tracking
├── No caching
├── Stream-based loop (complex)
└── CanonicalChainTip listener
After
FlashBlockService
├── SequenceManager (centralized)
│ ├── Pending sequence
│ └── Ring buffer cache (last 3 sequences)
├── Tokio select loop (clean)
├── Efficient batching
└── Smart build selection
Block Time Scenarios
1-Second Blocks (State Root Provided)
2-Second Blocks (State Root Computed)
B256::ZEROfor state_rootTesting
Test Coverage
Key Test Scenarios