mirror of
https://github.com/OffchainLabs/prysm.git
synced 2026-05-02 03:02:54 -04:00
Part 9 of proto array fork choice - get head (#4643)
This commit is contained in:
@@ -4,12 +4,49 @@ import (
|
||||
"bytes"
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"math"
|
||||
|
||||
"github.com/prysmaticlabs/prysm/shared/params"
|
||||
"go.opencensus.io/trace"
|
||||
)
|
||||
|
||||
// head starts from justified root and then follows the best descendant links
|
||||
// to find the best block for head.
|
||||
func (s *Store) head(ctx context.Context, justifiedRoot [32]byte) ([32]byte, error) {
|
||||
ctx, span := trace.StartSpan(ctx, "protoArrayForkChoice.head")
|
||||
defer span.End()
|
||||
|
||||
// Justified index has to be valid in node indices map, and can not be out of bound.
|
||||
justifiedIndex, ok := s.nodeIndices[justifiedRoot]
|
||||
if !ok {
|
||||
return [32]byte{}, errUnknownJustifiedRoot
|
||||
}
|
||||
if justifiedIndex >= uint64(len(s.nodes)) {
|
||||
return [32]byte{}, errInvalidJustifiedIndex
|
||||
}
|
||||
|
||||
justifiedNode := s.nodes[justifiedIndex]
|
||||
bestDescendantIndex := justifiedNode.bestDescendant
|
||||
// If the justified node doesn't have a best descendent,
|
||||
// the best node is itself.
|
||||
if bestDescendantIndex == nonExistentNode {
|
||||
bestDescendantIndex = justifiedIndex
|
||||
}
|
||||
if bestDescendantIndex >= uint64(len(s.nodes)) {
|
||||
return [32]byte{}, errInvalidBestDescendantIndex
|
||||
}
|
||||
|
||||
bestNode := s.nodes[bestDescendantIndex]
|
||||
//
|
||||
if !s.viableForHead(ctx, bestNode) {
|
||||
return [32]byte{}, fmt.Errorf("after tree filter, best node can't be head, finalized epochs %d != %d, justified epoch %d != %d",
|
||||
bestNode.finalizedEpoch, s.finalizedEpoch, bestNode.justifiedEpoch, s.justifiedEpoch)
|
||||
}
|
||||
|
||||
return bestNode.root, nil
|
||||
}
|
||||
|
||||
// insert registers a new block node to the fork choice store's node list.
|
||||
// It then updates the new node's parent with best child and descendant node.
|
||||
func (s *Store) insert(ctx context.Context,
|
||||
|
||||
@@ -5,6 +5,62 @@ import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestStore_Head_UnknownJustifiedRoot(t *testing.T) {
|
||||
s := &Store{nodeIndices: make(map[[32]byte]uint64)}
|
||||
|
||||
if _, err := s.head(context.Background(), [32]byte{}); err.Error() != errUnknownJustifiedRoot.Error() {
|
||||
t.Fatal("Did not get wanted error")
|
||||
}
|
||||
}
|
||||
|
||||
func TestStore_Head_UnknownJustifiedIndex(t *testing.T) {
|
||||
r := [32]byte{'A'}
|
||||
indices := make(map[[32]byte]uint64)
|
||||
indices[r] = 1
|
||||
s := &Store{nodeIndices: indices}
|
||||
|
||||
if _, err := s.head(context.Background(), r); err.Error() != errInvalidJustifiedIndex.Error() {
|
||||
t.Fatal("Did not get wanted error")
|
||||
}
|
||||
}
|
||||
|
||||
func TestStore_Head_Itself(t *testing.T) {
|
||||
r := [32]byte{'A'}
|
||||
indices := make(map[[32]byte]uint64)
|
||||
indices[r] = 0
|
||||
|
||||
// Since the justified node does not have a best descendant so the best node
|
||||
// is itself.
|
||||
s := &Store{nodeIndices: indices, nodes: []*Node{{root: r, bestDescendant: nonExistentNode}}}
|
||||
h, err := s.head(context.Background(), r)
|
||||
if err != nil {
|
||||
t.Fatal("Did not get wanted error")
|
||||
}
|
||||
|
||||
if h != r {
|
||||
t.Error("Did not get wanted head")
|
||||
}
|
||||
}
|
||||
|
||||
func TestStore_Head_BestDescendant(t *testing.T) {
|
||||
r := [32]byte{'A'}
|
||||
best := [32]byte{'B'}
|
||||
indices := make(map[[32]byte]uint64)
|
||||
indices[r] = 0
|
||||
|
||||
// Since the justified node's best descendent is at index 1 and it's root is `best`,
|
||||
// the head should be `best`.
|
||||
s := &Store{nodeIndices: indices, nodes: []*Node{{root: r, bestDescendant: 1}, {root: best}}}
|
||||
h, err := s.head(context.Background(), r)
|
||||
if err != nil {
|
||||
t.Fatal("Did not get wanted error")
|
||||
}
|
||||
|
||||
if h != best {
|
||||
t.Error("Did not get wanted head")
|
||||
}
|
||||
}
|
||||
|
||||
func TestStore_Insert_UnknownParent(t *testing.T) {
|
||||
// The new node does not have a parent.
|
||||
s := &Store{nodeIndices: make(map[[32]byte]uint64)}
|
||||
|
||||
Reference in New Issue
Block a user