Skip to content

refactor(gas_limiter): canonical + overlay design with epoch tag#488

Open
julio4 wants to merge 1 commit into
mainfrom
refactor/gas-limiter-overlay
Open

refactor(gas_limiter): canonical + overlay design with epoch tag#488
julio4 wants to merge 1 commit into
mainfrom
refactor/gas-limiter-overlay

Conversation

@julio4
Copy link
Copy Markdown
Member

@julio4 julio4 commented May 5, 2026

Refactor the per-address gas/compute limiter to use per-payload overlays over a shared canonical limiter.

Each payload job now records limiter usage in its own overlay and commits it back when the job finishes. This keeps in-flight payload builds isolated while preserving persistent sender debt across jobs. The
limiter also rejects stale overlay commits when the canonical state has already advanced.

Changes

  • Add canonical + overlay limiter model for gas and compute buckets.
  • Add epoch checks to prevent stale overlays from committing.
  • Add checkpoint/restore support for rolling back failed tx attempts.
  • Wire payload jobs to use limiter overlays.
  • Refresh limiter state before forking payload overlays.

@julio4 julio4 force-pushed the refactor/gas-limiter-overlay branch from b951e01 to f7c1bf1 Compare May 5, 2026 10:25
@akundaz
Copy link
Copy Markdown
Contributor

akundaz commented May 5, 2026

This conflicts hugely with my existing PR (#487). Can you describe to me

  • the api you need for continuous building
  • and the performance concerns you have

Then we can build on top of each other and streamline the work properly

@julio4
Copy link
Copy Markdown
Member Author

julio4 commented May 5, 2026

This conflicts hugely with my existing PR (#487). Can you describe to me

  • the api you need for continuous building
  • and the performance concerns you have

Then we can build on top of each other and streamline the work properly

Yes that's why I extracted it from continuous PR, so that we can merge it first and we can update 487 with this foundation.

There's detailed "What was missing" and "What this fixes for continuous mode" sections in the description upper, but tldr we need cheap copy/overlay as only the winning candidate should consume budgets.

@julio4 julio4 force-pushed the refactor/gas-limiter-overlay branch 3 times, most recently from 643d608 to c7f0ea2 Compare May 14, 2026 08:32
@julio4 julio4 force-pushed the refactor/gas-limiter-overlay branch from c7f0ea2 to 595ab27 Compare May 15, 2026 09:56
self.base.len()
}

/// Fork an overlay sharing this canonical's base. O(1).
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.

Rename methods for clarity:

  • refresh -> refill_buckets so it can't be confused with the overlay concept
  • fork -> begin
  • fold_overlay -> commit
    Makes it more clear this is basically a db transaction

if let Some(inner) = self.gas_limiter.as_ref() {
inner.refresh(block_number)
/// Snapshot the current overlay state for later [`Self::restore`].
pub fn checkpoint(&self) -> AddressLimiterCheckpoint {
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.

I don't think you need to include checkpoint and restore methods in the public api. If you want to introduce a snapshot system then the AddressBuckets type at the bottom should be able to manage its own snapshots

/// In-flight overlay. Reads/consumes go through here with `&self`; on
/// commit the accumulated deltas are folded back into the canonical.
#[derive(Debug)]
pub(super) struct GasLimiterOverlay {
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.

Can you work on following the generic pattern from bucket.rs when possible? It looks like there don't need to be separate GasLimiterOverlay and ComputeLimiterOverlay definitions

/// back into the canonical when this ctx is dropped. Shadows the
/// `address_limiter` field reached via `Deref` to `OpPayloadBuilderCtx`,
/// so `self.address_limiter` inside this ctx always hits the overlay.
pub address_limiter: AddressLimiterOverlay,
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.

An overlay is something that sits on top of something else to provide more information or context, but this is really a set of changes that are supposed to be atomically applied (or discarded) like a database transaction. I think naming it that way would help a lot with comprehension but since transaction is already taken can you rename the suffix to maybe Guard, Scope, Lease, or something else?

/// tracks how much was overdrawn.
#[derive(Debug, Clone)]
struct TokenBucket<T> {
pub(super) struct TokenBucket<T> {
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.

Other modules shouldn't need to carry around and know about TokenBuckets, just the higher up AddressBuckets and the session type, please restrict this

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.

2 participants