mirror of
https://gitlab.com/pulsechaincom/prysm-pulse.git
synced 2024-12-21 19:20:38 +00:00
Modify the algorithm of updateFinalizedBlockRoots
(#13486)
* rename error var * new algo * replay_test * add comment * review * fill out parent root * handle edge cases * review
This commit is contained in:
parent
cade09ba0b
commit
32fb183392
@ -224,7 +224,7 @@ func (s *Store) DeleteBlock(ctx context.Context, root [32]byte) error {
|
||||
return s.db.Update(func(tx *bolt.Tx) error {
|
||||
bkt := tx.Bucket(finalizedBlockRootsIndexBucket)
|
||||
if b := bkt.Get(root[:]); b != nil {
|
||||
return ErrDeleteJustifiedAndFinalized
|
||||
return ErrDeleteFinalized
|
||||
}
|
||||
|
||||
if err := tx.Bucket(blocksBucket).Delete(root[:]); err != nil {
|
||||
|
@ -289,7 +289,7 @@ func TestStore_DeleteBlock(t *testing.T) {
|
||||
require.Equal(t, b, nil)
|
||||
require.Equal(t, false, db.HasStateSummary(ctx, root2))
|
||||
|
||||
require.ErrorIs(t, db.DeleteBlock(ctx, root), ErrDeleteJustifiedAndFinalized)
|
||||
require.ErrorIs(t, db.DeleteBlock(ctx, root), ErrDeleteFinalized)
|
||||
}
|
||||
|
||||
func TestStore_DeleteJustifiedBlock(t *testing.T) {
|
||||
@ -309,7 +309,7 @@ func TestStore_DeleteJustifiedBlock(t *testing.T) {
|
||||
require.NoError(t, db.SaveBlock(ctx, blk))
|
||||
require.NoError(t, db.SaveState(ctx, st, root))
|
||||
require.NoError(t, db.SaveJustifiedCheckpoint(ctx, cp))
|
||||
require.ErrorIs(t, db.DeleteBlock(ctx, root), ErrDeleteJustifiedAndFinalized)
|
||||
require.ErrorIs(t, db.DeleteBlock(ctx, root), ErrDeleteFinalized)
|
||||
}
|
||||
|
||||
func TestStore_DeleteFinalizedBlock(t *testing.T) {
|
||||
@ -329,7 +329,7 @@ func TestStore_DeleteFinalizedBlock(t *testing.T) {
|
||||
require.NoError(t, db.SaveState(ctx, st, root))
|
||||
require.NoError(t, db.SaveGenesisBlockRoot(ctx, root))
|
||||
require.NoError(t, db.SaveFinalizedCheckpoint(ctx, cp))
|
||||
require.ErrorIs(t, db.DeleteBlock(ctx, root), ErrDeleteJustifiedAndFinalized)
|
||||
require.ErrorIs(t, db.DeleteBlock(ctx, root), ErrDeleteFinalized)
|
||||
}
|
||||
func TestStore_GenesisBlock(t *testing.T) {
|
||||
db := setupDB(t)
|
||||
|
@ -2,8 +2,8 @@ package kv
|
||||
|
||||
import "github.com/pkg/errors"
|
||||
|
||||
// ErrDeleteJustifiedAndFinalized is raised when we attempt to delete a finalized block/state
|
||||
var ErrDeleteJustifiedAndFinalized = errors.New("cannot delete finalized block or state")
|
||||
// ErrDeleteFinalized is raised when we attempt to delete a finalized block/state
|
||||
var ErrDeleteFinalized = errors.New("cannot delete finalized block or state")
|
||||
|
||||
// ErrNotFound can be used directly, or as a wrapped DBError, whenever a db method needs to
|
||||
// indicate that a value couldn't be found.
|
||||
|
@ -5,7 +5,6 @@ import (
|
||||
"context"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"github.com/prysmaticlabs/prysm/v5/beacon-chain/db/filters"
|
||||
"github.com/prysmaticlabs/prysm/v5/consensus-types/blocks"
|
||||
"github.com/prysmaticlabs/prysm/v5/consensus-types/interfaces"
|
||||
"github.com/prysmaticlabs/prysm/v5/encoding/bytesutil"
|
||||
@ -29,72 +28,76 @@ var containerFinalizedButNotCanonical = []byte("recent block needs reindexing to
|
||||
// beacon block chain using the finalized root alone as this would exclude all other blocks in the
|
||||
// finalized epoch from being indexed as "final and canonical".
|
||||
//
|
||||
// The algorithm for building the index works as follows:
|
||||
// - De-index all finalized beacon block roots from previous_finalized_epoch to
|
||||
// new_finalized_epoch. (I.e. delete these roots from the index, to be re-indexed.)
|
||||
// - Build the canonical finalized chain by walking up the ancestry chain from the finalized block
|
||||
// root until a parent is found in the index, or the parent is genesis or the origin checkpoint.
|
||||
// - Add all block roots in the database where epoch(block.slot) == checkpoint.epoch.
|
||||
//
|
||||
// This method ensures that all blocks from the current finalized epoch are considered "final" while
|
||||
// maintaining only canonical and finalized blocks older than the current finalized epoch.
|
||||
// The main part of the algorithm traverses parent->child block relationships in the
|
||||
// `blockParentRootIndicesBucket` bucket to find the path between the last finalized checkpoint
|
||||
// and the current finalized checkpoint. It relies on the invariant that there is a unique path
|
||||
// between two finalized checkpoints.
|
||||
func (s *Store) updateFinalizedBlockRoots(ctx context.Context, tx *bolt.Tx, checkpoint *ethpb.Checkpoint) error {
|
||||
ctx, span := trace.StartSpan(ctx, "BeaconDB.updateFinalizedBlockRoots")
|
||||
defer span.End()
|
||||
|
||||
bkt := tx.Bucket(finalizedBlockRootsIndexBucket)
|
||||
|
||||
root := checkpoint.Root
|
||||
var previousRoot []byte
|
||||
genesisRoot := tx.Bucket(blocksBucket).Get(genesisBlockRootKey)
|
||||
initCheckpointRoot := tx.Bucket(blocksBucket).Get(originCheckpointBlockRootKey)
|
||||
|
||||
// De-index recent finalized block roots, to be re-indexed.
|
||||
finalizedBkt := tx.Bucket(finalizedBlockRootsIndexBucket)
|
||||
previousFinalizedCheckpoint := ðpb.Checkpoint{}
|
||||
if b := bkt.Get(previousFinalizedCheckpointKey); b != nil {
|
||||
if b := finalizedBkt.Get(previousFinalizedCheckpointKey); b != nil {
|
||||
if err := decode(ctx, b, previousFinalizedCheckpoint); err != nil {
|
||||
tracing.AnnotateError(span, err)
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
blockRoots, err := s.BlockRoots(ctx, filters.NewFilter().
|
||||
SetStartEpoch(previousFinalizedCheckpoint.Epoch).
|
||||
SetEndEpoch(checkpoint.Epoch+1),
|
||||
)
|
||||
if err != nil {
|
||||
tracing.AnnotateError(span, err)
|
||||
return err
|
||||
}
|
||||
for _, root := range blockRoots {
|
||||
if err := bkt.Delete(root[:]); err != nil {
|
||||
tracing.AnnotateError(span, err)
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// Walk up the ancestry chain until we reach a block root present in the finalized block roots
|
||||
// index bucket or genesis block root.
|
||||
for {
|
||||
if bytes.Equal(root, genesisRoot) {
|
||||
break
|
||||
}
|
||||
|
||||
signedBlock, err := s.Block(ctx, bytesutil.ToBytes32(root))
|
||||
// Handle the case of checkpoint sync.
|
||||
if previousFinalizedCheckpoint.Root == nil && bytes.Equal(checkpoint.Root, tx.Bucket(blocksBucket).Get(originCheckpointBlockRootKey)) {
|
||||
container := ðpb.FinalizedBlockRootContainer{}
|
||||
enc, err := encode(ctx, container)
|
||||
if err != nil {
|
||||
tracing.AnnotateError(span, err)
|
||||
return err
|
||||
}
|
||||
if err := blocks.BeaconBlockIsNil(signedBlock); err != nil {
|
||||
if err = finalizedBkt.Put(checkpoint.Root, enc); err != nil {
|
||||
tracing.AnnotateError(span, err)
|
||||
return err
|
||||
}
|
||||
block := signedBlock.Block()
|
||||
return updatePrevFinalizedCheckpoint(ctx, span, finalizedBkt, checkpoint)
|
||||
}
|
||||
|
||||
parentRoot := block.ParentRoot()
|
||||
container := ðpb.FinalizedBlockRootContainer{
|
||||
ParentRoot: parentRoot[:],
|
||||
ChildRoot: previousRoot,
|
||||
var finalized [][]byte
|
||||
if previousFinalizedCheckpoint.Root == nil {
|
||||
genesisRoot := tx.Bucket(blocksBucket).Get(genesisBlockRootKey)
|
||||
_, finalized = pathToFinalizedCheckpoint(ctx, [][]byte{genesisRoot}, checkpoint.Root, tx)
|
||||
} else {
|
||||
if err := updateChildOfPrevFinalizedCheckpoint(
|
||||
ctx,
|
||||
span,
|
||||
finalizedBkt,
|
||||
tx.Bucket(blockParentRootIndicesBucket), previousFinalizedCheckpoint.Root,
|
||||
); err != nil {
|
||||
return err
|
||||
}
|
||||
_, finalized = pathToFinalizedCheckpoint(ctx, [][]byte{previousFinalizedCheckpoint.Root}, checkpoint.Root, tx)
|
||||
}
|
||||
|
||||
for i, r := range finalized {
|
||||
var container *ethpb.FinalizedBlockRootContainer
|
||||
switch i {
|
||||
case 0:
|
||||
container = ðpb.FinalizedBlockRootContainer{
|
||||
ParentRoot: previousFinalizedCheckpoint.Root,
|
||||
}
|
||||
if len(finalized) > 1 {
|
||||
container.ChildRoot = finalized[i+1]
|
||||
}
|
||||
case len(finalized) - 1:
|
||||
// We don't know the finalized child of the new finalized checkpoint.
|
||||
// It will be filled out in the next function call.
|
||||
container = ðpb.FinalizedBlockRootContainer{}
|
||||
if len(finalized) > 1 {
|
||||
container.ParentRoot = finalized[i-1]
|
||||
}
|
||||
default:
|
||||
container = ðpb.FinalizedBlockRootContainer{
|
||||
ParentRoot: finalized[i-1],
|
||||
ChildRoot: finalized[i+1],
|
||||
}
|
||||
}
|
||||
|
||||
enc, err := encode(ctx, container)
|
||||
@ -102,66 +105,13 @@ func (s *Store) updateFinalizedBlockRoots(ctx context.Context, tx *bolt.Tx, chec
|
||||
tracing.AnnotateError(span, err)
|
||||
return err
|
||||
}
|
||||
if err := bkt.Put(root, enc); err != nil {
|
||||
tracing.AnnotateError(span, err)
|
||||
return err
|
||||
}
|
||||
|
||||
// breaking here allows the initial checkpoint root to be correctly inserted,
|
||||
// but stops the loop from trying to search for its parent.
|
||||
if bytes.Equal(root, initCheckpointRoot) {
|
||||
break
|
||||
}
|
||||
|
||||
// Found parent, loop exit condition.
|
||||
pr := block.ParentRoot()
|
||||
if parentBytes := bkt.Get(pr[:]); parentBytes != nil {
|
||||
parent := ðpb.FinalizedBlockRootContainer{}
|
||||
if err := decode(ctx, parentBytes, parent); err != nil {
|
||||
tracing.AnnotateError(span, err)
|
||||
return err
|
||||
}
|
||||
parent.ChildRoot = root
|
||||
enc, err := encode(ctx, parent)
|
||||
if err != nil {
|
||||
tracing.AnnotateError(span, err)
|
||||
return err
|
||||
}
|
||||
if err := bkt.Put(pr[:], enc); err != nil {
|
||||
tracing.AnnotateError(span, err)
|
||||
return err
|
||||
}
|
||||
break
|
||||
}
|
||||
previousRoot = root
|
||||
root = pr[:]
|
||||
}
|
||||
|
||||
// Upsert blocks from the current finalized epoch.
|
||||
roots, err := s.BlockRoots(ctx, filters.NewFilter().SetStartEpoch(checkpoint.Epoch).SetEndEpoch(checkpoint.Epoch+1))
|
||||
if err != nil {
|
||||
tracing.AnnotateError(span, err)
|
||||
return err
|
||||
}
|
||||
for _, root := range roots {
|
||||
root := root[:]
|
||||
if bytes.Equal(root, checkpoint.Root) || bkt.Get(root) != nil {
|
||||
continue
|
||||
}
|
||||
if err := bkt.Put(root, containerFinalizedButNotCanonical); err != nil {
|
||||
if err = finalizedBkt.Put(r, enc); err != nil {
|
||||
tracing.AnnotateError(span, err)
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// Update previous checkpoint
|
||||
enc, err := encode(ctx, checkpoint)
|
||||
if err != nil {
|
||||
tracing.AnnotateError(span, err)
|
||||
return err
|
||||
}
|
||||
|
||||
return bkt.Put(previousFinalizedCheckpointKey, enc)
|
||||
return updatePrevFinalizedCheckpoint(ctx, span, finalizedBkt, checkpoint)
|
||||
}
|
||||
|
||||
// BackfillFinalizedIndex updates the finalized index for a contiguous chain of blocks that are the ancestors of the
|
||||
@ -242,8 +192,6 @@ func (s *Store) BackfillFinalizedIndex(ctx context.Context, blocks []blocks.ROBl
|
||||
|
||||
// IsFinalizedBlock returns true if the block root is present in the finalized block root index.
|
||||
// A beacon block root contained exists in this index if it is considered finalized and canonical.
|
||||
// Note: beacon blocks from the latest finalized epoch return true, whether or not they are
|
||||
// considered canonical in the "head view" of the beacon node.
|
||||
func (s *Store) IsFinalizedBlock(ctx context.Context, blockRoot [32]byte) bool {
|
||||
_, span := trace.StartSpan(ctx, "BeaconDB.IsFinalizedBlock")
|
||||
defer span.End()
|
||||
@ -296,3 +244,53 @@ func (s *Store) FinalizedChildBlock(ctx context.Context, blockRoot [32]byte) (in
|
||||
tracing.AnnotateError(span, err)
|
||||
return blk, err
|
||||
}
|
||||
|
||||
func pathToFinalizedCheckpoint(ctx context.Context, roots [][]byte, checkpointRoot []byte, tx *bolt.Tx) (bool, [][]byte) {
|
||||
if len(roots) == 0 || (len(roots) == 1 && roots[0] == nil) {
|
||||
return false, nil
|
||||
}
|
||||
|
||||
for _, r := range roots {
|
||||
if bytes.Equal(r, checkpointRoot) {
|
||||
return true, [][]byte{r}
|
||||
}
|
||||
children := lookupValuesForIndices(ctx, map[string][]byte{string(blockParentRootIndicesBucket): r}, tx)
|
||||
if len(children) == 0 {
|
||||
children = [][][]byte{nil}
|
||||
}
|
||||
isPath, path := pathToFinalizedCheckpoint(ctx, children[0], checkpointRoot, tx)
|
||||
if isPath {
|
||||
return true, append([][]byte{r}, path...)
|
||||
}
|
||||
}
|
||||
|
||||
return false, nil
|
||||
}
|
||||
|
||||
func updatePrevFinalizedCheckpoint(ctx context.Context, span *trace.Span, finalizedBkt *bolt.Bucket, checkpoint *ethpb.Checkpoint) error {
|
||||
enc, err := encode(ctx, checkpoint)
|
||||
if err != nil {
|
||||
tracing.AnnotateError(span, err)
|
||||
return err
|
||||
}
|
||||
return finalizedBkt.Put(previousFinalizedCheckpointKey, enc)
|
||||
}
|
||||
|
||||
func updateChildOfPrevFinalizedCheckpoint(ctx context.Context, span *trace.Span, finalizedBkt, parentBkt *bolt.Bucket, checkpointRoot []byte) error {
|
||||
container := ðpb.FinalizedBlockRootContainer{}
|
||||
if err := decode(ctx, finalizedBkt.Get(checkpointRoot), container); err != nil {
|
||||
tracing.AnnotateError(span, err)
|
||||
return err
|
||||
}
|
||||
container.ChildRoot = parentBkt.Get(checkpointRoot)
|
||||
enc, err := encode(ctx, container)
|
||||
if err != nil {
|
||||
tracing.AnnotateError(span, err)
|
||||
return err
|
||||
}
|
||||
if err = finalizedBkt.Put(checkpointRoot, enc); err != nil {
|
||||
tracing.AnnotateError(span, err)
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
@ -26,38 +26,30 @@ func TestStore_IsFinalizedBlock(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
|
||||
require.NoError(t, db.SaveGenesisBlockRoot(ctx, genesisBlockRoot))
|
||||
|
||||
blks := makeBlocks(t, 0, slotsPerEpoch*3, genesisBlockRoot)
|
||||
blks := makeBlocks(t, 0, slotsPerEpoch*2, genesisBlockRoot)
|
||||
require.NoError(t, db.SaveBlocks(ctx, blks))
|
||||
|
||||
root, err := blks[slotsPerEpoch].Block().HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
|
||||
cp := ðpb.Checkpoint{
|
||||
Epoch: 1,
|
||||
Root: root[:],
|
||||
}
|
||||
|
||||
st, err := util.NewBeaconState()
|
||||
require.NoError(t, err)
|
||||
// a state is required to save checkpoint
|
||||
require.NoError(t, db.SaveState(ctx, st, root))
|
||||
require.NoError(t, db.SaveFinalizedCheckpoint(ctx, cp))
|
||||
|
||||
// All blocks up to slotsPerEpoch*2 should be in the finalized index.
|
||||
for i := uint64(0); i < slotsPerEpoch*2; i++ {
|
||||
root, err := blks[i].Block().HashTreeRoot()
|
||||
for i := uint64(0); i <= slotsPerEpoch; i++ {
|
||||
root, err = blks[i].Block().HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, true, db.IsFinalizedBlock(ctx, root), "Block at index %d was not considered finalized in the index", i)
|
||||
assert.Equal(t, true, db.IsFinalizedBlock(ctx, root), "Block at index %d was not considered finalized", i)
|
||||
}
|
||||
for i := slotsPerEpoch * 3; i < uint64(len(blks)); i++ {
|
||||
root, err := blks[i].Block().HashTreeRoot()
|
||||
for i := slotsPerEpoch + 1; i < uint64(len(blks)); i++ {
|
||||
root, err = blks[i].Block().HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, false, db.IsFinalizedBlock(ctx, root), "Block at index %d was considered finalized in the index, but should not have", i)
|
||||
assert.Equal(t, false, db.IsFinalizedBlock(ctx, root), "Block at index %d was considered finalized, but should not have", i)
|
||||
}
|
||||
}
|
||||
|
||||
func TestStore_IsFinalizedBlockGenesis(t *testing.T) {
|
||||
func TestStore_IsFinalizedGenesisBlock(t *testing.T) {
|
||||
db := setupDB(t)
|
||||
ctx := context.Background()
|
||||
|
||||
@ -69,136 +61,114 @@ func TestStore_IsFinalizedBlockGenesis(t *testing.T) {
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, db.SaveBlock(ctx, wsb))
|
||||
require.NoError(t, db.SaveGenesisBlockRoot(ctx, root))
|
||||
assert.Equal(t, true, db.IsFinalizedBlock(ctx, root), "Finalized genesis block doesn't exist in db")
|
||||
}
|
||||
|
||||
// This test scenario is to test a specific edge case where the finalized block root is not part of
|
||||
// the finalized and canonical chain.
|
||||
//
|
||||
// Example:
|
||||
// 0 1 2 3 4 5 6 slot
|
||||
// a <- b <-- d <- e <- f <- g roots
|
||||
//
|
||||
// ^- c
|
||||
//
|
||||
// Imagine that epochs are 2 slots and that epoch 1, 2, and 3 are finalized. Checkpoint roots would
|
||||
// be c, e, and g. In this scenario, c was a finalized checkpoint root but no block built upon it so
|
||||
// it should not be considered "final and canonical" in the view at slot 6.
|
||||
func TestStore_IsFinalized_ForkEdgeCase(t *testing.T) {
|
||||
slotsPerEpoch := uint64(params.BeaconConfig().SlotsPerEpoch)
|
||||
blocks0 := makeBlocks(t, slotsPerEpoch*0, slotsPerEpoch, genesisBlockRoot)
|
||||
blocks1 := append(
|
||||
makeBlocks(t, slotsPerEpoch*1, 1, bytesutil.ToBytes32(sszRootOrDie(t, blocks0[len(blocks0)-1]))), // No block builds off of the first block in epoch.
|
||||
makeBlocks(t, slotsPerEpoch*1+1, slotsPerEpoch-1, bytesutil.ToBytes32(sszRootOrDie(t, blocks0[len(blocks0)-1])))...,
|
||||
)
|
||||
blocks2 := makeBlocks(t, slotsPerEpoch*2, slotsPerEpoch, bytesutil.ToBytes32(sszRootOrDie(t, blocks1[len(blocks1)-1])))
|
||||
|
||||
db := setupDB(t)
|
||||
ctx := context.Background()
|
||||
|
||||
require.NoError(t, db.SaveGenesisBlockRoot(ctx, genesisBlockRoot))
|
||||
require.NoError(t, db.SaveBlocks(ctx, blocks0))
|
||||
require.NoError(t, db.SaveBlocks(ctx, blocks1))
|
||||
require.NoError(t, db.SaveBlocks(ctx, blocks2))
|
||||
|
||||
// First checkpoint
|
||||
checkpoint1 := ðpb.Checkpoint{
|
||||
Root: sszRootOrDie(t, blocks1[0]),
|
||||
Epoch: 1,
|
||||
}
|
||||
|
||||
st, err := util.NewBeaconState()
|
||||
require.NoError(t, err)
|
||||
// A state is required to save checkpoint
|
||||
require.NoError(t, db.SaveState(ctx, st, bytesutil.ToBytes32(checkpoint1.Root)))
|
||||
require.NoError(t, db.SaveFinalizedCheckpoint(ctx, checkpoint1))
|
||||
// All blocks in blocks0 and blocks1 should be finalized and canonical.
|
||||
for i, block := range append(blocks0, blocks1...) {
|
||||
root := sszRootOrDie(t, block)
|
||||
assert.Equal(t, true, db.IsFinalizedBlock(ctx, bytesutil.ToBytes32(root)), "%d - Expected block %#x to be finalized", i, root)
|
||||
}
|
||||
|
||||
// Second checkpoint
|
||||
checkpoint2 := ðpb.Checkpoint{
|
||||
Root: sszRootOrDie(t, blocks2[0]),
|
||||
Epoch: 2,
|
||||
}
|
||||
// A state is required to save checkpoint
|
||||
require.NoError(t, db.SaveState(ctx, st, bytesutil.ToBytes32(checkpoint2.Root)))
|
||||
require.NoError(t, db.SaveFinalizedCheckpoint(ctx, checkpoint2))
|
||||
// All blocks in blocks0 and blocks2 should be finalized and canonical.
|
||||
for i, block := range append(blocks0, blocks2...) {
|
||||
root := sszRootOrDie(t, block)
|
||||
assert.Equal(t, true, db.IsFinalizedBlock(ctx, bytesutil.ToBytes32(root)), "%d - Expected block %#x to be finalized", i, root)
|
||||
}
|
||||
// All blocks in blocks1 should be finalized and canonical, except blocks1[0].
|
||||
for i, block := range blocks1 {
|
||||
root := sszRootOrDie(t, block)
|
||||
if db.IsFinalizedBlock(ctx, bytesutil.ToBytes32(root)) == (i == 0) {
|
||||
t.Errorf("Expected db.IsFinalizedBlock(ctx, blocks1[%d]) to be %v", i, i != 0)
|
||||
}
|
||||
}
|
||||
assert.Equal(t, true, db.IsFinalizedBlock(ctx, root))
|
||||
}
|
||||
|
||||
func TestStore_IsFinalizedChildBlock(t *testing.T) {
|
||||
slotsPerEpoch := uint64(params.BeaconConfig().SlotsPerEpoch)
|
||||
ctx := context.Background()
|
||||
db := setupDB(t)
|
||||
require.NoError(t, db.SaveGenesisBlockRoot(ctx, genesisBlockRoot))
|
||||
|
||||
eval := func(t testing.TB, ctx context.Context, db *Store, blks []interfaces.ReadOnlySignedBeaconBlock) {
|
||||
require.NoError(t, db.SaveBlocks(ctx, blks))
|
||||
root, err := blks[slotsPerEpoch].Block().HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
|
||||
cp := ðpb.Checkpoint{
|
||||
Epoch: 1,
|
||||
Root: root[:],
|
||||
}
|
||||
|
||||
st, err := util.NewBeaconState()
|
||||
require.NoError(t, err)
|
||||
// a state is required to save checkpoint
|
||||
require.NoError(t, db.SaveState(ctx, st, root))
|
||||
require.NoError(t, db.SaveFinalizedCheckpoint(ctx, cp))
|
||||
|
||||
// All blocks up to slotsPerEpoch should have a finalized child block.
|
||||
for i := uint64(0); i < slotsPerEpoch; i++ {
|
||||
root, err := blks[i].Block().HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, true, db.IsFinalizedBlock(ctx, root), "Block at index %d was not considered finalized in the index", i)
|
||||
blk, err := db.FinalizedChildBlock(ctx, root)
|
||||
assert.NoError(t, err)
|
||||
if blk == nil {
|
||||
t.Error("Child block doesn't exist for valid finalized block.")
|
||||
}
|
||||
}
|
||||
blks := makeBlocks(t, 0, slotsPerEpoch*2, genesisBlockRoot)
|
||||
require.NoError(t, db.SaveBlocks(ctx, blks))
|
||||
root, err := blks[slotsPerEpoch].Block().HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
cp := ðpb.Checkpoint{
|
||||
Epoch: 1,
|
||||
Root: root[:],
|
||||
}
|
||||
require.NoError(t, db.SaveFinalizedCheckpoint(ctx, cp))
|
||||
|
||||
setup := func(t testing.TB) *Store {
|
||||
db := setupDB(t)
|
||||
require.NoError(t, db.SaveGenesisBlockRoot(ctx, genesisBlockRoot))
|
||||
|
||||
return db
|
||||
for i := uint64(0); i < slotsPerEpoch; i++ {
|
||||
root, err = blks[i].Block().HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, true, db.IsFinalizedBlock(ctx, root), "Block at index %d was not considered finalized", i)
|
||||
blk, err := db.FinalizedChildBlock(ctx, root)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, false, blk == nil, "Child block at index %d was not considered finalized", i)
|
||||
}
|
||||
|
||||
t.Run("phase0", func(t *testing.T) {
|
||||
db := setup(t)
|
||||
|
||||
blks := makeBlocks(t, 0, slotsPerEpoch*3, genesisBlockRoot)
|
||||
eval(t, ctx, db, blks)
|
||||
})
|
||||
|
||||
t.Run("altair", func(t *testing.T) {
|
||||
db := setup(t)
|
||||
|
||||
blks := makeBlocksAltair(t, 0, slotsPerEpoch*3, genesisBlockRoot)
|
||||
eval(t, ctx, db, blks)
|
||||
})
|
||||
}
|
||||
|
||||
func sszRootOrDie(t *testing.T, block interfaces.ReadOnlySignedBeaconBlock) []byte {
|
||||
root, err := block.Block().HashTreeRoot()
|
||||
func TestStore_ChildRootOfPrevFinalizedCheckpointIsUpdated(t *testing.T) {
|
||||
slotsPerEpoch := uint64(params.BeaconConfig().SlotsPerEpoch)
|
||||
ctx := context.Background()
|
||||
db := setupDB(t)
|
||||
require.NoError(t, db.SaveGenesisBlockRoot(ctx, genesisBlockRoot))
|
||||
|
||||
blks := makeBlocks(t, 0, slotsPerEpoch*3, genesisBlockRoot)
|
||||
require.NoError(t, db.SaveBlocks(ctx, blks))
|
||||
root, err := blks[slotsPerEpoch].Block().HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
return root[:]
|
||||
cp := ðpb.Checkpoint{
|
||||
Epoch: 1,
|
||||
Root: root[:],
|
||||
}
|
||||
require.NoError(t, db.SaveFinalizedCheckpoint(ctx, cp))
|
||||
root2, err := blks[slotsPerEpoch*2].Block().HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
cp = ðpb.Checkpoint{
|
||||
Epoch: 2,
|
||||
Root: root2[:],
|
||||
}
|
||||
require.NoError(t, db.SaveFinalizedCheckpoint(ctx, cp))
|
||||
|
||||
require.NoError(t, db.db.View(func(tx *bolt.Tx) error {
|
||||
container := ðpb.FinalizedBlockRootContainer{}
|
||||
f := tx.Bucket(finalizedBlockRootsIndexBucket).Get(root[:])
|
||||
require.NoError(t, decode(ctx, f, container))
|
||||
r, err := blks[slotsPerEpoch+1].Block().HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
assert.DeepEqual(t, r[:], container.ChildRoot)
|
||||
return nil
|
||||
}))
|
||||
}
|
||||
|
||||
func TestStore_OrphanedBlockIsNotFinalized(t *testing.T) {
|
||||
slotsPerEpoch := uint64(params.BeaconConfig().SlotsPerEpoch)
|
||||
db := setupDB(t)
|
||||
ctx := context.Background()
|
||||
|
||||
require.NoError(t, db.SaveGenesisBlockRoot(ctx, genesisBlockRoot))
|
||||
blk0 := util.NewBeaconBlock()
|
||||
blk0.Block.ParentRoot = genesisBlockRoot[:]
|
||||
blk0Root, err := blk0.Block.HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
blk1 := util.NewBeaconBlock()
|
||||
blk1.Block.Slot = 1
|
||||
blk1.Block.ParentRoot = blk0Root[:]
|
||||
blk2 := util.NewBeaconBlock()
|
||||
blk2.Block.Slot = 2
|
||||
// orphan block at index 1
|
||||
blk2.Block.ParentRoot = blk0Root[:]
|
||||
blk2Root, err := blk2.Block.HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
sBlk0, err := consensusblocks.NewSignedBeaconBlock(blk0)
|
||||
require.NoError(t, err)
|
||||
sBlk1, err := consensusblocks.NewSignedBeaconBlock(blk1)
|
||||
require.NoError(t, err)
|
||||
sBlk2, err := consensusblocks.NewSignedBeaconBlock(blk2)
|
||||
require.NoError(t, err)
|
||||
blks := append([]interfaces.ReadOnlySignedBeaconBlock{sBlk0, sBlk1, sBlk2}, makeBlocks(t, 3, slotsPerEpoch*2-3, blk2Root)...)
|
||||
require.NoError(t, db.SaveBlocks(ctx, blks))
|
||||
|
||||
root, err := blks[slotsPerEpoch].Block().HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
cp := ðpb.Checkpoint{
|
||||
Epoch: 1,
|
||||
Root: root[:],
|
||||
}
|
||||
require.NoError(t, db.SaveFinalizedCheckpoint(ctx, cp))
|
||||
|
||||
for i := uint64(0); i <= slotsPerEpoch; i++ {
|
||||
root, err = blks[i].Block().HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
if i == 1 {
|
||||
assert.Equal(t, false, db.IsFinalizedBlock(ctx, root), "Block at index 1 was considered finalized, but should not have")
|
||||
} else {
|
||||
assert.Equal(t, true, db.IsFinalizedBlock(ctx, root), "Block at index %d was not considered finalized", i)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func makeBlocks(t *testing.T, i, n uint64, previousRoot [32]byte) []interfaces.ReadOnlySignedBeaconBlock {
|
||||
@ -219,24 +189,6 @@ func makeBlocks(t *testing.T, i, n uint64, previousRoot [32]byte) []interfaces.R
|
||||
return ifaceBlocks
|
||||
}
|
||||
|
||||
func makeBlocksAltair(t *testing.T, startIdx, num uint64, previousRoot [32]byte) []interfaces.ReadOnlySignedBeaconBlock {
|
||||
blocks := make([]*ethpb.SignedBeaconBlockAltair, num)
|
||||
ifaceBlocks := make([]interfaces.ReadOnlySignedBeaconBlock, num)
|
||||
for j := startIdx; j < num+startIdx; j++ {
|
||||
parentRoot := make([]byte, fieldparams.RootLength)
|
||||
copy(parentRoot, previousRoot[:])
|
||||
blocks[j-startIdx] = util.NewBeaconBlockAltair()
|
||||
blocks[j-startIdx].Block.Slot = primitives.Slot(j + 1)
|
||||
blocks[j-startIdx].Block.ParentRoot = parentRoot
|
||||
var err error
|
||||
previousRoot, err = blocks[j-startIdx].Block.HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
ifaceBlocks[j-startIdx], err = consensusblocks.NewSignedBeaconBlock(blocks[j-startIdx])
|
||||
require.NoError(t, err)
|
||||
}
|
||||
return ifaceBlocks
|
||||
}
|
||||
|
||||
func TestStore_BackfillFinalizedIndexSingle(t *testing.T) {
|
||||
db := setupDB(t)
|
||||
ctx := context.Background()
|
||||
|
@ -458,7 +458,7 @@ func (s *Store) DeleteState(ctx context.Context, blockRoot [32]byte) error {
|
||||
bkt = tx.Bucket(stateBucket)
|
||||
// Safeguard against deleting genesis, finalized, head state.
|
||||
if bytes.Equal(blockRoot[:], finalized.Root) || bytes.Equal(blockRoot[:], genesisBlockRoot) || bytes.Equal(blockRoot[:], justified.Root) {
|
||||
return ErrDeleteJustifiedAndFinalized
|
||||
return ErrDeleteFinalized
|
||||
}
|
||||
|
||||
// Nothing to delete if state doesn't exist.
|
||||
|
@ -189,7 +189,7 @@ func TestLoadBlocks_FirstBranch(t *testing.T) {
|
||||
roots, savedBlocks, err := tree1(t, beaconDB, bytesutil.PadTo([]byte{'A'}, 32))
|
||||
require.NoError(t, err)
|
||||
|
||||
filteredBlocks, err := s.loadBlocks(ctx, 0, 8, roots[len(roots)-1])
|
||||
filteredBlocks, err := s.loadBlocks(ctx, 0, 9, roots[len(roots)-1])
|
||||
require.NoError(t, err)
|
||||
|
||||
wanted := []*ethpb.SignedBeaconBlock{
|
||||
@ -220,7 +220,7 @@ func TestLoadBlocks_SecondBranch(t *testing.T) {
|
||||
roots, savedBlocks, err := tree1(t, beaconDB, bytesutil.PadTo([]byte{'A'}, 32))
|
||||
require.NoError(t, err)
|
||||
|
||||
filteredBlocks, err := s.loadBlocks(ctx, 0, 5, roots[5])
|
||||
filteredBlocks, err := s.loadBlocks(ctx, 0, 6, roots[5])
|
||||
require.NoError(t, err)
|
||||
|
||||
wanted := []*ethpb.SignedBeaconBlock{
|
||||
@ -249,7 +249,7 @@ func TestLoadBlocks_ThirdBranch(t *testing.T) {
|
||||
roots, savedBlocks, err := tree1(t, beaconDB, bytesutil.PadTo([]byte{'A'}, 32))
|
||||
require.NoError(t, err)
|
||||
|
||||
filteredBlocks, err := s.loadBlocks(ctx, 0, 7, roots[7])
|
||||
filteredBlocks, err := s.loadBlocks(ctx, 0, 8, roots[7])
|
||||
require.NoError(t, err)
|
||||
|
||||
wanted := []*ethpb.SignedBeaconBlock{
|
||||
@ -280,7 +280,7 @@ func TestLoadBlocks_SameSlots(t *testing.T) {
|
||||
roots, savedBlocks, err := tree2(t, beaconDB, bytesutil.PadTo([]byte{'A'}, 32))
|
||||
require.NoError(t, err)
|
||||
|
||||
filteredBlocks, err := s.loadBlocks(ctx, 0, 3, roots[6])
|
||||
filteredBlocks, err := s.loadBlocks(ctx, 0, 4, roots[6])
|
||||
require.NoError(t, err)
|
||||
|
||||
wanted := []*ethpb.SignedBeaconBlock{
|
||||
@ -309,7 +309,7 @@ func TestLoadBlocks_SameEndSlots(t *testing.T) {
|
||||
roots, savedBlocks, err := tree3(t, beaconDB, bytesutil.PadTo([]byte{'A'}, 32))
|
||||
require.NoError(t, err)
|
||||
|
||||
filteredBlocks, err := s.loadBlocks(ctx, 0, 2, roots[2])
|
||||
filteredBlocks, err := s.loadBlocks(ctx, 0, 3, roots[2])
|
||||
require.NoError(t, err)
|
||||
|
||||
wanted := []*ethpb.SignedBeaconBlock{
|
||||
@ -337,7 +337,7 @@ func TestLoadBlocks_SameEndSlotsWith2blocks(t *testing.T) {
|
||||
roots, savedBlocks, err := tree4(t, beaconDB, bytesutil.PadTo([]byte{'A'}, 32))
|
||||
require.NoError(t, err)
|
||||
|
||||
filteredBlocks, err := s.loadBlocks(ctx, 0, 2, roots[1])
|
||||
filteredBlocks, err := s.loadBlocks(ctx, 0, 3, roots[1])
|
||||
require.NoError(t, err)
|
||||
|
||||
wanted := []*ethpb.SignedBeaconBlock{
|
||||
@ -363,7 +363,7 @@ func TestLoadBlocks_BadStart(t *testing.T) {
|
||||
|
||||
roots, _, err := tree1(t, beaconDB, bytesutil.PadTo([]byte{'A'}, 32))
|
||||
require.NoError(t, err)
|
||||
_, err = s.loadBlocks(ctx, 0, 5, roots[8])
|
||||
_, err = s.loadBlocks(ctx, 0, 6, roots[8])
|
||||
assert.ErrorContains(t, "end block roots don't match", err)
|
||||
}
|
||||
|
||||
@ -374,63 +374,63 @@ func TestLoadBlocks_BadStart(t *testing.T) {
|
||||
// \- B7
|
||||
func tree1(t *testing.T, beaconDB db.Database, genesisRoot []byte) ([][32]byte, []*ethpb.SignedBeaconBlock, error) {
|
||||
b0 := util.NewBeaconBlock()
|
||||
b0.Block.Slot = 0
|
||||
b0.Block.Slot = 1
|
||||
b0.Block.ParentRoot = genesisRoot
|
||||
r0, err := b0.Block.HashTreeRoot()
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
b1 := util.NewBeaconBlock()
|
||||
b1.Block.Slot = 1
|
||||
b1.Block.Slot = 2
|
||||
b1.Block.ParentRoot = r0[:]
|
||||
r1, err := b1.Block.HashTreeRoot()
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
b2 := util.NewBeaconBlock()
|
||||
b2.Block.Slot = 2
|
||||
b2.Block.Slot = 3
|
||||
b2.Block.ParentRoot = r1[:]
|
||||
r2, err := b2.Block.HashTreeRoot()
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
b3 := util.NewBeaconBlock()
|
||||
b3.Block.Slot = 3
|
||||
b3.Block.Slot = 4
|
||||
b3.Block.ParentRoot = r1[:]
|
||||
r3, err := b3.Block.HashTreeRoot()
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
b4 := util.NewBeaconBlock()
|
||||
b4.Block.Slot = 4
|
||||
b4.Block.Slot = 5
|
||||
b4.Block.ParentRoot = r2[:]
|
||||
r4, err := b4.Block.HashTreeRoot()
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
b5 := util.NewBeaconBlock()
|
||||
b5.Block.Slot = 5
|
||||
b5.Block.Slot = 6
|
||||
b5.Block.ParentRoot = r3[:]
|
||||
r5, err := b5.Block.HashTreeRoot()
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
b6 := util.NewBeaconBlock()
|
||||
b6.Block.Slot = 6
|
||||
b6.Block.Slot = 7
|
||||
b6.Block.ParentRoot = r4[:]
|
||||
r6, err := b6.Block.HashTreeRoot()
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
b7 := util.NewBeaconBlock()
|
||||
b7.Block.Slot = 7
|
||||
b7.Block.Slot = 8
|
||||
b7.Block.ParentRoot = r6[:]
|
||||
r7, err := b7.Block.HashTreeRoot()
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
b8 := util.NewBeaconBlock()
|
||||
b8.Block.Slot = 8
|
||||
b8.Block.Slot = 9
|
||||
b8.Block.ParentRoot = r6[:]
|
||||
r8, err := b8.Block.HashTreeRoot()
|
||||
if err != nil {
|
||||
@ -466,21 +466,21 @@ func tree1(t *testing.T, beaconDB db.Database, genesisRoot []byte) ([][32]byte,
|
||||
// \- B2 -- B3
|
||||
func tree2(t *testing.T, beaconDB db.Database, genesisRoot []byte) ([][32]byte, []*ethpb.SignedBeaconBlock, error) {
|
||||
b0 := util.NewBeaconBlock()
|
||||
b0.Block.Slot = 0
|
||||
b0.Block.Slot = 1
|
||||
b0.Block.ParentRoot = genesisRoot
|
||||
r0, err := b0.Block.HashTreeRoot()
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
b1 := util.NewBeaconBlock()
|
||||
b1.Block.Slot = 1
|
||||
b1.Block.Slot = 2
|
||||
b1.Block.ParentRoot = r0[:]
|
||||
r1, err := b1.Block.HashTreeRoot()
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
b21 := util.NewBeaconBlock()
|
||||
b21.Block.Slot = 2
|
||||
b21.Block.Slot = 3
|
||||
b21.Block.ParentRoot = r1[:]
|
||||
b21.Block.StateRoot = bytesutil.PadTo([]byte{'A'}, 32)
|
||||
r21, err := b21.Block.HashTreeRoot()
|
||||
@ -488,7 +488,7 @@ func tree2(t *testing.T, beaconDB db.Database, genesisRoot []byte) ([][32]byte,
|
||||
return nil, nil, err
|
||||
}
|
||||
b22 := util.NewBeaconBlock()
|
||||
b22.Block.Slot = 2
|
||||
b22.Block.Slot = 3
|
||||
b22.Block.ParentRoot = r1[:]
|
||||
b22.Block.StateRoot = bytesutil.PadTo([]byte{'B'}, 32)
|
||||
r22, err := b22.Block.HashTreeRoot()
|
||||
@ -496,7 +496,7 @@ func tree2(t *testing.T, beaconDB db.Database, genesisRoot []byte) ([][32]byte,
|
||||
return nil, nil, err
|
||||
}
|
||||
b23 := util.NewBeaconBlock()
|
||||
b23.Block.Slot = 2
|
||||
b23.Block.Slot = 3
|
||||
b23.Block.ParentRoot = r1[:]
|
||||
b23.Block.StateRoot = bytesutil.PadTo([]byte{'C'}, 32)
|
||||
r23, err := b23.Block.HashTreeRoot()
|
||||
@ -504,7 +504,7 @@ func tree2(t *testing.T, beaconDB db.Database, genesisRoot []byte) ([][32]byte,
|
||||
return nil, nil, err
|
||||
}
|
||||
b24 := util.NewBeaconBlock()
|
||||
b24.Block.Slot = 2
|
||||
b24.Block.Slot = 3
|
||||
b24.Block.ParentRoot = r1[:]
|
||||
b24.Block.StateRoot = bytesutil.PadTo([]byte{'D'}, 32)
|
||||
r24, err := b24.Block.HashTreeRoot()
|
||||
@ -512,7 +512,7 @@ func tree2(t *testing.T, beaconDB db.Database, genesisRoot []byte) ([][32]byte,
|
||||
return nil, nil, err
|
||||
}
|
||||
b3 := util.NewBeaconBlock()
|
||||
b3.Block.Slot = 3
|
||||
b3.Block.Slot = 4
|
||||
b3.Block.ParentRoot = r24[:]
|
||||
r3, err := b3.Block.HashTreeRoot()
|
||||
if err != nil {
|
||||
@ -549,21 +549,21 @@ func tree2(t *testing.T, beaconDB db.Database, genesisRoot []byte) ([][32]byte,
|
||||
// \- B2
|
||||
func tree3(t *testing.T, beaconDB db.Database, genesisRoot []byte) ([][32]byte, []*ethpb.SignedBeaconBlock, error) {
|
||||
b0 := util.NewBeaconBlock()
|
||||
b0.Block.Slot = 0
|
||||
b0.Block.Slot = 1
|
||||
b0.Block.ParentRoot = genesisRoot
|
||||
r0, err := b0.Block.HashTreeRoot()
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
b1 := util.NewBeaconBlock()
|
||||
b1.Block.Slot = 1
|
||||
b1.Block.Slot = 2
|
||||
b1.Block.ParentRoot = r0[:]
|
||||
r1, err := b1.Block.HashTreeRoot()
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
b21 := util.NewBeaconBlock()
|
||||
b21.Block.Slot = 2
|
||||
b21.Block.Slot = 3
|
||||
b21.Block.ParentRoot = r1[:]
|
||||
b21.Block.StateRoot = bytesutil.PadTo([]byte{'A'}, 32)
|
||||
r21, err := b21.Block.HashTreeRoot()
|
||||
@ -571,7 +571,7 @@ func tree3(t *testing.T, beaconDB db.Database, genesisRoot []byte) ([][32]byte,
|
||||
return nil, nil, err
|
||||
}
|
||||
b22 := util.NewBeaconBlock()
|
||||
b22.Block.Slot = 2
|
||||
b22.Block.Slot = 3
|
||||
b22.Block.ParentRoot = r1[:]
|
||||
b22.Block.StateRoot = bytesutil.PadTo([]byte{'B'}, 32)
|
||||
r22, err := b22.Block.HashTreeRoot()
|
||||
@ -579,7 +579,7 @@ func tree3(t *testing.T, beaconDB db.Database, genesisRoot []byte) ([][32]byte,
|
||||
return nil, nil, err
|
||||
}
|
||||
b23 := util.NewBeaconBlock()
|
||||
b23.Block.Slot = 2
|
||||
b23.Block.Slot = 3
|
||||
b23.Block.ParentRoot = r1[:]
|
||||
b23.Block.StateRoot = bytesutil.PadTo([]byte{'C'}, 32)
|
||||
r23, err := b23.Block.HashTreeRoot()
|
||||
@ -587,7 +587,7 @@ func tree3(t *testing.T, beaconDB db.Database, genesisRoot []byte) ([][32]byte,
|
||||
return nil, nil, err
|
||||
}
|
||||
b24 := util.NewBeaconBlock()
|
||||
b24.Block.Slot = 2
|
||||
b24.Block.Slot = 3
|
||||
b24.Block.ParentRoot = r1[:]
|
||||
b24.Block.StateRoot = bytesutil.PadTo([]byte{'D'}, 32)
|
||||
r24, err := b24.Block.HashTreeRoot()
|
||||
@ -626,14 +626,14 @@ func tree3(t *testing.T, beaconDB db.Database, genesisRoot []byte) ([][32]byte,
|
||||
// \- B2
|
||||
func tree4(t *testing.T, beaconDB db.Database, genesisRoot []byte) ([][32]byte, []*ethpb.SignedBeaconBlock, error) {
|
||||
b0 := util.NewBeaconBlock()
|
||||
b0.Block.Slot = 0
|
||||
b0.Block.Slot = 1
|
||||
b0.Block.ParentRoot = genesisRoot
|
||||
r0, err := b0.Block.HashTreeRoot()
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
b21 := util.NewBeaconBlock()
|
||||
b21.Block.Slot = 2
|
||||
b21.Block.Slot = 3
|
||||
b21.Block.ParentRoot = r0[:]
|
||||
b21.Block.StateRoot = bytesutil.PadTo([]byte{'A'}, 32)
|
||||
r21, err := b21.Block.HashTreeRoot()
|
||||
@ -641,7 +641,7 @@ func tree4(t *testing.T, beaconDB db.Database, genesisRoot []byte) ([][32]byte,
|
||||
return nil, nil, err
|
||||
}
|
||||
b22 := util.NewBeaconBlock()
|
||||
b22.Block.Slot = 2
|
||||
b22.Block.Slot = 3
|
||||
b22.Block.ParentRoot = r0[:]
|
||||
b22.Block.StateRoot = bytesutil.PadTo([]byte{'B'}, 32)
|
||||
r22, err := b22.Block.HashTreeRoot()
|
||||
@ -649,7 +649,7 @@ func tree4(t *testing.T, beaconDB db.Database, genesisRoot []byte) ([][32]byte,
|
||||
return nil, nil, err
|
||||
}
|
||||
b23 := util.NewBeaconBlock()
|
||||
b23.Block.Slot = 2
|
||||
b23.Block.Slot = 3
|
||||
b23.Block.ParentRoot = r0[:]
|
||||
b23.Block.StateRoot = bytesutil.PadTo([]byte{'C'}, 32)
|
||||
r23, err := b23.Block.HashTreeRoot()
|
||||
@ -657,7 +657,7 @@ func tree4(t *testing.T, beaconDB db.Database, genesisRoot []byte) ([][32]byte,
|
||||
return nil, nil, err
|
||||
}
|
||||
b24 := util.NewBeaconBlock()
|
||||
b24.Block.Slot = 2
|
||||
b24.Block.Slot = 3
|
||||
b24.Block.ParentRoot = r0[:]
|
||||
b24.Block.StateRoot = bytesutil.PadTo([]byte{'D'}, 32)
|
||||
r24, err := b24.Block.HashTreeRoot()
|
||||
@ -697,17 +697,17 @@ func TestLoadFinalizedBlocks(t *testing.T) {
|
||||
gRoot, err := gBlock.Block.HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
util.SaveBlock(t, ctx, beaconDB, gBlock)
|
||||
require.NoError(t, beaconDB.SaveGenesisBlockRoot(ctx, [32]byte{}))
|
||||
require.NoError(t, beaconDB.SaveGenesisBlockRoot(ctx, gRoot))
|
||||
roots, _, err := tree1(t, beaconDB, gRoot[:])
|
||||
require.NoError(t, err)
|
||||
|
||||
filteredBlocks, err := s.loadFinalizedBlocks(ctx, 0, 8)
|
||||
filteredBlocks, err := s.loadFinalizedBlocks(ctx, 0, 9)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, 0, len(filteredBlocks))
|
||||
require.Equal(t, 1, len(filteredBlocks))
|
||||
require.NoError(t, beaconDB.SaveStateSummary(ctx, ðpb.StateSummary{Root: roots[8][:]}))
|
||||
|
||||
require.NoError(t, s.beaconDB.SaveFinalizedCheckpoint(ctx, ðpb.Checkpoint{Root: roots[8][:]}))
|
||||
filteredBlocks, err = s.loadFinalizedBlocks(ctx, 0, 8)
|
||||
filteredBlocks, err = s.loadFinalizedBlocks(ctx, 0, 9)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, 10, len(filteredBlocks))
|
||||
require.Equal(t, 7, len(filteredBlocks))
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user