github.com/alanchchen/go-ethereum@v1.6.6-0.20170601190819-6171d01b1195/core/blockchain_test.go (about) 1 // Copyright 2014 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 "fmt" 21 "math/big" 22 "math/rand" 23 "testing" 24 "time" 25 26 "github.com/ethereum/go-ethereum/common" 27 "github.com/ethereum/go-ethereum/consensus/ethash" 28 "github.com/ethereum/go-ethereum/core/state" 29 "github.com/ethereum/go-ethereum/core/types" 30 "github.com/ethereum/go-ethereum/core/vm" 31 "github.com/ethereum/go-ethereum/crypto" 32 "github.com/ethereum/go-ethereum/ethdb" 33 "github.com/ethereum/go-ethereum/event" 34 "github.com/ethereum/go-ethereum/params" 35 ) 36 37 // newTestBlockChain creates a blockchain without validation. 38 func newTestBlockChain(fake bool) *BlockChain { 39 db, _ := ethdb.NewMemDatabase() 40 gspec := &Genesis{ 41 Config: params.TestChainConfig, 42 Difficulty: big.NewInt(1), 43 } 44 gspec.MustCommit(db) 45 engine := ethash.NewFullFaker() 46 if !fake { 47 engine = ethash.NewTester() 48 } 49 blockchain, err := NewBlockChain(db, gspec.Config, engine, new(event.TypeMux), vm.Config{}) 50 if err != nil { 51 panic(err) 52 } 53 blockchain.SetValidator(bproc{}) 54 return blockchain 55 } 56 57 // Test fork of length N starting from block i 58 func testFork(t *testing.T, blockchain *BlockChain, i, n int, full bool, comparator func(td1, td2 *big.Int)) { 59 // Copy old chain up to #i into a new db 60 db, blockchain2, err := newCanonical(i, full) 61 if err != nil { 62 t.Fatal("could not make new canonical in testFork", err) 63 } 64 // Assert the chains have the same header/block at #i 65 var hash1, hash2 common.Hash 66 if full { 67 hash1 = blockchain.GetBlockByNumber(uint64(i)).Hash() 68 hash2 = blockchain2.GetBlockByNumber(uint64(i)).Hash() 69 } else { 70 hash1 = blockchain.GetHeaderByNumber(uint64(i)).Hash() 71 hash2 = blockchain2.GetHeaderByNumber(uint64(i)).Hash() 72 } 73 if hash1 != hash2 { 74 t.Errorf("chain content mismatch at %d: have hash %v, want hash %v", i, hash2, hash1) 75 } 76 // Extend the newly created chain 77 var ( 78 blockChainB []*types.Block 79 headerChainB []*types.Header 80 ) 81 if full { 82 blockChainB = makeBlockChain(blockchain2.CurrentBlock(), n, db, forkSeed) 83 if _, err := blockchain2.InsertChain(blockChainB); err != nil { 84 t.Fatalf("failed to insert forking chain: %v", err) 85 } 86 } else { 87 headerChainB = makeHeaderChain(blockchain2.CurrentHeader(), n, db, forkSeed) 88 if _, err := blockchain2.InsertHeaderChain(headerChainB, 1); err != nil { 89 t.Fatalf("failed to insert forking chain: %v", err) 90 } 91 } 92 // Sanity check that the forked chain can be imported into the original 93 var tdPre, tdPost *big.Int 94 95 if full { 96 tdPre = blockchain.GetTdByHash(blockchain.CurrentBlock().Hash()) 97 if err := testBlockChainImport(blockChainB, blockchain); err != nil { 98 t.Fatalf("failed to import forked block chain: %v", err) 99 } 100 tdPost = blockchain.GetTdByHash(blockChainB[len(blockChainB)-1].Hash()) 101 } else { 102 tdPre = blockchain.GetTdByHash(blockchain.CurrentHeader().Hash()) 103 if err := testHeaderChainImport(headerChainB, blockchain); err != nil { 104 t.Fatalf("failed to import forked header chain: %v", err) 105 } 106 tdPost = blockchain.GetTdByHash(headerChainB[len(headerChainB)-1].Hash()) 107 } 108 // Compare the total difficulties of the chains 109 comparator(tdPre, tdPost) 110 } 111 112 func printChain(bc *BlockChain) { 113 for i := bc.CurrentBlock().Number().Uint64(); i > 0; i-- { 114 b := bc.GetBlockByNumber(uint64(i)) 115 fmt.Printf("\t%x %v\n", b.Hash(), b.Difficulty()) 116 } 117 } 118 119 // testBlockChainImport tries to process a chain of blocks, writing them into 120 // the database if successful. 121 func testBlockChainImport(chain types.Blocks, blockchain *BlockChain) error { 122 for _, block := range chain { 123 // Try and process the block 124 err := blockchain.engine.VerifyHeader(blockchain, block.Header(), true) 125 if err == nil { 126 err = blockchain.validator.ValidateBody(block) 127 } 128 if err != nil { 129 if err == ErrKnownBlock { 130 continue 131 } 132 return err 133 } 134 statedb, err := state.New(blockchain.GetBlockByHash(block.ParentHash()).Root(), blockchain.chainDb) 135 if err != nil { 136 return err 137 } 138 receipts, _, usedGas, err := blockchain.Processor().Process(block, statedb, vm.Config{}) 139 if err != nil { 140 blockchain.reportBlock(block, receipts, err) 141 return err 142 } 143 err = blockchain.validator.ValidateState(block, blockchain.GetBlockByHash(block.ParentHash()), statedb, receipts, usedGas) 144 if err != nil { 145 blockchain.reportBlock(block, receipts, err) 146 return err 147 } 148 blockchain.mu.Lock() 149 WriteTd(blockchain.chainDb, block.Hash(), block.NumberU64(), new(big.Int).Add(block.Difficulty(), blockchain.GetTdByHash(block.ParentHash()))) 150 WriteBlock(blockchain.chainDb, block) 151 statedb.Commit(false) 152 blockchain.mu.Unlock() 153 } 154 return nil 155 } 156 157 // testHeaderChainImport tries to process a chain of header, writing them into 158 // the database if successful. 159 func testHeaderChainImport(chain []*types.Header, blockchain *BlockChain) error { 160 for _, header := range chain { 161 // Try and validate the header 162 if err := blockchain.engine.VerifyHeader(blockchain, header, false); err != nil { 163 return err 164 } 165 // Manually insert the header into the database, but don't reorganise (allows subsequent testing) 166 blockchain.mu.Lock() 167 WriteTd(blockchain.chainDb, header.Hash(), header.Number.Uint64(), new(big.Int).Add(header.Difficulty, blockchain.GetTdByHash(header.ParentHash))) 168 WriteHeader(blockchain.chainDb, header) 169 blockchain.mu.Unlock() 170 } 171 return nil 172 } 173 174 func insertChain(done chan bool, blockchain *BlockChain, chain types.Blocks, t *testing.T) { 175 _, err := blockchain.InsertChain(chain) 176 if err != nil { 177 fmt.Println(err) 178 t.FailNow() 179 } 180 done <- true 181 } 182 183 func TestLastBlock(t *testing.T) { 184 bchain := newTestBlockChain(false) 185 block := makeBlockChain(bchain.CurrentBlock(), 1, bchain.chainDb, 0)[0] 186 bchain.insert(block) 187 if block.Hash() != GetHeadBlockHash(bchain.chainDb) { 188 t.Errorf("Write/Get HeadBlockHash failed") 189 } 190 } 191 192 // Tests that given a starting canonical chain of a given size, it can be extended 193 // with various length chains. 194 func TestExtendCanonicalHeaders(t *testing.T) { testExtendCanonical(t, false) } 195 func TestExtendCanonicalBlocks(t *testing.T) { testExtendCanonical(t, true) } 196 197 func testExtendCanonical(t *testing.T, full bool) { 198 length := 5 199 200 // Make first chain starting from genesis 201 _, processor, err := newCanonical(length, full) 202 if err != nil { 203 t.Fatalf("failed to make new canonical chain: %v", err) 204 } 205 // Define the difficulty comparator 206 better := func(td1, td2 *big.Int) { 207 if td2.Cmp(td1) <= 0 { 208 t.Errorf("total difficulty mismatch: have %v, expected more than %v", td2, td1) 209 } 210 } 211 // Start fork from current height 212 testFork(t, processor, length, 1, full, better) 213 testFork(t, processor, length, 2, full, better) 214 testFork(t, processor, length, 5, full, better) 215 testFork(t, processor, length, 10, full, better) 216 } 217 218 // Tests that given a starting canonical chain of a given size, creating shorter 219 // forks do not take canonical ownership. 220 func TestShorterForkHeaders(t *testing.T) { testShorterFork(t, false) } 221 func TestShorterForkBlocks(t *testing.T) { testShorterFork(t, true) } 222 223 func testShorterFork(t *testing.T, full bool) { 224 length := 10 225 226 // Make first chain starting from genesis 227 _, processor, err := newCanonical(length, full) 228 if err != nil { 229 t.Fatalf("failed to make new canonical chain: %v", err) 230 } 231 // Define the difficulty comparator 232 worse := func(td1, td2 *big.Int) { 233 if td2.Cmp(td1) >= 0 { 234 t.Errorf("total difficulty mismatch: have %v, expected less than %v", td2, td1) 235 } 236 } 237 // Sum of numbers must be less than `length` for this to be a shorter fork 238 testFork(t, processor, 0, 3, full, worse) 239 testFork(t, processor, 0, 7, full, worse) 240 testFork(t, processor, 1, 1, full, worse) 241 testFork(t, processor, 1, 7, full, worse) 242 testFork(t, processor, 5, 3, full, worse) 243 testFork(t, processor, 5, 4, full, worse) 244 } 245 246 // Tests that given a starting canonical chain of a given size, creating longer 247 // forks do take canonical ownership. 248 func TestLongerForkHeaders(t *testing.T) { testLongerFork(t, false) } 249 func TestLongerForkBlocks(t *testing.T) { testLongerFork(t, true) } 250 251 func testLongerFork(t *testing.T, full bool) { 252 length := 10 253 254 // Make first chain starting from genesis 255 _, processor, err := newCanonical(length, full) 256 if err != nil { 257 t.Fatalf("failed to make new canonical chain: %v", err) 258 } 259 // Define the difficulty comparator 260 better := func(td1, td2 *big.Int) { 261 if td2.Cmp(td1) <= 0 { 262 t.Errorf("total difficulty mismatch: have %v, expected more than %v", td2, td1) 263 } 264 } 265 // Sum of numbers must be greater than `length` for this to be a longer fork 266 testFork(t, processor, 0, 11, full, better) 267 testFork(t, processor, 0, 15, full, better) 268 testFork(t, processor, 1, 10, full, better) 269 testFork(t, processor, 1, 12, full, better) 270 testFork(t, processor, 5, 6, full, better) 271 testFork(t, processor, 5, 8, full, better) 272 } 273 274 // Tests that given a starting canonical chain of a given size, creating equal 275 // forks do take canonical ownership. 276 func TestEqualForkHeaders(t *testing.T) { testEqualFork(t, false) } 277 func TestEqualForkBlocks(t *testing.T) { testEqualFork(t, true) } 278 279 func testEqualFork(t *testing.T, full bool) { 280 length := 10 281 282 // Make first chain starting from genesis 283 _, processor, err := newCanonical(length, full) 284 if err != nil { 285 t.Fatalf("failed to make new canonical chain: %v", err) 286 } 287 // Define the difficulty comparator 288 equal := func(td1, td2 *big.Int) { 289 if td2.Cmp(td1) != 0 { 290 t.Errorf("total difficulty mismatch: have %v, want %v", td2, td1) 291 } 292 } 293 // Sum of numbers must be equal to `length` for this to be an equal fork 294 testFork(t, processor, 0, 10, full, equal) 295 testFork(t, processor, 1, 9, full, equal) 296 testFork(t, processor, 2, 8, full, equal) 297 testFork(t, processor, 5, 5, full, equal) 298 testFork(t, processor, 6, 4, full, equal) 299 testFork(t, processor, 9, 1, full, equal) 300 } 301 302 // Tests that chains missing links do not get accepted by the processor. 303 func TestBrokenHeaderChain(t *testing.T) { testBrokenChain(t, false) } 304 func TestBrokenBlockChain(t *testing.T) { testBrokenChain(t, true) } 305 306 func testBrokenChain(t *testing.T, full bool) { 307 // Make chain starting from genesis 308 db, blockchain, err := newCanonical(10, full) 309 if err != nil { 310 t.Fatalf("failed to make new canonical chain: %v", err) 311 } 312 // Create a forked chain, and try to insert with a missing link 313 if full { 314 chain := makeBlockChain(blockchain.CurrentBlock(), 5, db, forkSeed)[1:] 315 if err := testBlockChainImport(chain, blockchain); err == nil { 316 t.Errorf("broken block chain not reported") 317 } 318 } else { 319 chain := makeHeaderChain(blockchain.CurrentHeader(), 5, db, forkSeed)[1:] 320 if err := testHeaderChainImport(chain, blockchain); err == nil { 321 t.Errorf("broken header chain not reported") 322 } 323 } 324 } 325 326 type bproc struct{} 327 328 func (bproc) ValidateBody(*types.Block) error { return nil } 329 func (bproc) ValidateState(block, parent *types.Block, state *state.StateDB, receipts types.Receipts, usedGas *big.Int) error { 330 return nil 331 } 332 func (bproc) Process(block *types.Block, statedb *state.StateDB, cfg vm.Config) (types.Receipts, []*types.Log, *big.Int, error) { 333 return nil, nil, new(big.Int), nil 334 } 335 336 func makeHeaderChainWithDiff(genesis *types.Block, d []int, seed byte) []*types.Header { 337 blocks := makeBlockChainWithDiff(genesis, d, seed) 338 headers := make([]*types.Header, len(blocks)) 339 for i, block := range blocks { 340 headers[i] = block.Header() 341 } 342 return headers 343 } 344 345 func makeBlockChainWithDiff(genesis *types.Block, d []int, seed byte) []*types.Block { 346 var chain []*types.Block 347 for i, difficulty := range d { 348 header := &types.Header{ 349 Coinbase: common.Address{seed}, 350 Number: big.NewInt(int64(i + 1)), 351 Difficulty: big.NewInt(int64(difficulty)), 352 UncleHash: types.EmptyUncleHash, 353 TxHash: types.EmptyRootHash, 354 ReceiptHash: types.EmptyRootHash, 355 Time: big.NewInt(int64(i) + 1), 356 } 357 if i == 0 { 358 header.ParentHash = genesis.Hash() 359 } else { 360 header.ParentHash = chain[i-1].Hash() 361 } 362 block := types.NewBlockWithHeader(header) 363 chain = append(chain, block) 364 } 365 return chain 366 } 367 368 // Tests that reorganising a long difficult chain after a short easy one 369 // overwrites the canonical numbers and links in the database. 370 func TestReorgLongHeaders(t *testing.T) { testReorgLong(t, false) } 371 func TestReorgLongBlocks(t *testing.T) { testReorgLong(t, true) } 372 373 func testReorgLong(t *testing.T, full bool) { 374 testReorg(t, []int{1, 2, 4}, []int{1, 2, 3, 4}, 10, full) 375 } 376 377 // Tests that reorganising a short difficult chain after a long easy one 378 // overwrites the canonical numbers and links in the database. 379 func TestReorgShortHeaders(t *testing.T) { testReorgShort(t, false) } 380 func TestReorgShortBlocks(t *testing.T) { testReorgShort(t, true) } 381 382 func testReorgShort(t *testing.T, full bool) { 383 testReorg(t, []int{1, 2, 3, 4}, []int{1, 10}, 11, full) 384 } 385 386 func testReorg(t *testing.T, first, second []int, td int64, full bool) { 387 bc := newTestBlockChain(true) 388 389 // Insert an easy and a difficult chain afterwards 390 if full { 391 bc.InsertChain(makeBlockChainWithDiff(bc.genesisBlock, first, 11)) 392 bc.InsertChain(makeBlockChainWithDiff(bc.genesisBlock, second, 22)) 393 } else { 394 bc.InsertHeaderChain(makeHeaderChainWithDiff(bc.genesisBlock, first, 11), 1) 395 bc.InsertHeaderChain(makeHeaderChainWithDiff(bc.genesisBlock, second, 22), 1) 396 } 397 // Check that the chain is valid number and link wise 398 if full { 399 prev := bc.CurrentBlock() 400 for block := bc.GetBlockByNumber(bc.CurrentBlock().NumberU64() - 1); block.NumberU64() != 0; prev, block = block, bc.GetBlockByNumber(block.NumberU64()-1) { 401 if prev.ParentHash() != block.Hash() { 402 t.Errorf("parent block hash mismatch: have %x, want %x", prev.ParentHash(), block.Hash()) 403 } 404 } 405 } else { 406 prev := bc.CurrentHeader() 407 for header := bc.GetHeaderByNumber(bc.CurrentHeader().Number.Uint64() - 1); header.Number.Uint64() != 0; prev, header = header, bc.GetHeaderByNumber(header.Number.Uint64()-1) { 408 if prev.ParentHash != header.Hash() { 409 t.Errorf("parent header hash mismatch: have %x, want %x", prev.ParentHash, header.Hash()) 410 } 411 } 412 } 413 // Make sure the chain total difficulty is the correct one 414 want := new(big.Int).Add(bc.genesisBlock.Difficulty(), big.NewInt(td)) 415 if full { 416 if have := bc.GetTdByHash(bc.CurrentBlock().Hash()); have.Cmp(want) != 0 { 417 t.Errorf("total difficulty mismatch: have %v, want %v", have, want) 418 } 419 } else { 420 if have := bc.GetTdByHash(bc.CurrentHeader().Hash()); have.Cmp(want) != 0 { 421 t.Errorf("total difficulty mismatch: have %v, want %v", have, want) 422 } 423 } 424 } 425 426 // Tests that the insertion functions detect banned hashes. 427 func TestBadHeaderHashes(t *testing.T) { testBadHashes(t, false) } 428 func TestBadBlockHashes(t *testing.T) { testBadHashes(t, true) } 429 430 func testBadHashes(t *testing.T, full bool) { 431 bc := newTestBlockChain(true) 432 433 // Create a chain, ban a hash and try to import 434 var err error 435 if full { 436 blocks := makeBlockChainWithDiff(bc.genesisBlock, []int{1, 2, 4}, 10) 437 BadHashes[blocks[2].Header().Hash()] = true 438 _, err = bc.InsertChain(blocks) 439 } else { 440 headers := makeHeaderChainWithDiff(bc.genesisBlock, []int{1, 2, 4}, 10) 441 BadHashes[headers[2].Hash()] = true 442 _, err = bc.InsertHeaderChain(headers, 1) 443 } 444 if err != ErrBlacklistedHash { 445 t.Errorf("error mismatch: have: %v, want: %v", err, ErrBlacklistedHash) 446 } 447 } 448 449 // Tests that bad hashes are detected on boot, and the chain rolled back to a 450 // good state prior to the bad hash. 451 func TestReorgBadHeaderHashes(t *testing.T) { testReorgBadHashes(t, false) } 452 func TestReorgBadBlockHashes(t *testing.T) { testReorgBadHashes(t, true) } 453 454 func testReorgBadHashes(t *testing.T, full bool) { 455 bc := newTestBlockChain(true) 456 457 // Create a chain, import and ban afterwards 458 headers := makeHeaderChainWithDiff(bc.genesisBlock, []int{1, 2, 3, 4}, 10) 459 blocks := makeBlockChainWithDiff(bc.genesisBlock, []int{1, 2, 3, 4}, 10) 460 461 if full { 462 if _, err := bc.InsertChain(blocks); err != nil { 463 t.Fatalf("failed to import blocks: %v", err) 464 } 465 if bc.CurrentBlock().Hash() != blocks[3].Hash() { 466 t.Errorf("last block hash mismatch: have: %x, want %x", bc.CurrentBlock().Hash(), blocks[3].Header().Hash()) 467 } 468 BadHashes[blocks[3].Header().Hash()] = true 469 defer func() { delete(BadHashes, blocks[3].Header().Hash()) }() 470 } else { 471 if _, err := bc.InsertHeaderChain(headers, 1); err != nil { 472 t.Fatalf("failed to import headers: %v", err) 473 } 474 if bc.CurrentHeader().Hash() != headers[3].Hash() { 475 t.Errorf("last header hash mismatch: have: %x, want %x", bc.CurrentHeader().Hash(), headers[3].Hash()) 476 } 477 BadHashes[headers[3].Hash()] = true 478 defer func() { delete(BadHashes, headers[3].Hash()) }() 479 } 480 481 // Create a new BlockChain and check that it rolled back the state. 482 ncm, err := NewBlockChain(bc.chainDb, bc.config, ethash.NewFaker(), new(event.TypeMux), vm.Config{}) 483 if err != nil { 484 t.Fatalf("failed to create new chain manager: %v", err) 485 } 486 if full { 487 if ncm.CurrentBlock().Hash() != blocks[2].Header().Hash() { 488 t.Errorf("last block hash mismatch: have: %x, want %x", ncm.CurrentBlock().Hash(), blocks[2].Header().Hash()) 489 } 490 if blocks[2].Header().GasLimit.Cmp(ncm.GasLimit()) != 0 { 491 t.Errorf("last block gasLimit mismatch: have: %x, want %x", ncm.GasLimit(), blocks[2].Header().GasLimit) 492 } 493 } else { 494 if ncm.CurrentHeader().Hash() != headers[2].Hash() { 495 t.Errorf("last header hash mismatch: have: %x, want %x", ncm.CurrentHeader().Hash(), headers[2].Hash()) 496 } 497 } 498 } 499 500 // Tests chain insertions in the face of one entity containing an invalid nonce. 501 func TestHeadersInsertNonceError(t *testing.T) { testInsertNonceError(t, false) } 502 func TestBlocksInsertNonceError(t *testing.T) { testInsertNonceError(t, true) } 503 504 func testInsertNonceError(t *testing.T, full bool) { 505 for i := 1; i < 25 && !t.Failed(); i++ { 506 // Create a pristine chain and database 507 db, blockchain, err := newCanonical(0, full) 508 if err != nil { 509 t.Fatalf("failed to create pristine chain: %v", err) 510 } 511 // Create and insert a chain with a failing nonce 512 var ( 513 failAt int 514 failRes int 515 failNum uint64 516 ) 517 if full { 518 blocks := makeBlockChain(blockchain.CurrentBlock(), i, db, 0) 519 520 failAt = rand.Int() % len(blocks) 521 failNum = blocks[failAt].NumberU64() 522 523 blockchain.engine = ethash.NewFakeFailer(failNum) 524 failRes, err = blockchain.InsertChain(blocks) 525 } else { 526 headers := makeHeaderChain(blockchain.CurrentHeader(), i, db, 0) 527 528 failAt = rand.Int() % len(headers) 529 failNum = headers[failAt].Number.Uint64() 530 531 blockchain.engine = ethash.NewFakeFailer(failNum) 532 blockchain.hc.engine = blockchain.engine 533 failRes, err = blockchain.InsertHeaderChain(headers, 1) 534 } 535 // Check that the returned error indicates the failure. 536 if failRes != failAt { 537 t.Errorf("test %d: failure index mismatch: have %d, want %d", i, failRes, failAt) 538 } 539 // Check that all no blocks after the failing block have been inserted. 540 for j := 0; j < i-failAt; j++ { 541 if full { 542 if block := blockchain.GetBlockByNumber(failNum + uint64(j)); block != nil { 543 t.Errorf("test %d: invalid block in chain: %v", i, block) 544 } 545 } else { 546 if header := blockchain.GetHeaderByNumber(failNum + uint64(j)); header != nil { 547 t.Errorf("test %d: invalid header in chain: %v", i, header) 548 } 549 } 550 } 551 } 552 } 553 554 // Tests that fast importing a block chain produces the same chain data as the 555 // classical full block processing. 556 func TestFastVsFullChains(t *testing.T) { 557 // Configure and generate a sample block chain 558 var ( 559 gendb, _ = ethdb.NewMemDatabase() 560 key, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") 561 address = crypto.PubkeyToAddress(key.PublicKey) 562 funds = big.NewInt(1000000000) 563 gspec = &Genesis{ 564 Config: params.TestChainConfig, 565 Alloc: GenesisAlloc{address: {Balance: funds}}, 566 } 567 genesis = gspec.MustCommit(gendb) 568 signer = types.NewEIP155Signer(gspec.Config.ChainId) 569 ) 570 blocks, receipts := GenerateChain(gspec.Config, genesis, gendb, 1024, func(i int, block *BlockGen) { 571 block.SetCoinbase(common.Address{0x00}) 572 573 // If the block number is multiple of 3, send a few bonus transactions to the miner 574 if i%3 == 2 { 575 for j := 0; j < i%4+1; j++ { 576 tx, err := types.SignTx(types.NewTransaction(block.TxNonce(address), common.Address{0x00}, big.NewInt(1000), bigTxGas, nil, nil), signer, key) 577 if err != nil { 578 panic(err) 579 } 580 block.AddTx(tx) 581 } 582 } 583 // If the block number is a multiple of 5, add a few bonus uncles to the block 584 if i%5 == 5 { 585 block.AddUncle(&types.Header{ParentHash: block.PrevBlock(i - 1).Hash(), Number: big.NewInt(int64(i - 1))}) 586 } 587 }) 588 // Import the chain as an archive node for the comparison baseline 589 archiveDb, _ := ethdb.NewMemDatabase() 590 gspec.MustCommit(archiveDb) 591 archive, _ := NewBlockChain(archiveDb, gspec.Config, ethash.NewFaker(), new(event.TypeMux), vm.Config{}) 592 593 if n, err := archive.InsertChain(blocks); err != nil { 594 t.Fatalf("failed to process block %d: %v", n, err) 595 } 596 597 // Fast import the chain as a non-archive node to test 598 fastDb, _ := ethdb.NewMemDatabase() 599 gspec.MustCommit(fastDb) 600 fast, _ := NewBlockChain(fastDb, gspec.Config, ethash.NewFaker(), new(event.TypeMux), vm.Config{}) 601 602 headers := make([]*types.Header, len(blocks)) 603 for i, block := range blocks { 604 headers[i] = block.Header() 605 } 606 if n, err := fast.InsertHeaderChain(headers, 1); err != nil { 607 t.Fatalf("failed to insert header %d: %v", n, err) 608 } 609 if n, err := fast.InsertReceiptChain(blocks, receipts); err != nil { 610 t.Fatalf("failed to insert receipt %d: %v", n, err) 611 } 612 // Iterate over all chain data components, and cross reference 613 for i := 0; i < len(blocks); i++ { 614 num, hash := blocks[i].NumberU64(), blocks[i].Hash() 615 616 if ftd, atd := fast.GetTdByHash(hash), archive.GetTdByHash(hash); ftd.Cmp(atd) != 0 { 617 t.Errorf("block #%d [%x]: td mismatch: have %v, want %v", num, hash, ftd, atd) 618 } 619 if fheader, aheader := fast.GetHeaderByHash(hash), archive.GetHeaderByHash(hash); fheader.Hash() != aheader.Hash() { 620 t.Errorf("block #%d [%x]: header mismatch: have %v, want %v", num, hash, fheader, aheader) 621 } 622 if fblock, ablock := fast.GetBlockByHash(hash), archive.GetBlockByHash(hash); fblock.Hash() != ablock.Hash() { 623 t.Errorf("block #%d [%x]: block mismatch: have %v, want %v", num, hash, fblock, ablock) 624 } else if types.DeriveSha(fblock.Transactions()) != types.DeriveSha(ablock.Transactions()) { 625 t.Errorf("block #%d [%x]: transactions mismatch: have %v, want %v", num, hash, fblock.Transactions(), ablock.Transactions()) 626 } else if types.CalcUncleHash(fblock.Uncles()) != types.CalcUncleHash(ablock.Uncles()) { 627 t.Errorf("block #%d [%x]: uncles mismatch: have %v, want %v", num, hash, fblock.Uncles(), ablock.Uncles()) 628 } 629 if freceipts, areceipts := GetBlockReceipts(fastDb, hash, GetBlockNumber(fastDb, hash)), GetBlockReceipts(archiveDb, hash, GetBlockNumber(archiveDb, hash)); types.DeriveSha(freceipts) != types.DeriveSha(areceipts) { 630 t.Errorf("block #%d [%x]: receipts mismatch: have %v, want %v", num, hash, freceipts, areceipts) 631 } 632 } 633 // Check that the canonical chains are the same between the databases 634 for i := 0; i < len(blocks)+1; i++ { 635 if fhash, ahash := GetCanonicalHash(fastDb, uint64(i)), GetCanonicalHash(archiveDb, uint64(i)); fhash != ahash { 636 t.Errorf("block #%d: canonical hash mismatch: have %v, want %v", i, fhash, ahash) 637 } 638 } 639 } 640 641 // Tests that various import methods move the chain head pointers to the correct 642 // positions. 643 func TestLightVsFastVsFullChainHeads(t *testing.T) { 644 // Configure and generate a sample block chain 645 var ( 646 gendb, _ = ethdb.NewMemDatabase() 647 key, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") 648 address = crypto.PubkeyToAddress(key.PublicKey) 649 funds = big.NewInt(1000000000) 650 gspec = &Genesis{Config: params.TestChainConfig, Alloc: GenesisAlloc{address: {Balance: funds}}} 651 genesis = gspec.MustCommit(gendb) 652 ) 653 height := uint64(1024) 654 blocks, receipts := GenerateChain(gspec.Config, genesis, gendb, int(height), nil) 655 656 // Configure a subchain to roll back 657 remove := []common.Hash{} 658 for _, block := range blocks[height/2:] { 659 remove = append(remove, block.Hash()) 660 } 661 // Create a small assertion method to check the three heads 662 assert := func(t *testing.T, kind string, chain *BlockChain, header uint64, fast uint64, block uint64) { 663 if num := chain.CurrentBlock().NumberU64(); num != block { 664 t.Errorf("%s head block mismatch: have #%v, want #%v", kind, num, block) 665 } 666 if num := chain.CurrentFastBlock().NumberU64(); num != fast { 667 t.Errorf("%s head fast-block mismatch: have #%v, want #%v", kind, num, fast) 668 } 669 if num := chain.CurrentHeader().Number.Uint64(); num != header { 670 t.Errorf("%s head header mismatch: have #%v, want #%v", kind, num, header) 671 } 672 } 673 // Import the chain as an archive node and ensure all pointers are updated 674 archiveDb, _ := ethdb.NewMemDatabase() 675 gspec.MustCommit(archiveDb) 676 677 archive, _ := NewBlockChain(archiveDb, gspec.Config, ethash.NewFaker(), new(event.TypeMux), vm.Config{}) 678 if n, err := archive.InsertChain(blocks); err != nil { 679 t.Fatalf("failed to process block %d: %v", n, err) 680 } 681 assert(t, "archive", archive, height, height, height) 682 archive.Rollback(remove) 683 assert(t, "archive", archive, height/2, height/2, height/2) 684 685 // Import the chain as a non-archive node and ensure all pointers are updated 686 fastDb, _ := ethdb.NewMemDatabase() 687 gspec.MustCommit(fastDb) 688 fast, _ := NewBlockChain(fastDb, gspec.Config, ethash.NewFaker(), new(event.TypeMux), vm.Config{}) 689 690 headers := make([]*types.Header, len(blocks)) 691 for i, block := range blocks { 692 headers[i] = block.Header() 693 } 694 if n, err := fast.InsertHeaderChain(headers, 1); err != nil { 695 t.Fatalf("failed to insert header %d: %v", n, err) 696 } 697 if n, err := fast.InsertReceiptChain(blocks, receipts); err != nil { 698 t.Fatalf("failed to insert receipt %d: %v", n, err) 699 } 700 assert(t, "fast", fast, height, height, 0) 701 fast.Rollback(remove) 702 assert(t, "fast", fast, height/2, height/2, 0) 703 704 // Import the chain as a light node and ensure all pointers are updated 705 lightDb, _ := ethdb.NewMemDatabase() 706 gspec.MustCommit(lightDb) 707 708 light, _ := NewBlockChain(lightDb, gspec.Config, ethash.NewFaker(), new(event.TypeMux), vm.Config{}) 709 if n, err := light.InsertHeaderChain(headers, 1); err != nil { 710 t.Fatalf("failed to insert header %d: %v", n, err) 711 } 712 assert(t, "light", light, height, 0, 0) 713 light.Rollback(remove) 714 assert(t, "light", light, height/2, 0, 0) 715 } 716 717 // Tests that chain reorganisations handle transaction removals and reinsertions. 718 func TestChainTxReorgs(t *testing.T) { 719 var ( 720 key1, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") 721 key2, _ = crypto.HexToECDSA("8a1f9a8f95be41cd7ccb6168179afb4504aefe388d1e14474d32c45c72ce7b7a") 722 key3, _ = crypto.HexToECDSA("49a7b37aa6f6645917e7b807e9d1c00d4fa71f18343b0d4122a4d2df64dd6fee") 723 addr1 = crypto.PubkeyToAddress(key1.PublicKey) 724 addr2 = crypto.PubkeyToAddress(key2.PublicKey) 725 addr3 = crypto.PubkeyToAddress(key3.PublicKey) 726 db, _ = ethdb.NewMemDatabase() 727 gspec = &Genesis{ 728 Config: params.TestChainConfig, 729 GasLimit: 3141592, 730 Alloc: GenesisAlloc{ 731 addr1: {Balance: big.NewInt(1000000)}, 732 addr2: {Balance: big.NewInt(1000000)}, 733 addr3: {Balance: big.NewInt(1000000)}, 734 }, 735 } 736 genesis = gspec.MustCommit(db) 737 signer = types.NewEIP155Signer(gspec.Config.ChainId) 738 ) 739 740 // Create two transactions shared between the chains: 741 // - postponed: transaction included at a later block in the forked chain 742 // - swapped: transaction included at the same block number in the forked chain 743 postponed, _ := types.SignTx(types.NewTransaction(0, addr1, big.NewInt(1000), bigTxGas, nil, nil), signer, key1) 744 swapped, _ := types.SignTx(types.NewTransaction(1, addr1, big.NewInt(1000), bigTxGas, nil, nil), signer, key1) 745 746 // Create two transactions that will be dropped by the forked chain: 747 // - pastDrop: transaction dropped retroactively from a past block 748 // - freshDrop: transaction dropped exactly at the block where the reorg is detected 749 var pastDrop, freshDrop *types.Transaction 750 751 // Create three transactions that will be added in the forked chain: 752 // - pastAdd: transaction added before the reorganization is detected 753 // - freshAdd: transaction added at the exact block the reorg is detected 754 // - futureAdd: transaction added after the reorg has already finished 755 var pastAdd, freshAdd, futureAdd *types.Transaction 756 757 chain, _ := GenerateChain(gspec.Config, genesis, db, 3, func(i int, gen *BlockGen) { 758 switch i { 759 case 0: 760 pastDrop, _ = types.SignTx(types.NewTransaction(gen.TxNonce(addr2), addr2, big.NewInt(1000), bigTxGas, nil, nil), signer, key2) 761 762 gen.AddTx(pastDrop) // This transaction will be dropped in the fork from below the split point 763 gen.AddTx(postponed) // This transaction will be postponed till block #3 in the fork 764 765 case 2: 766 freshDrop, _ = types.SignTx(types.NewTransaction(gen.TxNonce(addr2), addr2, big.NewInt(1000), bigTxGas, nil, nil), signer, key2) 767 768 gen.AddTx(freshDrop) // This transaction will be dropped in the fork from exactly at the split point 769 gen.AddTx(swapped) // This transaction will be swapped out at the exact height 770 771 gen.OffsetTime(9) // Lower the block difficulty to simulate a weaker chain 772 } 773 }) 774 // Import the chain. This runs all block validation rules. 775 evmux := &event.TypeMux{} 776 blockchain, _ := NewBlockChain(db, gspec.Config, ethash.NewFaker(), evmux, vm.Config{}) 777 if i, err := blockchain.InsertChain(chain); err != nil { 778 t.Fatalf("failed to insert original chain[%d]: %v", i, err) 779 } 780 781 // overwrite the old chain 782 chain, _ = GenerateChain(gspec.Config, genesis, db, 5, func(i int, gen *BlockGen) { 783 switch i { 784 case 0: 785 pastAdd, _ = types.SignTx(types.NewTransaction(gen.TxNonce(addr3), addr3, big.NewInt(1000), bigTxGas, nil, nil), signer, key3) 786 gen.AddTx(pastAdd) // This transaction needs to be injected during reorg 787 788 case 2: 789 gen.AddTx(postponed) // This transaction was postponed from block #1 in the original chain 790 gen.AddTx(swapped) // This transaction was swapped from the exact current spot in the original chain 791 792 freshAdd, _ = types.SignTx(types.NewTransaction(gen.TxNonce(addr3), addr3, big.NewInt(1000), bigTxGas, nil, nil), signer, key3) 793 gen.AddTx(freshAdd) // This transaction will be added exactly at reorg time 794 795 case 3: 796 futureAdd, _ = types.SignTx(types.NewTransaction(gen.TxNonce(addr3), addr3, big.NewInt(1000), bigTxGas, nil, nil), signer, key3) 797 gen.AddTx(futureAdd) // This transaction will be added after a full reorg 798 } 799 }) 800 if _, err := blockchain.InsertChain(chain); err != nil { 801 t.Fatalf("failed to insert forked chain: %v", err) 802 } 803 804 // removed tx 805 for i, tx := range (types.Transactions{pastDrop, freshDrop}) { 806 if txn, _, _, _ := GetTransaction(db, tx.Hash()); txn != nil { 807 t.Errorf("drop %d: tx %v found while shouldn't have been", i, txn) 808 } 809 if GetReceipt(db, tx.Hash()) != nil { 810 t.Errorf("drop %d: receipt found while shouldn't have been", i) 811 } 812 } 813 // added tx 814 for i, tx := range (types.Transactions{pastAdd, freshAdd, futureAdd}) { 815 if txn, _, _, _ := GetTransaction(db, tx.Hash()); txn == nil { 816 t.Errorf("add %d: expected tx to be found", i) 817 } 818 if GetReceipt(db, tx.Hash()) == nil { 819 t.Errorf("add %d: expected receipt to be found", i) 820 } 821 } 822 // shared tx 823 for i, tx := range (types.Transactions{postponed, swapped}) { 824 if txn, _, _, _ := GetTransaction(db, tx.Hash()); txn == nil { 825 t.Errorf("share %d: expected tx to be found", i) 826 } 827 if GetReceipt(db, tx.Hash()) == nil { 828 t.Errorf("share %d: expected receipt to be found", i) 829 } 830 } 831 } 832 833 func TestLogReorgs(t *testing.T) { 834 835 var ( 836 key1, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") 837 addr1 = crypto.PubkeyToAddress(key1.PublicKey) 838 db, _ = ethdb.NewMemDatabase() 839 // this code generates a log 840 code = common.Hex2Bytes("60606040525b7f24ec1d3ff24c2f6ff210738839dbc339cd45a5294d85c79361016243157aae7b60405180905060405180910390a15b600a8060416000396000f360606040526008565b00") 841 gspec = &Genesis{Config: params.TestChainConfig, Alloc: GenesisAlloc{addr1: {Balance: big.NewInt(10000000000000)}}} 842 genesis = gspec.MustCommit(db) 843 signer = types.NewEIP155Signer(gspec.Config.ChainId) 844 ) 845 846 var evmux event.TypeMux 847 blockchain, _ := NewBlockChain(db, gspec.Config, ethash.NewFaker(), &evmux, vm.Config{}) 848 849 subs := evmux.Subscribe(RemovedLogsEvent{}) 850 chain, _ := GenerateChain(params.TestChainConfig, genesis, db, 2, func(i int, gen *BlockGen) { 851 if i == 1 { 852 tx, err := types.SignTx(types.NewContractCreation(gen.TxNonce(addr1), new(big.Int), big.NewInt(1000000), new(big.Int), code), signer, key1) 853 if err != nil { 854 t.Fatalf("failed to create tx: %v", err) 855 } 856 gen.AddTx(tx) 857 } 858 }) 859 if _, err := blockchain.InsertChain(chain); err != nil { 860 t.Fatalf("failed to insert chain: %v", err) 861 } 862 863 chain, _ = GenerateChain(params.TestChainConfig, genesis, db, 3, func(i int, gen *BlockGen) {}) 864 if _, err := blockchain.InsertChain(chain); err != nil { 865 t.Fatalf("failed to insert forked chain: %v", err) 866 } 867 868 ev := <-subs.Chan() 869 if len(ev.Data.(RemovedLogsEvent).Logs) == 0 { 870 t.Error("expected logs") 871 } 872 } 873 874 func TestReorgSideEvent(t *testing.T) { 875 var ( 876 db, _ = ethdb.NewMemDatabase() 877 key1, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") 878 addr1 = crypto.PubkeyToAddress(key1.PublicKey) 879 gspec = &Genesis{ 880 Config: params.TestChainConfig, 881 Alloc: GenesisAlloc{addr1: {Balance: big.NewInt(10000000000000)}}, 882 } 883 genesis = gspec.MustCommit(db) 884 signer = types.NewEIP155Signer(gspec.Config.ChainId) 885 ) 886 887 evmux := &event.TypeMux{} 888 blockchain, _ := NewBlockChain(db, gspec.Config, ethash.NewFaker(), evmux, vm.Config{}) 889 890 chain, _ := GenerateChain(gspec.Config, genesis, db, 3, func(i int, gen *BlockGen) {}) 891 if _, err := blockchain.InsertChain(chain); err != nil { 892 t.Fatalf("failed to insert chain: %v", err) 893 } 894 895 replacementBlocks, _ := GenerateChain(gspec.Config, genesis, db, 4, func(i int, gen *BlockGen) { 896 tx, err := types.SignTx(types.NewContractCreation(gen.TxNonce(addr1), new(big.Int), big.NewInt(1000000), new(big.Int), nil), signer, key1) 897 if i == 2 { 898 gen.OffsetTime(-1) 899 } 900 if err != nil { 901 t.Fatalf("failed to create tx: %v", err) 902 } 903 gen.AddTx(tx) 904 }) 905 subs := evmux.Subscribe(ChainSideEvent{}) 906 if _, err := blockchain.InsertChain(replacementBlocks); err != nil { 907 t.Fatalf("failed to insert chain: %v", err) 908 } 909 910 // first two block of the secondary chain are for a brief moment considered 911 // side chains because up to that point the first one is considered the 912 // heavier chain. 913 expectedSideHashes := map[common.Hash]bool{ 914 replacementBlocks[0].Hash(): true, 915 replacementBlocks[1].Hash(): true, 916 chain[0].Hash(): true, 917 chain[1].Hash(): true, 918 chain[2].Hash(): true, 919 } 920 921 i := 0 922 923 const timeoutDura = 10 * time.Second 924 timeout := time.NewTimer(timeoutDura) 925 done: 926 for { 927 select { 928 case ev := <-subs.Chan(): 929 block := ev.Data.(ChainSideEvent).Block 930 if _, ok := expectedSideHashes[block.Hash()]; !ok { 931 t.Errorf("%d: didn't expect %x to be in side chain", i, block.Hash()) 932 } 933 i++ 934 935 if i == len(expectedSideHashes) { 936 timeout.Stop() 937 938 break done 939 } 940 timeout.Reset(timeoutDura) 941 942 case <-timeout.C: 943 t.Fatal("Timeout. Possibly not all blocks were triggered for sideevent") 944 } 945 } 946 947 // make sure no more events are fired 948 select { 949 case e := <-subs.Chan(): 950 t.Errorf("unexpected event fired: %v", e) 951 case <-time.After(250 * time.Millisecond): 952 } 953 954 } 955 956 // Tests if the canonical block can be fetched from the database during chain insertion. 957 func TestCanonicalBlockRetrieval(t *testing.T) { 958 bc := newTestBlockChain(false) 959 chain, _ := GenerateChain(bc.config, bc.genesisBlock, bc.chainDb, 10, func(i int, gen *BlockGen) {}) 960 961 for i := range chain { 962 go func(block *types.Block) { 963 // try to retrieve a block by its canonical hash and see if the block data can be retrieved. 964 for { 965 ch := GetCanonicalHash(bc.chainDb, block.NumberU64()) 966 if ch == (common.Hash{}) { 967 continue // busy wait for canonical hash to be written 968 } 969 if ch != block.Hash() { 970 t.Fatalf("unknown canonical hash, want %s, got %s", block.Hash().Hex(), ch.Hex()) 971 } 972 fb := GetBlock(bc.chainDb, ch, block.NumberU64()) 973 if fb == nil { 974 t.Fatalf("unable to retrieve block %d for canonical hash: %s", block.NumberU64(), ch.Hex()) 975 } 976 if fb.Hash() != block.Hash() { 977 t.Fatalf("invalid block hash for block %d, want %s, got %s", block.NumberU64(), block.Hash().Hex(), fb.Hash().Hex()) 978 } 979 return 980 } 981 }(chain[i]) 982 983 bc.InsertChain(types.Blocks{chain[i]}) 984 } 985 } 986 987 func TestEIP155Transition(t *testing.T) { 988 // Configure and generate a sample block chain 989 var ( 990 db, _ = ethdb.NewMemDatabase() 991 key, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") 992 address = crypto.PubkeyToAddress(key.PublicKey) 993 funds = big.NewInt(1000000000) 994 deleteAddr = common.Address{1} 995 gspec = &Genesis{ 996 Config: ¶ms.ChainConfig{ChainId: big.NewInt(1), EIP155Block: big.NewInt(2), HomesteadBlock: new(big.Int)}, 997 Alloc: GenesisAlloc{address: {Balance: funds}, deleteAddr: {Balance: new(big.Int)}}, 998 } 999 genesis = gspec.MustCommit(db) 1000 mux event.TypeMux 1001 ) 1002 1003 blockchain, _ := NewBlockChain(db, gspec.Config, ethash.NewFaker(), &mux, vm.Config{}) 1004 blocks, _ := GenerateChain(gspec.Config, genesis, db, 4, func(i int, block *BlockGen) { 1005 var ( 1006 tx *types.Transaction 1007 err error 1008 basicTx = func(signer types.Signer) (*types.Transaction, error) { 1009 return types.SignTx(types.NewTransaction(block.TxNonce(address), common.Address{}, new(big.Int), big.NewInt(21000), new(big.Int), nil), signer, key) 1010 } 1011 ) 1012 switch i { 1013 case 0: 1014 tx, err = basicTx(types.HomesteadSigner{}) 1015 if err != nil { 1016 t.Fatal(err) 1017 } 1018 block.AddTx(tx) 1019 case 2: 1020 tx, err = basicTx(types.HomesteadSigner{}) 1021 if err != nil { 1022 t.Fatal(err) 1023 } 1024 block.AddTx(tx) 1025 1026 tx, err = basicTx(types.NewEIP155Signer(gspec.Config.ChainId)) 1027 if err != nil { 1028 t.Fatal(err) 1029 } 1030 block.AddTx(tx) 1031 case 3: 1032 tx, err = basicTx(types.HomesteadSigner{}) 1033 if err != nil { 1034 t.Fatal(err) 1035 } 1036 block.AddTx(tx) 1037 1038 tx, err = basicTx(types.NewEIP155Signer(gspec.Config.ChainId)) 1039 if err != nil { 1040 t.Fatal(err) 1041 } 1042 block.AddTx(tx) 1043 } 1044 }) 1045 1046 if _, err := blockchain.InsertChain(blocks); err != nil { 1047 t.Fatal(err) 1048 } 1049 block := blockchain.GetBlockByNumber(1) 1050 if block.Transactions()[0].Protected() { 1051 t.Error("Expected block[0].txs[0] to not be replay protected") 1052 } 1053 1054 block = blockchain.GetBlockByNumber(3) 1055 if block.Transactions()[0].Protected() { 1056 t.Error("Expected block[3].txs[0] to not be replay protected") 1057 } 1058 if !block.Transactions()[1].Protected() { 1059 t.Error("Expected block[3].txs[1] to be replay protected") 1060 } 1061 if _, err := blockchain.InsertChain(blocks[4:]); err != nil { 1062 t.Fatal(err) 1063 } 1064 1065 // generate an invalid chain id transaction 1066 config := ¶ms.ChainConfig{ChainId: big.NewInt(2), EIP155Block: big.NewInt(2), HomesteadBlock: new(big.Int)} 1067 blocks, _ = GenerateChain(config, blocks[len(blocks)-1], db, 4, func(i int, block *BlockGen) { 1068 var ( 1069 tx *types.Transaction 1070 err error 1071 basicTx = func(signer types.Signer) (*types.Transaction, error) { 1072 return types.SignTx(types.NewTransaction(block.TxNonce(address), common.Address{}, new(big.Int), big.NewInt(21000), new(big.Int), nil), signer, key) 1073 } 1074 ) 1075 switch i { 1076 case 0: 1077 tx, err = basicTx(types.NewEIP155Signer(big.NewInt(2))) 1078 if err != nil { 1079 t.Fatal(err) 1080 } 1081 block.AddTx(tx) 1082 } 1083 }) 1084 _, err := blockchain.InsertChain(blocks) 1085 if err != types.ErrInvalidChainId { 1086 t.Error("expected error:", types.ErrInvalidChainId) 1087 } 1088 } 1089 1090 func TestEIP161AccountRemoval(t *testing.T) { 1091 // Configure and generate a sample block chain 1092 var ( 1093 db, _ = ethdb.NewMemDatabase() 1094 key, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") 1095 address = crypto.PubkeyToAddress(key.PublicKey) 1096 funds = big.NewInt(1000000000) 1097 theAddr = common.Address{1} 1098 gspec = &Genesis{ 1099 Config: ¶ms.ChainConfig{ 1100 ChainId: big.NewInt(1), 1101 HomesteadBlock: new(big.Int), 1102 EIP155Block: new(big.Int), 1103 EIP158Block: big.NewInt(2), 1104 }, 1105 Alloc: GenesisAlloc{address: {Balance: funds}}, 1106 } 1107 genesis = gspec.MustCommit(db) 1108 mux event.TypeMux 1109 blockchain, _ = NewBlockChain(db, gspec.Config, ethash.NewFaker(), &mux, vm.Config{}) 1110 ) 1111 blocks, _ := GenerateChain(gspec.Config, genesis, db, 3, func(i int, block *BlockGen) { 1112 var ( 1113 tx *types.Transaction 1114 err error 1115 signer = types.NewEIP155Signer(gspec.Config.ChainId) 1116 ) 1117 switch i { 1118 case 0: 1119 tx, err = types.SignTx(types.NewTransaction(block.TxNonce(address), theAddr, new(big.Int), big.NewInt(21000), new(big.Int), nil), signer, key) 1120 case 1: 1121 tx, err = types.SignTx(types.NewTransaction(block.TxNonce(address), theAddr, new(big.Int), big.NewInt(21000), new(big.Int), nil), signer, key) 1122 case 2: 1123 tx, err = types.SignTx(types.NewTransaction(block.TxNonce(address), theAddr, new(big.Int), big.NewInt(21000), new(big.Int), nil), signer, key) 1124 } 1125 if err != nil { 1126 t.Fatal(err) 1127 } 1128 block.AddTx(tx) 1129 }) 1130 // account must exist pre eip 161 1131 if _, err := blockchain.InsertChain(types.Blocks{blocks[0]}); err != nil { 1132 t.Fatal(err) 1133 } 1134 if !blockchain.stateCache.Exist(theAddr) { 1135 t.Error("expected account to exist") 1136 } 1137 1138 // account needs to be deleted post eip 161 1139 if _, err := blockchain.InsertChain(types.Blocks{blocks[1]}); err != nil { 1140 t.Fatal(err) 1141 } 1142 if blockchain.stateCache.Exist(theAddr) { 1143 t.Error("account should not exist") 1144 } 1145 1146 // account musn't be created post eip 161 1147 if _, err := blockchain.InsertChain(types.Blocks{blocks[2]}); err != nil { 1148 t.Fatal(err) 1149 } 1150 if blockchain.stateCache.Exist(theAddr) { 1151 t.Error("account should not exist") 1152 } 1153 }