mirror of
https://github.com/luxfi/evm.git
synced 2026-09-24 00:27:44 +00:00
Red review of the 0x9999 dated-fork activation (v1.99.33) found ONE HIGH that
blocked the production deploy, plus a money-path footgun and two guards. The
money path (V4 swap ABI, EXTCODESIZE marker, two-phase atomic settle) is
byte-for-byte unchanged — only the dispatch-path timestamp source, the SubBalance
fail-mode, the genesis-builder guard, and stale comments change. Bumps
precompile v0.5.53 -> v0.5.54 (Red L1 comment scrub).
H1 (HIGH, blocked deploy) — consensus-divergence on the relaunch/replay path:
core.LuxPrecompileOverrider.PrecompileOverride read the PROCESS-GLOBAL
params.lastRulesContext via GetRulesExtra(Rules{}). That global is rewritten
last-writer-wins by SetRulesContext on every Rules()/RulesAt() — including
concurrent eth_call/estimateGas/miner goroutines. The geth EVM invokes
PrecompileOverride LAZILY during opcode execution, a different instant than when
precompileHook set the global. On a live, RPC-serving post-fork node replaying a
PRE-fork RLP block (admin.importChain), a concurrent post-fork eth_call could
overwrite the global timestamp between the verify goroutine's NewEVM(pre-fork
block) and its tx dispatch -> the pre-fork block sees 0x9999 ENABLED and
dispatches SettleContract.Run during plain-account execution -> STATE DIVERGENCE.
Fix: the dispatch gate now decides from the overrider's OWN per-EVM fields
(o.chainConfig + o.timestamp) via the pure params.GetExtrasRules — which performs
the SAME dated-fork (extras.IsDexSettleActive) computation GetRulesExtra did,
minus the racy global read. Audited every GetRulesExtra reader: only the overrider
was on the precompile-dispatch path; no other dispatch/consensus-replay call site
consults the 0x9999 gate. Every replay of a given block now yields the same
enabled set on every validator, independent of concurrent activity.
L2 (money-path footgun) — registry stateDBBridge.SubBalance fail-open silent mint:
when the subBalancer type-assertion failed it logged + returned a zero 'previous
balance' WITHOUT subtracting, while the caller treats the debit as successful ->
native value minted. Now FAILS CLOSED: it panics, which the EVM recovers into a
reverted call, so the enclosing value move rolls back rather than committing
half-done. Structurally unreachable in prod (the concrete adapter implements
SubBalance) but no longer mints if a future StateDB omits it.
INFO1 (latent footgun) — genesis-config builders bypassed the dated fork:
SetAllGenesisPrecompiles/AllGenesisPrecompiles iterated ALL RegisteredModules()
incl the AlwaysOn 0x9999 and wrote timestamp-0 genesis configs, which would enable
0x9999 from block 0 on a fresh chain — bypassing the dated fork and re-introducing
the genesis-marker mutation. Both builders now skip AlwaysOn modules.
INFO2 (tests):
- core: -race regression TestDexSettle_PrecompileOverride_NoGlobalRace reproduces
the exact relaunch race (pre-fork verify vs concurrent post-fork eth_call
clobbering the global) and asserts the pre-fork side ALWAYS sees 0x9999 ABSENT,
post-fork ALWAYS PRESENT. PerEVMTimestamp pins the gate reads o.timestamp not the
global. Replay e2e asserts a pre-fork value transfer to 0x9999 credits a PLAIN
account WITHOUT invoking the precompile. All proven to FAIL under the old
global-read code and PASS under the fix; -race clean.
- extras + core: TestGenesisPrecompileBuilders_SkipAlwaysOn / _Skip9999 pin INFO1.
- subbalance test comment refreshed to 0x9999 + fail-closed semantics.