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

polygon/sync: handle bad blocks on chain tip #12320

Merged
merged 36 commits into from
Oct 17, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
a24cee2
wip
taratorio Oct 10, 2024
0f279a4
Merge branch 'main' of github.com:ledgerwatch/erigon into astrid-bloc…
taratorio Oct 10, 2024
23062e6
polygon/sync,p2p: publish block announcements to devp2p
taratorio Oct 10, 2024
39c42b8
add todo
taratorio Oct 10, 2024
510546f
move publishNewBlock after InsertBlocks for TD availability
taratorio Oct 10, 2024
49feec0
tidy
taratorio Oct 10, 2024
644aab5
Merge branch 'main' of github.com:ledgerwatch/erigon into astrid-bloc…
taratorio Oct 11, 2024
d53dcce
Merge branch 'main' of github.com:ledgerwatch/erigon into astrid-bloc…
taratorio Oct 14, 2024
8bc1543
add peer_tracker_tests
taratorio Oct 14, 2024
c75cb27
add message_sender_test
taratorio Oct 14, 2024
055514c
add publisher tests
taratorio Oct 14, 2024
cc72e2e
Merge branch 'main' of github.com:ledgerwatch/erigon into astrid-bloc…
taratorio Oct 14, 2024
606ce01
allow NewBlockMsg and NewBlockHashesMsg in sentry SendMessageById
taratorio Oct 14, 2024
11ce255
fix linter
taratorio Oct 15, 2024
3cfc9ad
Merge branch 'main' of github.com:ledgerwatch/erigon into astrid-bloc…
taratorio Oct 15, 2024
a92f1f4
polygon/sync: bad blocks on chain tip
taratorio Oct 15, 2024
fee8637
add comment
taratorio Oct 15, 2024
365ea2d
wip
taratorio Oct 15, 2024
64747a1
wip
taratorio Oct 15, 2024
794d9e8
Merge branch 'main' of github.com:ledgerwatch/erigon into astrid-bad-…
taratorio Oct 16, 2024
7fe3b9d
Merge branch 'main' of github.com:ledgerwatch/erigon into astrid-bad-…
taratorio Oct 16, 2024
ef403b9
Merge branch 'main' of github.com:ledgerwatch/erigon into astrid-bad-…
taratorio Oct 16, 2024
2b81794
wip: double check things
taratorio Oct 16, 2024
11f4ae5
add waiting for chain tip events info log
taratorio Oct 16, 2024
382ebdd
handleWaypointExecutionErr
taratorio Oct 16, 2024
0fc3d9a
Merge branch 'main' of github.com:ledgerwatch/erigon into astrid-bad-…
taratorio Oct 16, 2024
ddba4c0
implement and test LCA
taratorio Oct 16, 2024
36b816d
header by hash ccb tests
taratorio Oct 16, 2024
69b7969
prune node tests
taratorio Oct 16, 2024
7c7d261
Merge branch 'main' of github.com:ledgerwatch/erigon into astrid-bad-…
taratorio Oct 16, 2024
c0c59b8
stylistic
taratorio Oct 16, 2024
e3f5a3d
fix compilation
taratorio Oct 16, 2024
0811185
simplify bridge reorg and handling
taratorio Oct 17, 2024
9b56206
Merge branch 'main' of github.com:ledgerwatch/erigon into astrid-bad-…
taratorio Oct 17, 2024
d7bd861
add log for waypoin exec err
taratorio Oct 17, 2024
c01db8b
add log for penalizing peer for bad block
taratorio Oct 17, 2024
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
6 changes: 5 additions & 1 deletion eth/stagedsync/stage_polygon_sync.go
Original file line number Diff line number Diff line change
Expand Up @@ -1514,7 +1514,11 @@ func (e *polygonSyncStageExecutionEngine) UpdateForkChoice(ctx context.Context,
case <-ctx.Done():
return common.Hash{}, ctx.Err()
case result := <-resultCh:
return result.latestValidHash, result.validationErr
err := result.validationErr
if err != nil {
err = fmt.Errorf("%w: %w", polygonsync.ErrForkChoiceUpdateBadBlock, err)
}
return result.latestValidHash, err
}
}

