github.com/MetalBlockchain/subnet-evm@v0.4.9/core/genesis_test.go (about) 1 // (c) 2019-2021, Ava Labs, Inc. 2 // 3 // This file is a derived work, based on the go-ethereum library whose original 4 // notices appear below. 5 // 6 // It is distributed under a license compatible with the licensing terms of the 7 // original code from which it is derived. 8 // 9 // Much love to the original authors for their work. 10 // ********** 11 // Copyright 2017 The go-ethereum Authors 12 // This file is part of the go-ethereum library. 13 // 14 // The go-ethereum library is free software: you can redistribute it and/or modify 15 // it under the terms of the GNU Lesser General Public License as published by 16 // the Free Software Foundation, either version 3 of the License, or 17 // (at your option) any later version. 18 // 19 // The go-ethereum library is distributed in the hope that it will be useful, 20 // but WITHOUT ANY WARRANTY; without even the implied warranty of 21 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 22 // GNU Lesser General Public License for more details. 23 // 24 // You should have received a copy of the GNU Lesser General Public License 25 // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. 26 27 package core 28 29 import ( 30 _ "embed" 31 "math/big" 32 "reflect" 33 "testing" 34 35 "github.com/MetalBlockchain/subnet-evm/consensus/dummy" 36 "github.com/MetalBlockchain/subnet-evm/core/rawdb" 37 "github.com/MetalBlockchain/subnet-evm/core/state" 38 "github.com/MetalBlockchain/subnet-evm/core/vm" 39 "github.com/MetalBlockchain/subnet-evm/ethdb" 40 "github.com/MetalBlockchain/subnet-evm/params" 41 "github.com/MetalBlockchain/subnet-evm/precompile" 42 "github.com/davecgh/go-spew/spew" 43 "github.com/ethereum/go-ethereum/common" 44 "github.com/stretchr/testify/assert" 45 "github.com/stretchr/testify/require" 46 ) 47 48 func setupGenesisBlock(db ethdb.Database, genesis *Genesis, lastAcceptedHash common.Hash) (*params.ChainConfig, common.Hash, error) { 49 conf, err := SetupGenesisBlock(db, genesis, lastAcceptedHash, false) 50 stored := rawdb.ReadCanonicalHash(db, 0) 51 return conf, stored, err 52 } 53 54 func TestGenesisBlockForTesting(t *testing.T) { 55 genesisBlockForTestingHash := common.HexToHash("0x114ce61b50051f70768f982f7b59e82dd73b7bbd768e310c9d9f508d492e687b") 56 block := GenesisBlockForTesting(rawdb.NewMemoryDatabase(), common.Address{1}, big.NewInt(1)) 57 if block.Hash() != genesisBlockForTestingHash { 58 t.Errorf("wrong testing genesis hash, got %v, want %v", block.Hash(), genesisBlockForTestingHash) 59 } 60 } 61 62 func TestSetupGenesis(t *testing.T) { 63 preSubnetConfig := *params.TestPreSubnetEVMConfig 64 preSubnetConfig.SubnetEVMTimestamp = big.NewInt(100) 65 var ( 66 customghash = common.HexToHash("0x4a12fe7bf8d40d152d7e9de22337b115186a4662aa3a97217b36146202bbfc66") 67 customg = Genesis{ 68 Config: &preSubnetConfig, 69 Alloc: GenesisAlloc{ 70 {1}: {Balance: big.NewInt(1), Storage: map[common.Hash]common.Hash{{1}: {1}}}, 71 }, 72 GasLimit: preSubnetConfig.FeeConfig.GasLimit.Uint64(), 73 } 74 oldcustomg = customg 75 ) 76 77 rollbackpreSubnetConfig := preSubnetConfig 78 rollbackpreSubnetConfig.SubnetEVMTimestamp = big.NewInt(90) 79 oldcustomg.Config = &rollbackpreSubnetConfig 80 tests := []struct { 81 name string 82 fn func(ethdb.Database) (*params.ChainConfig, common.Hash, error) 83 wantConfig *params.ChainConfig 84 wantHash common.Hash 85 wantErr error 86 }{ 87 { 88 name: "genesis without ChainConfig", 89 fn: func(db ethdb.Database) (*params.ChainConfig, common.Hash, error) { 90 return setupGenesisBlock(db, new(Genesis), common.Hash{}) 91 }, 92 wantErr: errGenesisNoConfig, 93 wantConfig: nil, 94 }, 95 { 96 name: "no block in DB, genesis == nil", 97 fn: func(db ethdb.Database) (*params.ChainConfig, common.Hash, error) { 98 return setupGenesisBlock(db, nil, common.Hash{}) 99 }, 100 wantErr: ErrNoGenesis, 101 wantConfig: nil, 102 }, 103 { 104 name: "custom block in DB, genesis == nil", 105 fn: func(db ethdb.Database) (*params.ChainConfig, common.Hash, error) { 106 customg.MustCommit(db) 107 return setupGenesisBlock(db, nil, common.Hash{}) 108 }, 109 wantErr: ErrNoGenesis, 110 wantHash: customghash, 111 wantConfig: nil, 112 }, 113 { 114 name: "compatible config in DB", 115 fn: func(db ethdb.Database) (*params.ChainConfig, common.Hash, error) { 116 oldcustomg.MustCommit(db) 117 return setupGenesisBlock(db, &customg, customghash) 118 }, 119 wantHash: customghash, 120 wantConfig: customg.Config, 121 }, 122 { 123 name: "incompatible config for metal fork in DB", 124 fn: func(db ethdb.Database) (*params.ChainConfig, common.Hash, error) { 125 // Commit the 'old' genesis block with SubnetEVM transition at 90. 126 // Advance to block #4, past the SubnetEVM transition block of customg. 127 genesis := oldcustomg.MustCommit(db) 128 129 bc, _ := NewBlockChain(db, DefaultCacheConfig, oldcustomg.Config, dummy.NewFullFaker(), vm.Config{}, common.Hash{}) 130 defer bc.Stop() 131 132 blocks, _, _ := GenerateChain(oldcustomg.Config, genesis, dummy.NewFullFaker(), db, 4, 25, nil) 133 bc.InsertChain(blocks) 134 bc.CurrentBlock() 135 for _, block := range blocks { 136 if err := bc.Accept(block); err != nil { 137 t.Fatal(err) 138 } 139 } 140 141 // This should return a compatibility error. 142 return setupGenesisBlock(db, &customg, bc.lastAccepted.Hash()) 143 }, 144 wantHash: customghash, 145 wantConfig: customg.Config, 146 wantErr: ¶ms.ConfigCompatError{ 147 What: "SubnetEVM fork block timestamp", 148 StoredConfig: big.NewInt(90), 149 NewConfig: big.NewInt(100), 150 RewindTo: 89, 151 }, 152 }, 153 } 154 155 for _, test := range tests { 156 t.Run(test.name, func(t *testing.T) { 157 db := rawdb.NewMemoryDatabase() 158 config, hash, err := test.fn(db) 159 // Check the return values. 160 if !reflect.DeepEqual(err, test.wantErr) { 161 spew := spew.ConfigState{DisablePointerAddresses: true, DisableCapacities: true} 162 t.Errorf("returned error %#v, want %#v", spew.NewFormatter(err), spew.NewFormatter(test.wantErr)) 163 } 164 if !reflect.DeepEqual(config, test.wantConfig) { 165 t.Errorf("returned %v\nwant %v", config, test.wantConfig) 166 } 167 if hash != test.wantHash { 168 t.Errorf("returned hash %s, want %s", hash.Hex(), test.wantHash.Hex()) 169 } else if err == nil { 170 // Check database content. 171 stored := rawdb.ReadBlock(db, test.wantHash, 0) 172 if stored.Hash() != test.wantHash { 173 t.Errorf("block in DB has hash %s, want %s", stored.Hash(), test.wantHash) 174 } 175 } 176 }) 177 } 178 } 179 180 func TestStatefulPrecompilesConfigure(t *testing.T) { 181 type test struct { 182 getConfig func() *params.ChainConfig // Return the config that enables the stateful precompile at the genesis for the test 183 assertState func(t *testing.T, sdb *state.StateDB) // Check that the stateful precompiles were configured correctly 184 } 185 186 addr := common.HexToAddress("0x8db97C7cEcE249c2b98bDC0226Cc4C2A57BF52FC") 187 188 // Test suite to ensure that stateful precompiles are configured correctly in the genesis. 189 for name, test := range map[string]test{ 190 "allow list enabled in genesis": { 191 getConfig: func() *params.ChainConfig { 192 config := *params.TestChainConfig 193 config.ContractDeployerAllowListConfig = precompile.NewContractDeployerAllowListConfig(big.NewInt(0), []common.Address{addr}, nil) 194 return &config 195 }, 196 assertState: func(t *testing.T, sdb *state.StateDB) { 197 assert.Equal(t, precompile.AllowListAdmin, precompile.GetContractDeployerAllowListStatus(sdb, addr), "unexpected allow list status for modified address") 198 assert.Equal(t, uint64(1), sdb.GetNonce(precompile.ContractDeployerAllowListAddress)) 199 }, 200 }, 201 } { 202 t.Run(name, func(t *testing.T) { 203 config := test.getConfig() 204 205 genesis := &Genesis{ 206 Config: config, 207 Alloc: GenesisAlloc{ 208 {1}: {Balance: big.NewInt(1), Storage: map[common.Hash]common.Hash{{1}: {1}}}, 209 }, 210 GasLimit: config.FeeConfig.GasLimit.Uint64(), 211 } 212 213 db := rawdb.NewMemoryDatabase() 214 215 genesisBlock := genesis.ToBlock(nil) 216 genesisRoot := genesisBlock.Root() 217 218 _, err := SetupGenesisBlock(db, genesis, genesisBlock.Hash(), false) 219 if err != nil { 220 t.Fatal(err) 221 } 222 223 statedb, err := state.New(genesisRoot, state.NewDatabase(db), nil) 224 if err != nil { 225 t.Fatal(err) 226 } 227 228 if test.assertState != nil { 229 test.assertState(t, statedb) 230 } 231 }) 232 } 233 } 234 235 // regression test for precompile activation after header block 236 func TestPrecompileActivationAfterHeaderBlock(t *testing.T) { 237 db := rawdb.NewMemoryDatabase() 238 239 customg := Genesis{ 240 Config: params.SubnetEVMDefaultChainConfig, 241 Alloc: GenesisAlloc{ 242 {1}: {Balance: big.NewInt(1), Storage: map[common.Hash]common.Hash{{1}: {1}}}, 243 }, 244 GasLimit: params.SubnetEVMDefaultChainConfig.FeeConfig.GasLimit.Uint64(), 245 } 246 genesis := customg.MustCommit(db) 247 bc, _ := NewBlockChain(db, DefaultCacheConfig, customg.Config, dummy.NewFullFaker(), vm.Config{}, common.Hash{}) 248 defer bc.Stop() 249 250 // Advance header to block #4, past the ContractDeployerAllowListConfig. 251 blocks, _, _ := GenerateChain(customg.Config, genesis, dummy.NewFullFaker(), db, 4, 25, nil) 252 253 require := require.New(t) 254 _, err := bc.InsertChain(blocks) 255 require.NoError(err) 256 257 // accept up to block #2 258 for _, block := range blocks[:2] { 259 require.NoError(bc.Accept(block)) 260 } 261 block := bc.CurrentBlock() 262 263 require.Equal(blocks[1].Hash(), bc.lastAccepted.Hash()) 264 // header must be bigger than last accepted 265 require.Greater(block.Time(), bc.lastAccepted.Time()) 266 267 activatedGenesis := customg 268 contractDeployerConfig := precompile.NewContractDeployerAllowListConfig(big.NewInt(51), nil, nil) 269 activatedGenesis.Config.UpgradeConfig.PrecompileUpgrades = []params.PrecompileUpgrade{ 270 { 271 // Enable ContractDeployerAllowList at timestamp 50 272 ContractDeployerAllowListConfig: contractDeployerConfig, 273 }, 274 } 275 276 // assert block is after the activation block 277 require.Greater(block.Time(), contractDeployerConfig.Timestamp().Uint64()) 278 // assert last accepted block is before the activation block 279 require.Less(bc.lastAccepted.Time(), contractDeployerConfig.Timestamp().Uint64()) 280 281 // This should not return any error since the last accepted block is before the activation block. 282 config, _, err := setupGenesisBlock(db, &activatedGenesis, bc.lastAccepted.Hash()) 283 require.NoError(err) 284 if !reflect.DeepEqual(config, activatedGenesis.Config) { 285 t.Errorf("returned %v\nwant %v", config, activatedGenesis.Config) 286 } 287 }