Skip to content

Commit 8fcd753

Browse files
MariusVanDerWijdenmaoueh
authored andcommitted
core: use less memory during reorgs (ethereum#24616)
This PR significantly reduces the memory consumption of a long reorg
1 parent 6ac52b2 commit 8fcd753

File tree

2 files changed

+43
-13
lines changed

2 files changed

+43
-13
lines changed

core/blockchain.go

Lines changed: 25 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -2347,8 +2347,8 @@ func (bc *BlockChain) reorg(oldBlock, newBlock *types.Block) error {
23472347
oldChain types.Blocks
23482348
commonBlock *types.Block
23492349

2350-
deletedTxs types.Transactions
2351-
addedTxs types.Transactions
2350+
deletedTxs []common.Hash
2351+
addedTxs []common.Hash
23522352

23532353
deletedLogs [][]*types.Log
23542354
rebirthLogs [][]*types.Log
@@ -2358,7 +2358,9 @@ func (bc *BlockChain) reorg(oldBlock, newBlock *types.Block) error {
23582358
// Old chain is longer, gather all transactions and logs as deleted ones
23592359
for ; oldBlock != nil && oldBlock.NumberU64() != newBlock.NumberU64(); oldBlock = bc.GetBlock(oldBlock.ParentHash(), oldBlock.NumberU64()-1) {
23602360
oldChain = append(oldChain, oldBlock)
2361-
deletedTxs = append(deletedTxs, oldBlock.Transactions()...)
2361+
for _, tx := range oldBlock.Transactions() {
2362+
deletedTxs = append(deletedTxs, tx.Hash())
2363+
}
23622364

23632365
// Collect deleted logs for notification
23642366
logs := bc.collectLogs(oldBlock.Hash(), true)
@@ -2388,7 +2390,9 @@ func (bc *BlockChain) reorg(oldBlock, newBlock *types.Block) error {
23882390
}
23892391
// Remove an old block as well as stash away a new block
23902392
oldChain = append(oldChain, oldBlock)
2391-
deletedTxs = append(deletedTxs, oldBlock.Transactions()...)
2393+
for _, tx := range oldBlock.Transactions() {
2394+
deletedTxs = append(deletedTxs, tx.Hash())
2395+
}
23922396

23932397
// Collect deleted logs for notification
23942398
logs := bc.collectLogs(oldBlock.Hash(), true)
@@ -2407,6 +2411,7 @@ func (bc *BlockChain) reorg(oldBlock, newBlock *types.Block) error {
24072411
return fmt.Errorf("invalid new chain")
24082412
}
24092413
}
2414+
24102415
// Ensure the user sees large reorgs
24112416
if len(oldChain) > 0 && len(newChain) > 0 {
24122417
logFn := log.Info
@@ -2423,7 +2428,7 @@ func (bc *BlockChain) reorg(oldBlock, newBlock *types.Block) error {
24232428
} else if len(newChain) > 0 {
24242429
// Special case happens in the post merge stage that current head is
24252430
// the ancestor of new head while these two blocks are not consecutive
2426-
log.Info("Extend chain", "add", len(newChain), "number", newChain[0].NumberU64(), "hash", newChain[0].Hash())
2431+
log.Info("Extend chain", "add", len(newChain), "number", newChain[0].Number(), "hash", newChain[0].Hash())
24272432
blockReorgAddMeter.Mark(int64(len(newChain)))
24282433
} else {
24292434
// len(newChain) == 0 && len(oldChain) > 0
@@ -2436,19 +2441,17 @@ func (bc *BlockChain) reorg(oldBlock, newBlock *types.Block) error {
24362441
// Insert the block in the canonical way, re-writing history
24372442
bc.writeHeadBlock(newChain[i])
24382443

2439-
// Collect reborn logs due to chain reorg
2440-
logs := bc.collectLogs(newChain[i].Hash(), false)
2441-
if len(logs) > 0 {
2442-
rebirthLogs = append(rebirthLogs, logs)
2443-
}
24442444
// Collect the new added transactions.
2445-
addedTxs = append(addedTxs, newChain[i].Transactions()...)
2445+
for _, tx := range newChain[i].Transactions() {
2446+
addedTxs = append(addedTxs, tx.Hash())
2447+
}
24462448
}
2449+
24472450
// Delete useless indexes right now which includes the non-canonical
24482451
// transaction indexes, canonical chain indexes which above the head.
24492452
indexesBatch := bc.db.NewBatch()
2450-
for _, tx := range types.TxDifference(deletedTxs, addedTxs) {
2451-
rawdb.DeleteTxLookupEntry(indexesBatch, tx.Hash())
2453+
for _, tx := range types.HashDifference(deletedTxs, addedTxs) {
2454+
rawdb.DeleteTxLookupEntry(indexesBatch, tx)
24522455
}
24532456
// Delete any canonical number assignments above the new head
24542457
number := bc.CurrentBlock().NumberU64()
@@ -2462,6 +2465,15 @@ func (bc *BlockChain) reorg(oldBlock, newBlock *types.Block) error {
24622465
if err := indexesBatch.Write(); err != nil {
24632466
log.Crit("Failed to delete useless indexes", "err", err)
24642467
}
2468+
2469+
// Collect the logs
2470+
for i := len(newChain) - 1; i >= 1; i-- {
2471+
// Collect reborn logs due to chain reorg
2472+
logs := bc.collectLogs(newChain[i].Hash(), false)
2473+
if len(logs) > 0 {
2474+
rebirthLogs = append(rebirthLogs, logs)
2475+
}
2476+
}
24652477
// If any logs need to be fired, do it now. In theory we could avoid creating
24662478
// this goroutine if there are no events to fire, but realistcally that only
24672479
// ever happens if we're reorging empty blocks, which will only happen on idle

core/types/transaction.go

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -449,6 +449,24 @@ func TxDifference(a, b Transactions) Transactions {
449449
return keep
450450
}
451451

452+
// HashDifference returns a new set which is the difference between a and b.
453+
func HashDifference(a, b []common.Hash) []common.Hash {
454+
keep := make([]common.Hash, 0, len(a))
455+
456+
remove := make(map[common.Hash]struct{})
457+
for _, hash := range b {
458+
remove[hash] = struct{}{}
459+
}
460+
461+
for _, hash := range a {
462+
if _, ok := remove[hash]; !ok {
463+
keep = append(keep, hash)
464+
}
465+
}
466+
467+
return keep
468+
}
469+
452470
// TxByNonce implements the sort interface to allow sorting a list of transactions
453471
// by their nonces. This is usually only useful for sorting transactions from a
454472
// single account, otherwise a nonce comparison doesn't make much sense.

0 commit comments

Comments
 (0)