Expand Down
110 changes: 107 additions & 3 deletions polygon/sync/canonical_chain_builder.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,10 @@ type CanonicalChainBuilder interface {
Tip() *types.Header
Root() *types.Header
HeadersInRange(start uint64, count uint64) []*types.Header
Prune(newRootNum uint64) error
PruneRoot(newRootNum uint64) error
PruneNode(hash libcommon.Hash) error
Connect(ctx context.Context, headers []*types.Header) (newConnectedHeaders []*types.Header, err error)
LowestCommonAncestor(a, b libcommon.Hash) (*types.Header, bool)
}

type producerSlotIndex uint64
Expand Down Expand Up @@ -156,9 +158,9 @@ func (ccb *canonicalChainBuilder) HeadersInRange(start uint64, count uint64) []*
return headers[offset : offset+count]
}

func (ccb *canonicalChainBuilder) Prune(newRootNum uint64) error {
func (ccb *canonicalChainBuilder) PruneRoot(newRootNum uint64) error {
if (newRootNum < ccb.root.header.Number.Uint64()) || (newRootNum > ccb.Tip().Number.Uint64()) {
return errors.New("canonicalChainBuilder.Prune: newRootNum outside of the canonical chain")
return errors.New("canonicalChainBuilder.PruneRoot: newRootNum outside of the canonical chain")
}

newRoot := ccb.tip
Expand All @@ -170,6 +172,35 @@ func (ccb *canonicalChainBuilder) Prune(newRootNum uint64) error {
return nil
}

func (ccb *canonicalChainBuilder) PruneNode(hash libcommon.Hash) error {
if ccb.root.headerHash == hash {
return errors.New("canonicalChainBuilder.PruneNode: can't prune root node")
}

var exists bool
ccb.enumerate(func(node *forkTreeNode) bool {
if node.headerHash != hash {
return true
}

for idx, parentChild := range node.parent.children {
if parentChild.headerHash == hash {
exists = true
delete(node.parent.children, idx)
break
}
}

return false
})
if !exists {
return errors.New("canonicalChainBuilder.PruneNode: could not find node to prune")
}

ccb.tip = ccb.recalcTip() // tip may have changed after prunning, re-calc
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:
Expand All @@ -195,6 +226,23 @@ func (ccb *canonicalChainBuilder) updateTipIfNeeded(tipCandidate *forkTreeNode)
}
}

func (ccb *canonicalChainBuilder) recalcTip() *forkTreeNode {
var tip *forkTreeNode
ccb.enumerate(func(node *forkTreeNode) bool {
if tip == nil {
tip = node
return true
}

if compareForkTreeNodes(tip, node) < 0 {
tip = node
}

return true
})
return tip
}

// Connect connects a list of headers to the canonical chain builder tree.
// Returns the list of newly connected headers (filtering out headers that already exist in the tree)
// or an error in case the header is invalid or the header chain cannot reach any of the nodes in the tree.
Expand Down Expand Up @@ -291,3 +339,59 @@ func (ccb *canonicalChainBuilder) Connect(ctx context.Context, headers []*types.

return headers, nil
}

func (ccb *canonicalChainBuilder) LowestCommonAncestor(a, b libcommon.Hash) (*types.Header, bool) {
pathA := ccb.pathToRoot(a)
if len(pathA) == 0 {
// 'a' doesn't exist in the tree
return nil, false
}

pathB := ccb.pathToRoot(b)
if len(pathB) == 0 {
// 'b' doesn't exist in the tree
return nil, false
}

heightA := pathA[0].header.Number.Uint64()
heightB := pathB[0].header.Number.Uint64()
for heightA != heightB {
if heightA < heightB {
pathB = pathB[1:]
heightB = pathB[0].header.Number.Uint64()
} else if heightA > heightB {
pathA = pathA[1:]
heightA = pathA[0].header.Number.Uint64()
}
}

for i := 0; i < len(pathA); i++ {
if pathA[i].headerHash == pathB[i].headerHash {
return pathA[i].header, true
}
}

return nil, false
}

func (ccb *canonicalChainBuilder) pathToRoot(from libcommon.Hash) []*forkTreeNode {
path := make([]*forkTreeNode, 0, ccb.Tip().Number.Uint64()-ccb.Root().Number.Uint64())
pathToRootRec(ccb.root, from, &path)
return path
}

func pathToRootRec(node *forkTreeNode, from libcommon.Hash, path *[]*forkTreeNode) bool {
if node.headerHash == from {
*path = append(*path, node)
return true
}

for _, child := range node.children {
if pathToRootRec(child, from, path) {
*path = append(*path, node)
return true
}
}

return false
}
116 changes: 97 additions & 19 deletions polygon/sync/canonical_chain_builder_mock.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading
Loading