在默认自动采矿路径上连续采矿具有相同时间戳的区块
This is the fix @grandizzy asked for in #9142: @Rubilmax mind to open a ticket with a way to reproduce the problem you see? thank you! That ticket never got filed, so here it is. ## What it says on the box The default `anvil` (default automine, no `--block-time`, no `setBlockTimestampInterval` tweak) mines consecutive blocks with the identical `block.timestamp`. Confirmed with four ordinary `cast send` transfers, no flags: block 2 ts 1788310641 block 3 ts 1788310641 block 4 ts 1788310641 A forward time jump makes it worse - after `anvil_mine(1, 10000)`, every subsequent block freezes at that same timestamp: blocks 2-5 all ts 1788320438 ## Where `crates/anvil/src/eth/backend/time.rs:181-183`: // Ensures that the timestamp is always increasing if next_timestamp < last_timestamp { next_timestamp = last_timestamp + 1; } Comment says "always increasing", comparison is `<`, so equality sails through untouched. Sibling `set_next_block_timestamp` (~line 127/131) has a doc comment saying it "fails if it's before (or at the same time) the last timestamp" but only checks `<` too. ## Why it matters Yellow Paper eq. 55 requires `Hs > P(H)Hs` (strictly increasing). geth rejects `header.Time <= parent.Time` with `errOlderBlockTime`. Hardhat and Ganache both guarantee `parent+1`. anvil is the odd one out on the default path. Concretely, this makes downstream test suites go green when they should catch a real bug: - Uniswap V2 `_update`: `if (timeElapsed > 0)` - TWAP accumulators never accumulate across same-second blocks - Uniswap V3 `Oracle.write`: `if (last.blockTimestamp == blockTimestamp) return` - the observation write is silently dropped - Synthetix `StakingRewards.rewardPerToken` and similar reward-streaming contracts: zero accrual for that block A TWAP-manipulation guard test written against anvil can pass vacuously because the timestamp never actually advances between the manipulation block and the read block. ## Prior art #13694 proposed exactly this fix (`<` -> `<=`) and got a positive review (`zerosnacks`: "Makes sense, thanks!"), then the stale-bot closed it 2026-06-29 for inactivity, not on merit. The catch: #9142 itself is a legitimate feature request for same-timestamp blocks under `--block-time 0`, and it shipped. A naive blanket `<=` would break that. The distinction that needs preserving: same-timestamp is fine when it was explicitly requested (`interval == Some(0)` or an exact `setBlockTimestampInterval`/`setNextBlockTimestamp` override), but should not leak into the default automine path where nothing asked for it. That's plausibly why #13694 stalled rather than merged outright - it needed that narrower framing, not just the comparison flip. ## Suggested fix shape Clamp to strictly-increasing on the default path; only permit equal timestamps when the same-timestamp mode was explicitly opted into (matching what #9142 actually asked for, not a blanket relaxation). Happy to open a
内容来源: foundry-rs/foundry