Skip to content

Commit

Permalink
Imported fast finality reorganization from [email protected] (#75)
Browse files Browse the repository at this point in the history
* Imported fast finality reorganization from [email protected]

* Fix errors in test code
  • Loading branch information
ironbeer authored Oct 11, 2024
1 parent ffd283d commit de2e944
Show file tree
Hide file tree
Showing 3 changed files with 57 additions and 13 deletions.
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

0 comments on commit de2e944

Please sign in to comment.