Skip to content

Commit

Permalink
Merge pull request #131 from ethpandaops/pk910/fix-canonical-head-sel…
Browse files Browse the repository at this point in the history
…ection

fix canonical head selection
  • Loading branch information
pk910 authored Sep 18, 2024
2 parents 8732546 + bb1595c commit db7786b
Show file tree
Hide file tree
Showing 2 changed files with 58 additions and 47 deletions.
93 changes: 47 additions & 46 deletions indexer/beacon/canonical.go
Original file line number Diff line number Diff line change
Expand Up @@ -145,8 +145,51 @@ func (indexer *Indexer) computeCanonicalChain() bool {
}()

headForks := indexer.forkCache.getForkHeads()
if len(headForks) <= 1 {
// no forks, just get latest block

// compare forks, select the one with the most votes
headForkVotes := map[ForkKey]phase0.Gwei{}
chainHeads = make([]*ChainHead, 0, len(headForks))
var bestForkVotes phase0.Gwei = 0

for _, fork := range headForks {
if fork.Block == nil {
continue
}

forkVotes, epochParticipation := indexer.aggregateForkVotes(fork.ForkId, aggregateEpochs)
headForkVotes[fork.ForkId] = forkVotes
chainHeads = append(chainHeads, &ChainHead{
HeadBlock: fork.Block,
AggregatedHeadVotes: forkVotes,
PerEpochVotingPercent: epochParticipation,
})

if forkVotes > 0 {
participationStr := make([]string, len(epochParticipation))
for i, p := range epochParticipation {
participationStr[i] = fmt.Sprintf("%.2f%%", p)
}

indexer.logger.Infof(
"fork %v: votes in last 2 epochs: %v ETH (%v), head: %v (%v)",
fork.ForkId,
forkVotes/EtherGweiFactor,
strings.Join(participationStr, ", "),
fork.Block.Slot,
fork.Block.Root.String(),
)
}

if forkVotes > bestForkVotes || headBlock == nil {
bestForkVotes = forkVotes
headBlock = fork.Block
} else if forkVotes == bestForkVotes && headBlock.Slot < fork.Block.Slot {
headBlock = fork.Block
}
}

if headBlock == nil {
// just get latest block
latestBlocks := indexer.blockCache.getLatestBlocks(1, nil)
if len(latestBlocks) > 0 {
headBlock = latestBlocks[0]
Expand All @@ -157,8 +200,8 @@ func (indexer *Indexer) computeCanonicalChain() bool {
participationStr[i] = fmt.Sprintf("%.2f%%", p)
}

indexer.logger.Debugf(
"fork %v votes in last %v epochs: %v ETH (%v), head: %v (%v)",
indexer.logger.Infof(
"fallback fork %v votes in last %v epochs: %v ETH (%v), head: %v (%v)",
headBlock.forkId,
aggregateEpochs,
forkVotes/EtherGweiFactor,
Expand All @@ -173,48 +216,6 @@ func (indexer *Indexer) computeCanonicalChain() bool {
PerEpochVotingPercent: epochParticipation,
}}
}
} else {
// multiple forks, compare forks
headForkVotes := map[ForkKey]phase0.Gwei{}
chainHeads = make([]*ChainHead, 0, len(headForks))
var bestForkVotes phase0.Gwei = 0

for _, fork := range headForks {
if fork.Block == nil {
continue
}

forkVotes, epochParticipation := indexer.aggregateForkVotes(fork.ForkId, aggregateEpochs)
headForkVotes[fork.ForkId] = forkVotes
chainHeads = append(chainHeads, &ChainHead{
HeadBlock: fork.Block,
AggregatedHeadVotes: forkVotes,
PerEpochVotingPercent: epochParticipation,
})

if forkVotes > 0 {
participationStr := make([]string, len(epochParticipation))
for i, p := range epochParticipation {
participationStr[i] = fmt.Sprintf("%.2f%%", p)
}

indexer.logger.Infof(
"fork %v: votes in last 2 epochs: %v ETH (%v), head: %v (%v)",
fork.ForkId,
forkVotes/EtherGweiFactor,
strings.Join(participationStr, ", "),
fork.Block.Slot,
fork.Block.Root.String(),
)
}

if forkVotes > bestForkVotes || headBlock == nil {
bestForkVotes = forkVotes
headBlock = fork.Block
} else if forkVotes == bestForkVotes && headBlock.Slot < fork.Block.Slot {
headBlock = fork.Block
}
}
}

return true
Expand Down
12 changes: 11 additions & 1 deletion indexer/beacon/forkdetection.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package beacon

import (
"bytes"
"fmt"
"strings"

Expand Down Expand Up @@ -33,6 +34,7 @@ func (cache *forkCache) processBlock(block *Block) error {
}

chainState := cache.indexer.consensusPool.GetChainState()
_, finalizedRoot := chainState.GetFinalizedCheckpoint()

// get fork id from parent block
parentForkId := ForkKey(1)
Expand All @@ -46,7 +48,6 @@ func (cache *forkCache) processBlock(block *Block) error {
parentSlot = 0
parentIsProcessed = false
parentIsFinalized = true

} else if parentBlock := cache.indexer.blockCache.getBlockByRoot(*parentRoot); parentBlock == nil {
// parent block might already be finalized, check if it's in the database
blockHead := db.GetBlockHeadByRoot((*parentRoot)[:])
Expand All @@ -63,6 +64,15 @@ func (cache *forkCache) processBlock(block *Block) error {
parentIsFinalized = parentBlock.Slot < chainState.GetFinalizedSlot()
}

if bytes.Equal(block.Root[:], finalizedRoot[:]) && parentForkId == 1 {
// this is the finalization checkpoint, but we don't have a fork id for it. Just use the finalized forkId 0
parentForkId = 0
parentSlot = 0
parentIsProcessed = false
parentIsFinalized = true
cache.finalizedForkId = parentForkId
}

// check if this block (c) introduces a new fork, it does so if:
// 1. the parent (p) is known & processed and has 1 or more child blocks besides this one (c1, c2, ...)
// c c1 c2
Expand Down

0 comments on commit db7786b

Please sign in to comment.