-
Notifications
You must be signed in to change notification settings - Fork 917
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Part 4 of proto array fork choice - check nodes viable (#4625)
* Docs * Interface definitions * Fmt and gazelle * Rename interface to interfaces * Define all the type for protoarray * Gaz * Add error types * Add compute delta helper * Compute delta tests * Gaz * Add checking if nodes viable * Test for viable head * Test for non leaf node can lead to viable head * Extra space * Remove fmt print * Update beacon-chain/forkchoice/protoarray/nodes.go Co-Authored-By: Nishant Das <nishdas93@gmail.com> Co-authored-by: prylabs-bulldozer[bot] <58059840+prylabs-bulldozer[bot]@users.noreply.github.com> Co-authored-by: Nishant Das <nish1993@hotmail.com>
- Loading branch information
1 parent
663557e
commit 3388ab7
Showing
4 changed files
with
116 additions
and
3 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
package protoarray | ||
|
||
import ( | ||
"context" | ||
|
||
"go.opencensus.io/trace" | ||
) | ||
|
||
// leadsToViableHead returns true if the node or the best descendent of the node is viable for head. | ||
// Any node with diff finalized or justified epoch than the ones in fork choice store | ||
// should not be viable to head. | ||
func (s *Store) leadsToViableHead(ctx context.Context, node *Node) (bool, error) { | ||
ctx, span := trace.StartSpan(ctx, "protoArrayForkChoice.leadsToViableHead") | ||
defer span.End() | ||
|
||
var bestDescendentViable bool | ||
bestDescendentIndex := node.bestDescendant | ||
|
||
// If the best descendant is not part of the leaves. | ||
if bestDescendentIndex != nonExistentNode { | ||
// Protection against out of bound, best descendent index can not be | ||
// exceeds length of nodes list. | ||
if bestDescendentIndex >= uint64(len(s.nodes)) { | ||
return false, errInvalidBestDescendantIndex | ||
} | ||
|
||
bestDescendentNode := s.nodes[bestDescendentIndex] | ||
bestDescendentViable = s.viableForHead(ctx, bestDescendentNode) | ||
} | ||
|
||
// The node is viable as long as the best descendent is viable. | ||
return bestDescendentViable || s.viableForHead(ctx, node), nil | ||
} | ||
|
||
// viableForHead returns true if the node is viable to head. | ||
// Any node with diff finalized or justified epoch than the ones in fork choice store | ||
// should not be viable to head. | ||
func (s *Store) viableForHead(ctx context.Context, node *Node) bool { | ||
ctx, span := trace.StartSpan(ctx, "protoArrayForkChoice.viableForHead") | ||
defer span.End() | ||
|
||
// `node` is viable if its justified epoch and finalized epoch are the same as the one in `Store`. | ||
// It's also viable if we are in genesis epoch. | ||
justified := s.justifiedEpoch == node.justifiedEpoch || s.justifiedEpoch == 0 | ||
finalized := s.finalizedEpoch == node.finalizedEpoch || s.finalizedEpoch == 0 | ||
|
||
return justified && finalized | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,61 @@ | ||
package protoarray | ||
|
||
import ( | ||
"context" | ||
"testing" | ||
) | ||
|
||
func TestStore_leadsToViableHead(t *testing.T) { | ||
tests := []struct { | ||
n *Node | ||
justifiedEpoch uint64 | ||
finalizedEpoch uint64 | ||
want bool | ||
}{ | ||
{&Node{}, 0, 0, true}, | ||
{&Node{}, 1, 0, false}, | ||
{&Node{}, 0, 1, false}, | ||
{&Node{finalizedEpoch: 1, justifiedEpoch: 1}, 1, 1, true}, | ||
{&Node{finalizedEpoch: 1, justifiedEpoch: 1}, 2, 2, false}, | ||
{&Node{finalizedEpoch: 3, justifiedEpoch: 4}, 4, 3, true}, | ||
} | ||
for _, tc := range tests { | ||
s := &Store{ | ||
justifiedEpoch: tc.justifiedEpoch, | ||
finalizedEpoch: tc.finalizedEpoch, | ||
nodes: []*Node{tc.n}, | ||
} | ||
got, err := s.leadsToViableHead(context.Background(), tc.n) | ||
if err != nil { | ||
t.Fatal(err) | ||
} | ||
if got != tc.want { | ||
t.Errorf("viableForHead() = %v, want %v", got, tc.want) | ||
} | ||
} | ||
} | ||
|
||
func TestStore_viableForHead(t *testing.T) { | ||
tests := []struct { | ||
n *Node | ||
justifiedEpoch uint64 | ||
finalizedEpoch uint64 | ||
want bool | ||
}{ | ||
{&Node{}, 0, 0, true}, | ||
{&Node{}, 1, 0, false}, | ||
{&Node{}, 0, 1, false}, | ||
{&Node{finalizedEpoch: 1, justifiedEpoch: 1}, 1, 1, true}, | ||
{&Node{finalizedEpoch: 1, justifiedEpoch: 1}, 2, 2, false}, | ||
{&Node{finalizedEpoch: 3, justifiedEpoch: 4}, 4, 3, true}, | ||
} | ||
for _, tc := range tests { | ||
s := &Store{ | ||
justifiedEpoch: tc.justifiedEpoch, | ||
finalizedEpoch: tc.finalizedEpoch, | ||
} | ||
if got := s.viableForHead(context.Background(), tc.n); got != tc.want { | ||
t.Errorf("viableForHead() = %v, want %v", got, tc.want) | ||
} | ||
} | ||
} |