github.com/klaytn/klaytn@v1.12.1/blockchain/genesis_test.go (about) 1 // Modifications Copyright 2018 The klaytn Authors 2 // Copyright 2017 The go-ethereum Authors 3 // This file is part of the go-ethereum library. 4 // 5 // The go-ethereum library is free software: you can redistribute it and/or modify 6 // it under the terms of the GNU Lesser General Public License as published by 7 // the Free Software Foundation, either version 3 of the License, or 8 // (at your option) any later version. 9 // 10 // The go-ethereum library is distributed in the hope that it will be useful, 11 // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 // GNU Lesser General Public License for more details. 14 // 15 // You should have received a copy of the GNU Lesser General Public License 16 // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. 17 // 18 // This file is derived from core/genesis_test.go (2018/06/04). 19 // Modified and improved for the klaytn development. 20 21 package blockchain 22 23 import ( 24 "fmt" 25 "math/big" 26 "reflect" 27 "testing" 28 29 "github.com/davecgh/go-spew/spew" 30 "github.com/klaytn/klaytn/blockchain/types" 31 "github.com/klaytn/klaytn/blockchain/vm" 32 "github.com/klaytn/klaytn/common" 33 "github.com/klaytn/klaytn/consensus/gxhash" 34 "github.com/klaytn/klaytn/params" 35 "github.com/klaytn/klaytn/storage/database" 36 "github.com/stretchr/testify/assert" 37 ) 38 39 // TestDefaultGenesisBlock tests the genesis block generation functions: DefaultGenesisBlock, DefaultBaobabGenesisBlock 40 func TestDefaultGenesisBlock(t *testing.T) { 41 block := genCypressGenesisBlock().ToBlock(common.Hash{}, nil) 42 if block.Hash() != params.CypressGenesisHash { 43 t.Errorf("wrong cypress genesis hash, got %v, want %v", block.Hash(), params.CypressGenesisHash) 44 } 45 block = genBaobabGenesisBlock().ToBlock(common.Hash{}, nil) 46 if block.Hash() != params.BaobabGenesisHash { 47 t.Errorf("wrong baobab genesis hash, got %v, want %v", block.Hash(), params.BaobabGenesisHash) 48 } 49 } 50 51 // TestHardCodedChainConfigUpdate tests the public network's chainConfig update. 52 func TestHardCodedChainConfigUpdate(t *testing.T) { 53 cypressGenesisBlock, baobabGenesisBlock := genCypressGenesisBlock(), genBaobabGenesisBlock() 54 tests := []struct { 55 name string 56 newHFBlock *big.Int 57 originHFBlock *big.Int 58 fn func(database.DBManager, *big.Int) (*params.ChainConfig, common.Hash, error) 59 wantConfig *params.ChainConfig // expect value of the SetupGenesisBlock's first return value 60 wantHash common.Hash 61 wantErr error 62 wantStoredConfig *params.ChainConfig // expect value of the stored config in DB 63 resetFn func(*big.Int) 64 }{ 65 { 66 name: "cypress chainConfig update", 67 newHFBlock: big.NewInt(3), 68 fn: func(db database.DBManager, newHFBlock *big.Int) (*params.ChainConfig, common.Hash, error) { 69 cypressGenesisBlock.MustCommit(db) 70 cypressGenesisBlock.Config.IstanbulCompatibleBlock = newHFBlock 71 return SetupGenesisBlock(db, cypressGenesisBlock, params.CypressNetworkId, false, false) 72 }, 73 wantHash: params.CypressGenesisHash, 74 wantConfig: cypressGenesisBlock.Config, 75 wantStoredConfig: cypressGenesisBlock.Config, 76 }, 77 // TODO-klaytn: add more cypress test cases after cypress hard fork block numbers are added 78 { 79 // Because of the fork-ordering check logic, the istanbulCompatibleBlock should be less than the londonCompatibleBlock 80 name: "baobab chainConfig update - correct hard-fork block number order", 81 newHFBlock: big.NewInt(79999999), 82 fn: func(db database.DBManager, newHFBlock *big.Int) (*params.ChainConfig, common.Hash, error) { 83 baobabGenesisBlock.MustCommit(db) 84 baobabGenesisBlock.Config.IstanbulCompatibleBlock = newHFBlock 85 return SetupGenesisBlock(db, baobabGenesisBlock, params.BaobabNetworkId, false, false) 86 }, 87 wantHash: params.BaobabGenesisHash, 88 wantConfig: baobabGenesisBlock.Config, 89 wantStoredConfig: baobabGenesisBlock.Config, 90 }, 91 { 92 // This test fails because the new istanbulCompatibleBlock(90909999) is larger than londonCompatibleBlock(80295291) 93 name: "baobab chainConfig update - wrong hard-fork block number order", 94 newHFBlock: big.NewInt(90909999), 95 fn: func(db database.DBManager, newHFBlock *big.Int) (*params.ChainConfig, common.Hash, error) { 96 baobabGenesisBlock.MustCommit(db) 97 baobabGenesisBlock.Config.IstanbulCompatibleBlock = newHFBlock 98 return SetupGenesisBlock(db, baobabGenesisBlock, params.BaobabNetworkId, false, false) 99 }, 100 wantHash: common.Hash{}, 101 wantConfig: baobabGenesisBlock.Config, 102 wantStoredConfig: nil, 103 wantErr: fmt.Errorf("unsupported fork ordering: %v enabled at %v, but %v enabled at %v", 104 "istanbulBlock", big.NewInt(90909999), "londonBlock", big.NewInt(80295291)), 105 }, 106 { 107 name: "incompatible config in DB", 108 newHFBlock: big.NewInt(3), 109 fn: func(db database.DBManager, newHFBlock *big.Int) (*params.ChainConfig, common.Hash, error) { 110 // Commit the 'old' genesis block with Istanbul transition at #2. 111 // Advance to block #4, past the Istanbul transition block of customGenesis. 112 genesis := genCypressGenesisBlock() 113 genesisBlock := genesis.MustCommit(db) 114 115 bc, _ := NewBlockChain(db, nil, genesis.Config, gxhash.NewFullFaker(), vm.Config{}) 116 defer bc.Stop() 117 118 blocks, _ := GenerateChain(genesis.Config, genesisBlock, gxhash.NewFaker(), db, 4, nil) 119 bc.InsertChain(blocks) 120 // This should return a compatibility error. 121 newConfig := *genesis 122 newConfig.Config.IstanbulCompatibleBlock = newHFBlock 123 return SetupGenesisBlock(db, &newConfig, params.CypressNetworkId, true, false) 124 }, 125 wantHash: params.CypressGenesisHash, 126 wantConfig: cypressGenesisBlock.Config, 127 wantStoredConfig: params.CypressChainConfig, 128 wantErr: ¶ms.ConfigCompatError{ 129 What: "Istanbul Block", 130 StoredConfig: params.CypressChainConfig.IstanbulCompatibleBlock, 131 NewConfig: big.NewInt(3), 132 RewindTo: 2, 133 }, 134 }, 135 } 136 137 for _, test := range tests { 138 db := database.NewMemoryDBManager() 139 config, hash, err := test.fn(db, test.newHFBlock) 140 141 // Check the return values 142 assert.Equal(t, test.wantErr, err, test.name+": err is mismatching") 143 assert.Equal(t, test.wantConfig, config, test.name+": config is mismatching") 144 assert.Equal(t, test.wantHash, hash, test.name+": hash is mismatching") 145 146 // Check stored genesis block 147 if test.wantHash != (common.Hash{}) { 148 stored := db.ReadBlock(test.wantHash, 0) 149 assert.Equal(t, test.wantHash, stored.Hash(), test.name+": stored genesis block is not compatible") 150 } 151 152 // Check stored chainConfig 153 storedChainConfig := db.ReadChainConfig(test.wantHash) 154 assert.Equal(t, test.wantStoredConfig, storedChainConfig, test.name+": stored chainConfig is not compatible") 155 } 156 } 157 158 func TestSetupGenesis(t *testing.T) { 159 var ( 160 customGenesisHash = common.HexToHash("0x4eb4035b7a09619a9950c9a4751cc331843f2373ef38263d676b4a132ba4059c") 161 customChainId = uint64(4343) 162 customGenesis = genCustomGenesisBlock(customChainId) 163 ) 164 tests := []struct { 165 name string 166 fn func(database.DBManager) (*params.ChainConfig, common.Hash, error) 167 wantConfig *params.ChainConfig 168 wantHash common.Hash 169 wantErr error 170 }{ 171 { 172 name: "genesis without ChainConfig", 173 fn: func(db database.DBManager) (*params.ChainConfig, common.Hash, error) { 174 return SetupGenesisBlock(db, new(Genesis), params.UnusedNetworkId, false, false) 175 }, 176 wantErr: errGenesisNoConfig, 177 wantConfig: params.AllGxhashProtocolChanges, 178 }, 179 { 180 name: "no block in DB, genesis == nil, cypress networkId", 181 fn: func(db database.DBManager) (*params.ChainConfig, common.Hash, error) { 182 return SetupGenesisBlock(db, nil, params.CypressNetworkId, false, false) 183 }, 184 wantHash: params.CypressGenesisHash, 185 wantConfig: params.CypressChainConfig, 186 }, 187 { 188 name: "no block in DB, genesis == nil, baobab networkId", 189 fn: func(db database.DBManager) (*params.ChainConfig, common.Hash, error) { 190 return SetupGenesisBlock(db, nil, params.BaobabNetworkId, false, false) 191 }, 192 wantHash: params.BaobabGenesisHash, 193 wantConfig: params.BaobabChainConfig, 194 }, 195 { 196 name: "no block in DB, genesis == customGenesis, private network", 197 fn: func(db database.DBManager) (*params.ChainConfig, common.Hash, error) { 198 return SetupGenesisBlock(db, customGenesis, customChainId, true, false) 199 }, 200 wantHash: customGenesisHash, 201 wantConfig: customGenesis.Config, 202 }, 203 { 204 name: "cypress block in DB, genesis == nil, cypress networkId", 205 fn: func(db database.DBManager) (*params.ChainConfig, common.Hash, error) { 206 genCypressGenesisBlock().MustCommit(db) 207 return SetupGenesisBlock(db, nil, params.CypressNetworkId, false, false) 208 }, 209 wantHash: params.CypressGenesisHash, 210 wantConfig: params.CypressChainConfig, 211 }, 212 { 213 name: "baobab block in DB, genesis == nil, baobab networkId", 214 fn: func(db database.DBManager) (*params.ChainConfig, common.Hash, error) { 215 genBaobabGenesisBlock().MustCommit(db) 216 return SetupGenesisBlock(db, nil, params.BaobabNetworkId, false, false) 217 }, 218 wantHash: params.BaobabGenesisHash, 219 wantConfig: params.BaobabChainConfig, 220 }, 221 { 222 name: "custom block in DB, genesis == nil, custom networkId", 223 fn: func(db database.DBManager) (*params.ChainConfig, common.Hash, error) { 224 customGenesis.MustCommit(db) 225 return SetupGenesisBlock(db, nil, customChainId, true, false) 226 }, 227 wantHash: customGenesisHash, 228 wantConfig: customGenesis.Config, 229 }, 230 { 231 name: "cypress block in DB, genesis == baobab", 232 fn: func(db database.DBManager) (*params.ChainConfig, common.Hash, error) { 233 genCypressGenesisBlock().MustCommit(db) 234 return SetupGenesisBlock(db, genBaobabGenesisBlock(), params.BaobabNetworkId, false, false) 235 }, 236 wantErr: &GenesisMismatchError{Stored: params.CypressGenesisHash, New: params.BaobabGenesisHash}, 237 wantHash: params.BaobabGenesisHash, 238 wantConfig: params.BaobabChainConfig, 239 }, 240 { 241 name: "baobab block in DB, genesis == cypress", 242 fn: func(db database.DBManager) (*params.ChainConfig, common.Hash, error) { 243 genBaobabGenesisBlock().MustCommit(db) 244 return SetupGenesisBlock(db, genCypressGenesisBlock(), params.CypressNetworkId, false, false) 245 }, 246 wantErr: &GenesisMismatchError{Stored: params.BaobabGenesisHash, New: params.CypressGenesisHash}, 247 wantHash: params.CypressGenesisHash, 248 wantConfig: params.CypressChainConfig, 249 }, 250 { 251 name: "cypress block in DB, genesis == custom", 252 fn: func(db database.DBManager) (*params.ChainConfig, common.Hash, error) { 253 genCypressGenesisBlock().MustCommit(db) 254 return SetupGenesisBlock(db, genCustomGenesisBlock(customChainId), customChainId, true, false) 255 }, 256 wantErr: &GenesisMismatchError{Stored: params.CypressGenesisHash, New: customGenesisHash}, 257 wantHash: customGenesisHash, 258 wantConfig: customGenesis.Config, 259 }, 260 { 261 name: "baobab block in DB, genesis == custom", 262 fn: func(db database.DBManager) (*params.ChainConfig, common.Hash, error) { 263 genBaobabGenesisBlock().MustCommit(db) 264 return SetupGenesisBlock(db, customGenesis, customChainId, true, false) 265 }, 266 wantErr: &GenesisMismatchError{Stored: params.BaobabGenesisHash, New: customGenesisHash}, 267 wantHash: customGenesisHash, 268 wantConfig: customGenesis.Config, 269 }, 270 { 271 name: "custom block in DB, genesis == cypress", 272 fn: func(db database.DBManager) (*params.ChainConfig, common.Hash, error) { 273 customGenesis.MustCommit(db) 274 return SetupGenesisBlock(db, genCypressGenesisBlock(), params.CypressNetworkId, false, false) 275 }, 276 wantErr: &GenesisMismatchError{Stored: customGenesisHash, New: params.CypressGenesisHash}, 277 wantHash: params.CypressGenesisHash, 278 wantConfig: params.CypressChainConfig, 279 }, 280 { 281 name: "custom block in DB, genesis == baobab", 282 fn: func(db database.DBManager) (*params.ChainConfig, common.Hash, error) { 283 customGenesis.MustCommit(db) 284 return SetupGenesisBlock(db, genBaobabGenesisBlock(), params.BaobabNetworkId, false, false) 285 }, 286 wantErr: &GenesisMismatchError{Stored: customGenesisHash, New: params.BaobabGenesisHash}, 287 wantHash: params.BaobabGenesisHash, 288 wantConfig: params.BaobabChainConfig, 289 }, 290 { 291 name: "compatible config in DB", 292 fn: func(db database.DBManager) (*params.ChainConfig, common.Hash, error) { 293 customGenesis.MustCommit(db) 294 return SetupGenesisBlock(db, customGenesis, customChainId, true, false) 295 }, 296 wantHash: customGenesisHash, 297 wantConfig: customGenesis.Config, 298 }, 299 { 300 name: "incompatible config in DB", 301 fn: func(db database.DBManager) (*params.ChainConfig, common.Hash, error) { 302 // Commit the 'old' genesis block with Istanbul transition at #2. 303 // Advance to block #4, past the Istanbul transition block of customGenesis. 304 genesis := customGenesis.MustCommit(db) 305 306 bc, _ := NewBlockChain(db, nil, customGenesis.Config, gxhash.NewFullFaker(), vm.Config{}) 307 defer bc.Stop() 308 309 blocks, _ := GenerateChain(customGenesis.Config, genesis, gxhash.NewFaker(), db, 4, nil) 310 bc.InsertChain(blocks) 311 // This should return a compatibility error. 312 newConfig := *customGenesis 313 newConfig.Config.IstanbulCompatibleBlock = big.NewInt(3) 314 return SetupGenesisBlock(db, &newConfig, customChainId, true, false) 315 }, 316 wantHash: customGenesisHash, 317 wantConfig: customGenesis.Config, 318 wantErr: ¶ms.ConfigCompatError{ 319 What: "Istanbul Block", 320 StoredConfig: big.NewInt(2), 321 NewConfig: big.NewInt(3), 322 RewindTo: 1, 323 }, 324 }, 325 } 326 327 for _, test := range tests { 328 db := database.NewMemoryDBManager() 329 config, hash, err := test.fn(db) 330 // Check the return values. 331 if !reflect.DeepEqual(err, test.wantErr) { 332 spew := spew.ConfigState{DisablePointerAddresses: true, DisableCapacities: true} 333 t.Errorf("%s: returned error %#v, want %#v", test.name, spew.NewFormatter(err), spew.NewFormatter(test.wantErr)) 334 } 335 if !reflect.DeepEqual(config, test.wantConfig) { 336 t.Errorf("%s:\nreturned %v\nwant %v", test.name, config, test.wantConfig) 337 } 338 if hash != test.wantHash { 339 t.Errorf("%s: returned hash %s, want %s", test.name, hash.Hex(), test.wantHash.Hex()) 340 } else if err == nil { 341 // Check database content. 342 stored := db.ReadBlock(test.wantHash, 0) 343 if stored.Hash() != test.wantHash { 344 t.Errorf("%s: block in DB has hash %s, want %s", test.name, stored.Hash(), test.wantHash) 345 } 346 } 347 } 348 } 349 350 func genCypressGenesisBlock() *Genesis { 351 genesis := DefaultGenesisBlock() 352 genesis.Config = params.CypressChainConfig.Copy() 353 genesis.Governance = SetGenesisGovernance(genesis) 354 InitDeriveSha(genesis.Config) 355 return genesis 356 } 357 358 func genBaobabGenesisBlock() *Genesis { 359 genesis := DefaultBaobabGenesisBlock() 360 genesis.Config = params.BaobabChainConfig.Copy() 361 genesis.Governance = SetGenesisGovernance(genesis) 362 InitDeriveSha(genesis.Config) 363 return genesis 364 } 365 366 func genCustomGenesisBlock(customChainId uint64) *Genesis { 367 genesis := &Genesis{ 368 Config: ¶ms.ChainConfig{ 369 ChainID: new(big.Int).SetUint64(customChainId), 370 IstanbulCompatibleBlock: big.NewInt(2), 371 DeriveShaImpl: types.ImplDeriveShaConcat, 372 }, 373 Alloc: GenesisAlloc{ 374 common.HexToAddress("0x0100000000000000000000000000000000000000"): { 375 Balance: big.NewInt(1), Storage: map[common.Hash]common.Hash{{1}: {1}}, 376 }, 377 }, 378 } 379 genesis.Config.SetDefaultsForGenesis() 380 genesis.Governance = SetGenesisGovernance(genesis) 381 InitDeriveSha(genesis.Config) 382 return genesis 383 }