Skip to content

feat: continuous-build mode#458

Open
julio4 wants to merge 1 commit intomainfrom
feat/continuous-flashblock-build
Open

feat: continuous-build mode#458
julio4 wants to merge 1 commit intomainfrom
feat/continuous-flashblock-build

Conversation

@julio4
Copy link
Copy Markdown
Member

@julio4 julio4 commented Apr 9, 2026

📝 Summary

Adds a continuous flashblock building mode (under --flashblocks.continuous-build flag) that pre-seals candidates between scheduler triggers, so the best block is ready for instant publish when the timer fires.

Built on top of #438

How it works

  1. Fallback block built as usual
  2. Per flashblock interval, a blocking task runs a candidate loop:
    • Empty candidate sealed first (builder txs only) to guarantees a publishable result even if the scheduler fires immediately or the first candidate takes too much time to build
    • Pool candidates built continuously: clone base state → execute pool txs → add bottom builder txs → seal (state root) → keep if better than current best (by cumulative_gas_used)
    • Loop sleeps with exponential backoff when pool hasn't changed (driven by pool_change_epoch from a pool event listener)
    • When fb_cancel fires (scheduler trigger), the loop exits and returns the best candidate
  3. Publish: the async orchestrator receives the pre-sealed result and publishes instantly via WS + payload channels
  4. Spawn next: new blocking task starts immediately for the next interval

Details

  • Gas limiter isolation: AddressGasLimiter wraps Arc<DashMap>, new snapshot()/restore() methods deep-copy the token buckets so each candidate starts with the same gas budget
  • Pool change detection: A dedicated task listens to Pending and Replaced pool events, incrementing an AtomicU64 epoch. The candidate loop skips rebuilds when the epoch hasn't changed
  • State reconstruction: Each blocking task reconstructs State<DB> from (CacheState, TransitionState) + state_by_block_hash since State isn't Send. build_block is designed to leave transition_state intact (saves/restores it internally)
  • BestCandidate struct: All best-candidate state (cache, transitions, info, committed txs, sealed payload) grouped in a single struct, all updates are structurally enforced to be in same lockstep
  • publish_and_spawn_next function: returns FlashblockAction::Continue { fb_span, build_rx, build_start } or Exit
  • reserve_builder_tx_budget helper: Shared between sequential and continuous paths, adjusts gas/DA/uncompressed limits for bottom-of-block builder txs
  • next_after_seal: Shared between sequential and continuous paths, encapsulates the DA/gas limit advancement for the next flashblock
  • New metrics: continuous_build_duration, candidate_staleness, continuous_candidates_evaluated, continuous_candidates_improved

@julio4 julio4 force-pushed the reapply-async-payload-builder branch from d83dffd to cbe4b7a Compare April 15, 2026 06:45
@julio4 julio4 force-pushed the feat/continuous-flashblock-build branch from 895a4a2 to d45b137 Compare April 15, 2026 07:53
Base automatically changed from reapply-async-payload-builder to main April 16, 2026 10:21
fb_payload.base = None;

let best_gas_used = best.as_ref().map_or(0, |b| b.gas_used);
let is_new_best =
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why "better" is cumulative_gas_used instead of priority fee tips?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

my intuition is that the candidate know how to order to i.e. maximize prio fee; but the outer candidate loop only try to maximize filling blocks. But there may be cases where best candidate is selected when we had a better one in terms of fees

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what if a tx comes in with high fees during flashblock block building, txs with high gas usage would be prioritized over the high fee tx no? I think we should always use priority fee as the metric as a better block

Comment thread crates/op-rbuilder/src/metrics.rs
@julio4 julio4 force-pushed the feat/continuous-flashblock-build branch from d45b137 to 3435df5 Compare April 19, 2026 02:45
Comment thread crates/op-rbuilder/src/builder/payload.rs
Comment thread crates/op-rbuilder/src/builder/continuous.rs

let metrics = Arc::new(OpRBuilderMetrics::default());
let task_metrics = Arc::new(FlashblocksTaskMetrics::new());
let pool_change_epoch = Arc::new(AtomicU64::new(0));
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is the purpose of this pool change atomic?

Comment thread crates/op-rbuilder/src/builder/payload.rs
Comment thread crates/op-rbuilder/src/builder/continuous.rs
@avalonche
Copy link
Copy Markdown
Collaborator

did you push your changes correctly? don't see code changes for comments

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants