@@ -223,4 +223,88 @@ describe('FeePredictor', () => {
223223 } ,
224224 60_000 ,
225225 ) ;
226+
227+ it ( 'predictions match L1 across successive slots over time' , async ( ) => {
228+ const constantBaseFee = 50_000_000_000n ;
229+
230+ // Pin L1 fees to a constant by updating the oracle twice (sets both pre and post).
231+ await rollupCheatCodes . advanceSlots ( FEE_ORACLE_LAG + 1 ) ;
232+ await cheatCodes . setNextBlockBaseFeePerGas ( constantBaseFee ) ;
233+ await rollupCheatCodes . updateL1GasFeeOracle ( ) ;
234+ await rollupCheatCodes . advanceSlots ( FEE_ORACLE_LAG + 1 ) ;
235+ await cheatCodes . setNextBlockBaseFeePerGas ( constantBaseFee ) ;
236+ await rollupCheatCodes . updateL1GasFeeOracle ( ) ;
237+ await rollupCheatCodes . advanceSlots ( 3 ) ;
238+ await cheatCodes . mine ( ) ;
239+
240+ const manaTarget = await rollup . getManaTarget ( ) ;
241+ const rollupAddress = EthAddress . fromString ( rollup . address ) ;
242+
243+ /** Writes a fee header and slot number for the given checkpoint, then bumps the pending tip. */
244+ async function advanceCheckpoint ( checkpointNumber : CheckpointNumber , feeHeader : FeeHeader , slotNumber : bigint ) {
245+ const feeHeaderSlot = await rollup . getTempCheckpointLogStorageSlot (
246+ checkpointNumber ,
247+ TempCheckpointLogField . FeeHeader ,
248+ ) ;
249+ await cheatCodes . store ( rollupAddress , feeHeaderSlot , RollupContract . compressFeeHeader ( feeHeader ) ) ;
250+
251+ const slotNumberSlot = await rollup . getTempCheckpointLogStorageSlot (
252+ checkpointNumber ,
253+ TempCheckpointLogField . SlotNumber ,
254+ ) ;
255+ await cheatCodes . store ( rollupAddress , slotNumberSlot , slotNumber & ( ( 1n << 32n ) - 1n ) ) ;
256+
257+ const currentTips = await cheatCodes . load ( rollupAddress , RollupContract . chainTipsStorageSlot ) ;
258+ const provenCheckpointNumber = currentTips & ( ( 1n << 128n ) - 1n ) ;
259+ await cheatCodes . store (
260+ rollupAddress ,
261+ RollupContract . chainTipsStorageSlot ,
262+ RollupContract . packChainTips ( BigInt ( checkpointNumber ) , provenCheckpointNumber ) ,
263+ ) ;
264+ }
265+
266+ const pendingCheckpointNumber = await rollup . getCheckpointNumber ( ) ;
267+ const currentFeeHeader = ( await rollup . getCheckpoint ( pendingCheckpointNumber ) ) . feeHeader ;
268+
269+ let prevExcessMana = currentFeeHeader . excessMana ;
270+ let prevManaUsed = currentFeeHeader . manaUsed ;
271+ let nextCheckpointOffset = 1 ;
272+
273+ // Step through 6 successive slots, creating a fresh predictor each time.
274+ for ( let step = 0 ; step < 6 ; step ++ ) {
275+ const predictor = new FeePredictor ( rollup , slotDuration , l1GenesisTime ) ;
276+ const predicted = await predictor . getPredictedMinFees ( publicClient , ManaUsageEstimate . None ) ;
277+
278+ expect ( predicted . length ) . toBe ( FEE_ORACLE_LAG + 1 ) ;
279+
280+ const startSlot = await getPredictionStartSlot ( ) ;
281+ for ( let i = 0 ; i < predicted . length ; i ++ ) {
282+ const l1Fee = await rollup . getManaMinFeeAt ( getTimestamp ( startSlot + BigInt ( i ) ) , true ) ;
283+ expect ( predicted [ i ] . feePerL2Gas ) . toBe ( l1Fee ) ;
284+ }
285+
286+ // Advance: simulate proposing a checkpoint at the current slot with zero mana usage.
287+ const newExcessMana = computeExcessMana ( prevExcessMana , prevManaUsed , manaTarget ) ;
288+ const newCheckpointNumber = CheckpointNumber . add ( pendingCheckpointNumber , nextCheckpointOffset ) ;
289+ const newFeeHeader : FeeHeader = {
290+ excessMana : newExcessMana ,
291+ manaUsed : 0n ,
292+ ethPerFeeAsset : currentFeeHeader . ethPerFeeAsset ,
293+ congestionCost : 0n ,
294+ proverCost : 0n ,
295+ } ;
296+
297+ await advanceCheckpoint ( newCheckpointNumber , newFeeHeader , startSlot ) ;
298+
299+ // Warp to the next slot.
300+ const nextTimestamp = getTimestamp ( startSlot + 1n ) ;
301+ await cheatCodes . warp ( Number ( nextTimestamp ) ) ;
302+ await cheatCodes . setNextBlockBaseFeePerGas ( constantBaseFee ) ;
303+ await cheatCodes . mine ( ) ;
304+
305+ prevExcessMana = newExcessMana ;
306+ prevManaUsed = 0n ;
307+ nextCheckpointOffset ++ ;
308+ }
309+ } , 60_000 ) ;
226310} ) ;
0 commit comments