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 diffs of blockchain.go and headerchain.go from [email protected] #74

Merged
merged 3 commits into from
Oct 17, 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
58 changes: 27 additions & 31 deletions core/blockchain.go
Original file line number Diff line number Diff line change
Expand Up @@ -58,8 +58,8 @@ var (
headHeaderGauge = metrics.NewRegisteredGauge("chain/head/header", nil)
headFastBlockGauge = metrics.NewRegisteredGauge("chain/head/receipt", nil)
headFinalizedBlockGauge = metrics.NewRegisteredGauge("chain/head/finalized", nil)
headSafeBlockGauge = metrics.NewRegisteredGauge("chain/head/safe", nil)
justifiedBlockGauge = metrics.NewRegisteredGauge("chain/head/justified", nil)

justifiedBlockGauge = metrics.NewRegisteredGauge("chain/head/justified", nil)

chainInfoGauge = metrics.NewRegisteredGaugeInfo("chain/info", nil)

Expand Down Expand Up @@ -239,7 +239,6 @@ type BlockChain struct {
currentBlock atomic.Pointer[types.Header] // Current head of the chain
currentSnapBlock atomic.Pointer[types.Header] // Current head of snap-sync
currentFinalBlock atomic.Pointer[types.Header] // Latest (consensus) finalized block
currentSafeBlock atomic.Pointer[types.Header] // Latest (consensus) safe block

bodyCache *lru.Cache[common.Hash, *types.Body]
bodyRLPCache *lru.Cache[common.Hash, rlp.RawValue]
Expand Down Expand Up @@ -326,7 +325,6 @@ func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, genesis *Genesis
bc.currentBlock.Store(nil)
bc.currentSnapBlock.Store(nil)
bc.currentFinalBlock.Store(nil)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

currentFinalBlock周りの挙動はgo-ethereumに寄せたいです。

bc.currentSafeBlock.Store(nil)

// Update chain info data metrics
chainInfoGauge.Update(metrics.GaugeInfoValue{"chain_id": bc.chainConfig.ChainID.String()})
Expand Down Expand Up @@ -563,29 +561,27 @@ func (bc *BlockChain) loadLastState() error {
if block := bc.GetBlockByHash(head); block != nil {
bc.currentFinalBlock.Store(block.Header())
headFinalizedBlockGauge.Update(int64(block.NumberU64()))
bc.currentSafeBlock.Store(block.Header())
headSafeBlockGauge.Update(int64(block.NumberU64()))
}
}
// Issue a status log for the user
var (
currentSnapBlock = bc.CurrentSnapBlock()
currentFinalBlock = bc.currentFinalBlock.Load() // load directly to prevent panic by acccesing ethapi before it set during startup
currentFinalBlock = bc.CurrentFinalBlock()

headerTd = bc.GetTd(headHeader.Hash(), headHeader.Number.Uint64())
blockTd = bc.GetTd(headBlock.Hash(), headBlock.NumberU64())
)
if headHeader.Hash() != headBlock.Hash() {
log.Info("Loaded most recent local header", "number", headHeader.Number, "hash", headHeader.Hash(), "td", headerTd, "age", common.PrettyAge(time.Unix(int64(headHeader.Time), 0)))
log.Info("Loaded most recent local header", "number", headHeader.Number, "hash", headHeader.Hash(), "root", headHeader.Root, "td", headerTd, "age", common.PrettyAge(time.Unix(int64(headHeader.Time), 0)))
}
log.Info("Loaded most recent local block", "number", headBlock.Number(), "hash", headBlock.Hash(), "td", blockTd, "age", common.PrettyAge(time.Unix(int64(headBlock.Time()), 0)))
log.Info("Loaded most recent local block", "number", headBlock.Number(), "hash", headBlock.Hash(), "root", headBlock.Root(), "td", blockTd, "age", common.PrettyAge(time.Unix(int64(headBlock.Time()), 0)))
if headBlock.Hash() != currentSnapBlock.Hash() {
snapTd := bc.GetTd(currentSnapBlock.Hash(), currentSnapBlock.Number.Uint64())
log.Info("Loaded most recent local snap block", "number", currentSnapBlock.Number, "hash", currentSnapBlock.Hash(), "td", snapTd, "age", common.PrettyAge(time.Unix(int64(currentSnapBlock.Time), 0)))
log.Info("Loaded most recent local snap block", "number", currentSnapBlock.Number, "hash", currentSnapBlock.Hash(), "root", currentSnapBlock.Root, "td", snapTd, "age", common.PrettyAge(time.Unix(int64(currentSnapBlock.Time), 0)))
}
if currentFinalBlock != nil {
finalTd := bc.GetTd(currentFinalBlock.Hash(), currentFinalBlock.Number.Uint64())
log.Info("Loaded most recent local finalized block", "number", currentFinalBlock.Number, "hash", currentFinalBlock.Hash(), "td", finalTd, "age", common.PrettyAge(time.Unix(int64(currentFinalBlock.Time), 0)))
log.Info("Loaded most recent local finalized block", "number", currentFinalBlock.Number, "hash", currentFinalBlock.Hash(), "root", currentFinalBlock.Root, "td", finalTd, "age", common.PrettyAge(time.Unix(int64(currentFinalBlock.Time), 0)))
}
if pivot := rawdb.ReadLastPivotNumber(bc.db); pivot != nil {
log.Info("Loaded last snap-sync pivot marker", "number", *pivot)
Expand Down Expand Up @@ -648,16 +644,6 @@ func (bc *BlockChain) SetFinalized(header *types.Header) {
}
}

// SetSafe sets the safe block.
func (bc *BlockChain) SetSafe(header *types.Header) {
bc.currentSafeBlock.Store(header)
if header != nil {
headSafeBlockGauge.Update(int64(header.Number.Uint64()))
} else {
headSafeBlockGauge.Update(0)
}
}

// setHeadBeyondRoot rewinds the local chain to a new head with the extra condition
// that the rewind must pass the specified state root. This method is meant to be
// used when rewinding with snapshots enabled to ensure that we go back further than
Expand Down Expand Up @@ -829,7 +815,7 @@ func (bc *BlockChain) setHeadBeyondRoot(head uint64, time uint64, root common.Ha
// Clear safe block, finalized block if needed
if safe := bc.CurrentSafeBlock(); safe != nil && head < safe.Number.Uint64() {
log.Warn("SetHead invalidated safe block")
bc.SetSafe(nil)
justifiedBlockGauge.Update(0)
}
if finalized := bc.CurrentFinalBlock(); finalized != nil && head < finalized.Number.Uint64() {
log.Error("SetHead invalidated finalized block")
Expand Down Expand Up @@ -862,7 +848,6 @@ func (bc *BlockChain) SnapSyncCommitHead(hash common.Hash) error {
}
bc.currentBlock.Store(block.Header())
headBlockGauge.Update(int64(block.NumberU64()))
justifiedBlockGauge.Update(int64(bc.GetJustifiedNumber(block.Header())))
bc.chainmu.Unlock()

// Destroy any existing state snapshot and regenerate it in the background,
Expand Down Expand Up @@ -905,6 +890,7 @@ func (bc *BlockChain) ResetWithGenesisBlock(genesis *types.Block) error {
bc.currentBlock.Store(bc.genesisBlock.Header())
headBlockGauge.Update(int64(bc.genesisBlock.NumberU64()))
justifiedBlockGauge.Update(int64(bc.genesisBlock.NumberU64()))
headFinalizedBlockGauge.Update(int64(bc.genesisBlock.NumberU64()))
bc.hc.SetGenesis(bc.genesisBlock.Header())
bc.hc.SetCurrentHeader(bc.genesisBlock.Header())
bc.currentSnapBlock.Store(bc.genesisBlock.Header())
Expand Down Expand Up @@ -976,7 +962,6 @@ func (bc *BlockChain) writeHeadBlock(block *types.Block) {

bc.currentBlock.Store(block.Header())
headBlockGauge.Update(int64(block.NumberU64()))
justifiedBlockGauge.Update(int64(bc.GetJustifiedNumber(block.Header())))
}

// stopWithoutSaving stops the blockchain service. If any imports are currently in progress
Expand Down Expand Up @@ -1161,7 +1146,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 @@ -1520,7 +1505,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 @@ -1551,6 +1536,9 @@ func (bc *BlockChain) writeBlockAndSetHead(block *types.Block, receipts []*types
if finalizedHeader = pos.GetFinalizedHeader(bc, block.Header()); finalizedHeader != nil {
bc.SetFinalized(finalizedHeader)
}
if justifiedBlockNumber, _, err := pos.GetJustifiedNumberAndHash(bc, []*types.Header{block.Header()}); err == nil {
justifiedBlockGauge.Update(int64(justifiedBlockNumber))
}
}
// In theory, we should fire a ChainHeadEvent when we inject
// a canonical block, but sometimes we can insert a batch of
Expand Down Expand Up @@ -1679,7 +1667,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 @@ -2044,7 +2032,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 @@ -2275,6 +2263,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 @@ -2289,11 +2283,13 @@ 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)
)
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 Down
9 changes: 1 addition & 8 deletions core/blockchain_reader.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,13 +53,6 @@ func (bc *BlockChain) CurrentSnapBlock() *types.Header {
// CurrentFinalBlock retrieves the current finalized block of the canonical
// chain. The block is retrieved from the blockchain's internal cache.
func (bc *BlockChain) CurrentFinalBlock() *types.Header {
if p, ok := bc.engine.(consensus.PoS); ok {
currentHeader := bc.CurrentHeader()
if currentHeader == nil {
return nil
}
return p.GetFinalizedHeader(bc, currentHeader)
}
return bc.currentFinalBlock.Load()
}

Expand All @@ -76,7 +69,7 @@ func (bc *BlockChain) CurrentSafeBlock() *types.Header {
return bc.GetHeaderByHash(justifiedBlockHash)
}
}
return bc.currentSafeBlock.Load()
return nil
}

// HasHeader checks if a block header is present in the database or not, caching
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
}
18 changes: 3 additions & 15 deletions core/headerchain.go
Original file line number Diff line number Diff line change
Expand Up @@ -104,11 +104,12 @@ func NewHeaderChain(chainDb ethdb.Database, config *params.ChainConfig, engine c
}
hc.currentHeaderHash = hc.CurrentHeader().Hash()
headHeaderGauge.Update(hc.CurrentHeader().Number.Int64())

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 All @@ -120,17 +121,6 @@ func (hc *HeaderChain) getJustifiedNumber(header *types.Header) uint64 {
return 0
}

// getFinalizedNumber returns the highest finalized number before the specific block.
func (hc *HeaderChain) getFinalizedNumber(header *types.Header) uint64 {
if p, ok := hc.engine.(consensus.PoS); ok {
if finalizedHeader := p.GetFinalizedHeader(hc, header); finalizedHeader != nil {
return finalizedHeader.Number.Uint64()
}
}

return 0
}

// GetBlockNumber retrieves the block number belonging to the given hash
// from the cache or database
func (hc *HeaderChain) GetBlockNumber(hash common.Hash) *uint64 {
Expand Down Expand Up @@ -303,7 +293,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 @@ -644,8 +634,6 @@ func (hc *HeaderChain) setHead(headBlock uint64, headTime uint64, updateFn Updat
hc.currentHeader.Store(parent)
hc.currentHeaderHash = parentHash
headHeaderGauge.Update(parent.Number.Int64())
justifiedBlockGauge.Update(int64(hc.getJustifiedNumber(parent)))
headFinalizedBlockGauge.Update(int64(hc.getFinalizedNumber(parent)))

// If this is the first iteration, wipe any leftover data upwards too so
// we don't end up with dangling daps in the database
Expand Down
2 changes: 1 addition & 1 deletion eth/catalyst/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -358,7 +358,7 @@ func (api *ConsensusAPI) forkchoiceUpdated(update engine.ForkchoiceStateV1, payl
return engine.STATUS_INVALID, engine.InvalidForkChoiceState.With(errors.New("safe block not in canonical chain"))
}
// Set the safe block
api.eth.BlockChain().SetSafe(safeBlock.Header())
// api.eth.BlockChain().SetSafe(safeBlock.Header())
}
// If payload generation was requested, create a new block to be potentially
// sealed by the beacon client. The payload will be requested later, and we
Expand Down