core: doesn't process head block in reorg function

This commit is contained in:
rjl493456442 2019-05-08 10:38:12 +08:00
parent 03df23355e
commit d348ed2976
2 changed files with 87 additions and 88 deletions

View file

@ -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()...)

View file

@ -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)
}
}