mirror of
https://gitlab.com/pulsechaincom/prysm-pulse.git
synced 2025-01-17 15:28:45 +00:00
5d29ca4984
* init * bellatrix + altair tests passing * Add Phase0 support * add feature flag * phase0 test * restore testvectors * mod tidy * state tests * gaz * do not call precompute * fix test * Fix context * move to own's method * remove spectests pulltips * time import * remove phase0 * mod tidy * fix getters * Update beacon-chain/forkchoice/doubly-linked-tree/types.go * reviews * fix workspace * Recursive rlocks Co-authored-by: terencechain <terence@prysmaticlabs.com> Co-authored-by: Radosław Kapka <rkapka@wp.pl>
357 lines
15 KiB
Go
357 lines
15 KiB
Go
package doublylinkedtree
|
|
|
|
import (
|
|
"context"
|
|
"testing"
|
|
|
|
forkchoicetypes "github.com/prysmaticlabs/prysm/beacon-chain/forkchoice/types"
|
|
"github.com/prysmaticlabs/prysm/config/params"
|
|
types "github.com/prysmaticlabs/prysm/consensus-types/primitives"
|
|
"github.com/prysmaticlabs/prysm/testing/assert"
|
|
"github.com/prysmaticlabs/prysm/testing/require"
|
|
)
|
|
|
|
func TestStore_PruneThreshold(t *testing.T) {
|
|
s := &Store{
|
|
pruneThreshold: defaultPruneThreshold,
|
|
}
|
|
if got := s.PruneThreshold(); got != defaultPruneThreshold {
|
|
t.Errorf("PruneThreshold() = %v, want %v", got, defaultPruneThreshold)
|
|
}
|
|
}
|
|
|
|
func TestStore_JustifiedEpoch(t *testing.T) {
|
|
j := types.Epoch(100)
|
|
f := setup(j, j)
|
|
require.Equal(t, j, f.JustifiedCheckpoint().Epoch)
|
|
}
|
|
|
|
func TestStore_FinalizedEpoch(t *testing.T) {
|
|
j := types.Epoch(50)
|
|
f := setup(j, j)
|
|
require.Equal(t, j, f.FinalizedCheckpoint().Epoch)
|
|
}
|
|
|
|
func TestStore_NodeCount(t *testing.T) {
|
|
f := setup(0, 0)
|
|
state, blkRoot, err := prepareForkchoiceState(context.Background(), 1, indexToHash(1), params.BeaconConfig().ZeroHash, params.BeaconConfig().ZeroHash, 0, 0)
|
|
require.NoError(t, err)
|
|
require.NoError(t, f.InsertNode(context.Background(), state, blkRoot))
|
|
require.Equal(t, 2, f.NodeCount())
|
|
}
|
|
|
|
func TestStore_NodeByRoot(t *testing.T) {
|
|
f := setup(0, 0)
|
|
ctx := context.Background()
|
|
state, blkRoot, err := prepareForkchoiceState(context.Background(), 1, indexToHash(1), params.BeaconConfig().ZeroHash, params.BeaconConfig().ZeroHash, 0, 0)
|
|
require.NoError(t, err)
|
|
require.NoError(t, f.InsertNode(ctx, state, blkRoot))
|
|
state, blkRoot, err = prepareForkchoiceState(context.Background(), 2, indexToHash(2), indexToHash(1), params.BeaconConfig().ZeroHash, 0, 0)
|
|
require.NoError(t, err)
|
|
require.NoError(t, f.InsertNode(ctx, state, blkRoot))
|
|
node0 := f.store.treeRootNode
|
|
node1 := node0.children[0]
|
|
node2 := node1.children[0]
|
|
|
|
expectedRoots := map[[32]byte]*Node{
|
|
params.BeaconConfig().ZeroHash: node0,
|
|
indexToHash(1): node1,
|
|
indexToHash(2): node2,
|
|
}
|
|
|
|
require.Equal(t, 3, f.NodeCount())
|
|
for root, node := range f.store.nodeByRoot {
|
|
v, ok := expectedRoots[root]
|
|
require.Equal(t, ok, true)
|
|
require.Equal(t, v, node)
|
|
}
|
|
}
|
|
|
|
func TestForkChoice_HasNode(t *testing.T) {
|
|
f := setup(0, 0)
|
|
ctx := context.Background()
|
|
state, blkRoot, err := prepareForkchoiceState(context.Background(), 1, indexToHash(1), params.BeaconConfig().ZeroHash, params.BeaconConfig().ZeroHash, 0, 0)
|
|
require.NoError(t, err)
|
|
require.NoError(t, f.InsertNode(ctx, state, blkRoot))
|
|
require.Equal(t, true, f.HasNode(indexToHash(1)))
|
|
}
|
|
|
|
func TestStore_Head_UnknownJustifiedRoot(t *testing.T) {
|
|
f := setup(0, 0)
|
|
|
|
f.store.justifiedCheckpoint = &forkchoicetypes.Checkpoint{Epoch: 1, Root: [32]byte{'a'}}
|
|
_, err := f.store.head(context.Background())
|
|
assert.ErrorContains(t, errUnknownJustifiedRoot.Error(), err)
|
|
}
|
|
|
|
func TestStore_Head_Itself(t *testing.T) {
|
|
f := setup(0, 0)
|
|
state, blkRoot, err := prepareForkchoiceState(context.Background(), 1, indexToHash(1), params.BeaconConfig().ZeroHash, params.BeaconConfig().ZeroHash, 0, 0)
|
|
require.NoError(t, err)
|
|
require.NoError(t, f.InsertNode(context.Background(), state, blkRoot))
|
|
|
|
// Since the justified node does not have a best descendant so the best node
|
|
// is itself.
|
|
f.store.justifiedCheckpoint = &forkchoicetypes.Checkpoint{Epoch: 0, Root: indexToHash(1)}
|
|
h, err := f.store.head(context.Background())
|
|
require.NoError(t, err)
|
|
assert.Equal(t, indexToHash(1), h)
|
|
}
|
|
|
|
func TestStore_Head_BestDescendant(t *testing.T) {
|
|
f := setup(0, 0)
|
|
ctx := context.Background()
|
|
state, blkRoot, err := prepareForkchoiceState(context.Background(), 1, indexToHash(1), params.BeaconConfig().ZeroHash, params.BeaconConfig().ZeroHash, 0, 0)
|
|
require.NoError(t, err)
|
|
require.NoError(t, f.InsertNode(ctx, state, blkRoot))
|
|
state, blkRoot, err = prepareForkchoiceState(context.Background(), 2, indexToHash(2), indexToHash(1), params.BeaconConfig().ZeroHash, 0, 0)
|
|
require.NoError(t, err)
|
|
require.NoError(t, f.InsertNode(ctx, state, blkRoot))
|
|
state, blkRoot, err = prepareForkchoiceState(context.Background(), 3, indexToHash(3), indexToHash(1), params.BeaconConfig().ZeroHash, 0, 0)
|
|
require.NoError(t, err)
|
|
require.NoError(t, f.InsertNode(ctx, state, blkRoot))
|
|
state, blkRoot, err = prepareForkchoiceState(context.Background(), 4, indexToHash(4), indexToHash(2), params.BeaconConfig().ZeroHash, 0, 0)
|
|
require.NoError(t, err)
|
|
require.NoError(t, f.InsertNode(ctx, state, blkRoot))
|
|
f.store.justifiedCheckpoint = &forkchoicetypes.Checkpoint{Epoch: 0, Root: indexToHash(1)}
|
|
h, err := f.store.head(context.Background())
|
|
require.NoError(t, err)
|
|
require.Equal(t, h, indexToHash(4))
|
|
}
|
|
|
|
func TestStore_UpdateBestDescendant_ContextCancelled(t *testing.T) {
|
|
ctx, cancel := context.WithCancel(context.Background())
|
|
f := setup(0, 0)
|
|
state, blkRoot, err := prepareForkchoiceState(ctx, 1, indexToHash(1), params.BeaconConfig().ZeroHash, params.BeaconConfig().ZeroHash, 0, 0)
|
|
require.NoError(t, err)
|
|
require.NoError(t, f.InsertNode(ctx, state, blkRoot))
|
|
cancel()
|
|
state, blkRoot, err = prepareForkchoiceState(ctx, 2, indexToHash(2), indexToHash(1), params.BeaconConfig().ZeroHash, 0, 0)
|
|
require.NoError(t, err)
|
|
err = f.InsertNode(ctx, state, blkRoot)
|
|
require.ErrorContains(t, "context canceled", err)
|
|
}
|
|
|
|
func TestStore_Insert(t *testing.T) {
|
|
// The new node does not have a parent.
|
|
treeRootNode := &Node{slot: 0, root: indexToHash(0)}
|
|
nodeByRoot := map[[32]byte]*Node{indexToHash(0): treeRootNode}
|
|
nodeByPayload := map[[32]byte]*Node{indexToHash(0): treeRootNode}
|
|
jc := &forkchoicetypes.Checkpoint{Epoch: 0}
|
|
fc := &forkchoicetypes.Checkpoint{Epoch: 0}
|
|
s := &Store{nodeByRoot: nodeByRoot, treeRootNode: treeRootNode, nodeByPayload: nodeByPayload, justifiedCheckpoint: jc, finalizedCheckpoint: fc}
|
|
payloadHash := [32]byte{'a'}
|
|
_, err := s.insert(context.Background(), 100, indexToHash(100), indexToHash(0), payloadHash, 1, 1)
|
|
require.NoError(t, err)
|
|
assert.Equal(t, 2, len(s.nodeByRoot), "Did not insert block")
|
|
assert.Equal(t, (*Node)(nil), treeRootNode.parent, "Incorrect parent")
|
|
assert.Equal(t, 1, len(treeRootNode.children), "Incorrect children number")
|
|
assert.Equal(t, payloadHash, treeRootNode.children[0].payloadHash, "Incorrect payload hash")
|
|
child := treeRootNode.children[0]
|
|
assert.Equal(t, types.Epoch(1), child.justifiedEpoch, "Incorrect justification")
|
|
assert.Equal(t, types.Epoch(1), child.finalizedEpoch, "Incorrect finalization")
|
|
assert.Equal(t, indexToHash(100), child.root, "Incorrect root")
|
|
}
|
|
|
|
func TestStore_Prune_LessThanThreshold(t *testing.T) {
|
|
// Define 100 nodes in store.
|
|
numOfNodes := uint64(100)
|
|
f := setup(0, 0)
|
|
ctx := context.Background()
|
|
state, blkRoot, err := prepareForkchoiceState(ctx, 1, indexToHash(1), params.BeaconConfig().ZeroHash, params.BeaconConfig().ZeroHash, 0, 0)
|
|
require.NoError(t, err)
|
|
require.NoError(t, f.InsertNode(ctx, state, blkRoot))
|
|
for i := uint64(2); i < numOfNodes; i++ {
|
|
state, blkRoot, err = prepareForkchoiceState(ctx, types.Slot(i), indexToHash(i), indexToHash(i-1), params.BeaconConfig().ZeroHash, 0, 0)
|
|
require.NoError(t, err)
|
|
require.NoError(t, f.InsertNode(ctx, state, blkRoot))
|
|
}
|
|
|
|
s := f.store
|
|
s.pruneThreshold = 100
|
|
|
|
// Finalized root has depth 99 so everything before it should be pruned,
|
|
// but PruneThreshold is at 100 so nothing will be pruned.
|
|
s.finalizedCheckpoint.Root = indexToHash(99)
|
|
require.NoError(t, s.prune(context.Background()))
|
|
assert.Equal(t, 100, len(s.nodeByRoot), "Incorrect nodes count")
|
|
}
|
|
|
|
func TestStore_Prune_MoreThanThreshold(t *testing.T) {
|
|
// Define 100 nodes in store.
|
|
numOfNodes := uint64(100)
|
|
f := setup(0, 0)
|
|
ctx := context.Background()
|
|
state, blkRoot, err := prepareForkchoiceState(ctx, 1, indexToHash(1), params.BeaconConfig().ZeroHash, params.BeaconConfig().ZeroHash, 0, 0)
|
|
require.NoError(t, err)
|
|
require.NoError(t, f.InsertNode(ctx, state, blkRoot))
|
|
for i := uint64(2); i < numOfNodes; i++ {
|
|
state, blkRoot, err = prepareForkchoiceState(ctx, types.Slot(i), indexToHash(i), indexToHash(i-1), params.BeaconConfig().ZeroHash, 0, 0)
|
|
require.NoError(t, err)
|
|
require.NoError(t, f.InsertNode(ctx, state, blkRoot))
|
|
}
|
|
|
|
s := f.store
|
|
s.pruneThreshold = 0
|
|
|
|
// Finalized root is at index 99 so everything before 99 should be pruned.
|
|
s.finalizedCheckpoint.Root = indexToHash(99)
|
|
require.NoError(t, s.prune(context.Background()))
|
|
assert.Equal(t, 1, len(s.nodeByRoot), "Incorrect nodes count")
|
|
}
|
|
|
|
func TestStore_Prune_MoreThanOnce(t *testing.T) {
|
|
// Define 100 nodes in store.
|
|
numOfNodes := uint64(100)
|
|
f := setup(0, 0)
|
|
ctx := context.Background()
|
|
state, blkRoot, err := prepareForkchoiceState(ctx, 1, indexToHash(1), params.BeaconConfig().ZeroHash, params.BeaconConfig().ZeroHash, 0, 0)
|
|
require.NoError(t, err)
|
|
require.NoError(t, f.InsertNode(ctx, state, blkRoot))
|
|
for i := uint64(2); i < numOfNodes; i++ {
|
|
state, blkRoot, err = prepareForkchoiceState(ctx, types.Slot(i), indexToHash(i), indexToHash(i-1), params.BeaconConfig().ZeroHash, 0, 0)
|
|
require.NoError(t, err)
|
|
require.NoError(t, f.InsertNode(ctx, state, blkRoot))
|
|
}
|
|
|
|
s := f.store
|
|
s.pruneThreshold = 0
|
|
|
|
// Finalized root is at index 11 so everything before 11 should be pruned.
|
|
s.finalizedCheckpoint.Root = indexToHash(10)
|
|
require.NoError(t, s.prune(context.Background()))
|
|
assert.Equal(t, 90, len(s.nodeByRoot), "Incorrect nodes count")
|
|
|
|
// One more time.
|
|
s.finalizedCheckpoint.Root = indexToHash(20)
|
|
require.NoError(t, s.prune(context.Background()))
|
|
assert.Equal(t, 80, len(s.nodeByRoot), "Incorrect nodes count")
|
|
}
|
|
|
|
// This unit tests starts with a simple branch like this
|
|
//
|
|
// - 1
|
|
// /
|
|
// -- 0 -- 2
|
|
//
|
|
// And we finalize 1. As a result only 1 should survive
|
|
func TestStore_Prune_NoDanglingBranch(t *testing.T) {
|
|
f := setup(0, 0)
|
|
ctx := context.Background()
|
|
state, blkRoot, err := prepareForkchoiceState(ctx, 1, indexToHash(1), params.BeaconConfig().ZeroHash, params.BeaconConfig().ZeroHash, 0, 0)
|
|
require.NoError(t, err)
|
|
require.NoError(t, f.InsertNode(ctx, state, blkRoot))
|
|
state, blkRoot, err = prepareForkchoiceState(ctx, 2, indexToHash(2), params.BeaconConfig().ZeroHash, params.BeaconConfig().ZeroHash, 0, 0)
|
|
require.NoError(t, err)
|
|
require.NoError(t, f.InsertNode(ctx, state, blkRoot))
|
|
f.store.pruneThreshold = 0
|
|
|
|
s := f.store
|
|
s.finalizedCheckpoint.Root = indexToHash(1)
|
|
require.NoError(t, s.prune(context.Background()))
|
|
require.Equal(t, len(s.nodeByRoot), 1)
|
|
}
|
|
|
|
// This test starts with the following branching diagram
|
|
/// We start with the following diagram
|
|
//
|
|
// E -- F
|
|
// /
|
|
// C -- D
|
|
// / \
|
|
// A -- B G -- H -- I
|
|
// \ \
|
|
// J -- K -- L
|
|
//
|
|
//
|
|
func TestStore_tips(t *testing.T) {
|
|
ctx := context.Background()
|
|
f := setup(1, 1)
|
|
|
|
state, blkRoot, err := prepareForkchoiceState(ctx, 100, [32]byte{'a'}, params.BeaconConfig().ZeroHash, params.BeaconConfig().ZeroHash, 1, 1)
|
|
require.NoError(t, err)
|
|
require.NoError(t, f.InsertNode(ctx, state, blkRoot))
|
|
state, blkRoot, err = prepareForkchoiceState(ctx, 101, [32]byte{'b'}, [32]byte{'a'}, params.BeaconConfig().ZeroHash, 1, 1)
|
|
require.NoError(t, err)
|
|
require.NoError(t, f.InsertNode(ctx, state, blkRoot))
|
|
state, blkRoot, err = prepareForkchoiceState(ctx, 102, [32]byte{'c'}, [32]byte{'b'}, params.BeaconConfig().ZeroHash, 1, 1)
|
|
require.NoError(t, err)
|
|
require.NoError(t, f.InsertNode(ctx, state, blkRoot))
|
|
state, blkRoot, err = prepareForkchoiceState(ctx, 102, [32]byte{'j'}, [32]byte{'b'}, params.BeaconConfig().ZeroHash, 1, 1)
|
|
require.NoError(t, err)
|
|
require.NoError(t, f.InsertNode(ctx, state, blkRoot))
|
|
state, blkRoot, err = prepareForkchoiceState(ctx, 103, [32]byte{'d'}, [32]byte{'c'}, params.BeaconConfig().ZeroHash, 1, 1)
|
|
require.NoError(t, err)
|
|
require.NoError(t, f.InsertNode(ctx, state, blkRoot))
|
|
state, blkRoot, err = prepareForkchoiceState(ctx, 104, [32]byte{'e'}, [32]byte{'d'}, params.BeaconConfig().ZeroHash, 1, 1)
|
|
require.NoError(t, err)
|
|
require.NoError(t, f.InsertNode(ctx, state, blkRoot))
|
|
state, blkRoot, err = prepareForkchoiceState(ctx, 104, [32]byte{'g'}, [32]byte{'d'}, params.BeaconConfig().ZeroHash, 1, 1)
|
|
require.NoError(t, err)
|
|
require.NoError(t, f.InsertNode(ctx, state, blkRoot))
|
|
state, blkRoot, err = prepareForkchoiceState(ctx, 105, [32]byte{'f'}, [32]byte{'e'}, params.BeaconConfig().ZeroHash, 1, 1)
|
|
require.NoError(t, err)
|
|
require.NoError(t, f.InsertNode(ctx, state, blkRoot))
|
|
state, blkRoot, err = prepareForkchoiceState(ctx, 105, [32]byte{'h'}, [32]byte{'g'}, params.BeaconConfig().ZeroHash, 1, 1)
|
|
require.NoError(t, err)
|
|
require.NoError(t, f.InsertNode(ctx, state, blkRoot))
|
|
state, blkRoot, err = prepareForkchoiceState(ctx, 105, [32]byte{'k'}, [32]byte{'g'}, params.BeaconConfig().ZeroHash, 1, 1)
|
|
require.NoError(t, err)
|
|
require.NoError(t, f.InsertNode(ctx, state, blkRoot))
|
|
state, blkRoot, err = prepareForkchoiceState(ctx, 106, [32]byte{'i'}, [32]byte{'h'}, params.BeaconConfig().ZeroHash, 1, 1)
|
|
require.NoError(t, err)
|
|
require.NoError(t, f.InsertNode(ctx, state, blkRoot))
|
|
state, blkRoot, err = prepareForkchoiceState(ctx, 106, [32]byte{'l'}, [32]byte{'k'}, params.BeaconConfig().ZeroHash, 1, 1)
|
|
require.NoError(t, err)
|
|
require.NoError(t, f.InsertNode(ctx, state, blkRoot))
|
|
expectedMap := map[[32]byte]types.Slot{
|
|
[32]byte{'f'}: 105,
|
|
[32]byte{'i'}: 106,
|
|
[32]byte{'l'}: 106,
|
|
[32]byte{'j'}: 102,
|
|
}
|
|
roots, slots := f.store.tips()
|
|
for i, r := range roots {
|
|
expectedSlot, ok := expectedMap[r]
|
|
require.Equal(t, true, ok)
|
|
require.Equal(t, slots[i], expectedSlot)
|
|
}
|
|
}
|
|
|
|
func TestStore_PruneMapsNodes(t *testing.T) {
|
|
f := setup(0, 0)
|
|
ctx := context.Background()
|
|
state, blkRoot, err := prepareForkchoiceState(ctx, 1, indexToHash(1), params.BeaconConfig().ZeroHash, params.BeaconConfig().ZeroHash, 0, 0)
|
|
require.NoError(t, err)
|
|
require.NoError(t, f.InsertNode(ctx, state, blkRoot))
|
|
state, blkRoot, err = prepareForkchoiceState(ctx, 2, indexToHash(2), params.BeaconConfig().ZeroHash, params.BeaconConfig().ZeroHash, 0, 0)
|
|
require.NoError(t, err)
|
|
require.NoError(t, f.InsertNode(ctx, state, blkRoot))
|
|
|
|
s := f.store
|
|
s.pruneThreshold = 0
|
|
s.finalizedCheckpoint.Root = indexToHash(1)
|
|
require.NoError(t, s.prune(context.Background()))
|
|
require.Equal(t, len(s.nodeByRoot), 1)
|
|
|
|
}
|
|
|
|
func TestStore_HasParent(t *testing.T) {
|
|
f := setup(1, 1)
|
|
ctx := context.Background()
|
|
state, blkRoot, err := prepareForkchoiceState(ctx, 1, indexToHash(1), params.BeaconConfig().ZeroHash, params.BeaconConfig().ZeroHash, 1, 1)
|
|
require.NoError(t, err)
|
|
require.NoError(t, f.InsertNode(ctx, state, blkRoot))
|
|
state, blkRoot, err = prepareForkchoiceState(ctx, 2, indexToHash(2), indexToHash(1), params.BeaconConfig().ZeroHash, 1, 1)
|
|
require.NoError(t, err)
|
|
require.NoError(t, f.InsertNode(ctx, state, blkRoot))
|
|
state, blkRoot, err = prepareForkchoiceState(ctx, 3, indexToHash(3), indexToHash(2), params.BeaconConfig().ZeroHash, 1, 1)
|
|
require.NoError(t, err)
|
|
require.NoError(t, f.InsertNode(ctx, state, blkRoot))
|
|
require.Equal(t, false, f.HasParent(params.BeaconConfig().ZeroHash))
|
|
require.Equal(t, true, f.HasParent(indexToHash(1)))
|
|
require.Equal(t, true, f.HasParent(indexToHash(2)))
|
|
require.Equal(t, true, f.HasParent(indexToHash(3)))
|
|
require.Equal(t, false, f.HasParent(indexToHash(4)))
|
|
}
|