Files
evm/precompile/modules/module.go
zeekayandHanzo Dev d260656efc evm: gate DEX 0x9999 genesis injection on protocol ActivationTime (preserve pre-2025 genesis)
The AlwaysOn DEX settlement precompile (0x9999) had its EXTCODESIZE marker
baked into EVERY chain's genesis state unconditionally (parent==nil in
ApplyPrecompileActivations), mutating the genesis state root. This changed the
genesis hash of every chain genesised before the DEX activation, breaking RLP
re-import of the real archived Lux mainnet (0x3f4fa2a0), Lux testnet
(0x1c5fe377) and Zoo mainnet (0x7c548af4) — all re-genesised Nov 2024, before
the Dec-2025 activation.

Fix: an AlwaysOn system precompile carries a protocol ActivationTime (Dec 2025
for 0x9999, set by the registry bridge — a fork-like constant, not per-net
config). Its genesis marker is installed ONLY IF ActivationTime <= the genesis
timestamp; otherwise it activates later, on the block transition that crosses
ActivationTime during history replay. Dispatch (GetExtrasRules) is gated on the
same timestamp so a codeless address never dispatches. A chain born before
activation reproduces its ORIGINAL genesis byte-for-byte; a fresh chain born
at/after activation still gets 0x9999 at genesis.

Verified against the real RLP block-0 of all three chains (byte-identical
reproduction) plus a fresh post-activation chain. Corrects two pre-existing
tests that had hardcoded the buggy with-0x9999 hashes as "canonical".

Co-authored-by: Hanzo Dev <[email protected]>
2026-07-02 16:50:11 -07:00

58 lines
2.5 KiB
Go

// Copyright (C) 2019-2025, Lux Industries, Inc. All rights reserved.
// See the file LICENSE for licensing terms.
package modules
import (
"bytes"
"github.com/luxfi/evm/precompile/contract"
"github.com/luxfi/geth/common"
)
type Module struct {
// ConfigKey is the key used in json config files to specify this precompile config.
ConfigKey string
// Address returns the address where the stateful precompile is accessible.
Address common.Address
// Contract returns a thread-safe singleton that can be used as the StatefulPrecompiledContract when
// this config is enabled.
Contract contract.StatefulPrecompiledContract
// Configurator is used to configure the stateful precompile when the config is enabled.
contract.Configurator
// AlwaysOn marks a precompile that is a SYSTEM precompile activated by the Lux
// protocol on every chain with NO per-network config entry (neither a genesis-inlined
// precompile nor a precompileUpgrades timestamp). It takes no per-network parameters
// and resolves everything from the runtime (consensus context / atomic state). The DEX
// settlement precompile (0x9999) is the canonical case. An always-on module's
// Configurator is never invoked (no activating config); the host installs its
// EXTCODESIZE marker and dispatches Run. Bridged from
// github.com/luxfi/precompile/modules.Module.AlwaysOn.
AlwaysOn bool
// ActivationTime is the protocol timestamp at which an AlwaysOn system precompile
// becomes present (EXTCODESIZE marker installed + Run dispatched) on every Lux chain.
// It is NOT per-network config — it is a protocol constant, the analog of a fork
// timestamp, applied uniformly. The zero value means "present from genesis" (the
// historical always-on behavior). A non-zero value means the precompile is ABSENT
// before that timestamp and activates at the block transition crossing it — exactly
// like a dated fork — so a chain whose genesis predates ActivationTime does NOT carry
// the precompile in its genesis state (preserving that chain's original genesis hash),
// and the precompile activates later during history replay at the crossing block.
// Ignored unless AlwaysOn is set. Set by the registry bridge, not the JSON config.
ActivationTime uint64
}
type moduleArray []Module
func (u moduleArray) Len() int {
return len(u)
}
func (u moduleArray) Swap(i, j int) {
u[i], u[j] = u[j], u[i]
}
func (m moduleArray) Less(i, j int) bool {
return bytes.Compare(m[i].Address.Bytes(), m[j].Address.Bytes()) < 0
}