diff --git a/indexer/beacon/canonical.go b/indexer/beacon/canonical.go index 065e5d27..f959bb1d 100644 --- a/indexer/beacon/canonical.go +++ b/indexer/beacon/canonical.go @@ -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] @@ -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, @@ -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 diff --git a/indexer/beacon/forkdetection.go b/indexer/beacon/forkdetection.go index 428c9c8c..4db82f3d 100644 --- a/indexer/beacon/forkdetection.go +++ b/indexer/beacon/forkdetection.go @@ -1,6 +1,7 @@ package beacon import ( + "bytes" "fmt" "strings" @@ -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) @@ -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)[:]) @@ -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