From 83a0144333a19f4673030a3768b30a2f88976c84 Mon Sep 17 00:00:00 2001 From: pk910 Date: Mon, 22 Dec 2025 14:18:16 +0100 Subject: [PATCH 1/2] fix finalization issue when two epochs are finalized at the same time --- indexer/beacon/finalization.go | 2 +- indexer/beacon/indexer_getter.go | 31 +++++++++++++++++++++++++------ 2 files changed, 26 insertions(+), 7 deletions(-) diff --git a/indexer/beacon/finalization.go b/indexer/beacon/finalization.go index 1ca980e2..e487f52e 100644 --- a/indexer/beacon/finalization.go +++ b/indexer/beacon/finalization.go @@ -29,7 +29,7 @@ func (indexer *Indexer) processFinalityEvent(finalityEvent *v1.Finality) error { oldLastFinalizedEpoch := indexer.lastFinalizedEpoch for finalizeEpoch := indexer.lastFinalizedEpoch; finalizeEpoch < finalityEvent.Finalized.Epoch; finalizeEpoch++ { - readyClients := indexer.GetReadyClientsByCheckpoint(finalityEvent.Finalized.Root, true) + readyClients := indexer.GetReadyClientsByCheckpoint(finalityEvent.Finalized.Epoch, finalityEvent.Finalized.Root, true) retryCount := 5 for { diff --git a/indexer/beacon/indexer_getter.go b/indexer/beacon/indexer_getter.go index 20cadaa6..85ed43b9 100644 --- a/indexer/beacon/indexer_getter.go +++ b/indexer/beacon/indexer_getter.go @@ -28,17 +28,36 @@ func (indexer *Indexer) GetAllClients() []*Client { } // GetReadyClientsByCheckpoint returns a slice of clients that are ready for processing based on the finalized root and preference for archive clients. -func (indexer *Indexer) GetReadyClientsByCheckpoint(finalizedRoot phase0.Root, preferArchive bool) []*Client { +func (indexer *Indexer) GetReadyClientsByCheckpoint(finalizedEpoch phase0.Epoch, finalizedRoot phase0.Root, preferArchive bool) []*Client { clients := make([]*Client, 0) + finalizedSlot := indexer.consensusPool.GetChainState().EpochToSlot(finalizedEpoch) + for _, client := range indexer.clients { if client.client.GetStatus() != consensus.ClientStatusOnline { continue } _, root, _, _ := client.client.GetFinalityCheckpoint() - if !bytes.Equal(root[:], finalizedRoot[:]) && !bytes.Equal(root[:], consensus.NullRoot[:]) { - continue + if !bytes.Equal(root[:], finalizedRoot[:]) { + block := indexer.blockCache.getBlockByRoot(root) + if block == nil { + // block is not in the cache, probably a very old block before the finalizatio checkpoint + continue + } + + if block.Slot < finalizedSlot { + // block is before the finalized slot, so client is lagging behind + continue + } + + isInChain, _ := indexer.blockCache.getCanonicalDistance(finalizedRoot, root, 0) + if !isInChain { + // block is not in the canonical chain, so client is on a different fork + continue + } + + fmt.Println("client is ready for epoch", finalizedEpoch, "with block", block.Slot) } clients = append(clients, client) @@ -101,10 +120,10 @@ func (indexer *Indexer) GetReadyClientByBlockRoot(blockRoot phase0.Root, preferA // GetReadyClients returns a slice of clients that are on the finalized chain and preference for archive clients. func (indexer *Indexer) GetReadyClients(preferArchive bool) []*Client { - _, finalizedRoot := indexer.consensusPool.GetChainState().GetFinalizedCheckpoint() - clients := indexer.GetReadyClientsByCheckpoint(finalizedRoot, preferArchive) + finalizedEpoch, finalizedRoot := indexer.consensusPool.GetChainState().GetFinalizedCheckpoint() + clients := indexer.GetReadyClientsByCheckpoint(finalizedEpoch, finalizedRoot, preferArchive) if len(clients) == 0 { - clients = indexer.GetReadyClientsByCheckpoint(consensus.NullRoot, preferArchive) + clients = indexer.GetReadyClientsByCheckpoint(finalizedEpoch, consensus.NullRoot, preferArchive) } return clients } From d286946f482a24fe4a7f60302bdf5f58799c5a23 Mon Sep 17 00:00:00 2001 From: pk910 Date: Mon, 22 Dec 2025 14:19:01 +0100 Subject: [PATCH 2/2] remove debug output --- indexer/beacon/indexer_getter.go | 2 -- 1 file changed, 2 deletions(-) diff --git a/indexer/beacon/indexer_getter.go b/indexer/beacon/indexer_getter.go index 85ed43b9..321dfe9a 100644 --- a/indexer/beacon/indexer_getter.go +++ b/indexer/beacon/indexer_getter.go @@ -56,8 +56,6 @@ func (indexer *Indexer) GetReadyClientsByCheckpoint(finalizedEpoch phase0.Epoch, // block is not in the canonical chain, so client is on a different fork continue } - - fmt.Println("client is ready for epoch", finalizedEpoch, "with block", block.Slot) } clients = append(clients, client)