From ac9f9e0a25f7da5f57351b085db590e5a37c237f Mon Sep 17 00:00:00 2001 From: battlmonstr Date: Sun, 14 Jan 2024 14:40:47 +0100 Subject: [PATCH] polygon/sync: fork choice logic (#9228) --- polygon/sync/canonical_chain_builder.go | 27 ++++++++++++++++++++----- 1 file changed, 22 insertions(+), 5 deletions(-) diff --git a/polygon/sync/canonical_chain_builder.go b/polygon/sync/canonical_chain_builder.go index ea864c5cc..2c6d63285 100644 --- a/polygon/sync/canonical_chain_builder.go +++ b/polygon/sync/canonical_chain_builder.go @@ -1,6 +1,7 @@ package sync import ( + "bytes" "errors" "fmt" "time" @@ -142,13 +143,29 @@ func (impl *canonicalChainBuilderImpl) Prune(newRootNum uint64) error { return nil } +// compareForkTreeNodes compares 2 fork tree nodes. +// It returns a positive number if the chain ending at node1 is "better" than the chain ending at node2. +// The better node belongs to the canonical chain, and it has: +// * a greater total difficulty, +// * or a smaller block number, +// * or a lexicographically greater hash. +// See: https://github.com/maticnetwork/bor/blob/master/core/forkchoice.go#L82 +func compareForkTreeNodes(node1 *forkTreeNode, node2 *forkTreeNode) int { + difficultyDiff := int64(node1.totalDifficulty) - int64(node2.totalDifficulty) + if difficultyDiff != 0 { + return int(difficultyDiff) + } + blockNumDiff := node1.header.Number.Cmp(node2.header.Number) + if blockNumDiff != 0 { + return -blockNumDiff + } + return bytes.Compare(node1.headerHash.Bytes(), node2.headerHash.Bytes()) +} + func (impl *canonicalChainBuilderImpl) updateTipIfNeeded(tipCandidate *forkTreeNode) { - if tipCandidate.totalDifficulty > impl.tip.totalDifficulty { + if compareForkTreeNodes(tipCandidate, impl.tip) > 0 { impl.tip = tipCandidate } - // else if tipCandidate.totalDifficulty == impl.tip.totalDifficulty { - // TODO: is it possible? which one is selected? - // } } func (impl *canonicalChainBuilderImpl) Connect(headers []*types.Header) error { @@ -200,7 +217,7 @@ func (impl *canonicalChainBuilderImpl) Connect(headers []*types.Header) error { // attach nodes for the new headers for i, header := range headers { - if (header.Number == nil) && (header.Number.Uint64() != parent.header.Number.Uint64()+1) { + if (header.Number == nil) || (header.Number.Uint64() != parent.header.Number.Uint64()+1) { return errors.New("canonicalChainBuilderImpl.Connect: invalid header.Number") }