Skip to content

Commit

Permalink
blockchain: fix inconsistent reorg behavior
Browse files Browse the repository at this point in the history
If the chain is reorganized because the newly submit block has
higher justified block number, it can be reverted back to the
old chain prior to reorg because the old blocks cause `ErrKnownBlock`
during insertion via the `insertChain` method, which invokes
`writeKnownBlock` to set the old chain as the canonical chain again.
  • Loading branch information
NganSM committed Jan 9, 2024
1 parent 95e3707 commit 65df573
Showing 1 changed file with 15 additions and 3 deletions.
18 changes: 15 additions & 3 deletions core/blockchain.go
Original file line number Diff line number Diff line change
Expand Up @@ -1665,7 +1665,7 @@ func (bc *BlockChain) insertChain(chain types.Blocks, verifySeals bool) (int, er
)
for block != nil && bc.skipBlock(err, it) {
externTd = new(big.Int).Add(externTd, block.Difficulty())
if localTd.Cmp(externTd) < 0 {
if bc.reorgNeeded(current, localTd, block, externTd) {
break
}
log.Debug("Ignoring already known block", "number", block.Number(), "hash", block.Hash())
Expand Down Expand Up @@ -1734,7 +1734,19 @@ func (bc *BlockChain) insertChain(chain types.Blocks, verifySeals bool) (int, er
}
}()

for ; block != nil && err == nil || errors.Is(err, ErrKnownBlock); block, err = it.next() {
var (
current = bc.CurrentBlock()
localTd = bc.GetTd(current.Hash(), current.NumberU64())
externTd = common.Big0
)

if block != nil {
externTd = bc.GetTd(block.ParentHash(), block.NumberU64()-1)
}

for ; (block != nil && err == nil) || errors.Is(err, ErrKnownBlock); block, err = it.next() {
// err == ErrknownBlock means block != nil
externTd = new(big.Int).Add(externTd, block.Difficulty())
// If the chain is terminating, stop processing blocks
if bc.insertStopped() {
log.Debug("Abort during block processing")
Expand All @@ -1751,7 +1763,7 @@ func (bc *BlockChain) insertChain(chain types.Blocks, verifySeals bool) (int, er
// just skip the block (we already validated it once fully (and crashed), since
// its header and body was already in the database). But if the corresponding
// snapshot layer is missing, forcibly rerun the execution to build it.
if bc.skipBlock(err, it) {
if bc.skipBlock(err, it) && bc.reorgNeeded(current, localTd, block, externTd) {
logger := log.Debug
if bc.chainConfig.Clique == nil {
logger = log.Warn
Expand Down

0 comments on commit 65df573

Please sign in to comment.