@@ -1436,11 +1436,10 @@ func (bc *BlockChain) insertChain(chain types.Blocks, verifySeals bool) (int, er
1436
1436
1437
1437
// Peek the error for the first block to decide the directing import logic
1438
1438
it := newInsertIterator (chain , results , bc .validator )
1439
-
1440
1439
block , err := it .next ()
1441
1440
1442
- // Left-trim all the known blocks
1443
- if err == ErrKnownBlock {
1441
+ // Left-trim all the known blocks that don't need to build snapshot
1442
+ if bc . skipBlock ( err , it ) {
1444
1443
// First block (and state) is known
1445
1444
// 1. We did a roll-back, and should now do a re-import
1446
1445
// 2. The block is stored as a sidechain, and is lying about it's stateroot, and passes a stateroot
@@ -1451,7 +1450,7 @@ func (bc *BlockChain) insertChain(chain types.Blocks, verifySeals bool) (int, er
1451
1450
localTd = bc .GetTd (current .Hash (), current .NumberU64 ())
1452
1451
externTd = bc .GetTd (block .ParentHash (), block .NumberU64 ()- 1 ) // The first block can't be nil
1453
1452
)
1454
- for block != nil && err == ErrKnownBlock {
1453
+ for block != nil && bc . skipBlock ( err , it ) {
1455
1454
externTd = new (big.Int ).Add (externTd , block .Difficulty ())
1456
1455
if localTd .Cmp (externTd ) < 0 {
1457
1456
break
@@ -1469,7 +1468,7 @@ func (bc *BlockChain) insertChain(chain types.Blocks, verifySeals bool) (int, er
1469
1468
// When node runs a fast sync again, it can re-import a batch of known blocks via
1470
1469
// `insertChain` while a part of them have higher total difficulty than current
1471
1470
// head full block(new pivot point).
1472
- for block != nil && err == ErrKnownBlock {
1471
+ for block != nil && bc . skipBlock ( err , it ) {
1473
1472
log .Debug ("Writing previously known block" , "number" , block .Number (), "hash" , block .Hash ())
1474
1473
if err := bc .writeKnownBlock (block ); err != nil {
1475
1474
return it .index , err
@@ -1501,8 +1500,10 @@ func (bc *BlockChain) insertChain(chain types.Blocks, verifySeals bool) (int, er
1501
1500
// If there are any still remaining, mark as ignored
1502
1501
return it .index , err
1503
1502
1504
- // Some other error occurred, abort
1505
- case err != nil :
1503
+ // Some other error(except ErrKnownBlock) occurred, abort.
1504
+ // ErrKnownBlock is allowed here since some known blocks
1505
+ // still need re-execution to generate snapshots that are missing
1506
+ case err != nil && ! errors .Is (err , ErrKnownBlock ):
1506
1507
bc .futureBlocks .Remove (block .Hash ())
1507
1508
stats .ignored += len (it .chain )
1508
1509
bc .reportBlock (block , nil , err )
@@ -1520,7 +1521,7 @@ func (bc *BlockChain) insertChain(chain types.Blocks, verifySeals bool) (int, er
1520
1521
}
1521
1522
}()
1522
1523
1523
- for ; block != nil && err == nil || err == ErrKnownBlock ; block , err = it .next () {
1524
+ for ; block != nil && err == nil || errors . Is ( err , ErrKnownBlock ) ; block , err = it .next () {
1524
1525
// If the chain is terminating, stop processing blocks
1525
1526
if bc .insertStopped () {
1526
1527
log .Debug ("Abort during block processing" )
@@ -1535,8 +1536,9 @@ func (bc *BlockChain) insertChain(chain types.Blocks, verifySeals bool) (int, er
1535
1536
// Clique blocks where they can share state among each other, so importing an
1536
1537
// older block might complete the state of the subsequent one. In this case,
1537
1538
// just skip the block (we already validated it once fully (and crashed), since
1538
- // its header and body was already in the database).
1539
- if err == ErrKnownBlock {
1539
+ // its header and body was already in the database). But if the corresponding
1540
+ // snapshot layer is missing, forcibly rerun the execution to build it.
1541
+ if bc .skipBlock (err , it ) {
1540
1542
logger := log .Debug
1541
1543
if bc .chainConfig .Clique == nil {
1542
1544
logger = log .Warn
@@ -2013,6 +2015,47 @@ func (bc *BlockChain) futureBlocksLoop() {
2013
2015
}
2014
2016
}
2015
2017
2018
+ // skipBlock returns 'true', if the block being imported can be skipped over, meaning
2019
+ // that the block does not need to be processed but can be considered already fully 'done'.
2020
+ func (bc * BlockChain ) skipBlock (err error , it * insertIterator ) bool {
2021
+ // We can only ever bypass processing if the only error returned by the validator
2022
+ // is ErrKnownBlock, which means all checks passed, but we already have the block
2023
+ // and state.
2024
+ if ! errors .Is (err , ErrKnownBlock ) {
2025
+ return false
2026
+ }
2027
+ // If we're not using snapshots, we can skip this, since we have both block
2028
+ // and (trie-) state
2029
+ if bc .snaps == nil {
2030
+ return true
2031
+ }
2032
+ var (
2033
+ header = it .current () // header can't be nil
2034
+ parentRoot common.Hash
2035
+ )
2036
+ // If we also have the snapshot-state, we can skip the processing.
2037
+ if bc .snaps .Snapshot (header .Root ) != nil {
2038
+ return true
2039
+ }
2040
+ // In this case, we have the trie-state but not snapshot-state. If the parent
2041
+ // snapshot-state exists, we need to process this in order to not get a gap
2042
+ // in the snapshot layers.
2043
+ // Resolve parent block
2044
+ if parent := it .previous (); parent != nil {
2045
+ parentRoot = parent .Root
2046
+ } else if parent = bc .GetHeaderByHash (header .ParentHash ); parent != nil {
2047
+ parentRoot = parent .Root
2048
+ }
2049
+ if parentRoot == (common.Hash {}) {
2050
+ return false // Theoretically impossible case
2051
+ }
2052
+ // Parent is also missing snapshot: we can skip this. Otherwise process.
2053
+ if bc .snaps .Snapshot (parentRoot ) == nil {
2054
+ return true
2055
+ }
2056
+ return false
2057
+ }
2058
+
2016
2059
// maintainTxIndex is responsible for the construction and deletion of the
2017
2060
// transaction index.
2018
2061
//
0 commit comments