Skip to content

Commit 7882a61

Browse files
committed
fix(test): make reorg-based mineEmptyBlock advance L1 time
The v5 mineEmptyBlock rewrite (gas-limit + anvil_reorg, mempool-safe) froze L1 time: anvil stamps a reorg's replacement blocks as parent+N*interval, resetting the wall-clock advance that the mine step produced. next's gas_price_ladder test (added after the v5 fork) drives L1 time forward via mineEmptyBlock and asserts L1TxUtils' stall/timeout ladder; with time frozen, timePassed stays 0, the tx never times out, and the test hits Jest's 40s wall. Neither public line had both the new impl and this test, so the collision only surfaced in the forward-port. Reproduce the wall-clock advance (>=1s per block) through a temporary block-timestamp interval during the reorg, then restore any pre-existing interval (read as pending-latest, since anvil exposes no getter) so deploy-set slot spacing is preserved. Verified: gas_price_ladder 1/1 (was 40s timeout), eth_cheat_codes 22/22, l1_tx_utils 51/51.
1 parent f50abe3 commit 7882a61

1 file changed

Lines changed: 23 additions & 2 deletions

File tree

yarn-project/ethereum/src/test/eth_cheat_codes.ts

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -505,19 +505,40 @@ export class EthCheatCodes {
505505
* reorg is needed because anvil applies a new gas limit only to future blocks: without it the just-mined
506506
* blocks would keep the tiny gas limit, and an `eth_call` against `latest` (whose gas is capped by the
507507
* block gas limit) would revert with "intrinsic gas too high".
508+
*
509+
* The replacement blocks advance L1 time. `anvil_reorg` stamps each replacement as `parent + N*interval`,
510+
* so on its own it would freeze L1 time at the parent timestamp; callers that measure elapsed L1 time
511+
* (L1TxUtils stall/timeout detection, `syncDateProvider`-driven slot advancement) rely on it moving
512+
* forward. We reproduce the wall-clock advance the mine step just made (at least 1s per block) via a
513+
* temporary block-timestamp interval, then restore any pre-existing interval.
508514
*/
509515
public async mineEmptyBlock(blockCount: number = 1): Promise<void> {
510516
await this.execWithPausedAnvil(async () => {
511517
const originalGasLimit = await this.getBlockGasLimit();
518+
const parentTimestamp = await this.lastBlockTimestamp();
519+
// anvil has no getter for the block-timestamp interval, but the pending block is stamped
520+
// `latest + interval`, so this delta is the standing interval (0 when none is set).
521+
const priorInterval = (await this.nextBlockTimestamp()) - parentTimestamp;
512522
try {
513523
await this.setBlockGasLimit(1n);
514524
await this.doMine(blockCount);
515525
} finally {
516526
await this.setBlockGasLimit(originalGasLimit);
517527
}
528+
const advance = (await this.lastBlockTimestamp()) - parentTimestamp;
529+
const perBlockInterval = Math.max(1, Math.floor(advance / blockCount));
518530
// Replace the tiny-gas-limit blocks with empty blocks at the restored gas limit, keeping the same
519-
// height and timestamps. The reorged-out blocks held no transactions, so nothing returns to the pool.
520-
await this.doRpcCall('anvil_reorg', [blockCount, []]);
531+
// height. The reorged-out blocks held no transactions, so nothing returns to the pool.
532+
await this.doRpcCall('anvil_setBlockTimestampInterval', [perBlockInterval]);
533+
try {
534+
await this.doRpcCall('anvil_reorg', [blockCount, []]);
535+
} finally {
536+
if (priorInterval > 0) {
537+
await this.doRpcCall('anvil_setBlockTimestampInterval', [priorInterval]);
538+
} else {
539+
await this.doRpcCall('anvil_removeBlockTimestampInterval', []);
540+
}
541+
}
521542
});
522543

523544
this.logger.warn(`Mined ${blockCount} empty L1 ${pluralize('block', blockCount)}`);

0 commit comments

Comments
 (0)