Files
evm/core/genesis_cancun_test.go
zeekay 7341b4a885 fix(evm): bind chain identity before NewBlockChain reprocess (no new type)
The 0x9999 DEX value path is identity-gated: the asset resolver refuses to
admit a market unless the running chain's identity matches. core.NewBlockChain
re-executes accepted blocks during construction (loadLastState recovery /
populateMissingTries backfill), but the identity was only bound onto the chain
AFTER eth.New returned (vm.go SetConsensusContext) — so an unclean restart after
a 0x9999 swap re-executed that block with networkID 0 / C-Chain Empty, reverted
the committed swap, failed ValidateState, and the node could not boot.

Fix is purely timing: hand NewBlockChain the *runtime.Runtime the VM already
holds (eth.Settings.ChainRuntime -> core.NewBlockChain) and bind the consensus
context BEFORE reprocess. No new identity type — networkID/chainID already live
on runtime.Runtime; the context is just the last-mile transport to geth's
ConsensusContext API. stdlib runtime aliased stdruntime in blockchain.go.
2026-06-23 08:53:26 -07:00

101 lines
3.0 KiB
Go

package core
import (
"math/big"
"testing"
"github.com/luxfi/evm/consensus/dummy"
"github.com/luxfi/evm/params"
"github.com/luxfi/geth/core/rawdb"
"github.com/luxfi/geth/core/vm"
"github.com/luxfi/geth/triedb"
"github.com/stretchr/testify/require"
)
func TestGenesisCancun(t *testing.T) {
require := require.New(t)
// Test with Cancun enabled (default TestChainConfig)
t.Run("WithCancun", func(t *testing.T) {
gspec := &Genesis{
Config: params.TestChainConfig,
Alloc: GenesisAlloc{},
BaseFee: big.NewInt(875000000),
Timestamp: 0, // Cancun is active at time 0
}
db := rawdb.NewMemoryDatabase()
tdb := triedb.NewDatabase(db, triedb.HashDefaults)
genesisBlock, err := gspec.Commit(db, tdb)
require.NoError(err)
// Check if header has Cancun fields
header := genesisBlock.Header()
t.Logf("Has ParentBeaconRoot: %v", header.ParentBeaconRoot != nil)
t.Logf("Has ExcessBlobGas: %v", header.ExcessBlobGas != nil)
t.Logf("Has BlobGasUsed: %v", header.BlobGasUsed != nil)
// Try to read it back
hash := genesisBlock.Hash()
readHeader := rawdb.ReadHeader(db, hash, 0)
if readHeader == nil {
t.Logf("FAIL: Cannot read header with Cancun fields")
} else {
t.Logf("SUCCESS: Can read header with Cancun fields")
}
// Try to create blockchain
engine := dummy.NewCoinbaseFaker()
chain, err := NewBlockChain(db, DefaultCacheConfig, gspec, engine, vm.Config{}, hash, false, nil)
if err != nil {
t.Logf("FAIL: Cannot create blockchain with Cancun: %v", err)
} else {
t.Logf("SUCCESS: Created blockchain with Cancun")
chain.Stop()
}
})
// Test without Cancun
t.Run("WithoutCancun", func(t *testing.T) {
// TestDurangoChainConfig has Shanghai enabled but no Cancun/blob features
gspec := &Genesis{
Config: params.TestDurangoChainConfig,
Alloc: GenesisAlloc{},
BaseFee: big.NewInt(875000000),
Timestamp: 0,
}
db := rawdb.NewMemoryDatabase()
tdb := triedb.NewDatabase(db, triedb.HashDefaults)
genesisBlock, err := gspec.Commit(db, tdb)
require.NoError(err)
// Check if header has Cancun fields (should NOT have them)
header := genesisBlock.Header()
t.Logf("Has ParentBeaconRoot: %v (expected: false)", header.ParentBeaconRoot != nil)
t.Logf("Has ExcessBlobGas: %v (expected: false)", header.ExcessBlobGas != nil)
t.Logf("Has BlobGasUsed: %v (expected: false)", header.BlobGasUsed != nil)
// Try to read it back
hash := genesisBlock.Hash()
readHeader := rawdb.ReadHeader(db, hash, 0)
if readHeader == nil {
t.Logf("FAIL: Cannot read header without Cancun fields")
} else {
t.Logf("SUCCESS: Can read header without Cancun fields")
}
// Try to create blockchain
engine := dummy.NewCoinbaseFaker()
chain, err := NewBlockChain(db, DefaultCacheConfig, gspec, engine, vm.Config{}, hash, false, nil)
if err != nil {
t.Logf("FAIL: Cannot create blockchain without Cancun: %v", err)
} else {
t.Logf("SUCCESS: Created blockchain without Cancun")
chain.Stop()
}
})
}