Skip to content

fix(sequencer): anchor fee asset price modifier to predicted parent#23113

Open
spalladino wants to merge 1 commit intomerge-train/spartanfrom
spl/fee-asset-price-oracle-read-fix
Open

fix(sequencer): anchor fee asset price modifier to predicted parent#23113
spalladino wants to merge 1 commit intomerge-train/spartanfrom
spl/fee-asset-price-oracle-read-fix

Conversation

@spalladino
Copy link
Copy Markdown
Contributor

Motivation

Under proposer pipelining, checkpoint N's fee asset price modifier is computed in slot N-1 before checkpoint N-1 has landed on L1. The proposer was reading rollupContract.getEthPerFeeAsset(), which still reflects the latest published checkpoint (commonly N-2), while L1 later applies the modifier against checkpoint N-1's ethPerFeeAsset. The mismatch produced a 1-checkpoint drift between the proposer's intended new price and the price L1 actually stored, causing the e2e price-convergence test to oscillate around the target instead of converging.

Approach

Threads the predicted parent's ethPerFeeAsset through to the modifier computation. buildPipelinedParentSimulationOverridesPlan already derives that fee header for global-variable simulation overrides; the pending fee header on the resulting plan is used as the reference price for the bps calculation. Non-pipelined paths and genesis (checkpoint < 2) fall back to today's getEthPerFeeAsset() read.

Changes

  • ethereum: FeeAssetPriceOracle.computePriceModifier() now takes an optional currentPriceE12; when supplied, the L1 read is skipped.
  • sequencer-client: SequencerPublisher.getFeeAssetPriceModifier() forwards the optional predicted price; checkpoint_proposal_job reads it from the pipelined simulation overrides plan and passes it through.
  • end-to-end: enables proposer pipelining + inboxLag: 2 in fee_asset_price_oracle_gossip.test.ts.
  • ethereum (tests): adds 3 unit tests covering the L1-read fallback, the predicted-price short-circuit, and concrete-value consistency with RollupContract.computeChildFeeHeader (asserting modifier truncation leaves a sub-bp gap to target).

Note: if pipelining is enabled at checkpoint ≥ 2 but proposedCheckpointData is missing, the predicted-parent will be undefined and the code silently falls back to the stale L1 read. That's a pre-existing failure-mode behavior, not introduced here.

Under proposer pipelining the modifier for checkpoint N is computed in slot
N-1, before checkpoint N-1 has landed on L1. The proposer was deriving the
modifier off `rollupContract.getEthPerFeeAsset()`, which still reflects the
latest published checkpoint (commonly N-2). When L1 later applied the modifier
in `computeNewEthPerFeeAsset`, it multiplied it against checkpoint N-1's
`ethPerFeeAsset` — one step ahead of the proposer's reference — causing a
1-checkpoint drift between intended and stored prices.

Threads the predicted parent's `ethPerFeeAsset` (already computed for the
pipelined simulation override) through `getFeeAssetPriceModifier()` into
`FeeAssetPriceOracle.computePriceModifier()`. Non-pipelined and genesis
(checkpoint < 2) paths fall back to today's L1 read.
Copy link
Copy Markdown
Collaborator

@just-mitch just-mitch left a comment

Choose a reason for hiding this comment

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

Kind of interesting that it seems to work regardless of what the parent actually does.

E.g. if we're far below what I perceive to be the true value, I expect you to add 100bps. Regardless of what you actually did, I'm still going to add 100bps.

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