mirror of
https://github.com/luxfi/evm.git
synced 2026-09-24 00:27:44 +00:00
Wires the existing cevm (C++ EVM) byte-exact shadow verifier so it observes EVERY block of the real ./core suite, and reports the true tally — without weakening the gate or ever letting cevm apply state. - core/main_cevm_test.go (//go:build cevm): a cevm-only TestMain that runs the whole ./core suite then prints the aggregate parallel.CevmShadowStats(). Because state_processor.go:124 routes every block through parallel.DefaultExecutor().ExecuteBlock — which under -tags cevm is the cevmShadowExecutor — this is the honest whole-suite count. main_test.go's goleak TestMain is gated //go:build !cevm so exactly one TestMain exists per build. - core/parallel/cevm_shadow_registration_test.go (//go:build cevm): asserts DefaultExecutor() is the cevmShadowExecutor (not the no-op fallback) — the precondition for the whole claim. - core/parallel/cevm_shadow_e2e_test.go: scaled the real-StateProcessor agreement proof from 3 to 256 genuine InsertChain blocks (768 transfers). cevm's independent real-MPT process_block root byte-matched the Go EVM header.Root on ALL 256/256 blocks (0 disagree, 0 finalize-gap). - Four precompile test files (genesis_dexsettle_reproduce, precompile_alwayson, precompile_statedb_subbalance, precompile_env_call) gated //go:build !cevm: they alone pull precompile/registry -> luxfi/precompile/dex -> luxfi/dex/pkg/dex whose cgo file #includes the absent dex_gpu.h, breaking the CGO_ENABLED=1 build the bridge needs. They are precompile tests, not block-execution tests, and still run in every non-cevm build — an orthogonal blocker isolated, not a cevm regression. HONEST RESULTS (CGO_ENABLED=1 -tags cevm): - Whole ./core suite: 78 PASS / 0 FAIL / 32 SKIP. cevm observed all 9794 blocks; it declined every one as no-preimage (the production default runs preimages OFF, and the shadow needs trie-key preimages to recover the 20-byte addresses that seed cevm) — 0 disagree, 0 errored, 0 false roots. The Go EVM applied every block; cevm never touched state. - Real-block agreement (preimages ON, the config the shadow requires), driven through core.BlockChain.InsertChain -> StateProcessor.Process -> the shadow: 256/256 blocks byte-exact agreement (768 transfers). Default (!cevm) build unchanged: ./core and ./core/parallel green in both CGO modes; the 10 gated precompile tests present in the default build. Co-authored-by: Hanzo Dev <[email protected]>
173 lines
8.6 KiB
Go
173 lines
8.6 KiB
Go
// Copyright (C) 2025-2026, Lux Industries Inc. All rights reserved.
|
|
// See the file LICENSE for licensing terms.
|
|
|
|
// Excluded under -tags cevm: this test imports precompile/registry, which
|
|
// transitively pulls luxfi/precompile/dex -> luxfi/dex/pkg/dex whose cgo file
|
|
// #includes the (absent) dex_gpu.h header — breaking the CGO_ENABLED=1 build the
|
|
// cevm shadow verifier needs. It is an unrelated precompile-settle test, not a
|
|
// block-execution test, so gating it out of the cevm test binary keeps cgo ON
|
|
// for the real ./core block suite while this test still runs in every other
|
|
// build. Orthogonal blocker, not a cevm regression.
|
|
//go:build !cevm
|
|
|
|
package core
|
|
|
|
import (
|
|
"encoding/json"
|
|
"fmt"
|
|
"math/big"
|
|
"testing"
|
|
|
|
"github.com/holiman/uint256"
|
|
"github.com/luxfi/evm/core/state"
|
|
"github.com/luxfi/evm/precompile/registry"
|
|
"github.com/luxfi/geth/core/rawdb"
|
|
"github.com/luxfi/geth/core/tracing"
|
|
gethtypes "github.com/luxfi/geth/core/types"
|
|
"github.com/stretchr/testify/require"
|
|
|
|
// Register the full precompile set (incl. the AlwaysOn DEX settlement module at
|
|
// 0x9999), exactly as the production node does.
|
|
_ "github.com/luxfi/evm/precompile/registry"
|
|
)
|
|
|
|
// This file is the ship-gate regression for the DEX settlement precompile (0x9999)
|
|
// genesis-injection fix. Before the fix, 0x9999's EXTCODESIZE marker was baked into
|
|
// EVERY chain's genesis state unconditionally, which mutated the genesis state root and
|
|
// changed the genesis hash of every pre-2025 chain — breaking RLP re-import of the real
|
|
// archived Lux mainnet, Lux testnet and Zoo mainnet (all re-genesised Nov 2024, before
|
|
// the DEX settlement activation, Dec 2025). The fix gates the injection on the
|
|
// precompile's protocol ActivationTime: it lands in genesis state ONLY IF
|
|
// ActivationTime <= the genesis timestamp, so a chain born before activation reproduces
|
|
// its ORIGINAL genesis byte-for-byte, and 0x9999 instead activates later, at the block
|
|
// crossing the timestamp.
|
|
//
|
|
// The three real genesis hashes below are the authoritative block-0 hashes of the RLP
|
|
// exports in ~/work/lux/state/rlp/{lux-mainnet,lux-testnet,zoo-mainnet}. They are the
|
|
// literal import targets; if a computed hash drifts from them, the archived chains
|
|
// cannot be re-imported. addr9999 is defined in precompile_alwayson_test.go.
|
|
|
|
// canonicalGenesisJSON is the 2-account genesis shared by the Nov-2024 re-genesis of
|
|
// Lux mainnet, Lux testnet and Zoo mainnet: the historical warp precompile marker at
|
|
// 0x02..05 (code 0x01) + the treasury at 0x9011 funded with 2e30 wei — stateRoot
|
|
// 0x2d1cedac…, NO 0x9999. The three chains differ ONLY in chainId and genesis timestamp
|
|
// (all other header fields — gasLimit 0xb71b00, baseFee 25e9, zero difficulty/nonce/
|
|
// coinbase/mixhash, empty extraData, 16-field pre-withdrawals header — are identical).
|
|
// quasarTimestamp is set far in the future so Cancun is inactive at genesis and the
|
|
// header stays in the original pre-withdrawals (16-field) format.
|
|
const canonicalGenesisJSON = `{
|
|
"alloc": {
|
|
"0200000000000000000000000000000000000005": {"balance":"0x0","code":"0x01","nonce":"0x1"},
|
|
"9011E888251AB053B7bD1cdB598Db4f9DEd94714": {"balance":"0x193e5939a08ce9dbd480000000"}
|
|
},
|
|
"baseFeePerGas": "0x5d21dba00",
|
|
"coinbase": "0x0000000000000000000000000000000000000000",
|
|
"config": {
|
|
"berlinBlock":0,"byzantiumBlock":0,"chainId":%d,"constantinopleBlock":0,
|
|
"durangoTimestamp":0,"eip150Block":0,"eip155Block":0,"eip158Block":0,
|
|
"quasarTimestamp":253399622400,"evmTimestamp":0,
|
|
"fortunaTimestamp":253399622400,"graniteTimestamp":253399622400,
|
|
"homesteadBlock":0,"istanbulBlock":0,"londonBlock":0,"muirGlacierBlock":0,
|
|
"petersburgBlock":0,"terminalTotalDifficulty":0,
|
|
"feeConfig":{"baseFeeChangeDenominator":36,"blockGasCostStep":200000,"gasLimit":12000000,
|
|
"maxBlockGasCost":1000000,"minBaseFee":25000000000,"minBlockGasCost":0,
|
|
"targetBlockRate":2,"targetGas":15000000}
|
|
},
|
|
"difficulty": "0x0",
|
|
"extraData": "0x",
|
|
"gasLimit": "0xb71b00",
|
|
"gasUsed": "0x0",
|
|
"mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
|
|
"nonce": "0x0",
|
|
"number": "0x0",
|
|
"parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
|
|
"timestamp": "%s"
|
|
}`
|
|
|
|
func canonicalGenesis(t *testing.T, chainID uint64, timestampHex string) *Genesis {
|
|
t.Helper()
|
|
var g Genesis
|
|
require.NoError(t, json.Unmarshal([]byte(fmt.Sprintf(canonicalGenesisJSON, chainID, timestampHex)), &g))
|
|
return &g
|
|
}
|
|
|
|
// TestGenesisReproduce_PreDexActivationChains is the hard ship gate: the fixed build
|
|
// reproduces the ORIGINAL block-0 genesis hash of each real archived chain, byte-
|
|
// identical, so its RLP re-imports. All three were re-genesised in Nov 2024, before the
|
|
// DEX settlement activation (Dec 2025), so NONE carries 0x9999 in genesis state.
|
|
func TestGenesisReproduce_PreDexActivationChains(t *testing.T) {
|
|
cases := []struct {
|
|
name string
|
|
chainID uint64
|
|
timestampHex string // block-0 header timestamp, from the RLP export
|
|
wantHash string // authoritative block-0 hash, the RLP import target
|
|
}{
|
|
{"lux-mainnet-96369", 96369, "0x672485c2", "0x3f4fa2a0b0ce089f52bf0ae9199c75ffdd76ecafc987794050cb0d286f1ec61e"},
|
|
{"lux-testnet-96368", 96368, "0x67259912", "0x1c5fe37764b8bc146dc88bc1c2e0259cd8369b07a06439bcfa1782b5d4fb0995"},
|
|
{"zoo-mainnet-200200", 200200, "0x6727e9c3", "0x7c548af47de27560779ccc67dda32a540944accc71dac3343da3b9cd18f14933"},
|
|
}
|
|
for _, tc := range cases {
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
g := canonicalGenesis(t, tc.chainID, tc.timestampHex)
|
|
// Genesis timestamp is Nov 2024, strictly before the DEX activation.
|
|
require.Less(t, g.Timestamp, registry.DexSettleActivationTime,
|
|
"precondition: this chain's genesis must predate DEX settlement activation")
|
|
|
|
blk := g.ToBlock()
|
|
require.Equal(t, tc.wantHash, blk.Hash().Hex(),
|
|
"%s genesis hash MUST reproduce byte-identically or the archived RLP cannot import", tc.name)
|
|
|
|
// 0x9999 must NOT be in the genesis state (this is what preserves the hash).
|
|
sdb := genesisState(t, g)
|
|
require.Empty(t, sdb.GetCode(addr9999),
|
|
"0x9999 must be absent from a pre-activation chain's genesis state")
|
|
require.Zero(t, sdb.GetNonce(addr9999),
|
|
"0x9999 must carry no activation nonce at a pre-activation genesis")
|
|
})
|
|
}
|
|
}
|
|
|
|
// TestGenesisReproduce_FreshChainWantsDexAtGenesis pins condition 4: a genuinely fresh
|
|
// chain whose genesis timestamp is at/after the DEX activation DOES get 0x9999 injected
|
|
// into its genesis state (EXTCODESIZE marker present from block 0), and its genesis hash
|
|
// therefore differs from the same chain built with a pre-activation timestamp.
|
|
func TestGenesisReproduce_FreshChainWantsDexAtGenesis(t *testing.T) {
|
|
freshTS := registry.DexSettleActivationTime + 3600 // one hour after activation
|
|
g := canonicalGenesis(t, 424242, fmt.Sprintf("0x%x", freshTS))
|
|
require.GreaterOrEqual(t, g.Timestamp, registry.DexSettleActivationTime)
|
|
|
|
sdb := genesisState(t, g)
|
|
require.Equal(t, []byte{0x01}, sdb.GetCode(addr9999),
|
|
"a chain genesised at/after DEX activation MUST carry the 0x9999 marker at genesis")
|
|
require.Equal(t, uint64(1), sdb.GetNonce(addr9999),
|
|
"0x9999 must carry the activation nonce at a post-activation genesis")
|
|
|
|
// Its hash must differ from the identical chain built one second before activation
|
|
// (which omits 0x9999) — proving the injection is genuinely timestamp-gated, not inert.
|
|
pre := canonicalGenesis(t, 424242, fmt.Sprintf("0x%x", registry.DexSettleActivationTime-1))
|
|
require.NotEqual(t, pre.ToBlock().Hash(), g.ToBlock().Hash(),
|
|
"genesis hash must change across the activation boundary")
|
|
}
|
|
|
|
// genesisState rebuilds the committed genesis account trie so the test can inspect
|
|
// getCode(0x9999). It mirrors (*Genesis).toBlock exactly (ApplyPrecompileActivations at
|
|
// parent==nil, then alloc) and its root MUST equal ToBlock's, which it asserts.
|
|
func genesisState(t *testing.T, g *Genesis) *state.StateDB {
|
|
t.Helper()
|
|
db := rawdb.NewMemoryDatabase()
|
|
statedb, err := state.New(gethtypes.EmptyRootHash, state.NewDatabase(db), nil)
|
|
require.NoError(t, err)
|
|
require.NoError(t, ApplyPrecompileActivations(g.Config, nil, NewBlockContext(big.NewInt(int64(g.Number)), g.Timestamp), statedb))
|
|
for addr, acct := range g.Alloc {
|
|
statedb.SetBalance(addr, uint256.MustFromBig(acct.Balance), tracing.BalanceIncreaseGenesisBalance)
|
|
_ = statedb.SetCode(addr, acct.Code, tracing.CodeChangeGenesis)
|
|
statedb.SetNonce(addr, acct.Nonce, tracing.NonceChangeGenesis)
|
|
for k, v := range acct.Storage {
|
|
statedb.SetState(addr, k, v)
|
|
}
|
|
}
|
|
require.Equal(t, g.ToBlock().Root(), statedb.IntermediateRoot(false),
|
|
"rebuilt genesis state root must equal ToBlock's — otherwise this inspection is not authoritative")
|
|
return statedb
|
|
}
|