diff --git a/core/blockchain.go b/core/blockchain.go index d580d708d9..c91c72a44e 100644 --- a/core/blockchain.go +++ b/core/blockchain.go @@ -2186,7 +2186,7 @@ func (bc *BlockChain) collectLogs(b *types.Block, removed bool) []*types.Log { func (bc *BlockChain) reorg(oldHead *types.Header, newHead *types.Block) error { var ( newChain types.Blocks - oldChain types.Blocks + oldChain []*types.Header commonBlock *types.Block deletedTxs []common.Hash @@ -2202,7 +2202,7 @@ func (bc *BlockChain) reorg(oldHead *types.Header, newHead *types.Block) error { if oldBlock.NumberU64() > newBlock.NumberU64() { // Old chain is longer, gather all transactions and logs as deleted ones for ; oldBlock != nil && oldBlock.NumberU64() != newBlock.NumberU64(); oldBlock = bc.GetBlock(oldBlock.ParentHash(), oldBlock.NumberU64()-1) { - oldChain = append(oldChain, oldBlock) + oldChain = append(oldChain, oldBlock.Header()) for _, tx := range oldBlock.Transactions() { deletedTxs = append(deletedTxs, tx.Hash()) } @@ -2228,7 +2228,7 @@ func (bc *BlockChain) reorg(oldHead *types.Header, newHead *types.Block) error { break } // Remove an old block as well as stash away a new block - oldChain = append(oldChain, oldBlock) + oldChain = append(oldChain, oldBlock.Header()) for _, tx := range oldBlock.Transactions() { deletedTxs = append(deletedTxs, tx.Hash()) } @@ -2261,7 +2261,7 @@ func (bc *BlockChain) reorg(oldHead *types.Header, newHead *types.Block) error { } else if len(newChain) > 0 { // Special case happens in the post merge stage that current head is // the ancestor of new head while these two blocks are not consecutive - log.Info("Extend chain", "add", len(newChain), "number", newChain[0].Number(), "hash", newChain[0].Hash()) + log.Info("Extend chain", "add", len(newChain), "number", newChain[0].Number, "hash", newChain[0].Hash()) blockReorgAddMeter.Mark(int64(len(newChain))) } else { // len(newChain) == 0 && len(oldChain) > 0 @@ -2273,6 +2273,10 @@ func (bc *BlockChain) reorg(oldHead *types.Header, newHead *types.Block) error { // reads should be blocked until the mutation is complete. bc.txLookupLock.Lock() + var stats runtime.MemStats + runtime.ReadMemStats(&stats) + panic(stats.HeapInuse) + // Insert the new chain segment in incremental order, from the old // to the new. The new chain head (newChain[0]) is not inserted here, // as it will be handled separately outside of this function @@ -2325,8 +2329,9 @@ func (bc *BlockChain) reorg(oldHead *types.Header, newHead *types.Block) error { // Deleted logs + blocks: var deletedLogs []*types.Log for i := len(oldChain) - 1; i >= 0; i-- { + oldBlock = bc.GetBlock(oldChain[i].Hash(), oldChain[i].Number.Uint64()) // Collect deleted logs for notification - if logs := bc.collectLogs(oldChain[i], true); len(logs) > 0 { + if logs := bc.collectLogs(oldBlock, true); len(logs) > 0 { deletedLogs = append(deletedLogs, logs...) } if len(deletedLogs) > 512 { diff --git a/core/blockchain_test.go b/core/blockchain_test.go index 9f491e1bfd..ae2eedd3dd 100644 --- a/core/blockchain_test.go +++ b/core/blockchain_test.go @@ -4231,3 +4231,35 @@ func TestPragueRequests(t *testing.T) { t.Fatalf("block %d: failed to insert into chain: %v", n, err) } } + +func BenchmarkReorg(b *testing.B) { + chainLength := b.N + + dir := b.TempDir() + db, err := rawdb.NewLevelDBDatabase(dir, 128, 128, "", false) + if err != nil { + b.Fatalf("cannot create temporary database: %v", err) + } + defer db.Close() + gspec := &Genesis{ + Config: params.TestChainConfig, + Alloc: types.GenesisAlloc{benchRootAddr: {Balance: math.BigPow(2, 254)}}, + } + blockchain, _ := NewBlockChain(db, nil, gspec, nil, ethash.NewFaker(), vm.Config{}, nil) + defer blockchain.Stop() + + // Insert an easy and a difficult chain afterwards + easyBlocks, _ := GenerateChain(params.TestChainConfig, blockchain.GetBlockByHash(blockchain.CurrentBlock().Hash()), ethash.NewFaker(), db, chainLength, genValueTx(500)) + diffBlocks, _ := GenerateChain(params.TestChainConfig, blockchain.GetBlockByHash(blockchain.CurrentBlock().Hash()), ethash.NewFaker(), db, chainLength, genValueTx(500)) + + if _, err := blockchain.InsertChain(easyBlocks); err != nil { + b.Fatalf("failed to insert easy chain: %v", err) + } + b.ResetTimer() + if _, err := blockchain.InsertChain(diffBlocks); err != nil { + b.Fatalf("failed to insert difficult chain: %v", err) + } +} + +// BenchmarkReorg-8 10000 362204 ns/op 271290 B/op 1256 allocs/op 151412736 bytes of heap used +// BenchmarkReorg-8 10000 381835 ns/op 276959 B/op 1324 allocs/op 152895488 bytes of heap used