github.com/prysmaticlabs/prysm@v1.4.4/beacon-chain/db/kv/blocks_test.go (about)

     1  package kv
     2  
     3  import (
     4  	"context"
     5  	"sort"
     6  	"testing"
     7  
     8  	types "github.com/prysmaticlabs/eth2-types"
     9  	"github.com/prysmaticlabs/prysm/beacon-chain/db/filters"
    10  	ethpb "github.com/prysmaticlabs/prysm/proto/eth/v1alpha1"
    11  	"github.com/prysmaticlabs/prysm/proto/eth/v1alpha1/wrapper"
    12  	"github.com/prysmaticlabs/prysm/proto/interfaces"
    13  	"github.com/prysmaticlabs/prysm/shared/bytesutil"
    14  	"github.com/prysmaticlabs/prysm/shared/params"
    15  	"github.com/prysmaticlabs/prysm/shared/testutil"
    16  	"github.com/prysmaticlabs/prysm/shared/testutil/assert"
    17  	"github.com/prysmaticlabs/prysm/shared/testutil/require"
    18  	"google.golang.org/protobuf/proto"
    19  )
    20  
    21  func TestStore_SaveBlock_NoDuplicates(t *testing.T) {
    22  	BlockCacheSize = 1
    23  	db := setupDB(t)
    24  	slot := types.Slot(20)
    25  	ctx := context.Background()
    26  	// First we save a previous block to ensure the cache max size is reached.
    27  	prevBlock := testutil.NewBeaconBlock()
    28  	prevBlock.Block.Slot = slot - 1
    29  	prevBlock.Block.ParentRoot = bytesutil.PadTo([]byte{1, 2, 3}, 32)
    30  	require.NoError(t, db.SaveBlock(ctx, wrapper.WrappedPhase0SignedBeaconBlock(prevBlock)))
    31  
    32  	block := testutil.NewBeaconBlock()
    33  	block.Block.Slot = slot
    34  	block.Block.ParentRoot = bytesutil.PadTo([]byte{1, 2, 3}, 32)
    35  	// Even with a full cache, saving new blocks should not cause
    36  	// duplicated blocks in the DB.
    37  	for i := 0; i < 100; i++ {
    38  		require.NoError(t, db.SaveBlock(ctx, wrapper.WrappedPhase0SignedBeaconBlock(block)))
    39  	}
    40  	f := filters.NewFilter().SetStartSlot(slot).SetEndSlot(slot)
    41  	retrieved, _, err := db.Blocks(ctx, f)
    42  	require.NoError(t, err)
    43  	assert.Equal(t, 1, len(retrieved))
    44  	// We reset the block cache size.
    45  	BlockCacheSize = 256
    46  }
    47  
    48  func TestStore_BlocksCRUD(t *testing.T) {
    49  	db := setupDB(t)
    50  	ctx := context.Background()
    51  
    52  	block := testutil.NewBeaconBlock()
    53  	block.Block.Slot = 20
    54  	block.Block.ParentRoot = bytesutil.PadTo([]byte{1, 2, 3}, 32)
    55  
    56  	blockRoot, err := block.Block.HashTreeRoot()
    57  	require.NoError(t, err)
    58  	retrievedBlock, err := db.Block(ctx, blockRoot)
    59  	require.NoError(t, err)
    60  	assert.DeepEqual(t, (*ethpb.SignedBeaconBlock)(nil), retrievedBlock.Proto(), "Expected nil block")
    61  	require.NoError(t, db.SaveBlock(ctx, wrapper.WrappedPhase0SignedBeaconBlock(block)))
    62  	assert.Equal(t, true, db.HasBlock(ctx, blockRoot), "Expected block to exist in the db")
    63  	retrievedBlock, err = db.Block(ctx, blockRoot)
    64  	require.NoError(t, err)
    65  	assert.Equal(t, true, proto.Equal(block, retrievedBlock.Proto()), "Wanted: %v, received: %v", block, retrievedBlock)
    66  	require.NoError(t, db.deleteBlock(ctx, blockRoot))
    67  	assert.Equal(t, false, db.HasBlock(ctx, blockRoot), "Expected block to have been deleted from the db")
    68  }
    69  
    70  func TestStore_BlocksBatchDelete(t *testing.T) {
    71  	db := setupDB(t)
    72  	ctx := context.Background()
    73  	numBlocks := 10
    74  	totalBlocks := make([]interfaces.SignedBeaconBlock, numBlocks)
    75  	blockRoots := make([][32]byte, 0)
    76  	oddBlocks := make([]interfaces.SignedBeaconBlock, 0)
    77  	for i := 0; i < len(totalBlocks); i++ {
    78  		b := testutil.NewBeaconBlock()
    79  		b.Block.Slot = types.Slot(i)
    80  		b.Block.ParentRoot = bytesutil.PadTo([]byte("parent"), 32)
    81  		totalBlocks[i] = wrapper.WrappedPhase0SignedBeaconBlock(b)
    82  		if i%2 == 0 {
    83  			r, err := totalBlocks[i].Block().HashTreeRoot()
    84  			require.NoError(t, err)
    85  			blockRoots = append(blockRoots, r)
    86  		} else {
    87  			oddBlocks = append(oddBlocks, totalBlocks[i])
    88  		}
    89  	}
    90  	require.NoError(t, db.SaveBlocks(ctx, totalBlocks))
    91  	retrieved, _, err := db.Blocks(ctx, filters.NewFilter().SetParentRoot(bytesutil.PadTo([]byte("parent"), 32)))
    92  	require.NoError(t, err)
    93  	assert.Equal(t, numBlocks, len(retrieved), "Unexpected number of blocks received")
    94  	// We delete all even indexed blocks.
    95  	require.NoError(t, db.deleteBlocks(ctx, blockRoots))
    96  	// When we retrieve the data, only the odd indexed blocks should remain.
    97  	retrieved, _, err = db.Blocks(ctx, filters.NewFilter().SetParentRoot(bytesutil.PadTo([]byte("parent"), 32)))
    98  	require.NoError(t, err)
    99  	sort.Slice(retrieved, func(i, j int) bool {
   100  		return retrieved[i].Block().Slot() < retrieved[j].Block().Slot()
   101  	})
   102  	for i, block := range retrieved {
   103  		assert.Equal(t, true, proto.Equal(block.Proto(), oddBlocks[i].Proto()), "Wanted: %v, received: %v", block, oddBlocks[i])
   104  	}
   105  }
   106  
   107  func TestStore_BlocksHandleZeroCase(t *testing.T) {
   108  	db := setupDB(t)
   109  	ctx := context.Background()
   110  	numBlocks := 10
   111  	totalBlocks := make([]interfaces.SignedBeaconBlock, numBlocks)
   112  	for i := 0; i < len(totalBlocks); i++ {
   113  		b := testutil.NewBeaconBlock()
   114  		b.Block.Slot = types.Slot(i)
   115  		b.Block.ParentRoot = bytesutil.PadTo([]byte("parent"), 32)
   116  		totalBlocks[i] = wrapper.WrappedPhase0SignedBeaconBlock(b)
   117  		_, err := totalBlocks[i].Block().HashTreeRoot()
   118  		require.NoError(t, err)
   119  	}
   120  	require.NoError(t, db.SaveBlocks(ctx, totalBlocks))
   121  	zeroFilter := filters.NewFilter().SetStartSlot(0).SetEndSlot(0)
   122  	retrieved, _, err := db.Blocks(ctx, zeroFilter)
   123  	require.NoError(t, err)
   124  	assert.Equal(t, 1, len(retrieved), "Unexpected number of blocks received, expected one")
   125  }
   126  
   127  func TestStore_BlocksHandleInvalidEndSlot(t *testing.T) {
   128  	db := setupDB(t)
   129  	ctx := context.Background()
   130  	numBlocks := 10
   131  	totalBlocks := make([]interfaces.SignedBeaconBlock, numBlocks)
   132  	// Save blocks from slot 1 onwards.
   133  	for i := 0; i < len(totalBlocks); i++ {
   134  		b := testutil.NewBeaconBlock()
   135  		b.Block.Slot = types.Slot(i) + 1
   136  		b.Block.ParentRoot = bytesutil.PadTo([]byte("parent"), 32)
   137  		totalBlocks[i] = wrapper.WrappedPhase0SignedBeaconBlock(b)
   138  		_, err := totalBlocks[i].Block().HashTreeRoot()
   139  		require.NoError(t, err)
   140  	}
   141  	require.NoError(t, db.SaveBlocks(ctx, totalBlocks))
   142  	badFilter := filters.NewFilter().SetStartSlot(5).SetEndSlot(1)
   143  	_, _, err := db.Blocks(ctx, badFilter)
   144  	require.ErrorContains(t, errInvalidSlotRange.Error(), err)
   145  
   146  	goodFilter := filters.NewFilter().SetStartSlot(0).SetEndSlot(1)
   147  	requested, _, err := db.Blocks(ctx, goodFilter)
   148  	require.NoError(t, err)
   149  	assert.Equal(t, 1, len(requested), "Unexpected number of blocks received, only expected two")
   150  }
   151  
   152  func TestStore_GenesisBlock(t *testing.T) {
   153  	db := setupDB(t)
   154  	ctx := context.Background()
   155  	genesisBlock := testutil.NewBeaconBlock()
   156  	genesisBlock.Block.ParentRoot = bytesutil.PadTo([]byte{1, 2, 3}, 32)
   157  	blockRoot, err := genesisBlock.Block.HashTreeRoot()
   158  	require.NoError(t, err)
   159  	require.NoError(t, db.SaveGenesisBlockRoot(ctx, blockRoot))
   160  	require.NoError(t, db.SaveBlock(ctx, wrapper.WrappedPhase0SignedBeaconBlock(genesisBlock)))
   161  	retrievedBlock, err := db.GenesisBlock(ctx)
   162  	require.NoError(t, err)
   163  	assert.Equal(t, true, proto.Equal(genesisBlock, retrievedBlock.Proto()), "Wanted: %v, received: %v", genesisBlock, retrievedBlock)
   164  }
   165  
   166  func TestStore_BlocksCRUD_NoCache(t *testing.T) {
   167  	db := setupDB(t)
   168  	ctx := context.Background()
   169  	block := testutil.NewBeaconBlock()
   170  	block.Block.Slot = 20
   171  	block.Block.ParentRoot = bytesutil.PadTo([]byte{1, 2, 3}, 32)
   172  	blockRoot, err := block.Block.HashTreeRoot()
   173  	require.NoError(t, err)
   174  	retrievedBlock, err := db.Block(ctx, blockRoot)
   175  	require.NoError(t, err)
   176  	require.DeepEqual(t, (*ethpb.SignedBeaconBlock)(nil), retrievedBlock.Proto(), "Expected nil block")
   177  	require.NoError(t, db.SaveBlock(ctx, wrapper.WrappedPhase0SignedBeaconBlock(block)))
   178  	db.blockCache.Del(string(blockRoot[:]))
   179  	assert.Equal(t, true, db.HasBlock(ctx, blockRoot), "Expected block to exist in the db")
   180  	retrievedBlock, err = db.Block(ctx, blockRoot)
   181  	require.NoError(t, err)
   182  	assert.Equal(t, true, proto.Equal(block, retrievedBlock.Proto()), "Wanted: %v, received: %v", block, retrievedBlock)
   183  	require.NoError(t, db.deleteBlock(ctx, blockRoot))
   184  	assert.Equal(t, false, db.HasBlock(ctx, blockRoot), "Expected block to have been deleted from the db")
   185  }
   186  
   187  func TestStore_Blocks_FiltersCorrectly(t *testing.T) {
   188  	db := setupDB(t)
   189  	b4 := testutil.NewBeaconBlock()
   190  	b4.Block.Slot = 4
   191  	b4.Block.ParentRoot = bytesutil.PadTo([]byte("parent"), 32)
   192  	b5 := testutil.NewBeaconBlock()
   193  	b5.Block.Slot = 5
   194  	b5.Block.ParentRoot = bytesutil.PadTo([]byte("parent2"), 32)
   195  	b6 := testutil.NewBeaconBlock()
   196  	b6.Block.Slot = 6
   197  	b6.Block.ParentRoot = bytesutil.PadTo([]byte("parent2"), 32)
   198  	b7 := testutil.NewBeaconBlock()
   199  	b7.Block.Slot = 7
   200  	b7.Block.ParentRoot = bytesutil.PadTo([]byte("parent3"), 32)
   201  	b8 := testutil.NewBeaconBlock()
   202  	b8.Block.Slot = 8
   203  	b8.Block.ParentRoot = bytesutil.PadTo([]byte("parent4"), 32)
   204  	blocks := []interfaces.SignedBeaconBlock{
   205  		wrapper.WrappedPhase0SignedBeaconBlock(b4),
   206  		wrapper.WrappedPhase0SignedBeaconBlock(b5),
   207  		wrapper.WrappedPhase0SignedBeaconBlock(b6),
   208  		wrapper.WrappedPhase0SignedBeaconBlock(b7),
   209  		wrapper.WrappedPhase0SignedBeaconBlock(b8),
   210  	}
   211  	ctx := context.Background()
   212  	require.NoError(t, db.SaveBlocks(ctx, blocks))
   213  
   214  	tests := []struct {
   215  		filter            *filters.QueryFilter
   216  		expectedNumBlocks int
   217  	}{
   218  		{
   219  			filter:            filters.NewFilter().SetParentRoot(bytesutil.PadTo([]byte("parent2"), 32)),
   220  			expectedNumBlocks: 2,
   221  		},
   222  		{
   223  			// No block meets the criteria below.
   224  			filter:            filters.NewFilter().SetParentRoot(bytesutil.PadTo([]byte{3, 4, 5}, 32)),
   225  			expectedNumBlocks: 0,
   226  		},
   227  		{
   228  			// Block slot range filter criteria.
   229  			filter:            filters.NewFilter().SetStartSlot(5).SetEndSlot(7),
   230  			expectedNumBlocks: 3,
   231  		},
   232  		{
   233  			filter:            filters.NewFilter().SetStartSlot(7).SetEndSlot(7),
   234  			expectedNumBlocks: 1,
   235  		},
   236  		{
   237  			filter:            filters.NewFilter().SetStartSlot(4).SetEndSlot(8),
   238  			expectedNumBlocks: 5,
   239  		},
   240  		{
   241  			filter:            filters.NewFilter().SetStartSlot(4).SetEndSlot(5),
   242  			expectedNumBlocks: 2,
   243  		},
   244  		{
   245  			filter:            filters.NewFilter().SetStartSlot(5).SetEndSlot(9),
   246  			expectedNumBlocks: 4,
   247  		},
   248  		{
   249  			filter:            filters.NewFilter().SetEndSlot(7),
   250  			expectedNumBlocks: 4,
   251  		},
   252  		{
   253  			filter:            filters.NewFilter().SetEndSlot(8),
   254  			expectedNumBlocks: 5,
   255  		},
   256  		{
   257  			filter:            filters.NewFilter().SetStartSlot(5).SetEndSlot(10),
   258  			expectedNumBlocks: 4,
   259  		},
   260  		{
   261  			// Composite filter criteria.
   262  			filter: filters.NewFilter().
   263  				SetParentRoot(bytesutil.PadTo([]byte("parent2"), 32)).
   264  				SetStartSlot(6).
   265  				SetEndSlot(8),
   266  			expectedNumBlocks: 1,
   267  		},
   268  	}
   269  	for _, tt := range tests {
   270  		retrievedBlocks, _, err := db.Blocks(ctx, tt.filter)
   271  		require.NoError(t, err)
   272  		assert.Equal(t, tt.expectedNumBlocks, len(retrievedBlocks), "Unexpected number of blocks")
   273  	}
   274  }
   275  
   276  func TestStore_Blocks_VerifyBlockRoots(t *testing.T) {
   277  	ctx := context.Background()
   278  	db := setupDB(t)
   279  	b1 := testutil.NewBeaconBlock()
   280  	b1.Block.Slot = 1
   281  	r1, err := b1.Block.HashTreeRoot()
   282  	require.NoError(t, err)
   283  	b2 := testutil.NewBeaconBlock()
   284  	b2.Block.Slot = 2
   285  	r2, err := b2.Block.HashTreeRoot()
   286  	require.NoError(t, err)
   287  
   288  	require.NoError(t, db.SaveBlock(ctx, wrapper.WrappedPhase0SignedBeaconBlock(b1)))
   289  	require.NoError(t, db.SaveBlock(ctx, wrapper.WrappedPhase0SignedBeaconBlock(b2)))
   290  
   291  	filter := filters.NewFilter().SetStartSlot(b1.Block.Slot).SetEndSlot(b2.Block.Slot)
   292  	roots, err := db.BlockRoots(ctx, filter)
   293  	require.NoError(t, err)
   294  
   295  	assert.DeepEqual(t, [][32]byte{r1, r2}, roots)
   296  }
   297  
   298  func TestStore_Blocks_Retrieve_SlotRange(t *testing.T) {
   299  	db := setupDB(t)
   300  	totalBlocks := make([]interfaces.SignedBeaconBlock, 500)
   301  	for i := 0; i < 500; i++ {
   302  		b := testutil.NewBeaconBlock()
   303  		b.Block.Slot = types.Slot(i)
   304  		b.Block.ParentRoot = bytesutil.PadTo([]byte("parent"), 32)
   305  		totalBlocks[i] = wrapper.WrappedPhase0SignedBeaconBlock(b)
   306  	}
   307  	ctx := context.Background()
   308  	require.NoError(t, db.SaveBlocks(ctx, totalBlocks))
   309  	retrieved, _, err := db.Blocks(ctx, filters.NewFilter().SetStartSlot(100).SetEndSlot(399))
   310  	require.NoError(t, err)
   311  	assert.Equal(t, 300, len(retrieved))
   312  }
   313  
   314  func TestStore_Blocks_Retrieve_Epoch(t *testing.T) {
   315  	db := setupDB(t)
   316  	slots := params.BeaconConfig().SlotsPerEpoch.Mul(7)
   317  	totalBlocks := make([]interfaces.SignedBeaconBlock, slots)
   318  	for i := types.Slot(0); i < slots; i++ {
   319  		b := testutil.NewBeaconBlock()
   320  		b.Block.Slot = i
   321  		b.Block.ParentRoot = bytesutil.PadTo([]byte("parent"), 32)
   322  		totalBlocks[i] = wrapper.WrappedPhase0SignedBeaconBlock(b)
   323  	}
   324  	ctx := context.Background()
   325  	require.NoError(t, db.SaveBlocks(ctx, totalBlocks))
   326  	retrieved, _, err := db.Blocks(ctx, filters.NewFilter().SetStartEpoch(5).SetEndEpoch(6))
   327  	require.NoError(t, err)
   328  	want := params.BeaconConfig().SlotsPerEpoch.Mul(2)
   329  	assert.Equal(t, uint64(want), uint64(len(retrieved)))
   330  	retrieved, _, err = db.Blocks(ctx, filters.NewFilter().SetStartEpoch(0).SetEndEpoch(0))
   331  	require.NoError(t, err)
   332  	want = params.BeaconConfig().SlotsPerEpoch
   333  	assert.Equal(t, uint64(want), uint64(len(retrieved)))
   334  }
   335  
   336  func TestStore_Blocks_Retrieve_SlotRangeWithStep(t *testing.T) {
   337  	db := setupDB(t)
   338  	totalBlocks := make([]interfaces.SignedBeaconBlock, 500)
   339  	for i := 0; i < 500; i++ {
   340  		b := testutil.NewBeaconBlock()
   341  		b.Block.Slot = types.Slot(i)
   342  		b.Block.ParentRoot = bytesutil.PadTo([]byte("parent"), 32)
   343  		totalBlocks[i] = wrapper.WrappedPhase0SignedBeaconBlock(b)
   344  	}
   345  	const step = 2
   346  	ctx := context.Background()
   347  	require.NoError(t, db.SaveBlocks(ctx, totalBlocks))
   348  	retrieved, _, err := db.Blocks(ctx, filters.NewFilter().SetStartSlot(100).SetEndSlot(399).SetSlotStep(step))
   349  	require.NoError(t, err)
   350  	assert.Equal(t, 150, len(retrieved))
   351  	for _, b := range retrieved {
   352  		assert.Equal(t, types.Slot(0), (b.Block().Slot()-100)%step, "Unexpect block slot %d", b.Block().Slot())
   353  	}
   354  }
   355  
   356  func TestStore_SaveBlock_CanGetHighestAt(t *testing.T) {
   357  	db := setupDB(t)
   358  	ctx := context.Background()
   359  
   360  	block1 := testutil.NewBeaconBlock()
   361  	block1.Block.Slot = 1
   362  	require.NoError(t, db.SaveBlock(ctx, wrapper.WrappedPhase0SignedBeaconBlock(block1)))
   363  	block2 := testutil.NewBeaconBlock()
   364  	block2.Block.Slot = 10
   365  	require.NoError(t, db.SaveBlock(ctx, wrapper.WrappedPhase0SignedBeaconBlock(block2)))
   366  	block3 := testutil.NewBeaconBlock()
   367  	block3.Block.Slot = 100
   368  	require.NoError(t, db.SaveBlock(ctx, wrapper.WrappedPhase0SignedBeaconBlock(block3)))
   369  
   370  	highestAt, err := db.HighestSlotBlocksBelow(ctx, 2)
   371  	require.NoError(t, err)
   372  	assert.Equal(t, false, len(highestAt) <= 0, "Got empty highest at slice")
   373  	assert.Equal(t, true, proto.Equal(block1, highestAt[0].Proto()), "Wanted: %v, received: %v", block1, highestAt[0])
   374  	highestAt, err = db.HighestSlotBlocksBelow(ctx, 11)
   375  	require.NoError(t, err)
   376  	assert.Equal(t, false, len(highestAt) <= 0, "Got empty highest at slice")
   377  	assert.Equal(t, true, proto.Equal(block2, highestAt[0].Proto()), "Wanted: %v, received: %v", block2, highestAt[0])
   378  	highestAt, err = db.HighestSlotBlocksBelow(ctx, 101)
   379  	require.NoError(t, err)
   380  	assert.Equal(t, false, len(highestAt) <= 0, "Got empty highest at slice")
   381  	assert.Equal(t, true, proto.Equal(block3, highestAt[0].Proto()), "Wanted: %v, received: %v", block3, highestAt[0])
   382  
   383  	r3, err := block3.Block.HashTreeRoot()
   384  	require.NoError(t, err)
   385  	require.NoError(t, db.deleteBlock(ctx, r3))
   386  
   387  	highestAt, err = db.HighestSlotBlocksBelow(ctx, 101)
   388  	require.NoError(t, err)
   389  	assert.Equal(t, true, proto.Equal(block2, highestAt[0].Proto()), "Wanted: %v, received: %v", block2, highestAt[0])
   390  }
   391  
   392  func TestStore_GenesisBlock_CanGetHighestAt(t *testing.T) {
   393  	db := setupDB(t)
   394  	ctx := context.Background()
   395  
   396  	genesisBlock := testutil.NewBeaconBlock()
   397  	genesisRoot, err := genesisBlock.Block.HashTreeRoot()
   398  	require.NoError(t, err)
   399  	require.NoError(t, db.SaveGenesisBlockRoot(ctx, genesisRoot))
   400  	require.NoError(t, db.SaveBlock(ctx, wrapper.WrappedPhase0SignedBeaconBlock(genesisBlock)))
   401  	block1 := testutil.NewBeaconBlock()
   402  	block1.Block.Slot = 1
   403  	require.NoError(t, db.SaveBlock(ctx, wrapper.WrappedPhase0SignedBeaconBlock(block1)))
   404  
   405  	highestAt, err := db.HighestSlotBlocksBelow(ctx, 2)
   406  	require.NoError(t, err)
   407  	assert.Equal(t, true, proto.Equal(block1, highestAt[0].Proto()), "Wanted: %v, received: %v", block1, highestAt[0])
   408  	highestAt, err = db.HighestSlotBlocksBelow(ctx, 1)
   409  	require.NoError(t, err)
   410  	assert.Equal(t, true, proto.Equal(genesisBlock, highestAt[0].Proto()), "Wanted: %v, received: %v", genesisBlock, highestAt[0])
   411  	highestAt, err = db.HighestSlotBlocksBelow(ctx, 0)
   412  	require.NoError(t, err)
   413  	assert.Equal(t, true, proto.Equal(genesisBlock, highestAt[0].Proto()), "Wanted: %v, received: %v", genesisBlock, highestAt[0])
   414  }
   415  
   416  func TestStore_SaveBlocks_HasCachedBlocks(t *testing.T) {
   417  	db := setupDB(t)
   418  	ctx := context.Background()
   419  
   420  	b := make([]interfaces.SignedBeaconBlock, 500)
   421  	for i := 0; i < 500; i++ {
   422  		blk := testutil.NewBeaconBlock()
   423  		blk.Block.ParentRoot = bytesutil.PadTo([]byte("parent"), 32)
   424  		blk.Block.Slot = types.Slot(i)
   425  		b[i] = wrapper.WrappedPhase0SignedBeaconBlock(blk)
   426  	}
   427  
   428  	require.NoError(t, db.SaveBlock(ctx, b[0]))
   429  	require.NoError(t, db.SaveBlocks(ctx, b))
   430  	f := filters.NewFilter().SetStartSlot(0).SetEndSlot(500)
   431  
   432  	blks, _, err := db.Blocks(ctx, f)
   433  	require.NoError(t, err)
   434  	assert.Equal(t, 500, len(blks), "Did not get wanted blocks")
   435  }
   436  
   437  func TestStore_SaveBlocks_HasRootsMatched(t *testing.T) {
   438  	db := setupDB(t)
   439  	ctx := context.Background()
   440  
   441  	b := make([]interfaces.SignedBeaconBlock, 500)
   442  	for i := 0; i < 500; i++ {
   443  		blk := testutil.NewBeaconBlock()
   444  		blk.Block.ParentRoot = bytesutil.PadTo([]byte("parent"), 32)
   445  		blk.Block.Slot = types.Slot(i)
   446  		b[i] = wrapper.WrappedPhase0SignedBeaconBlock(blk)
   447  	}
   448  
   449  	require.NoError(t, db.SaveBlocks(ctx, b))
   450  	f := filters.NewFilter().SetStartSlot(0).SetEndSlot(500)
   451  
   452  	blks, roots, err := db.Blocks(ctx, f)
   453  	require.NoError(t, err)
   454  	assert.Equal(t, 500, len(blks), "Did not get wanted blocks")
   455  
   456  	for i, blk := range blks {
   457  		rt, err := blk.Block().HashTreeRoot()
   458  		require.NoError(t, err)
   459  		assert.Equal(t, roots[i], rt, "mismatch of block roots")
   460  	}
   461  }
   462  
   463  func TestStore_BlocksBySlot_BlockRootsBySlot(t *testing.T) {
   464  	db := setupDB(t)
   465  	ctx := context.Background()
   466  
   467  	b1 := testutil.NewBeaconBlock()
   468  	b1.Block.Slot = 20
   469  	require.NoError(t, db.SaveBlock(ctx, wrapper.WrappedPhase0SignedBeaconBlock(b1)))
   470  	b2 := testutil.NewBeaconBlock()
   471  	b2.Block.Slot = 100
   472  	b2.Block.ParentRoot = bytesutil.PadTo([]byte("parent1"), 32)
   473  	require.NoError(t, db.SaveBlock(ctx, wrapper.WrappedPhase0SignedBeaconBlock(b2)))
   474  	b3 := testutil.NewBeaconBlock()
   475  	b3.Block.Slot = 100
   476  	b3.Block.ParentRoot = bytesutil.PadTo([]byte("parent2"), 32)
   477  	require.NoError(t, db.SaveBlock(ctx, wrapper.WrappedPhase0SignedBeaconBlock(b3)))
   478  
   479  	r1, err := b1.Block.HashTreeRoot()
   480  	require.NoError(t, err)
   481  	r2, err := b2.Block.HashTreeRoot()
   482  	require.NoError(t, err)
   483  	r3, err := b3.Block.HashTreeRoot()
   484  	require.NoError(t, err)
   485  
   486  	hasBlocks, retrievedBlocks, err := db.BlocksBySlot(ctx, 1)
   487  	require.NoError(t, err)
   488  	assert.Equal(t, 0, len(retrievedBlocks), "Unexpected number of blocks received, expected none")
   489  	assert.Equal(t, false, hasBlocks, "Expected no blocks")
   490  	hasBlocks, retrievedBlocks, err = db.BlocksBySlot(ctx, 20)
   491  	require.NoError(t, err)
   492  	assert.Equal(t, true, proto.Equal(b1, retrievedBlocks[0].Proto()), "Wanted: %v, received: %v", b1, retrievedBlocks[0])
   493  	assert.Equal(t, true, hasBlocks, "Expected to have blocks")
   494  	hasBlocks, retrievedBlocks, err = db.BlocksBySlot(ctx, 100)
   495  	require.NoError(t, err)
   496  	assert.Equal(t, true, proto.Equal(b2, retrievedBlocks[0].Proto()), "Wanted: %v, received: %v", b2, retrievedBlocks[0])
   497  	assert.Equal(t, true, proto.Equal(b3, retrievedBlocks[1].Proto()), "Wanted: %v, received: %v", b3, retrievedBlocks[1])
   498  	assert.Equal(t, true, hasBlocks, "Expected to have blocks")
   499  
   500  	hasBlockRoots, retrievedBlockRoots, err := db.BlockRootsBySlot(ctx, 1)
   501  	require.NoError(t, err)
   502  	assert.DeepEqual(t, [][32]byte{}, retrievedBlockRoots)
   503  	assert.Equal(t, false, hasBlockRoots, "Expected no block roots")
   504  	hasBlockRoots, retrievedBlockRoots, err = db.BlockRootsBySlot(ctx, 20)
   505  	require.NoError(t, err)
   506  	assert.DeepEqual(t, [][32]byte{r1}, retrievedBlockRoots)
   507  	assert.Equal(t, true, hasBlockRoots, "Expected no block roots")
   508  	hasBlockRoots, retrievedBlockRoots, err = db.BlockRootsBySlot(ctx, 100)
   509  	require.NoError(t, err)
   510  	assert.DeepEqual(t, [][32]byte{r2, r3}, retrievedBlockRoots)
   511  	assert.Equal(t, true, hasBlockRoots, "Expected no block roots")
   512  }