Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Imported fast finality reorganization from [email protected] #75

Merged
merged 2 commits into from
Oct 11, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 20 additions & 8 deletions core/blockchain.go
Original file line number Diff line number Diff line change
Expand Up @@ -1151,7 +1151,7 @@ func (bc *BlockChain) InsertReceiptChain(blockChain types.Blocks, receiptChain [

// Rewind may have occurred, skip in that case.
if bc.CurrentHeader().Number.Cmp(head.Number()) >= 0 {
reorg, err := bc.forker.ReorgNeeded(bc.CurrentSnapBlock(), head.Header())
reorg, err := bc.forker.ReorgNeededWithFastFinality(bc.CurrentSnapBlock(), head.Header())
if err != nil {
log.Warn("Reorg failed", "err", err)
return false
Expand Down Expand Up @@ -1510,7 +1510,7 @@ func (bc *BlockChain) writeBlockAndSetHead(block *types.Block, receipts []*types
return NonStatTy, err
}
currentBlock := bc.CurrentBlock()
reorg, err := bc.forker.ReorgNeeded(currentBlock, block.Header())
reorg, err := bc.forker.ReorgNeededWithFastFinality(currentBlock, block.Header())
if err != nil {
return NonStatTy, err
}
Expand Down Expand Up @@ -1669,7 +1669,7 @@ func (bc *BlockChain) insertChain(chain types.Blocks, setHead bool) (int, error)
current = bc.CurrentBlock()
)
for block != nil && bc.skipBlock(err, it) {
reorg, err = bc.forker.ReorgNeeded(current, block.Header())
reorg, err = bc.forker.ReorgNeededWithFastFinality(current, block.Header())
if err != nil {
return it.index, err
}
Expand Down Expand Up @@ -2034,7 +2034,7 @@ func (bc *BlockChain) insertSideChain(block *types.Block, it *insertIterator) (i
//
// If the externTd was larger than our local TD, we now need to reimport the previous
// blocks to regenerate the required state
reorg, err := bc.forker.ReorgNeeded(current, lastBlock.Header())
reorg, err := bc.forker.ReorgNeededWithFastFinality(current, lastBlock.Header())
if err != nil {
return it.index, err
}
Expand Down Expand Up @@ -2265,6 +2265,12 @@ func (bc *BlockChain) reorg(oldHead *types.Header, newHead *types.Block) error {
// rewind the canonical chain to a lower point.
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))
}
// Reset the tx lookup cache in case to clear stale txlookups.
// This is done before writing any new chain data to avoid the
// weird scenario that canonical chain is changed while the
// stale lookups are still cached.
bc.txLookupCache.Purge()

// Insert the new chain(except the head block(reverse order)),
// taking care of the proper incremental order.
for i := len(newChain) - 1; i >= 1; i-- {
Expand All @@ -2279,11 +2285,14 @@ func (bc *BlockChain) reorg(oldHead *types.Header, newHead *types.Block) error {

// Delete useless indexes right now which includes the non-canonical
// transaction indexes, canonical chain indexes which above the head.
indexesBatch := bc.db.NewBatch()
for _, tx := range types.HashDifference(deletedTxs, addedTxs) {
var (
indexesBatch = bc.db.NewBatch()
diffs = types.HashDifference(deletedTxs, addedTxs)
blockBatch = bc.db.NewBatch()
)
for _, tx := range diffs {
rawdb.DeleteTxLookupEntry(indexesBatch, tx)
}

// Delete all hash markers that are not part of the new canonical chain.
// Because the reorg function does not handle new chain head, all hash
// markers greater than or equal to new chain head should be deleted.
Expand All @@ -2296,11 +2305,14 @@ func (bc *BlockChain) reorg(oldHead *types.Header, newHead *types.Block) error {
if hash == (common.Hash{}) {
break
}
rawdb.DeleteCanonicalHash(indexesBatch, i)
rawdb.DeleteCanonicalHash(blockBatch, i)
}
if err := indexesBatch.Write(); err != nil {
log.Crit("Failed to delete useless indexes", "err", err)
}
if err := blockBatch.Write(); err != nil {
log.Crit("Failed to delete useless indexes use block batch", "err", err)
}

// Send out events for logs from the old canon chain, and 'reborn'
// logs from the new canon chain. The number of logs can be very
Expand Down
32 changes: 32 additions & 0 deletions core/forkchoice.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import (

"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/math"
"github.com/ethereum/go-ethereum/consensus"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/params"
Expand All @@ -36,6 +37,12 @@ type ChainReader interface {
// Config retrieves the header chain's chain configuration.
Config() *params.ChainConfig

// Engine retrieves the blockchain's consensus engine.
Engine() consensus.Engine

// GetJustifiedNumber returns the highest justified blockNumber on the branch including and before `header`
GetJustifiedNumber(header *types.Header) uint64

// GetTd returns the total difficulty of a local block.
GetTd(common.Hash, uint64) *big.Int
}
Expand Down Expand Up @@ -111,3 +118,28 @@ func (f *ForkChoice) ReorgNeeded(current *types.Header, extern *types.Header) (b
}
return reorg, nil
}

// ReorgNeededWithFastFinality compares justified block numbers firstly, backoff to compare tds when equal
func (f *ForkChoice) ReorgNeededWithFastFinality(current *types.Header, header *types.Header) (bool, error) {
_, ok := f.chain.Engine().(consensus.PoS)
if !ok {
return f.ReorgNeeded(current, header)
}

justifiedNumber, curJustifiedNumber := uint64(0), uint64(0)
if f.chain.Config().IsFastFinalityEnabled(header.Number) {
justifiedNumber = f.chain.GetJustifiedNumber(header)
}
if f.chain.Config().IsFastFinalityEnabled(current.Number) {
curJustifiedNumber = f.chain.GetJustifiedNumber(current)
}
if justifiedNumber == curJustifiedNumber {
return f.ReorgNeeded(current, header)
}

if justifiedNumber > curJustifiedNumber && header.Number.Cmp(current.Number) <= 0 {
log.Info("Chain find higher justifiedNumber", "fromHeight", current.Number, "fromHash", current.Hash(), "fromMiner", current.Coinbase, "fromJustified", curJustifiedNumber,
"toHeight", header.Number, "toHash", header.Hash(), "toMiner", header.Coinbase, "toJustified", justifiedNumber)
}
return justifiedNumber > curJustifiedNumber, nil
}
10 changes: 5 additions & 5 deletions core/headerchain.go
Original file line number Diff line number Diff line change
Expand Up @@ -104,14 +104,14 @@ func NewHeaderChain(chainDb ethdb.Database, config *params.ChainConfig, engine c
}
hc.currentHeaderHash = hc.CurrentHeader().Hash()
headHeaderGauge.Update(hc.CurrentHeader().Number.Int64())
headJustifiedBlockGauge.Update(int64(hc.getJustifiedNumber(hc.CurrentHeader())))
headJustifiedBlockGauge.Update(int64(hc.GetJustifiedNumber(hc.CurrentHeader())))
headFinalizedBlockGauge.Update(int64(hc.getFinalizedNumber(hc.CurrentHeader())))

return hc, nil
}

// getJustifiedNumber returns the highest justified blockNumber on the branch including and before `header`.
func (hc *HeaderChain) getJustifiedNumber(header *types.Header) uint64 {
func (hc *HeaderChain) GetJustifiedNumber(header *types.Header) uint64 {
if p, ok := hc.engine.(consensus.PoS); ok {
justifiedBlockNumber, _, err := p.GetJustifiedNumberAndHash(hc, []*types.Header{header})
if err == nil {
Expand Down Expand Up @@ -306,7 +306,7 @@ func (hc *HeaderChain) writeHeadersAndSetHead(headers []*types.Header, forker *F
}
)
// Ask the fork choicer if the reorg is necessary
if reorg, err := forker.ReorgNeeded(hc.CurrentHeader(), lastHeader); err != nil {
if reorg, err := forker.ReorgNeededWithFastFinality(hc.CurrentHeader(), lastHeader); err != nil {
return nil, err
} else if !reorg {
if inserted != 0 {
Expand Down Expand Up @@ -561,7 +561,7 @@ func (hc *HeaderChain) SetCurrentHeader(head *types.Header) {
hc.currentHeader.Store(head)
hc.currentHeaderHash = head.Hash()
headHeaderGauge.Update(head.Number.Int64())
headJustifiedBlockGauge.Update(int64(hc.getJustifiedNumber(head)))
headJustifiedBlockGauge.Update(int64(hc.GetJustifiedNumber(head)))
headFinalizedBlockGauge.Update(int64(hc.getFinalizedNumber(head)))
}

Expand Down Expand Up @@ -649,7 +649,7 @@ func (hc *HeaderChain) setHead(headBlock uint64, headTime uint64, updateFn Updat
hc.currentHeader.Store(parent)
hc.currentHeaderHash = parentHash
headHeaderGauge.Update(parent.Number.Int64())
headJustifiedBlockGauge.Update(int64(hc.getJustifiedNumber(parent)))
headJustifiedBlockGauge.Update(int64(hc.GetJustifiedNumber(parent)))
headFinalizedBlockGauge.Update(int64(hc.getFinalizedNumber(parent)))

// If this is the first iteration, wipe any leftover data upwards too so
Expand Down