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