github.com/ethereum/go-ethereum@v1.16.1/core/genesis_test.go (about) 1 // Copyright 2017 The go-ethereum Authors 2 // This file is part of the go-ethereum library. 3 // 4 // The go-ethereum library is free software: you can redistribute it and/or modify 5 // it under the terms of the GNU Lesser General Public License as published by 6 // the Free Software Foundation, either version 3 of the License, or 7 // (at your option) any later version. 8 // 9 // The go-ethereum library is distributed in the hope that it will be useful, 10 // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 // GNU Lesser General Public License for more details. 13 // 14 // You should have received a copy of the GNU Lesser General Public License 15 // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. 16 17 package core 18 19 import ( 20 "bytes" 21 "encoding/json" 22 "math/big" 23 "reflect" 24 "testing" 25 26 "github.com/davecgh/go-spew/spew" 27 "github.com/ethereum/go-ethereum/common" 28 "github.com/ethereum/go-ethereum/consensus/ethash" 29 "github.com/ethereum/go-ethereum/core/rawdb" 30 "github.com/ethereum/go-ethereum/core/types" 31 "github.com/ethereum/go-ethereum/ethdb" 32 "github.com/ethereum/go-ethereum/params" 33 "github.com/ethereum/go-ethereum/triedb" 34 "github.com/ethereum/go-ethereum/triedb/pathdb" 35 ) 36 37 func TestSetupGenesis(t *testing.T) { 38 testSetupGenesis(t, rawdb.HashScheme) 39 testSetupGenesis(t, rawdb.PathScheme) 40 } 41 42 func testSetupGenesis(t *testing.T, scheme string) { 43 var ( 44 customghash = common.HexToHash("0x89c99d90b79719238d2645c7642f2c9295246e80775b38cfd162b696817fbd50") 45 customg = Genesis{ 46 Config: ¶ms.ChainConfig{HomesteadBlock: big.NewInt(3), Ethash: ¶ms.EthashConfig{}}, 47 Alloc: types.GenesisAlloc{ 48 {1}: {Balance: big.NewInt(1), Storage: map[common.Hash]common.Hash{{1}: {1}}}, 49 }, 50 } 51 oldcustomg = customg 52 ) 53 oldcustomg.Config = ¶ms.ChainConfig{HomesteadBlock: big.NewInt(2), Ethash: ¶ms.EthashConfig{}} 54 55 tests := []struct { 56 name string 57 fn func(ethdb.Database) (*params.ChainConfig, common.Hash, *params.ConfigCompatError, error) 58 wantConfig *params.ChainConfig 59 wantHash common.Hash 60 wantErr error 61 wantCompactErr *params.ConfigCompatError 62 }{ 63 { 64 name: "genesis without ChainConfig", 65 fn: func(db ethdb.Database) (*params.ChainConfig, common.Hash, *params.ConfigCompatError, error) { 66 return SetupGenesisBlock(db, triedb.NewDatabase(db, newDbConfig(scheme)), new(Genesis)) 67 }, 68 wantErr: errGenesisNoConfig, 69 }, 70 { 71 name: "no block in DB, genesis == nil", 72 fn: func(db ethdb.Database) (*params.ChainConfig, common.Hash, *params.ConfigCompatError, error) { 73 return SetupGenesisBlock(db, triedb.NewDatabase(db, newDbConfig(scheme)), nil) 74 }, 75 wantHash: params.MainnetGenesisHash, 76 wantConfig: params.MainnetChainConfig, 77 }, 78 { 79 name: "mainnet block in DB, genesis == nil", 80 fn: func(db ethdb.Database) (*params.ChainConfig, common.Hash, *params.ConfigCompatError, error) { 81 DefaultGenesisBlock().MustCommit(db, triedb.NewDatabase(db, newDbConfig(scheme))) 82 return SetupGenesisBlock(db, triedb.NewDatabase(db, newDbConfig(scheme)), nil) 83 }, 84 wantHash: params.MainnetGenesisHash, 85 wantConfig: params.MainnetChainConfig, 86 }, 87 { 88 name: "custom block in DB, genesis == nil", 89 fn: func(db ethdb.Database) (*params.ChainConfig, common.Hash, *params.ConfigCompatError, error) { 90 tdb := triedb.NewDatabase(db, newDbConfig(scheme)) 91 customg.Commit(db, tdb) 92 return SetupGenesisBlock(db, tdb, nil) 93 }, 94 wantHash: customghash, 95 wantConfig: customg.Config, 96 }, 97 { 98 name: "custom block in DB, genesis == sepolia", 99 fn: func(db ethdb.Database) (*params.ChainConfig, common.Hash, *params.ConfigCompatError, error) { 100 tdb := triedb.NewDatabase(db, newDbConfig(scheme)) 101 customg.Commit(db, tdb) 102 return SetupGenesisBlock(db, tdb, DefaultSepoliaGenesisBlock()) 103 }, 104 wantErr: &GenesisMismatchError{Stored: customghash, New: params.SepoliaGenesisHash}, 105 }, 106 { 107 name: "custom block in DB, genesis == hoodi", 108 fn: func(db ethdb.Database) (*params.ChainConfig, common.Hash, *params.ConfigCompatError, error) { 109 tdb := triedb.NewDatabase(db, newDbConfig(scheme)) 110 customg.Commit(db, tdb) 111 return SetupGenesisBlock(db, tdb, DefaultHoodiGenesisBlock()) 112 }, 113 wantErr: &GenesisMismatchError{Stored: customghash, New: params.HoodiGenesisHash}, 114 }, 115 { 116 name: "compatible config in DB", 117 fn: func(db ethdb.Database) (*params.ChainConfig, common.Hash, *params.ConfigCompatError, error) { 118 tdb := triedb.NewDatabase(db, newDbConfig(scheme)) 119 oldcustomg.Commit(db, tdb) 120 return SetupGenesisBlock(db, tdb, &customg) 121 }, 122 wantHash: customghash, 123 wantConfig: customg.Config, 124 }, 125 { 126 name: "incompatible config in DB", 127 fn: func(db ethdb.Database) (*params.ChainConfig, common.Hash, *params.ConfigCompatError, error) { 128 // Commit the 'old' genesis block with Homestead transition at #2. 129 // Advance to block #4, past the homestead transition block of customg. 130 tdb := triedb.NewDatabase(db, newDbConfig(scheme)) 131 oldcustomg.Commit(db, tdb) 132 133 bc, _ := NewBlockChain(db, &oldcustomg, ethash.NewFullFaker(), DefaultConfig().WithStateScheme(scheme)) 134 defer bc.Stop() 135 136 _, blocks, _ := GenerateChainWithGenesis(&oldcustomg, ethash.NewFaker(), 4, nil) 137 bc.InsertChain(blocks) 138 139 // This should return a compatibility error. 140 return SetupGenesisBlock(db, tdb, &customg) 141 }, 142 wantHash: customghash, 143 wantConfig: customg.Config, 144 wantCompactErr: ¶ms.ConfigCompatError{ 145 What: "Homestead fork block", 146 StoredBlock: big.NewInt(2), 147 NewBlock: big.NewInt(3), 148 RewindToBlock: 1, 149 }, 150 }, 151 } 152 153 for _, test := range tests { 154 db := rawdb.NewMemoryDatabase() 155 config, hash, compatErr, err := test.fn(db) 156 // Check the return values. 157 if !reflect.DeepEqual(err, test.wantErr) { 158 spew := spew.ConfigState{DisablePointerAddresses: true, DisableCapacities: true} 159 t.Errorf("%s: returned error %#v, want %#v", test.name, spew.NewFormatter(err), spew.NewFormatter(test.wantErr)) 160 } 161 if !reflect.DeepEqual(compatErr, test.wantCompactErr) { 162 spew := spew.ConfigState{DisablePointerAddresses: true, DisableCapacities: true} 163 t.Errorf("%s: returned error %#v, want %#v", test.name, spew.NewFormatter(compatErr), spew.NewFormatter(test.wantCompactErr)) 164 } 165 if !reflect.DeepEqual(config, test.wantConfig) { 166 t.Errorf("%s:\nreturned %v\nwant %v", test.name, config, test.wantConfig) 167 } 168 if hash != test.wantHash { 169 t.Errorf("%s: returned hash %s, want %s", test.name, hash.Hex(), test.wantHash.Hex()) 170 } else if err == nil { 171 // Check database content. 172 stored := rawdb.ReadBlock(db, test.wantHash, 0) 173 if stored.Hash() != test.wantHash { 174 t.Errorf("%s: block in DB has hash %s, want %s", test.name, stored.Hash(), test.wantHash) 175 } 176 } 177 } 178 } 179 180 // TestGenesisHashes checks the congruity of default genesis data to 181 // corresponding hardcoded genesis hash values. 182 func TestGenesisHashes(t *testing.T) { 183 for i, c := range []struct { 184 genesis *Genesis 185 want common.Hash 186 }{ 187 {DefaultGenesisBlock(), params.MainnetGenesisHash}, 188 {DefaultSepoliaGenesisBlock(), params.SepoliaGenesisHash}, 189 {DefaultHoleskyGenesisBlock(), params.HoleskyGenesisHash}, 190 {DefaultHoodiGenesisBlock(), params.HoodiGenesisHash}, 191 } { 192 // Test via MustCommit 193 db := rawdb.NewMemoryDatabase() 194 if have := c.genesis.MustCommit(db, triedb.NewDatabase(db, triedb.HashDefaults)).Hash(); have != c.want { 195 t.Errorf("case: %d a), want: %s, got: %s", i, c.want.Hex(), have.Hex()) 196 } 197 // Test via ToBlock 198 if have := c.genesis.ToBlock().Hash(); have != c.want { 199 t.Errorf("case: %d a), want: %s, got: %s", i, c.want.Hex(), have.Hex()) 200 } 201 } 202 } 203 204 func TestGenesisCommit(t *testing.T) { 205 genesis := &Genesis{ 206 BaseFee: big.NewInt(params.InitialBaseFee), 207 Config: params.TestChainConfig, 208 // difficulty is nil 209 } 210 211 db := rawdb.NewMemoryDatabase() 212 genesisBlock := genesis.MustCommit(db, triedb.NewDatabase(db, triedb.HashDefaults)) 213 214 if genesis.Difficulty != nil { 215 t.Fatalf("assumption wrong") 216 } 217 218 // This value should have been set as default in the ToBlock method. 219 if genesisBlock.Difficulty().Cmp(params.GenesisDifficulty) != 0 { 220 t.Errorf("assumption wrong: want: %d, got: %v", params.GenesisDifficulty, genesisBlock.Difficulty()) 221 } 222 } 223 224 func TestReadWriteGenesisAlloc(t *testing.T) { 225 var ( 226 db = rawdb.NewMemoryDatabase() 227 alloc = &types.GenesisAlloc{ 228 {1}: {Balance: big.NewInt(1), Storage: map[common.Hash]common.Hash{{1}: {1}}}, 229 {2}: {Balance: big.NewInt(2), Storage: map[common.Hash]common.Hash{{2}: {2}}}, 230 } 231 hash, _ = hashAlloc(alloc, false) 232 ) 233 blob, _ := json.Marshal(alloc) 234 rawdb.WriteGenesisStateSpec(db, hash, blob) 235 236 var reload types.GenesisAlloc 237 err := reload.UnmarshalJSON(rawdb.ReadGenesisStateSpec(db, hash)) 238 if err != nil { 239 t.Fatalf("Failed to load genesis state %v", err) 240 } 241 if len(reload) != len(*alloc) { 242 t.Fatal("Unexpected genesis allocation") 243 } 244 for addr, account := range reload { 245 want, ok := (*alloc)[addr] 246 if !ok { 247 t.Fatal("Account is not found") 248 } 249 if !reflect.DeepEqual(want, account) { 250 t.Fatal("Unexpected account") 251 } 252 } 253 } 254 255 func newDbConfig(scheme string) *triedb.Config { 256 if scheme == rawdb.HashScheme { 257 return triedb.HashDefaults 258 } 259 config := *pathdb.Defaults 260 config.NoAsyncFlush = true 261 return &triedb.Config{PathDB: &config} 262 } 263 264 func TestVerkleGenesisCommit(t *testing.T) { 265 var verkleTime uint64 = 0 266 verkleConfig := ¶ms.ChainConfig{ 267 ChainID: big.NewInt(1), 268 HomesteadBlock: big.NewInt(0), 269 DAOForkBlock: nil, 270 DAOForkSupport: false, 271 EIP150Block: big.NewInt(0), 272 EIP155Block: big.NewInt(0), 273 EIP158Block: big.NewInt(0), 274 ByzantiumBlock: big.NewInt(0), 275 ConstantinopleBlock: big.NewInt(0), 276 PetersburgBlock: big.NewInt(0), 277 IstanbulBlock: big.NewInt(0), 278 MuirGlacierBlock: big.NewInt(0), 279 BerlinBlock: big.NewInt(0), 280 LondonBlock: big.NewInt(0), 281 ArrowGlacierBlock: big.NewInt(0), 282 GrayGlacierBlock: big.NewInt(0), 283 MergeNetsplitBlock: nil, 284 ShanghaiTime: &verkleTime, 285 CancunTime: &verkleTime, 286 PragueTime: &verkleTime, 287 OsakaTime: &verkleTime, 288 VerkleTime: &verkleTime, 289 TerminalTotalDifficulty: big.NewInt(0), 290 EnableVerkleAtGenesis: true, 291 Ethash: nil, 292 Clique: nil, 293 BlobScheduleConfig: ¶ms.BlobScheduleConfig{ 294 Cancun: params.DefaultCancunBlobConfig, 295 Prague: params.DefaultPragueBlobConfig, 296 Osaka: params.DefaultOsakaBlobConfig, 297 Verkle: params.DefaultPragueBlobConfig, 298 }, 299 } 300 301 genesis := &Genesis{ 302 BaseFee: big.NewInt(params.InitialBaseFee), 303 Config: verkleConfig, 304 Timestamp: verkleTime, 305 Difficulty: big.NewInt(0), 306 Alloc: types.GenesisAlloc{ 307 {1}: {Balance: big.NewInt(1), Storage: map[common.Hash]common.Hash{{1}: {1}}}, 308 }, 309 } 310 311 expected := common.FromHex("018d20eebb130b5e2b796465fe36aafab650650729a92435aec071bf2386f080") 312 got := genesis.ToBlock().Root().Bytes() 313 if !bytes.Equal(got, expected) { 314 t.Fatalf("invalid genesis state root, expected %x, got %x", expected, got) 315 } 316 317 db := rawdb.NewMemoryDatabase() 318 319 config := *pathdb.Defaults 320 config.NoAsyncFlush = true 321 322 triedb := triedb.NewDatabase(db, &triedb.Config{ 323 IsVerkle: true, 324 PathDB: &config, 325 }) 326 block := genesis.MustCommit(db, triedb) 327 if !bytes.Equal(block.Root().Bytes(), expected) { 328 t.Fatalf("invalid genesis state root, expected %x, got %x", expected, block.Root()) 329 } 330 331 // Test that the trie is verkle 332 if !triedb.IsVerkle() { 333 t.Fatalf("expected trie to be verkle") 334 } 335 vdb := rawdb.NewTable(db, string(rawdb.VerklePrefix)) 336 if !rawdb.HasAccountTrieNode(vdb, nil) { 337 t.Fatal("could not find node") 338 } 339 }