From d348ed2976039b2081ae8d6763de42b54884670f Mon Sep 17 00:00:00 2001 From: rjl493456442 Date: Wed, 8 May 2019 10:38:12 +0800 Subject: [PATCH] core: doesn't process head block in reorg function --- core/blockchain.go | 37 +++++------ core/blockchain_test.go | 138 ++++++++++++++++++++-------------------- 2 files changed, 87 insertions(+), 88 deletions(-) diff --git a/core/blockchain.go b/core/blockchain.go index 759143c30a..8cbef71734 100644 --- a/core/blockchain.go +++ b/core/blockchain.go @@ -1164,14 +1164,13 @@ func (bc *BlockChain) insertChain(chain types.Blocks, verifySeals bool) (int, [] localTd = bc.GetTd(current.Hash(), current.NumberU64()) externTd = bc.GetTd(block.ParentHash(), block.NumberU64()-1) // The first block can't be nil ) - externTd = new(big.Int).Add(externTd, block.Difficulty()) - for block != nil && err == ErrKnownBlock && localTd.Cmp(externTd) >= 0 { + for block != nil && err == ErrKnownBlock { + externTd = new(big.Int).Add(externTd, block.Difficulty()) + if localTd.Cmp(externTd) < 0 { + break + } stats.ignored++ block, err = it.next() - - if block != nil { - externTd = new(big.Int).Add(externTd, block.Difficulty()) - } } // The remaining blocks are still known blocks, the only scenario here is: // During the fast sync, the pivot point is already submitted but rollback @@ -1181,15 +1180,13 @@ func (bc *BlockChain) insertChain(chain types.Blocks, verifySeals bool) (int, [] // When node runs a fast sync again, it can re-import a batch of known blocks via // `insertChain` while a part of them have higher total difficulty than current // head full block(new pivot point). - if err == ErrKnownBlock { - for block != nil && err == ErrKnownBlock { - if err := bc.writeKnownBlock(block); err != nil { - return it.index, nil, nil, err - } - lastCanon = block - - block, err = it.next() + for block != nil && err == ErrKnownBlock { + if err := bc.writeKnownBlock(block); err != nil { + return it.index, nil, nil, err } + lastCanon = block + + block, err = it.next() } // Falls through to the block import } @@ -1571,15 +1568,15 @@ func (bc *BlockChain) reorg(oldBlock, newBlock *types.Block) error { } else { log.Error("Impossible reorg, please file an issue", "oldnum", oldBlock.Number(), "oldhash", oldBlock.Hash(), "newnum", newBlock.Number(), "newhash", newBlock.Hash()) } - // Insert the new chain, taking care of the proper incremental order - for i := len(newChain) - 1; i >= 0; i-- { + // Insert the new chain(except the head block(reverse order)), + // taking care of the proper incremental order. + for i := len(newChain) - 1; i >= 1; i-- { // Insert the block in the canonical way, re-writing history bc.insert(newChain[i]) - // Collect reborn logs due to chain reorg (except head block (reverse order)) - if i != 0 { - collectLogs(newChain[i].Hash(), false) - } + // Collect reborn logs due to chain reorg + collectLogs(newChain[i].Hash(), false) + // Write lookup entries for hash based transaction/receipt searches rawdb.WriteTxLookupEntries(bc.db, newChain[i]) addedTxs = append(addedTxs, newChain[i].Transactions()...) diff --git a/core/blockchain_test.go b/core/blockchain_test.go index fe2b6ab017..70e3207f58 100644 --- a/core/blockchain_test.go +++ b/core/blockchain_test.go @@ -1819,76 +1819,17 @@ func testInsertKnownChainData(t *testing.T, typ string) { // The head shouldn't change. asserter(t, blocks3[len(blocks3)-1]) - // Rollback the heavier chain and re-insert the longer chain again - for i := 0; i < len(blocks3); i++ { - rollback = append(rollback, blocks3[i].Hash()) - } - chain.Rollback(rollback) - - if err := inserter(append(blocks, blocks2...), append(receipts, receipts2...)); err != nil { - t.Fatalf("failed to insert chain data: %v", err) - } - asserter(t, blocks2[len(blocks2)-1]) -} - -// Benchmarks large blocks with value transfers to non-existing accounts -func benchmarkLargeNumberOfValueToNonexisting(b *testing.B, numTxs, numBlocks int, recipientFn func(uint64) common.Address, dataFn func(uint64) []byte) { - var ( - signer = types.HomesteadSigner{} - testBankKey, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") - testBankAddress = crypto.PubkeyToAddress(testBankKey.PublicKey) - bankFunds = big.NewInt(100000000000000000) - gspec = Genesis{ - Config: params.TestChainConfig, - Alloc: GenesisAlloc{ - testBankAddress: {Balance: bankFunds}, - common.HexToAddress("0xc0de"): { - Code: []byte{0x60, 0x01, 0x50}, - Balance: big.NewInt(0), - }, // push 1, pop - }, - GasLimit: 100e6, // 100 M + if typ != "headers" { + // Rollback the heavier chain and re-insert the longer chain again + for i := 0; i < len(blocks3); i++ { + rollback = append(rollback, blocks3[i].Hash()) } - ) - // Generate the original common chain segment and the two competing forks - engine := ethash.NewFaker() - db := rawdb.NewMemoryDatabase() - genesis := gspec.MustCommit(db) - - blockGenerator := func(i int, block *BlockGen) { - block.SetCoinbase(common.Address{1}) - for txi := 0; txi < numTxs; txi++ { - uniq := uint64(i*numTxs + txi) - recipient := recipientFn(uniq) - tx, err := types.SignTx(types.NewTransaction(uniq, recipient, big.NewInt(1), params.TxGas, big.NewInt(1), nil), signer, testBankKey) - if err != nil { - b.Error(err) - } - block.AddTx(tx) - } - } - - shared, _ := GenerateChain(params.TestChainConfig, genesis, engine, db, numBlocks, blockGenerator) - b.StopTimer() - b.ResetTimer() - for i := 0; i < b.N; i++ { - // Import the shared chain and the original canonical one - diskdb := rawdb.NewMemoryDatabase() - gspec.MustCommit(diskdb) - - chain, err := NewBlockChain(diskdb, nil, params.TestChainConfig, engine, vm.Config{}, nil) - if err != nil { - b.Fatalf("failed to create tester chain: %v", err) - } - b.StartTimer() - if _, err := chain.InsertChain(shared); err != nil { - b.Fatalf("failed to insert shared chain: %v", err) - } - b.StopTimer() - if got := chain.CurrentBlock().Transactions().Len(); got != numTxs*numBlocks { - b.Fatalf("Transactions were not included, expected %d, got %d", numTxs*numBlocks, got) + chain.Rollback(rollback) + if err := inserter(append(blocks, blocks2...), append(receipts, receipts2...)); err != nil { + t.Fatalf("failed to insert chain data: %v", err) } + asserter(t, blocks2[len(blocks2)-1]) } } @@ -2012,6 +1953,67 @@ func TestReorgToShorterRemovesCanonMappingHeaderChain(t *testing.T) { } } +// Benchmarks large blocks with value transfers to non-existing accounts +func benchmarkLargeNumberOfValueToNonexisting(b *testing.B, numTxs, numBlocks int, recipientFn func(uint64) common.Address, dataFn func(uint64) []byte) { + var ( + signer = types.HomesteadSigner{} + testBankKey, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") + testBankAddress = crypto.PubkeyToAddress(testBankKey.PublicKey) + bankFunds = big.NewInt(100000000000000000) + gspec = Genesis{ + Config: params.TestChainConfig, + Alloc: GenesisAlloc{ + testBankAddress: {Balance: bankFunds}, + common.HexToAddress("0xc0de"): { + Code: []byte{0x60, 0x01, 0x50}, + Balance: big.NewInt(0), + }, // push 1, pop + }, + GasLimit: 100e6, // 100 M + } + ) + // Generate the original common chain segment and the two competing forks + engine := ethash.NewFaker() + db := rawdb.NewMemoryDatabase() + genesis := gspec.MustCommit(db) + + blockGenerator := func(i int, block *BlockGen) { + block.SetCoinbase(common.Address{1}) + for txi := 0; txi < numTxs; txi++ { + uniq := uint64(i*numTxs + txi) + recipient := recipientFn(uniq) + tx, err := types.SignTx(types.NewTransaction(uniq, recipient, big.NewInt(1), params.TxGas, big.NewInt(1), nil), signer, testBankKey) + if err != nil { + b.Error(err) + } + block.AddTx(tx) + } + } + + shared, _ := GenerateChain(params.TestChainConfig, genesis, engine, db, numBlocks, blockGenerator) + b.StopTimer() + b.ResetTimer() + for i := 0; i < b.N; i++ { + // Import the shared chain and the original canonical one + diskdb := rawdb.NewMemoryDatabase() + gspec.MustCommit(diskdb) + + chain, err := NewBlockChain(diskdb, nil, params.TestChainConfig, engine, vm.Config{}, nil) + if err != nil { + b.Fatalf("failed to create tester chain: %v", err) + } + b.StartTimer() + if _, err := chain.InsertChain(shared); err != nil { + b.Fatalf("failed to insert shared chain: %v", err) + } + b.StopTimer() + if got := chain.CurrentBlock().Transactions().Len(); got != numTxs*numBlocks { + b.Fatalf("Transactions were not included, expected %d, got %d", numTxs*numBlocks, got) + + } + } +} + func BenchmarkBlockChain_1x1000ValueTransferToNonexisting(b *testing.B) { var ( numTxs = 1000 @@ -2062,4 +2064,4 @@ func BenchmarkBlockChain_1x1000Executions(b *testing.B) { } benchmarkLargeNumberOfValueToNonexisting(b, numTxs, numBlocks, recipientFn, dataFn) -} \ No newline at end of file +}