From 98964ae1c400971cf48df12ea2496b7e0dba642f Mon Sep 17 00:00:00 2001 From: niuxiaojie81 <85773309@qq.com> Date: Sun, 4 Feb 2024 17:02:37 +0800 Subject: [PATCH] =?UTF-8?q?=E5=A4=84=E7=90=86=E5=8C=BA=E5=9D=97=E5=88=86?= =?UTF-8?q?=E5=8F=89=E6=B5=81=E7=A8=8B=E4=B8=8BVerifyHeader=E7=9A=84?= =?UTF-8?q?=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- consensus/cbft/cbft.go | 37 +++++++++++++++++++++++++++++------- consensus/errors.go | 4 ++++ core/blockchain.go | 11 ++++++++--- eth/fetcher/block_fetcher.go | 10 ++++++++-- 4 files changed, 50 insertions(+), 12 deletions(-) diff --git a/consensus/cbft/cbft.go b/consensus/cbft/cbft.go index 682ddca3be..bd7e70497d 100644 --- a/consensus/cbft/cbft.go +++ b/consensus/cbft/cbft.go @@ -648,10 +648,13 @@ func (cbft *Cbft) VerifyHeader(chain consensus.ChainReader, header *types.Header } parent := chain.GetHeader(header.ParentHash, number-1) + // 当 parentBlock 出现分叉,且 cbft 还未同步该分叉区块(只有旧的分叉块高的区块) + // 那么此时 cbft 无法查询到该分叉区块,在这种正常流程下为了避免出现 unknown ancestor。增加了 forked ancestor + forked := false if parent == nil { var parentBlock *types.Block if async { - parentBlock = cbft.GetBlockWithLock(header.ParentHash, number-1) + parentBlock, forked = cbft.GetBlockWithLock(header.ParentHash, number-1) } else { parentBlock = cbft.GetBlockWithoutLock(header.ParentHash, number-1) } @@ -663,6 +666,10 @@ func (cbft *Cbft) VerifyHeader(chain consensus.ChainReader, header *types.Header // Find it again from the blockChain p := chain.GetHeader(header.ParentHash, number-1) if p == nil { + if forked { + cbft.log.Warn("VerifyHeader, forked ancestor", "blockNumber", number, "blockHash", header.Hash(), "parentHash", header.ParentHash) + return consensus.ErrForkedAncestor + } cbft.log.Warn("VerifyHeader, unknown ancestor", "blockNumber", number, "blockHash", header.Hash(), "parentHash", header.ParentHash) return consensus.ErrUnknownAncestor } @@ -743,11 +750,16 @@ func (cbft *Cbft) VerifyHeaders(chain consensus.ChainReader, headers []*types.He } func (cbft *Cbft) verifyHeaderWorker(chain consensus.ChainReader, headers []*types.Header, index int) error { - var parent *types.Header + var ( + parent *types.Header + parentBlock *types.Block + forked = false + ) + if index == 0 { parent = chain.GetHeader(headers[0].ParentHash, headers[0].Number.Uint64()-1) if parent == nil { - parentBlock := cbft.GetBlockWithLock(headers[0].ParentHash, headers[0].Number.Uint64()-1) + parentBlock, forked = cbft.GetBlockWithLock(headers[0].ParentHash, headers[0].Number.Uint64()-1) if parentBlock != nil { parent = parentBlock.Header() } @@ -761,6 +773,10 @@ func (cbft *Cbft) verifyHeaderWorker(chain consensus.ChainReader, headers []*typ } if parent == nil { + if forked { + cbft.log.Warn("VerifyHeaderWorker, forked ancestor", "blockNumber", headers[index].Number.Uint64(), "blockHash", headers[index].Hash(), "parentHash", headers[index].ParentHash) + return consensus.ErrForkedAncestor + } cbft.log.Warn("VerifyHeaderWorker, unknown ancestor", "blockNumber", headers[index].Number.Uint64(), "blockHash", headers[index].Hash(), "parentHash", headers[index].ParentHash) return consensus.ErrUnknownAncestor } @@ -1336,22 +1352,29 @@ func (cbft *Cbft) GetBlock(hash common.Hash, number uint64) *types.Block { } // GetBlockWithLock synchronously obtains blocks according to the specified number and hash. -func (cbft *Cbft) GetBlockWithLock(hash common.Hash, number uint64) *types.Block { - result := make(chan *types.Block, 1) +func (cbft *Cbft) GetBlockWithLock(hash common.Hash, number uint64) (*types.Block, bool) { + type result struct { + block *types.Block + forked bool + } + resultCh := make(chan result, 1) cbft.asyncCallCh <- func() { block, _ := cbft.blockTree.FindBlockAndQC(hash, number) + var forked bool if block == nil { if eb := cbft.state.FindBlock(hash, number); eb != nil { block = eb } else { cbft.log.Debug("Get block failed", "hash", hash, "number", number) + _, _, forked = cbft.blockTree.IsForked(hash, number) } } - result <- block + resultCh <- result{block: block, forked: forked} } - return <-result + ret := <-resultCh + return ret.block, ret.forked } // GetBlockWithoutLock returns the block corresponding to the specified number and hash. diff --git a/consensus/errors.go b/consensus/errors.go index a005c5f63d..37b56def17 100644 --- a/consensus/errors.go +++ b/consensus/errors.go @@ -23,6 +23,10 @@ var ( // that is unknown. ErrUnknownAncestor = errors.New("unknown ancestor") + // ErrForkedAncestor is returned when validating a block requires an ancestor + // that is forked. + ErrForkedAncestor = errors.New("forked ancestor") + // ErrPrunedAncestor is returned when validating a block requires an ancestor // that is known, but the state of which is not available. ErrPrunedAncestor = errors.New("pruned ancestor") diff --git a/core/blockchain.go b/core/blockchain.go index 2f8f2cf999..2a2e1393d6 100644 --- a/core/blockchain.go +++ b/core/blockchain.go @@ -27,6 +27,8 @@ import ( "sync/atomic" "time" + lru "github.com/hashicorp/golang-lru" + "github.com/PlatONnetwork/PlatON-Go/common" "github.com/PlatONnetwork/PlatON-Go/common/mclock" "github.com/PlatONnetwork/PlatON-Go/common/prque" @@ -43,7 +45,6 @@ import ( "github.com/PlatONnetwork/PlatON-Go/metrics" "github.com/PlatONnetwork/PlatON-Go/params" "github.com/PlatONnetwork/PlatON-Go/trie" - lru "github.com/hashicorp/golang-lru" ) var ( @@ -1563,19 +1564,23 @@ func (bc *BlockChain) insertChain(chain types.Blocks, verifySeals bool) (int, er // Some other error(except ErrKnownBlock) occurred, abort. // ErrKnownBlock is allowed here since some known blocks // still need re-execution to generate snapshots that are missing - case err != nil && !errors.Is(err, ErrKnownBlock): + case err != nil && !errors.Is(err, ErrKnownBlock) && !errors.Is(err, consensus.ErrForkedAncestor): bc.futureBlocks.Remove(block.Hash()) stats.ignored += len(it.chain) bc.reportBlock(block, nil, err) return it.index, err } // No validation errors for the first block (or chain prefix skipped) - for ; block != nil && (err == nil || errors.Is(err, ErrKnownBlock)); block, err = it.next() { + for ; block != nil && (err == nil || errors.Is(err, ErrKnownBlock) || errors.Is(err, consensus.ErrForkedAncestor)); block, err = it.next() { // If the chain is terminating, stop processing blocks if bc.insertStopped() { log.Debug("Abort during block processing") break } + if errors.Is(err, consensus.ErrForkedAncestor) { + return it.index, nil + } + start := time.Now() err = bc.engine.InsertChain(block) if err != nil { diff --git a/eth/fetcher/block_fetcher.go b/eth/fetcher/block_fetcher.go index 2c4b170a9f..219971d63e 100644 --- a/eth/fetcher/block_fetcher.go +++ b/eth/fetcher/block_fetcher.go @@ -717,19 +717,25 @@ func (f *BlockFetcher) insert(peer string, block *types.Block) { case consensus.ErrFutureBlock: // Weird future block, don't fail, but neither propagate + case consensus.ErrForkedAncestor: + log.Warn("Forked parent of propagated block", "peer", peer, "number", block.Number(), "hash", hash, "parent", block.ParentHash()) + return + case consensus.ErrUnknownAncestor: // If the parent's unknown, abort insertion log.Warn("Unknown parent of propagated block", "peer", peer, "number", block.Number(), "hash", hash, "parent", block.ParentHash()) + f.dropPeer(peer) + return default: // Something went very wrong, drop the peer - log.Debug("Propagated block verification failed", "peer", peer, "number", block.Number(), "hash", hash, "err", err) + log.Warn("Propagated block verification failed", "peer", peer, "number", block.Number(), "hash", hash, "err", err) f.dropPeer(peer) return } // Run the actual import and log any issues if _, err := f.insertChain(types.Blocks{block}); err != nil { - log.Debug("Propagated block import failed", "peer", peer, "number", block.Number(), "hash", hash, "err", err) + log.Warn("Propagated block import failed", "peer", peer, "number", block.Number(), "hash", hash, "err", err) return } // If import succeeded, broadcast the block