mirror of
https://github.com/luxfi/evm.git
synced 2026-09-24 00:27:44 +00:00
Replace the v1.99.32 "always-on, dispatch-only, no marker" activation of the
0x9999 DEX settlement money path with the CTO's exact model: a SINGLE canonical
dated fork that both enables dispatch AND installs the EXTCODESIZE marker —
forward, at the fork boundary, never in historical genesis.
The fork: extras.DexSettleActivationTime = 1766704800 (Dec 25 2025 00:00:00 UTC),
defined ONCE in params/extras/network_upgrades.go alongside the Durango/Quasar/
Fortuna/Granite built-in upgrades. NOT per-net config (no per-net upgrade.json
precompileUpgrades entry, no genesisPrecompiles entry) — one dated fork, identical
on every Lux network, DRY. This is the proper canonical fork mechanism for a
system precompile that takes no per-net parameters (0x9999 resolves protocolFee-
Controller=DefaultDAOTreasury and dChainID at runtime from the consensus context).
Two coupled effects, both gated on that one timestamp:
1. DISPATCH (params/config_extra.go GetExtrasRules): the AlwaysOnModules() inject
into the enabled precompile set is now wrapped in extras.IsDexSettleActive(ts)
— present at/after Dec 25, ABSENT before. This is REQUIRED for canonical
history: replaying a pre-Dec-25 block (the ~/work/lux/state RLP snapshot, e.g.
lux-mainnet 96369 = 1,082,780 blocks via admin.importChain) must see 0x9999 as
a PLAIN ACCOUNT so a historical value transfer to that address behaves as it
did originally, not as a precompile dispatch. The prior unconditional inject
would have diverged replay from canonical state.
2. MARKER (core/state_processor_ext.go ApplyPrecompileActivations): on the block
transition that CROSSES the fork (params.IsDexSettleForkTransition →
extras.IsForkTransition), write the STANDARD precompile-activation marker
(SetNonce=1 + SetCode{0x1}) into 0x9999 — identical to the config-driven path.
This is the forward state upgrade: EXTCODESIZE(0x9999)>0, eth_getCode!=0x, and
Solidity's contract-existence guard passes for a typed IPoolManager(0x9999)
.swap(...). The prior change DROPPED this marker to avoid mutating genesis;
installing it forward at the fork preserves the genesis hash (pre-activation
blocks get NO marker) while making typed calls work post-activation. Reverts
the v1.99.32 "writes NO genesis state for always-on modules" skip.
IsForkTransition fires exactly once (!parentForked && currentForked). For a fresh
net whose genesis timestamp is already >= the fork (parent==nil), it fires at
genesis — so fresh/local/new nets carry the marker from block 0 via the SAME
mechanism, no separate genesisPrecompiles entry (CTO step 4). For an existing net
(genesis ts < fork) it does NOT fire at genesis — genesis hash immutable — and
fires forward at the Dec 25 block.
KEPT byte-for-byte: runtime DChainID via BCLookup.Lookup("D"), DefaultDAOTreasury
protocolFeeController, networkID/cChainID from runtime context, AlwaysOn module
tagging + AlwaysOnModules(), all settlement/money-path logic.
0x9010: with precompile v0.5.53 the 0x9010 module is no longer registered, so the
EVM never dispatches it and eth_getCode(0x9010)=0x. registry comment updated to
LP-9999. No EVM-side 0x9010 dispatch reference existed.
deps: precompile v0.5.52 -> v0.5.53.
Tests (core/precompile_alwayson_test.go, rewritten — DRY, replaces the prior
unconditional/no-marker assertions):
- TestDexSettle_DispatchGate_TimestampGated: 0x9999 absent pre-fork, present
at/after (replay safety + post-activation dispatch).
- TestDexSettle_NoGenesisMarker_ExistingNet: genesis (ts<fork) writes no marker
(genesis hash immutable).
- TestDexSettle_MarkerInstalledAtForkTransition: marker (nonce=1 + code, EXTCODESIZE>0)
installed at the boundary block.
- TestDexSettle_ForkTransitionFiresOnce: fires once; fresh-net genesis>=fork at
block 0; existing-net genesis<fork not at genesis.
- TestAlwaysOn_9999_Registered: 0x9999 bridged AlwaysOn.
core + params/extras green incl. the real-mainnet genesis-hash guards. (Two
pre-existing unrelated failures on pristine main: params/config_test.go references
a removed DurangoTimestamp field; params/extras mainnet upgrade.json ringConfig/
warpConfig timestamp guards — both fail identically with these changes stashed.)