@@ -23,6 +23,7 @@ import (
2323 "io"
2424 "math/big"
2525 "runtime"
26+ "slices"
2627 "strings"
2728 "sync"
2829 "sync/atomic"
@@ -1435,7 +1436,7 @@ func (bc *BlockChain) writeBlockWithoutState(block *types.Block, td *big.Int) (e
14351436func (bc * BlockChain ) writeKnownBlock (block * types.Block ) error {
14361437 current := bc .CurrentBlock ()
14371438 if block .ParentHash () != current .Hash () {
1438- if err := bc .reorg (current , block ); err != nil {
1439+ if err := bc .reorg (current , block . Header () ); err != nil {
14391440 return err
14401441 }
14411442 }
@@ -1541,7 +1542,7 @@ func (bc *BlockChain) writeBlockAndSetHead(block *types.Block, receipts []*types
15411542
15421543 // Reorganise the chain if the parent is not the head block
15431544 if block .ParentHash () != currentBlock .Hash () {
1544- if err := bc .reorg (currentBlock , block ); err != nil {
1545+ if err := bc .reorg (currentBlock , block . Header () ); err != nil {
15451546 return NonStatTy , err
15461547 }
15471548 }
@@ -2154,8 +2155,8 @@ func (bc *BlockChain) recoverAncestors(block *types.Block, makeWitness bool) (co
21542155 return block .Hash (), nil
21552156}
21562157
2157- // collectLogs collects the logs that were generated or removed during
2158- // the processing of a block. These logs are later announced as deleted or reborn.
2158+ // collectLogs collects the logs that were generated or removed during the
2159+ // processing of a block. These logs are later announced as deleted or reborn.
21592160func (bc * BlockChain ) collectLogs (b * types.Block , removed bool ) []* types.Log {
21602161 var blobGasPrice * big.Int
21612162 excessBlobGas := b .ExcessBlobGas ()
@@ -2181,70 +2182,55 @@ func (bc *BlockChain) collectLogs(b *types.Block, removed bool) []*types.Log {
21812182// reorg takes two blocks, an old chain and a new chain and will reconstruct the
21822183// blocks and inserts them to be part of the new canonical chain and accumulates
21832184// potential missing transactions and post an event about them.
2185+ //
21842186// Note the new head block won't be processed here, callers need to handle it
21852187// externally.
2186- func (bc * BlockChain ) reorg (oldHead * types.Header , newHead * types.Block ) error {
2188+ func (bc * BlockChain ) reorg (oldHead * types.Header , newHead * types.Header ) error {
21872189 var (
2188- newChain types.Blocks
2189- oldChain types.Blocks
2190- commonBlock * types.Block
2191-
2192- deletedTxs []common.Hash
2193- addedTxs []common.Hash
2190+ newChain []* types.Header
2191+ oldChain []* types.Header
2192+ commonBlock * types.Header
21942193 )
2195- oldBlock := bc .GetBlock (oldHead .Hash (), oldHead .Number .Uint64 ())
2196- if oldBlock == nil {
2197- return errors .New ("current head block missing" )
2198- }
2199- newBlock := newHead
2200-
22012194 // Reduce the longer chain to the same number as the shorter one
2202- if oldBlock . NumberU64 () > newBlock . NumberU64 () {
2195+ if oldHead . Number . Uint64 () > newHead . Number . Uint64 () {
22032196 // Old chain is longer, gather all transactions and logs as deleted ones
2204- for ; oldBlock != nil && oldBlock .NumberU64 () != newBlock .NumberU64 (); oldBlock = bc .GetBlock (oldBlock .ParentHash (), oldBlock .NumberU64 ()- 1 ) {
2205- oldChain = append (oldChain , oldBlock )
2206- for _ , tx := range oldBlock .Transactions () {
2207- deletedTxs = append (deletedTxs , tx .Hash ())
2208- }
2197+ for ; oldHead != nil && oldHead .Number .Uint64 () != newHead .Number .Uint64 (); oldHead = bc .GetHeader (oldHead .ParentHash , oldHead .Number .Uint64 ()- 1 ) {
2198+ oldChain = append (oldChain , oldHead )
22092199 }
22102200 } else {
22112201 // New chain is longer, stash all blocks away for subsequent insertion
2212- for ; newBlock != nil && newBlock . NumberU64 () != oldBlock . NumberU64 (); newBlock = bc .GetBlock ( newBlock .ParentHash (), newBlock . NumberU64 ()- 1 ) {
2213- newChain = append (newChain , newBlock )
2202+ for ; newHead != nil && newHead . Number . Uint64 () != oldHead . Number . Uint64 (); newHead = bc .GetHeader ( newHead .ParentHash , newHead . Number . Uint64 ()- 1 ) {
2203+ newChain = append (newChain , newHead )
22142204 }
22152205 }
2216- if oldBlock == nil {
2206+ if oldHead == nil {
22172207 return errInvalidOldChain
22182208 }
2219- if newBlock == nil {
2209+ if newHead == nil {
22202210 return errInvalidNewChain
22212211 }
22222212 // Both sides of the reorg are at the same number, reduce both until the common
22232213 // ancestor is found
22242214 for {
22252215 // If the common ancestor was found, bail out
2226- if oldBlock .Hash () == newBlock .Hash () {
2227- commonBlock = oldBlock
2216+ if oldHead .Hash () == newHead .Hash () {
2217+ commonBlock = oldHead
22282218 break
22292219 }
22302220 // Remove an old block as well as stash away a new block
2231- oldChain = append (oldChain , oldBlock )
2232- for _ , tx := range oldBlock .Transactions () {
2233- deletedTxs = append (deletedTxs , tx .Hash ())
2234- }
2235- newChain = append (newChain , newBlock )
2221+ oldChain = append (oldChain , oldHead )
2222+ newChain = append (newChain , newHead )
22362223
22372224 // Step back with both chains
2238- oldBlock = bc .GetBlock ( oldBlock .ParentHash (), oldBlock . NumberU64 ()- 1 )
2239- if oldBlock == nil {
2225+ oldHead = bc .GetHeader ( oldHead .ParentHash , oldHead . Number . Uint64 ()- 1 )
2226+ if oldHead == nil {
22402227 return errInvalidOldChain
22412228 }
2242- newBlock = bc .GetBlock ( newBlock .ParentHash (), newBlock . NumberU64 ()- 1 )
2243- if newBlock == nil {
2229+ newHead = bc .GetHeader ( newHead .ParentHash , newHead . Number . Uint64 ()- 1 )
2230+ if newHead == nil {
22442231 return errInvalidNewChain
22452232 }
22462233 }
2247-
22482234 // Ensure the user sees large reorgs
22492235 if len (oldChain ) > 0 && len (newChain ) > 0 {
22502236 logFn := log .Info
@@ -2253,63 +2239,120 @@ func (bc *BlockChain) reorg(oldHead *types.Header, newHead *types.Block) error {
22532239 msg = "Large chain reorg detected"
22542240 logFn = log .Warn
22552241 }
2256- logFn (msg , "number" , commonBlock .Number () , "hash" , commonBlock .Hash (),
2242+ logFn (msg , "number" , commonBlock .Number , "hash" , commonBlock .Hash (),
22572243 "drop" , len (oldChain ), "dropfrom" , oldChain [0 ].Hash (), "add" , len (newChain ), "addfrom" , newChain [0 ].Hash ())
22582244 blockReorgAddMeter .Mark (int64 (len (newChain )))
22592245 blockReorgDropMeter .Mark (int64 (len (oldChain )))
22602246 blockReorgMeter .Mark (1 )
22612247 } else if len (newChain ) > 0 {
22622248 // Special case happens in the post merge stage that current head is
22632249 // the ancestor of new head while these two blocks are not consecutive
2264- log .Info ("Extend chain" , "add" , len (newChain ), "number" , newChain [0 ].Number () , "hash" , newChain [0 ].Hash ())
2250+ log .Info ("Extend chain" , "add" , len (newChain ), "number" , newChain [0 ].Number , "hash" , newChain [0 ].Hash ())
22652251 blockReorgAddMeter .Mark (int64 (len (newChain )))
22662252 } else {
22672253 // len(newChain) == 0 && len(oldChain) > 0
22682254 // rewind the canonical chain to a lower point.
2269- log .Error ("Impossible reorg, please file an issue" , "oldnum" , oldBlock .Number () , "oldhash" , oldBlock .Hash (), "oldblocks" , len (oldChain ), "newnum" , newBlock .Number () , "newhash" , newBlock .Hash (), "newblocks" , len (newChain ))
2255+ log .Error ("Impossible reorg, please file an issue" , "oldnum" , oldHead .Number , "oldhash" , oldHead .Hash (), "oldblocks" , len (oldChain ), "newnum" , newHead .Number , "newhash" , newHead .Hash (), "newblocks" , len (newChain ))
22702256 }
22712257 // Acquire the tx-lookup lock before mutation. This step is essential
22722258 // as the txlookups should be changed atomically, and all subsequent
22732259 // reads should be blocked until the mutation is complete.
22742260 bc .txLookupLock .Lock ()
22752261
2276- // Insert the new chain segment in incremental order, from the old
2277- // to the new. The new chain head (newChain[0]) is not inserted here,
2278- // as it will be handled separately outside of this function
2279- for i := len (newChain ) - 1 ; i >= 1 ; i -- {
2280- // Insert the block in the canonical way, re-writing history
2281- bc .writeHeadBlock (newChain [i ])
2262+ // Reorg can be executed, start reducing the chain's old blocks and appending
2263+ // the new blocks
2264+ var (
2265+ deletedTxs []common.Hash
2266+ rebirthTxs []common.Hash
22822267
2283- // Collect the new added transactions.
2284- for _ , tx := range newChain [i ].Transactions () {
2285- addedTxs = append (addedTxs , tx .Hash ())
2268+ deletedLogs []* types.Log
2269+ rebirthLogs []* types.Log
2270+ )
2271+ // Deleted log emission on the API uses forward order, which is borked, but
2272+ // we'll leave it in for legacy reasons.
2273+ //
2274+ // TODO(karalabe): This should be nuked out, no idea how, deprecate some APIs?
2275+ {
2276+ for i := len (oldChain ) - 1 ; i >= 0 ; i -- {
2277+ block := bc .GetBlock (oldChain [i ].Hash (), oldChain [i ].Number .Uint64 ())
2278+ if block == nil {
2279+ return errInvalidOldChain // Corrupt database, mostly here to avoid weird panics
2280+ }
2281+ if logs := bc .collectLogs (block , true ); len (logs ) > 0 {
2282+ deletedLogs = append (deletedLogs , logs ... )
2283+ }
2284+ if len (deletedLogs ) > 512 {
2285+ bc .rmLogsFeed .Send (RemovedLogsEvent {deletedLogs })
2286+ deletedLogs = nil
2287+ }
2288+ }
2289+ if len (deletedLogs ) > 0 {
2290+ bc .rmLogsFeed .Send (RemovedLogsEvent {deletedLogs })
22862291 }
22872292 }
2293+ // Undo old blocks in reverse order
2294+ for i := 0 ; i < len (oldChain ); i ++ {
2295+ // Collect all the deleted transactions
2296+ block := bc .GetBlock (oldChain [i ].Hash (), oldChain [i ].Number .Uint64 ())
2297+ if block == nil {
2298+ return errInvalidOldChain // Corrupt database, mostly here to avoid weird panics
2299+ }
2300+ for _ , tx := range block .Transactions () {
2301+ deletedTxs = append (deletedTxs , tx .Hash ())
2302+ }
2303+ // Collect deleted logs and emit them for new integrations
2304+ if logs := bc .collectLogs (block , true ); len (logs ) > 0 {
2305+ // Emit revertals latest first, older then
2306+ slices .Reverse (logs )
22882307
2308+ // TODO(karalabe): Hook into the reverse emission part
2309+ }
2310+ }
2311+ // Apply new blocks in forward order
2312+ for i := len (newChain ) - 1 ; i >= 1 ; i -- {
2313+ // Collect all the included transactions
2314+ block := bc .GetBlock (newChain [i ].Hash (), newChain [i ].Number .Uint64 ())
2315+ if block == nil {
2316+ return errInvalidNewChain // Corrupt database, mostly here to avoid weird panics
2317+ }
2318+ for _ , tx := range block .Transactions () {
2319+ rebirthTxs = append (rebirthTxs , tx .Hash ())
2320+ }
2321+ // Collect inserted logs and emit them
2322+ if logs := bc .collectLogs (block , false ); len (logs ) > 0 {
2323+ rebirthLogs = append (rebirthLogs , logs ... )
2324+ }
2325+ if len (rebirthLogs ) > 512 {
2326+ bc .logsFeed .Send (rebirthLogs )
2327+ rebirthLogs = nil
2328+ }
2329+ // Update the head block
2330+ bc .writeHeadBlock (block )
2331+ }
2332+ if len (rebirthLogs ) > 0 {
2333+ bc .logsFeed .Send (rebirthLogs )
2334+ }
22892335 // Delete useless indexes right now which includes the non-canonical
22902336 // transaction indexes, canonical chain indexes which above the head.
2291- var (
2292- indexesBatch = bc .db .NewBatch ()
2293- diffs = types .HashDifference (deletedTxs , addedTxs )
2294- )
2295- for _ , tx := range diffs {
2296- rawdb .DeleteTxLookupEntry (indexesBatch , tx )
2337+ batch := bc .db .NewBatch ()
2338+ for _ , tx := range types .HashDifference (deletedTxs , rebirthTxs ) {
2339+ rawdb .DeleteTxLookupEntry (batch , tx )
22972340 }
22982341 // Delete all hash markers that are not part of the new canonical chain.
22992342 // Because the reorg function does not handle new chain head, all hash
23002343 // markers greater than or equal to new chain head should be deleted.
2301- number := commonBlock .NumberU64 ()
2344+ number := commonBlock .Number
23022345 if len (newChain ) > 1 {
2303- number = newChain [1 ].NumberU64 ()
2346+ number = newChain [1 ].Number
23042347 }
2305- for i := number + 1 ; ; i ++ {
2348+ for i := number . Uint64 () + 1 ; ; i ++ {
23062349 hash := rawdb .ReadCanonicalHash (bc .db , i )
23072350 if hash == (common.Hash {}) {
23082351 break
23092352 }
2310- rawdb .DeleteCanonicalHash (indexesBatch , i )
2353+ rawdb .DeleteCanonicalHash (batch , i )
23112354 }
2312- if err := indexesBatch .Write (); err != nil {
2355+ if err := batch .Write (); err != nil {
23132356 log .Crit ("Failed to delete useless indexes" , "err" , err )
23142357 }
23152358 // Reset the tx lookup cache to clear stale txlookup cache.
@@ -2318,40 +2361,6 @@ func (bc *BlockChain) reorg(oldHead *types.Header, newHead *types.Block) error {
23182361 // Release the tx-lookup lock after mutation.
23192362 bc .txLookupLock .Unlock ()
23202363
2321- // Send out events for logs from the old canon chain, and 'reborn'
2322- // logs from the new canon chain. The number of logs can be very
2323- // high, so the events are sent in batches of size around 512.
2324-
2325- // Deleted logs + blocks:
2326- var deletedLogs []* types.Log
2327- for i := len (oldChain ) - 1 ; i >= 0 ; i -- {
2328- // Collect deleted logs for notification
2329- if logs := bc .collectLogs (oldChain [i ], true ); len (logs ) > 0 {
2330- deletedLogs = append (deletedLogs , logs ... )
2331- }
2332- if len (deletedLogs ) > 512 {
2333- bc .rmLogsFeed .Send (RemovedLogsEvent {deletedLogs })
2334- deletedLogs = nil
2335- }
2336- }
2337- if len (deletedLogs ) > 0 {
2338- bc .rmLogsFeed .Send (RemovedLogsEvent {deletedLogs })
2339- }
2340-
2341- // New logs:
2342- var rebirthLogs []* types.Log
2343- for i := len (newChain ) - 1 ; i >= 1 ; i -- {
2344- if logs := bc .collectLogs (newChain [i ], false ); len (logs ) > 0 {
2345- rebirthLogs = append (rebirthLogs , logs ... )
2346- }
2347- if len (rebirthLogs ) > 512 {
2348- bc .logsFeed .Send (rebirthLogs )
2349- rebirthLogs = nil
2350- }
2351- }
2352- if len (rebirthLogs ) > 0 {
2353- bc .logsFeed .Send (rebirthLogs )
2354- }
23552364 return nil
23562365}
23572366
@@ -2389,7 +2398,7 @@ func (bc *BlockChain) SetCanonical(head *types.Block) (common.Hash, error) {
23892398 // Run the reorg if necessary and set the given block as new head.
23902399 start := time .Now ()
23912400 if head .ParentHash () != bc .CurrentBlock ().Hash () {
2392- if err := bc .reorg (bc .CurrentBlock (), head ); err != nil {
2401+ if err := bc .reorg (bc .CurrentBlock (), head . Header () ); err != nil {
23932402 return common.Hash {}, err
23942403 }
23952404 }
0 commit comments