From 182bd615ac0fc45b85896fd5c3d6349bd72ac7bb Mon Sep 17 00:00:00 2001 From: Preston Van Loon Date: Sun, 16 Jan 2022 12:44:42 -0600 Subject: [PATCH] refactoring: Deduplicate code (#10090) * Deduplicate sync committee indices from state * Deduplicate code in listblocks RPC endpoints, which only differ in response object * Deduplicate test code in config/fieldparams * Delete stale benchmark target. This is already included in go_default_test * deduplicate test cases in TestIsSlashableValidator_OK and fix blst BUILD file * Deduplicate TestStore_IsFinalizedChildBlock * Revert crypto/bls/blst/BUILD.bazel * Deduplicate TestStore_SaveBlock_NoDuplicates * Use a generic wrapper for beacon blocks to streamline test * Deduplicate TestStore_BlocksCRUD * Deduplicate TestStore_BlocksHandleZeroCase * Deduplicate TestStore_BlocksBatchDelete * deduplicate TestStore_BlocksHandleInvalidEndSlot * Deduplicate TestStore_BlocksCRUD_NoCache * Deduplicate common block test setup. Make TestStore_Blocks_FiltersCorrectly support multiple forks in test * Deduplicate the rest of these tests * lint * Deprecation warning * Add test for WrappedSignedBeaconBlock * Test error path --- beacon-chain/core/helpers/validators_test.go | 101 +- beacon-chain/core/transition/BUILD.bazel | 30 - beacon-chain/db/kv/BUILD.bazel | 2 - beacon-chain/db/kv/block_altair_test.go | 534 ----------- beacon-chain/db/kv/block_merge_test.go | 534 ----------- beacon-chain/db/kv/blocks_test.go | 878 ++++++++++-------- .../db/kv/finalized_block_roots_test.go | 101 +- beacon-chain/rpc/eth/beacon/sync_committee.go | 33 +- .../rpc/prysm/v1alpha1/beacon/blocks.go | 158 +--- config/fieldparams/BUILD.bazel | 10 +- config/fieldparams/common_test.go | 22 + config/fieldparams/mainnet_test.go | 13 +- config/fieldparams/minimal_test.go | 13 +- proto/prysm/v1alpha1/wrapper/beacon_block.go | 22 + .../v1alpha1/wrapper/beacon_block_test.go | 36 + 15 files changed, 678 insertions(+), 1809 deletions(-) delete mode 100644 beacon-chain/db/kv/block_altair_test.go delete mode 100644 beacon-chain/db/kv/block_merge_test.go create mode 100644 config/fieldparams/common_test.go diff --git a/beacon-chain/core/helpers/validators_test.go b/beacon-chain/core/helpers/validators_test.go index ee628d1d7d..a7a7bef918 100644 --- a/beacon-chain/core/helpers/validators_test.go +++ b/beacon-chain/core/helpers/validators_test.go @@ -131,94 +131,19 @@ func TestIsSlashableValidator_OK(t *testing.T) { for _, test := range tests { t.Run(test.name, func(t *testing.T) { - slashableValidator := IsSlashableValidator(test.validator.ActivationEpoch, - test.validator.WithdrawableEpoch, test.validator.Slashed, test.epoch) - assert.Equal(t, test.slashable, slashableValidator, "Expected active validator slashable to be %t", test.slashable) - }) - } -} - -func TestIsSlashableValidatorUsingTrie_OK(t *testing.T) { - tests := []struct { - name string - validator *ethpb.Validator - epoch types.Epoch - slashable bool - }{ - { - name: "Unset withdrawable, slashable", - validator: ðpb.Validator{ - WithdrawableEpoch: params.BeaconConfig().FarFutureEpoch, - }, - epoch: 0, - slashable: true, - }, - { - name: "before withdrawable, slashable", - validator: ðpb.Validator{ - WithdrawableEpoch: 5, - }, - epoch: 3, - slashable: true, - }, - { - name: "inactive, not slashable", - validator: ðpb.Validator{ - ActivationEpoch: 5, - WithdrawableEpoch: params.BeaconConfig().FarFutureEpoch, - }, - epoch: 2, - slashable: false, - }, - { - name: "after withdrawable, not slashable", - validator: ðpb.Validator{ - WithdrawableEpoch: 3, - }, - epoch: 3, - slashable: false, - }, - { - name: "slashed and withdrawable, not slashable", - validator: ðpb.Validator{ - Slashed: true, - ExitEpoch: params.BeaconConfig().FarFutureEpoch, - WithdrawableEpoch: 1, - }, - epoch: 2, - slashable: false, - }, - { - name: "slashed, not slashable", - validator: ðpb.Validator{ - Slashed: true, - ExitEpoch: params.BeaconConfig().FarFutureEpoch, - WithdrawableEpoch: params.BeaconConfig().FarFutureEpoch, - }, - epoch: 2, - slashable: false, - }, - { - name: "inactive and slashed, not slashable", - validator: ðpb.Validator{ - Slashed: true, - ActivationEpoch: 4, - ExitEpoch: params.BeaconConfig().FarFutureEpoch, - WithdrawableEpoch: params.BeaconConfig().FarFutureEpoch, - }, - epoch: 2, - slashable: false, - }, - } - - for _, test := range tests { - beaconState, err := v1.InitializeFromProto(ðpb.BeaconState{Validators: []*ethpb.Validator{test.validator}}) - require.NoError(t, err) - readOnlyVal, err := beaconState.ValidatorAtIndexReadOnly(0) - require.NoError(t, err) - t.Run(test.name, func(t *testing.T) { - slashableValidator := IsSlashableValidatorUsingTrie(readOnlyVal, test.epoch) - assert.Equal(t, test.slashable, slashableValidator, "Expected active validator slashable to be %t", test.slashable) + t.Run("without trie", func(t *testing.T) { + slashableValidator := IsSlashableValidator(test.validator.ActivationEpoch, + test.validator.WithdrawableEpoch, test.validator.Slashed, test.epoch) + assert.Equal(t, test.slashable, slashableValidator, "Expected active validator slashable to be %t", test.slashable) + }) + t.Run("with trie", func(t *testing.T) { + beaconState, err := v1.InitializeFromProto(ðpb.BeaconState{Validators: []*ethpb.Validator{test.validator}}) + require.NoError(t, err) + readOnlyVal, err := beaconState.ValidatorAtIndexReadOnly(0) + require.NoError(t, err) + slashableValidator := IsSlashableValidatorUsingTrie(readOnlyVal, test.epoch) + assert.Equal(t, test.slashable, slashableValidator, "Expected active validator slashable to be %t", test.slashable) + }) }) } } diff --git a/beacon-chain/core/transition/BUILD.bazel b/beacon-chain/core/transition/BUILD.bazel index 9ad96d1ad5..c177247221 100644 --- a/beacon-chain/core/transition/BUILD.bazel +++ b/beacon-chain/core/transition/BUILD.bazel @@ -1,7 +1,5 @@ load("@prysm//tools/go:def.bzl", "go_library", "go_test") -# gazelle:exclude testdata - go_library( name = "go_default_library", srcs = [ @@ -105,31 +103,3 @@ go_test( "@org_golang_google_protobuf//proto:go_default_library", ], ) - -go_test( - name = "go_benchmark_test", - size = "large", - srcs = ["benchmarks_test.go"], - args = [ - "-test.bench=.", - "-test.benchmem", - "-test.v", - ], - local = True, - tags = [ - "benchmark", - "manual", - "no-cache", - ], - deps = [ - "//beacon-chain/core/blocks:go_default_library", - "//beacon-chain/core/helpers:go_default_library", - "//beacon-chain/core/transition:go_default_library", - "//beacon-chain/state/v1:go_default_library", - "//config/params:go_default_library", - "//proto/prysm/v1alpha1:go_default_library", - "//testing/benchmark:go_default_library", - "//testing/require:go_default_library", - "@org_golang_google_protobuf//proto:go_default_library", - ], -) diff --git a/beacon-chain/db/kv/BUILD.bazel b/beacon-chain/db/kv/BUILD.bazel index 13853a7a0a..924a4815ad 100644 --- a/beacon-chain/db/kv/BUILD.bazel +++ b/beacon-chain/db/kv/BUILD.bazel @@ -77,8 +77,6 @@ go_test( srcs = [ "archived_point_test.go", "backup_test.go", - "block_altair_test.go", - "block_merge_test.go", "blocks_test.go", "checkpoint_test.go", "deposit_contract_test.go", diff --git a/beacon-chain/db/kv/block_altair_test.go b/beacon-chain/db/kv/block_altair_test.go deleted file mode 100644 index 109ea263c8..0000000000 --- a/beacon-chain/db/kv/block_altair_test.go +++ /dev/null @@ -1,534 +0,0 @@ -package kv - -import ( - "context" - "sort" - "testing" - - types "github.com/prysmaticlabs/eth2-types" - "github.com/prysmaticlabs/prysm/beacon-chain/db/filters" - "github.com/prysmaticlabs/prysm/config/params" - "github.com/prysmaticlabs/prysm/encoding/bytesutil" - v2 "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1" - "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1/block" - "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1/wrapper" - "github.com/prysmaticlabs/prysm/testing/assert" - "github.com/prysmaticlabs/prysm/testing/require" - "github.com/prysmaticlabs/prysm/testing/util" - "google.golang.org/protobuf/proto" -) - -func TestStore_SaveAltairBlock_NoDuplicates(t *testing.T) { - BlockCacheSize = 1 - db := setupDB(t) - slot := types.Slot(20) - ctx := context.Background() - // First we save a previous block to ensure the cache max size is reached. - prevBlock := util.NewBeaconBlockAltair() - prevBlock.Block.Slot = slot - 1 - prevBlock.Block.ParentRoot = bytesutil.PadTo([]byte{1, 2, 3}, 32) - wsb, err := wrapper.WrappedAltairSignedBeaconBlock(prevBlock) - require.NoError(t, err) - require.NoError(t, db.SaveBlock(ctx, wsb)) - - block := util.NewBeaconBlockAltair() - block.Block.Slot = slot - block.Block.ParentRoot = bytesutil.PadTo([]byte{1, 2, 3}, 32) - // Even with a full cache, saving new blocks should not cause - // duplicated blocks in the DB. - for i := 0; i < 100; i++ { - wsb, err = wrapper.WrappedAltairSignedBeaconBlock(block) - require.NoError(t, err) - require.NoError(t, db.SaveBlock(ctx, wsb)) - } - f := filters.NewFilter().SetStartSlot(slot).SetEndSlot(slot) - retrieved, _, err := db.Blocks(ctx, f) - require.NoError(t, err) - assert.Equal(t, 1, len(retrieved)) - // We reset the block cache size. - BlockCacheSize = 256 -} - -func TestStore_AltairBlocksCRUD(t *testing.T) { - db := setupDB(t) - ctx := context.Background() - - block := util.NewBeaconBlockAltair() - block.Block.Slot = 20 - block.Block.ParentRoot = bytesutil.PadTo([]byte{1, 2, 3}, 32) - - blockRoot, err := block.Block.HashTreeRoot() - require.NoError(t, err) - retrievedBlock, err := db.Block(ctx, blockRoot) - require.NoError(t, err) - assert.DeepEqual(t, nil, retrievedBlock, "Expected nil block") - wsb, err := wrapper.WrappedAltairSignedBeaconBlock(block) - require.NoError(t, err) - require.NoError(t, db.SaveBlock(ctx, wsb)) - assert.Equal(t, true, db.HasBlock(ctx, blockRoot), "Expected block to exist in the db") - retrievedBlock, err = db.Block(ctx, blockRoot) - require.NoError(t, err) - assert.Equal(t, true, proto.Equal(block, retrievedBlock.Proto()), "Wanted: %v, received: %v", block, retrievedBlock) - require.NoError(t, db.deleteBlock(ctx, blockRoot)) - assert.Equal(t, false, db.HasBlock(ctx, blockRoot), "Expected block to have been deleted from the db") -} - -func TestStore_AltairBlocksBatchDelete(t *testing.T) { - db := setupDB(t) - ctx := context.Background() - numBlocks := 10 - totalBlocks := make([]block.SignedBeaconBlock, numBlocks) - blockRoots := make([][32]byte, 0) - oddBlocks := make([]block.SignedBeaconBlock, 0) - for i := 0; i < len(totalBlocks); i++ { - b := util.NewBeaconBlockAltair() - b.Block.Slot = types.Slot(i) - b.Block.ParentRoot = bytesutil.PadTo([]byte("parent"), 32) - wb, err := wrapper.WrappedAltairSignedBeaconBlock(b) - require.NoError(t, err) - totalBlocks[i] = wb - if i%2 == 0 { - r, err := totalBlocks[i].Block().HashTreeRoot() - require.NoError(t, err) - blockRoots = append(blockRoots, r) - } else { - oddBlocks = append(oddBlocks, totalBlocks[i]) - } - } - require.NoError(t, db.SaveBlocks(ctx, totalBlocks)) - retrieved, _, err := db.Blocks(ctx, filters.NewFilter().SetParentRoot(bytesutil.PadTo([]byte("parent"), 32))) - require.NoError(t, err) - assert.Equal(t, numBlocks, len(retrieved), "Unexpected number of blocks received") - // We delete all even indexed blocks. - require.NoError(t, db.deleteBlocks(ctx, blockRoots)) - // When we retrieve the data, only the odd indexed blocks should remain. - retrieved, _, err = db.Blocks(ctx, filters.NewFilter().SetParentRoot(bytesutil.PadTo([]byte("parent"), 32))) - require.NoError(t, err) - sort.Slice(retrieved, func(i, j int) bool { - return retrieved[i].Block().Slot() < retrieved[j].Block().Slot() - }) - for i, block := range retrieved { - assert.Equal(t, true, proto.Equal(block.Proto(), oddBlocks[i].Proto()), "Wanted: %v, received: %v", block, oddBlocks[i]) - } -} - -func TestStore_AltairBlocksHandleZeroCase(t *testing.T) { - db := setupDB(t) - ctx := context.Background() - numBlocks := 10 - totalBlocks := make([]block.SignedBeaconBlock, numBlocks) - for i := 0; i < len(totalBlocks); i++ { - b := util.NewBeaconBlockAltair() - b.Block.Slot = types.Slot(i) - b.Block.ParentRoot = bytesutil.PadTo([]byte("parent"), 32) - wb, err := wrapper.WrappedAltairSignedBeaconBlock(b) - require.NoError(t, err) - totalBlocks[i] = wb - _, err = totalBlocks[i].Block().HashTreeRoot() - require.NoError(t, err) - } - require.NoError(t, db.SaveBlocks(ctx, totalBlocks)) - zeroFilter := filters.NewFilter().SetStartSlot(0).SetEndSlot(0) - retrieved, _, err := db.Blocks(ctx, zeroFilter) - require.NoError(t, err) - assert.Equal(t, 1, len(retrieved), "Unexpected number of blocks received, expected one") -} - -func TestStore_AltairBlocksHandleInvalidEndSlot(t *testing.T) { - db := setupDB(t) - ctx := context.Background() - numBlocks := 10 - totalBlocks := make([]block.SignedBeaconBlock, numBlocks) - // Save blocks from slot 1 onwards. - for i := 0; i < len(totalBlocks); i++ { - b := util.NewBeaconBlockAltair() - b.Block.Slot = types.Slot(i) + 1 - b.Block.ParentRoot = bytesutil.PadTo([]byte("parent"), 32) - wb, err := wrapper.WrappedAltairSignedBeaconBlock(b) - require.NoError(t, err) - totalBlocks[i] = wb - _, err = totalBlocks[i].Block().HashTreeRoot() - require.NoError(t, err) - } - require.NoError(t, db.SaveBlocks(ctx, totalBlocks)) - badFilter := filters.NewFilter().SetStartSlot(5).SetEndSlot(1) - _, _, err := db.Blocks(ctx, badFilter) - require.ErrorContains(t, errInvalidSlotRange.Error(), err) - - goodFilter := filters.NewFilter().SetStartSlot(0).SetEndSlot(1) - requested, _, err := db.Blocks(ctx, goodFilter) - require.NoError(t, err) - assert.Equal(t, 1, len(requested), "Unexpected number of blocks received, only expected two") -} - -func TestStore_AltairBlocksCRUD_NoCache(t *testing.T) { - db := setupDB(t) - ctx := context.Background() - block := util.NewBeaconBlockAltair() - block.Block.Slot = 20 - block.Block.ParentRoot = bytesutil.PadTo([]byte{1, 2, 3}, 32) - blockRoot, err := block.Block.HashTreeRoot() - require.NoError(t, err) - retrievedBlock, err := db.Block(ctx, blockRoot) - require.NoError(t, err) - require.DeepEqual(t, nil, retrievedBlock, "Expected nil block") - wsb, err := wrapper.WrappedAltairSignedBeaconBlock(block) - require.NoError(t, err) - require.NoError(t, db.SaveBlock(ctx, wsb)) - db.blockCache.Del(string(blockRoot[:])) - assert.Equal(t, true, db.HasBlock(ctx, blockRoot), "Expected block to exist in the db") - retrievedBlock, err = db.Block(ctx, blockRoot) - require.NoError(t, err) - assert.Equal(t, true, proto.Equal(block, retrievedBlock.Proto()), "Wanted: %v, received: %v", block, retrievedBlock) - require.NoError(t, db.deleteBlock(ctx, blockRoot)) - assert.Equal(t, false, db.HasBlock(ctx, blockRoot), "Expected block to have been deleted from the db") -} - -func TestStore_AltairBlocks_FiltersCorrectly(t *testing.T) { - db := setupDB(t) - b4 := util.NewBeaconBlockAltair() - b4.Block.Slot = 4 - b4.Block.ParentRoot = bytesutil.PadTo([]byte("parent"), 32) - b5 := util.NewBeaconBlockAltair() - b5.Block.Slot = 5 - b5.Block.ParentRoot = bytesutil.PadTo([]byte("parent2"), 32) - b6 := util.NewBeaconBlockAltair() - b6.Block.Slot = 6 - b6.Block.ParentRoot = bytesutil.PadTo([]byte("parent2"), 32) - b7 := util.NewBeaconBlockAltair() - b7.Block.Slot = 7 - b7.Block.ParentRoot = bytesutil.PadTo([]byte("parent3"), 32) - b8 := util.NewBeaconBlockAltair() - b8.Block.Slot = 8 - b8.Block.ParentRoot = bytesutil.PadTo([]byte("parent4"), 32) - blocks := make([]block.SignedBeaconBlock, 0) - for _, b := range []*v2.SignedBeaconBlockAltair{b4, b5, b6, b7, b8} { - blk, err := wrapper.WrappedAltairSignedBeaconBlock(b) - require.NoError(t, err) - blocks = append(blocks, blk) - } - ctx := context.Background() - require.NoError(t, db.SaveBlocks(ctx, blocks)) - - tests := []struct { - filter *filters.QueryFilter - expectedNumBlocks int - }{ - { - filter: filters.NewFilter().SetParentRoot(bytesutil.PadTo([]byte("parent2"), 32)), - expectedNumBlocks: 2, - }, - { - // No block meets the criteria below. - filter: filters.NewFilter().SetParentRoot(bytesutil.PadTo([]byte{3, 4, 5}, 32)), - expectedNumBlocks: 0, - }, - { - // Block slot range filter criteria. - filter: filters.NewFilter().SetStartSlot(5).SetEndSlot(7), - expectedNumBlocks: 3, - }, - { - filter: filters.NewFilter().SetStartSlot(7).SetEndSlot(7), - expectedNumBlocks: 1, - }, - { - filter: filters.NewFilter().SetStartSlot(4).SetEndSlot(8), - expectedNumBlocks: 5, - }, - { - filter: filters.NewFilter().SetStartSlot(4).SetEndSlot(5), - expectedNumBlocks: 2, - }, - { - filter: filters.NewFilter().SetStartSlot(5).SetEndSlot(9), - expectedNumBlocks: 4, - }, - { - filter: filters.NewFilter().SetEndSlot(7), - expectedNumBlocks: 4, - }, - { - filter: filters.NewFilter().SetEndSlot(8), - expectedNumBlocks: 5, - }, - { - filter: filters.NewFilter().SetStartSlot(5).SetEndSlot(10), - expectedNumBlocks: 4, - }, - { - // Composite filter criteria. - filter: filters.NewFilter(). - SetParentRoot(bytesutil.PadTo([]byte("parent2"), 32)). - SetStartSlot(6). - SetEndSlot(8), - expectedNumBlocks: 1, - }, - } - for _, tt := range tests { - retrievedBlocks, _, err := db.Blocks(ctx, tt.filter) - require.NoError(t, err) - assert.Equal(t, tt.expectedNumBlocks, len(retrievedBlocks), "Unexpected number of blocks") - } -} - -func TestStore_AltairBlocks_VerifyBlockRoots(t *testing.T) { - ctx := context.Background() - db := setupDB(t) - b1 := util.NewBeaconBlockAltair() - b1.Block.Slot = 1 - r1, err := b1.Block.HashTreeRoot() - require.NoError(t, err) - b2 := util.NewBeaconBlockAltair() - b2.Block.Slot = 2 - r2, err := b2.Block.HashTreeRoot() - require.NoError(t, err) - - for _, b := range []*v2.SignedBeaconBlockAltair{b1, b2} { - wsb, err := wrapper.WrappedAltairSignedBeaconBlock(b) - require.NoError(t, err) - require.NoError(t, db.SaveBlock(ctx, wsb)) - } - - filter := filters.NewFilter().SetStartSlot(b1.Block.Slot).SetEndSlot(b2.Block.Slot) - roots, err := db.BlockRoots(ctx, filter) - require.NoError(t, err) - - assert.DeepEqual(t, [][32]byte{r1, r2}, roots) -} - -func TestStore_AltairBlocks_Retrieve_SlotRange(t *testing.T) { - db := setupDB(t) - totalBlocks := make([]block.SignedBeaconBlock, 500) - for i := 0; i < 500; i++ { - b := util.NewBeaconBlockAltair() - b.Block.Slot = types.Slot(i) - b.Block.ParentRoot = bytesutil.PadTo([]byte("parent"), 32) - wb, err := wrapper.WrappedAltairSignedBeaconBlock(b) - require.NoError(t, err) - totalBlocks[i] = wb - } - ctx := context.Background() - require.NoError(t, db.SaveBlocks(ctx, totalBlocks)) - retrieved, _, err := db.Blocks(ctx, filters.NewFilter().SetStartSlot(100).SetEndSlot(399)) - require.NoError(t, err) - assert.Equal(t, 300, len(retrieved)) -} - -func TestStore_AltairBlocks_Retrieve_Epoch(t *testing.T) { - db := setupDB(t) - slots := params.BeaconConfig().SlotsPerEpoch.Mul(7) - totalBlocks := make([]block.SignedBeaconBlock, slots) - for i := types.Slot(0); i < slots; i++ { - b := util.NewBeaconBlockAltair() - b.Block.Slot = i - b.Block.ParentRoot = bytesutil.PadTo([]byte("parent"), 32) - wb, err := wrapper.WrappedAltairSignedBeaconBlock(b) - require.NoError(t, err) - totalBlocks[i] = wb - } - ctx := context.Background() - require.NoError(t, db.SaveBlocks(ctx, totalBlocks)) - retrieved, _, err := db.Blocks(ctx, filters.NewFilter().SetStartEpoch(5).SetEndEpoch(6)) - require.NoError(t, err) - want := params.BeaconConfig().SlotsPerEpoch.Mul(2) - assert.Equal(t, uint64(want), uint64(len(retrieved))) - retrieved, _, err = db.Blocks(ctx, filters.NewFilter().SetStartEpoch(0).SetEndEpoch(0)) - require.NoError(t, err) - want = params.BeaconConfig().SlotsPerEpoch - assert.Equal(t, uint64(want), uint64(len(retrieved))) -} - -func TestStore_AltairBlocks_Retrieve_SlotRangeWithStep(t *testing.T) { - db := setupDB(t) - totalBlocks := make([]block.SignedBeaconBlock, 500) - for i := 0; i < 500; i++ { - b := util.NewBeaconBlockAltair() - b.Block.Slot = types.Slot(i) - b.Block.ParentRoot = bytesutil.PadTo([]byte("parent"), 32) - wb, err := wrapper.WrappedAltairSignedBeaconBlock(b) - require.NoError(t, err) - totalBlocks[i] = wb - } - const step = 2 - ctx := context.Background() - require.NoError(t, db.SaveBlocks(ctx, totalBlocks)) - retrieved, _, err := db.Blocks(ctx, filters.NewFilter().SetStartSlot(100).SetEndSlot(399).SetSlotStep(step)) - require.NoError(t, err) - assert.Equal(t, 150, len(retrieved)) - for _, b := range retrieved { - assert.Equal(t, types.Slot(0), (b.Block().Slot()-100)%step, "Unexpect block slot %d", b.Block().Slot()) - } -} - -func TestStore_SaveAltairBlock_CanGetHighestAt(t *testing.T) { - db := setupDB(t) - ctx := context.Background() - - block1 := util.NewBeaconBlockAltair() - block1.Block.Slot = 1 - block2 := util.NewBeaconBlockAltair() - block2.Block.Slot = 10 - block3 := util.NewBeaconBlockAltair() - block3.Block.Slot = 100 - - for _, b := range []*v2.SignedBeaconBlockAltair{block1, block2, block3} { - wsb, err := wrapper.WrappedAltairSignedBeaconBlock(b) - require.NoError(t, err) - require.NoError(t, db.SaveBlock(ctx, wsb)) - } - - highestAt, err := db.HighestSlotBlocksBelow(ctx, 2) - require.NoError(t, err) - assert.Equal(t, false, len(highestAt) <= 0, "Got empty highest at slice") - assert.Equal(t, true, proto.Equal(block1, highestAt[0].Proto()), "Wanted: %v, received: %v", block1, highestAt[0]) - highestAt, err = db.HighestSlotBlocksBelow(ctx, 11) - require.NoError(t, err) - assert.Equal(t, false, len(highestAt) <= 0, "Got empty highest at slice") - assert.Equal(t, true, proto.Equal(block2, highestAt[0].Proto()), "Wanted: %v, received: %v", block2, highestAt[0]) - highestAt, err = db.HighestSlotBlocksBelow(ctx, 101) - require.NoError(t, err) - assert.Equal(t, false, len(highestAt) <= 0, "Got empty highest at slice") - assert.Equal(t, true, proto.Equal(block3, highestAt[0].Proto()), "Wanted: %v, received: %v", block3, highestAt[0]) - - r3, err := block3.Block.HashTreeRoot() - require.NoError(t, err) - require.NoError(t, db.deleteBlock(ctx, r3)) - - highestAt, err = db.HighestSlotBlocksBelow(ctx, 101) - require.NoError(t, err) - assert.Equal(t, true, proto.Equal(block2, highestAt[0].Proto()), "Wanted: %v, received: %v", block2, highestAt[0]) -} - -func TestStore_GenesisAltairBlock_CanGetHighestAt(t *testing.T) { - db := setupDB(t) - ctx := context.Background() - - genesisBlock := util.NewBeaconBlockAltair() - genesisRoot, err := genesisBlock.Block.HashTreeRoot() - require.NoError(t, err) - require.NoError(t, db.SaveGenesisBlockRoot(ctx, genesisRoot)) - wsb, err := wrapper.WrappedAltairSignedBeaconBlock(genesisBlock) - require.NoError(t, err) - require.NoError(t, db.SaveBlock(ctx, wsb)) - block1 := util.NewBeaconBlockAltair() - block1.Block.Slot = 1 - wsb, err = wrapper.WrappedAltairSignedBeaconBlock(block1) - require.NoError(t, err) - require.NoError(t, db.SaveBlock(ctx, wsb)) - - highestAt, err := db.HighestSlotBlocksBelow(ctx, 2) - require.NoError(t, err) - assert.Equal(t, true, proto.Equal(block1, highestAt[0].Proto()), "Wanted: %v, received: %v", block1, highestAt[0]) - highestAt, err = db.HighestSlotBlocksBelow(ctx, 1) - require.NoError(t, err) - assert.Equal(t, true, proto.Equal(genesisBlock, highestAt[0].Proto()), "Wanted: %v, received: %v", genesisBlock, highestAt[0]) - highestAt, err = db.HighestSlotBlocksBelow(ctx, 0) - require.NoError(t, err) - assert.Equal(t, true, proto.Equal(genesisBlock, highestAt[0].Proto()), "Wanted: %v, received: %v", genesisBlock, highestAt[0]) -} - -func TestStore_SaveAltairBlocks_HasCachedBlocks(t *testing.T) { - db := setupDB(t) - ctx := context.Background() - - var err error - b := make([]block.SignedBeaconBlock, 500) - for i := 0; i < 500; i++ { - blk := util.NewBeaconBlockAltair() - blk.Block.ParentRoot = bytesutil.PadTo([]byte("parent"), 32) - blk.Block.Slot = types.Slot(i) - b[i], err = wrapper.WrappedAltairSignedBeaconBlock(blk) - require.NoError(t, err) - } - - require.NoError(t, db.SaveBlock(ctx, b[0])) - require.NoError(t, db.SaveBlocks(ctx, b)) - f := filters.NewFilter().SetStartSlot(0).SetEndSlot(500) - - blks, _, err := db.Blocks(ctx, f) - require.NoError(t, err) - assert.Equal(t, 500, len(blks), "Did not get wanted blocks") -} - -func TestStore_SaveAltairBlocks_HasRootsMatched(t *testing.T) { - db := setupDB(t) - ctx := context.Background() - - var err error - b := make([]block.SignedBeaconBlock, 500) - for i := 0; i < 500; i++ { - blk := util.NewBeaconBlockAltair() - blk.Block.ParentRoot = bytesutil.PadTo([]byte("parent"), 32) - blk.Block.Slot = types.Slot(i) - b[i], err = wrapper.WrappedAltairSignedBeaconBlock(blk) - require.NoError(t, err) - } - - require.NoError(t, db.SaveBlocks(ctx, b)) - f := filters.NewFilter().SetStartSlot(0).SetEndSlot(500) - - blks, roots, err := db.Blocks(ctx, f) - require.NoError(t, err) - assert.Equal(t, 500, len(blks), "Did not get wanted blocks") - - for i, blk := range blks { - rt, err := blk.Block().HashTreeRoot() - require.NoError(t, err) - assert.Equal(t, roots[i], rt, "mismatch of block roots") - } -} - -func TestStore_AltairBlocksBySlot_BlockRootsBySlot(t *testing.T) { - db := setupDB(t) - ctx := context.Background() - - b1 := util.NewBeaconBlockAltair() - b1.Block.Slot = 20 - b2 := util.NewBeaconBlockAltair() - b2.Block.Slot = 100 - b2.Block.ParentRoot = bytesutil.PadTo([]byte("parent1"), 32) - b3 := util.NewBeaconBlockAltair() - b3.Block.Slot = 100 - b3.Block.ParentRoot = bytesutil.PadTo([]byte("parent2"), 32) - - for _, b := range []*v2.SignedBeaconBlockAltair{b1, b2, b3} { - wsb, err := wrapper.WrappedAltairSignedBeaconBlock(b) - require.NoError(t, err) - require.NoError(t, db.SaveBlock(ctx, wsb)) - } - - r1, err := b1.Block.HashTreeRoot() - require.NoError(t, err) - r2, err := b2.Block.HashTreeRoot() - require.NoError(t, err) - r3, err := b3.Block.HashTreeRoot() - require.NoError(t, err) - - hasBlocks, retrievedBlocks, err := db.BlocksBySlot(ctx, 1) - require.NoError(t, err) - assert.Equal(t, 0, len(retrievedBlocks), "Unexpected number of blocks received, expected none") - assert.Equal(t, false, hasBlocks, "Expected no blocks") - hasBlocks, retrievedBlocks, err = db.BlocksBySlot(ctx, 20) - require.NoError(t, err) - assert.Equal(t, true, proto.Equal(b1, retrievedBlocks[0].Proto()), "Wanted: %v, received: %v", b1, retrievedBlocks[0]) - assert.Equal(t, true, hasBlocks, "Expected to have blocks") - hasBlocks, retrievedBlocks, err = db.BlocksBySlot(ctx, 100) - require.NoError(t, err) - assert.Equal(t, true, proto.Equal(b2, retrievedBlocks[0].Proto()), "Wanted: %v, received: %v", b2, retrievedBlocks[0]) - assert.Equal(t, true, proto.Equal(b3, retrievedBlocks[1].Proto()), "Wanted: %v, received: %v", b3, retrievedBlocks[1]) - assert.Equal(t, true, hasBlocks, "Expected to have blocks") - - hasBlockRoots, retrievedBlockRoots, err := db.BlockRootsBySlot(ctx, 1) - require.NoError(t, err) - assert.DeepEqual(t, [][32]byte{}, retrievedBlockRoots) - assert.Equal(t, false, hasBlockRoots, "Expected no block roots") - hasBlockRoots, retrievedBlockRoots, err = db.BlockRootsBySlot(ctx, 20) - require.NoError(t, err) - assert.DeepEqual(t, [][32]byte{r1}, retrievedBlockRoots) - assert.Equal(t, true, hasBlockRoots, "Expected no block roots") - hasBlockRoots, retrievedBlockRoots, err = db.BlockRootsBySlot(ctx, 100) - require.NoError(t, err) - assert.DeepEqual(t, [][32]byte{r2, r3}, retrievedBlockRoots) - assert.Equal(t, true, hasBlockRoots, "Expected no block roots") -} diff --git a/beacon-chain/db/kv/block_merge_test.go b/beacon-chain/db/kv/block_merge_test.go deleted file mode 100644 index 631372556d..0000000000 --- a/beacon-chain/db/kv/block_merge_test.go +++ /dev/null @@ -1,534 +0,0 @@ -package kv - -import ( - "context" - "sort" - "testing" - - types "github.com/prysmaticlabs/eth2-types" - "github.com/prysmaticlabs/prysm/beacon-chain/db/filters" - "github.com/prysmaticlabs/prysm/config/params" - "github.com/prysmaticlabs/prysm/encoding/bytesutil" - v2 "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1" - "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1/block" - "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1/wrapper" - "github.com/prysmaticlabs/prysm/testing/assert" - "github.com/prysmaticlabs/prysm/testing/require" - "github.com/prysmaticlabs/prysm/testing/util" - "google.golang.org/protobuf/proto" -) - -func TestStore_SaveBellatrixBlock_NoDuplicates(t *testing.T) { - BlockCacheSize = 1 - db := setupDB(t) - slot := types.Slot(20) - ctx := context.Background() - // First we save a previous block to ensure the cache max size is reached. - prevBlock := util.NewBeaconBlockMerge() - prevBlock.Block.Slot = slot - 1 - prevBlock.Block.ParentRoot = bytesutil.PadTo([]byte{1, 2, 3}, 32) - wsb, err := wrapper.WrappedMergeSignedBeaconBlock(prevBlock) - require.NoError(t, err) - require.NoError(t, db.SaveBlock(ctx, wsb)) - - block := util.NewBeaconBlockMerge() - block.Block.Slot = slot - block.Block.ParentRoot = bytesutil.PadTo([]byte{1, 2, 3}, 32) - // Even with a full cache, saving new blocks should not cause - // duplicated blocks in the DB. - for i := 0; i < 100; i++ { - wsb, err = wrapper.WrappedMergeSignedBeaconBlock(block) - require.NoError(t, err) - require.NoError(t, db.SaveBlock(ctx, wsb)) - } - f := filters.NewFilter().SetStartSlot(slot).SetEndSlot(slot) - retrieved, _, err := db.Blocks(ctx, f) - require.NoError(t, err) - assert.Equal(t, 1, len(retrieved)) - // We reset the block cache size. - BlockCacheSize = 256 -} - -func TestStore_BellatrixBlocksCRUD(t *testing.T) { - db := setupDB(t) - ctx := context.Background() - - block := util.NewBeaconBlockMerge() - block.Block.Slot = 20 - block.Block.ParentRoot = bytesutil.PadTo([]byte{1, 2, 3}, 32) - - blockRoot, err := block.Block.HashTreeRoot() - require.NoError(t, err) - retrievedBlock, err := db.Block(ctx, blockRoot) - require.NoError(t, err) - assert.DeepEqual(t, nil, retrievedBlock, "Expected nil block") - wsb, err := wrapper.WrappedMergeSignedBeaconBlock(block) - require.NoError(t, err) - require.NoError(t, db.SaveBlock(ctx, wsb)) - assert.Equal(t, true, db.HasBlock(ctx, blockRoot), "Expected block to exist in the db") - retrievedBlock, err = db.Block(ctx, blockRoot) - require.NoError(t, err) - assert.Equal(t, true, proto.Equal(block, retrievedBlock.Proto()), "Wanted: %v, received: %v", block, retrievedBlock) - require.NoError(t, db.deleteBlock(ctx, blockRoot)) - assert.Equal(t, false, db.HasBlock(ctx, blockRoot), "Expected block to have been deleted from the db") -} - -func TestStore_BellatrixBlocksBatchDelete(t *testing.T) { - db := setupDB(t) - ctx := context.Background() - numBlocks := 10 - totalBlocks := make([]block.SignedBeaconBlock, numBlocks) - blockRoots := make([][32]byte, 0) - oddBlocks := make([]block.SignedBeaconBlock, 0) - for i := 0; i < len(totalBlocks); i++ { - b := util.NewBeaconBlockMerge() - b.Block.Slot = types.Slot(i) - b.Block.ParentRoot = bytesutil.PadTo([]byte("parent"), 32) - wb, err := wrapper.WrappedMergeSignedBeaconBlock(b) - require.NoError(t, err) - totalBlocks[i] = wb - if i%2 == 0 { - r, err := totalBlocks[i].Block().HashTreeRoot() - require.NoError(t, err) - blockRoots = append(blockRoots, r) - } else { - oddBlocks = append(oddBlocks, totalBlocks[i]) - } - } - require.NoError(t, db.SaveBlocks(ctx, totalBlocks)) - retrieved, _, err := db.Blocks(ctx, filters.NewFilter().SetParentRoot(bytesutil.PadTo([]byte("parent"), 32))) - require.NoError(t, err) - assert.Equal(t, numBlocks, len(retrieved), "Unexpected number of blocks received") - // We delete all even indexed blocks. - require.NoError(t, db.deleteBlocks(ctx, blockRoots)) - // When we retrieve the data, only the odd indexed blocks should remain. - retrieved, _, err = db.Blocks(ctx, filters.NewFilter().SetParentRoot(bytesutil.PadTo([]byte("parent"), 32))) - require.NoError(t, err) - sort.Slice(retrieved, func(i, j int) bool { - return retrieved[i].Block().Slot() < retrieved[j].Block().Slot() - }) - for i, block := range retrieved { - assert.Equal(t, true, proto.Equal(block.Proto(), oddBlocks[i].Proto()), "Wanted: %v, received: %v", block, oddBlocks[i]) - } -} - -func TestStore_BellatrixBlocksHandleZeroCase(t *testing.T) { - db := setupDB(t) - ctx := context.Background() - numBlocks := 10 - totalBlocks := make([]block.SignedBeaconBlock, numBlocks) - for i := 0; i < len(totalBlocks); i++ { - b := util.NewBeaconBlockMerge() - b.Block.Slot = types.Slot(i) - b.Block.ParentRoot = bytesutil.PadTo([]byte("parent"), 32) - wb, err := wrapper.WrappedMergeSignedBeaconBlock(b) - require.NoError(t, err) - totalBlocks[i] = wb - _, err = totalBlocks[i].Block().HashTreeRoot() - require.NoError(t, err) - } - require.NoError(t, db.SaveBlocks(ctx, totalBlocks)) - zeroFilter := filters.NewFilter().SetStartSlot(0).SetEndSlot(0) - retrieved, _, err := db.Blocks(ctx, zeroFilter) - require.NoError(t, err) - assert.Equal(t, 1, len(retrieved), "Unexpected number of blocks received, expected one") -} - -func TestStore_BellatrixBlocksHandleInvalidEndSlot(t *testing.T) { - db := setupDB(t) - ctx := context.Background() - numBlocks := 10 - totalBlocks := make([]block.SignedBeaconBlock, numBlocks) - // Save blocks from slot 1 onwards. - for i := 0; i < len(totalBlocks); i++ { - b := util.NewBeaconBlockMerge() - b.Block.Slot = types.Slot(i) + 1 - b.Block.ParentRoot = bytesutil.PadTo([]byte("parent"), 32) - wb, err := wrapper.WrappedMergeSignedBeaconBlock(b) - require.NoError(t, err) - totalBlocks[i] = wb - _, err = totalBlocks[i].Block().HashTreeRoot() - require.NoError(t, err) - } - require.NoError(t, db.SaveBlocks(ctx, totalBlocks)) - badFilter := filters.NewFilter().SetStartSlot(5).SetEndSlot(1) - _, _, err := db.Blocks(ctx, badFilter) - require.ErrorContains(t, errInvalidSlotRange.Error(), err) - - goodFilter := filters.NewFilter().SetStartSlot(0).SetEndSlot(1) - requested, _, err := db.Blocks(ctx, goodFilter) - require.NoError(t, err) - assert.Equal(t, 1, len(requested), "Unexpected number of blocks received, only expected two") -} - -func TestStore_BellatrixBlocksCRUD_NoCache(t *testing.T) { - db := setupDB(t) - ctx := context.Background() - block := util.NewBeaconBlockMerge() - block.Block.Slot = 20 - block.Block.ParentRoot = bytesutil.PadTo([]byte{1, 2, 3}, 32) - blockRoot, err := block.Block.HashTreeRoot() - require.NoError(t, err) - retrievedBlock, err := db.Block(ctx, blockRoot) - require.NoError(t, err) - require.DeepEqual(t, nil, retrievedBlock, "Expected nil block") - wsb, err := wrapper.WrappedMergeSignedBeaconBlock(block) - require.NoError(t, err) - require.NoError(t, db.SaveBlock(ctx, wsb)) - db.blockCache.Del(string(blockRoot[:])) - assert.Equal(t, true, db.HasBlock(ctx, blockRoot), "Expected block to exist in the db") - retrievedBlock, err = db.Block(ctx, blockRoot) - require.NoError(t, err) - assert.Equal(t, true, proto.Equal(block, retrievedBlock.Proto()), "Wanted: %v, received: %v", block, retrievedBlock) - require.NoError(t, db.deleteBlock(ctx, blockRoot)) - assert.Equal(t, false, db.HasBlock(ctx, blockRoot), "Expected block to have been deleted from the db") -} - -func TestStore_BellatrixBlocks_FiltersCorrectly(t *testing.T) { - db := setupDB(t) - b4 := util.NewBeaconBlockMerge() - b4.Block.Slot = 4 - b4.Block.ParentRoot = bytesutil.PadTo([]byte("parent"), 32) - b5 := util.NewBeaconBlockMerge() - b5.Block.Slot = 5 - b5.Block.ParentRoot = bytesutil.PadTo([]byte("parent2"), 32) - b6 := util.NewBeaconBlockMerge() - b6.Block.Slot = 6 - b6.Block.ParentRoot = bytesutil.PadTo([]byte("parent2"), 32) - b7 := util.NewBeaconBlockMerge() - b7.Block.Slot = 7 - b7.Block.ParentRoot = bytesutil.PadTo([]byte("parent3"), 32) - b8 := util.NewBeaconBlockMerge() - b8.Block.Slot = 8 - b8.Block.ParentRoot = bytesutil.PadTo([]byte("parent4"), 32) - blocks := make([]block.SignedBeaconBlock, 0) - for _, b := range []*v2.SignedBeaconBlockMerge{b4, b5, b6, b7, b8} { - blk, err := wrapper.WrappedMergeSignedBeaconBlock(b) - require.NoError(t, err) - blocks = append(blocks, blk) - } - ctx := context.Background() - require.NoError(t, db.SaveBlocks(ctx, blocks)) - - tests := []struct { - filter *filters.QueryFilter - expectedNumBlocks int - }{ - { - filter: filters.NewFilter().SetParentRoot(bytesutil.PadTo([]byte("parent2"), 32)), - expectedNumBlocks: 2, - }, - { - // No block meets the criteria below. - filter: filters.NewFilter().SetParentRoot(bytesutil.PadTo([]byte{3, 4, 5}, 32)), - expectedNumBlocks: 0, - }, - { - // Block slot range filter criteria. - filter: filters.NewFilter().SetStartSlot(5).SetEndSlot(7), - expectedNumBlocks: 3, - }, - { - filter: filters.NewFilter().SetStartSlot(7).SetEndSlot(7), - expectedNumBlocks: 1, - }, - { - filter: filters.NewFilter().SetStartSlot(4).SetEndSlot(8), - expectedNumBlocks: 5, - }, - { - filter: filters.NewFilter().SetStartSlot(4).SetEndSlot(5), - expectedNumBlocks: 2, - }, - { - filter: filters.NewFilter().SetStartSlot(5).SetEndSlot(9), - expectedNumBlocks: 4, - }, - { - filter: filters.NewFilter().SetEndSlot(7), - expectedNumBlocks: 4, - }, - { - filter: filters.NewFilter().SetEndSlot(8), - expectedNumBlocks: 5, - }, - { - filter: filters.NewFilter().SetStartSlot(5).SetEndSlot(10), - expectedNumBlocks: 4, - }, - { - // Composite filter criteria. - filter: filters.NewFilter(). - SetParentRoot(bytesutil.PadTo([]byte("parent2"), 32)). - SetStartSlot(6). - SetEndSlot(8), - expectedNumBlocks: 1, - }, - } - for _, tt := range tests { - retrievedBlocks, _, err := db.Blocks(ctx, tt.filter) - require.NoError(t, err) - assert.Equal(t, tt.expectedNumBlocks, len(retrievedBlocks), "Unexpected number of blocks") - } -} - -func TestStore_BellatrixBlocks_VerifyBlockRoots(t *testing.T) { - ctx := context.Background() - db := setupDB(t) - b1 := util.NewBeaconBlockMerge() - b1.Block.Slot = 1 - r1, err := b1.Block.HashTreeRoot() - require.NoError(t, err) - b2 := util.NewBeaconBlockMerge() - b2.Block.Slot = 2 - r2, err := b2.Block.HashTreeRoot() - require.NoError(t, err) - - for _, b := range []*v2.SignedBeaconBlockMerge{b1, b2} { - wsb, err := wrapper.WrappedMergeSignedBeaconBlock(b) - require.NoError(t, err) - require.NoError(t, db.SaveBlock(ctx, wsb)) - } - - filter := filters.NewFilter().SetStartSlot(b1.Block.Slot).SetEndSlot(b2.Block.Slot) - roots, err := db.BlockRoots(ctx, filter) - require.NoError(t, err) - - assert.DeepEqual(t, [][32]byte{r1, r2}, roots) -} - -func TestStore_BellatrixBlocks_Retrieve_SlotRange(t *testing.T) { - db := setupDB(t) - totalBlocks := make([]block.SignedBeaconBlock, 500) - for i := 0; i < 500; i++ { - b := util.NewBeaconBlockMerge() - b.Block.Slot = types.Slot(i) - b.Block.ParentRoot = bytesutil.PadTo([]byte("parent"), 32) - wb, err := wrapper.WrappedMergeSignedBeaconBlock(b) - require.NoError(t, err) - totalBlocks[i] = wb - } - ctx := context.Background() - require.NoError(t, db.SaveBlocks(ctx, totalBlocks)) - retrieved, _, err := db.Blocks(ctx, filters.NewFilter().SetStartSlot(100).SetEndSlot(399)) - require.NoError(t, err) - assert.Equal(t, 300, len(retrieved)) -} - -func TestStore_BellatrixBlocks_Retrieve_Epoch(t *testing.T) { - db := setupDB(t) - slots := params.BeaconConfig().SlotsPerEpoch.Mul(7) - totalBlocks := make([]block.SignedBeaconBlock, slots) - for i := types.Slot(0); i < slots; i++ { - b := util.NewBeaconBlockMerge() - b.Block.Slot = i - b.Block.ParentRoot = bytesutil.PadTo([]byte("parent"), 32) - wb, err := wrapper.WrappedMergeSignedBeaconBlock(b) - require.NoError(t, err) - totalBlocks[i] = wb - } - ctx := context.Background() - require.NoError(t, db.SaveBlocks(ctx, totalBlocks)) - retrieved, _, err := db.Blocks(ctx, filters.NewFilter().SetStartEpoch(5).SetEndEpoch(6)) - require.NoError(t, err) - want := params.BeaconConfig().SlotsPerEpoch.Mul(2) - assert.Equal(t, uint64(want), uint64(len(retrieved))) - retrieved, _, err = db.Blocks(ctx, filters.NewFilter().SetStartEpoch(0).SetEndEpoch(0)) - require.NoError(t, err) - want = params.BeaconConfig().SlotsPerEpoch - assert.Equal(t, uint64(want), uint64(len(retrieved))) -} - -func TestStore_BellatrixBlocks_Retrieve_SlotRangeWithStep(t *testing.T) { - db := setupDB(t) - totalBlocks := make([]block.SignedBeaconBlock, 500) - for i := 0; i < 500; i++ { - b := util.NewBeaconBlockMerge() - b.Block.Slot = types.Slot(i) - b.Block.ParentRoot = bytesutil.PadTo([]byte("parent"), 32) - wb, err := wrapper.WrappedMergeSignedBeaconBlock(b) - require.NoError(t, err) - totalBlocks[i] = wb - } - const step = 2 - ctx := context.Background() - require.NoError(t, db.SaveBlocks(ctx, totalBlocks)) - retrieved, _, err := db.Blocks(ctx, filters.NewFilter().SetStartSlot(100).SetEndSlot(399).SetSlotStep(step)) - require.NoError(t, err) - assert.Equal(t, 150, len(retrieved)) - for _, b := range retrieved { - assert.Equal(t, types.Slot(0), (b.Block().Slot()-100)%step, "Unexpect block slot %d", b.Block().Slot()) - } -} - -func TestStore_SaveBellatrixBlock_CanGetHighestAt(t *testing.T) { - db := setupDB(t) - ctx := context.Background() - - block1 := util.NewBeaconBlockMerge() - block1.Block.Slot = 1 - block2 := util.NewBeaconBlockMerge() - block2.Block.Slot = 10 - block3 := util.NewBeaconBlockMerge() - block3.Block.Slot = 100 - - for _, b := range []*v2.SignedBeaconBlockMerge{block1, block2, block3} { - wsb, err := wrapper.WrappedMergeSignedBeaconBlock(b) - require.NoError(t, err) - require.NoError(t, db.SaveBlock(ctx, wsb)) - } - - highestAt, err := db.HighestSlotBlocksBelow(ctx, 2) - require.NoError(t, err) - assert.Equal(t, false, len(highestAt) <= 0, "Got empty highest at slice") - assert.Equal(t, true, proto.Equal(block1, highestAt[0].Proto()), "Wanted: %v, received: %v", block1, highestAt[0]) - highestAt, err = db.HighestSlotBlocksBelow(ctx, 11) - require.NoError(t, err) - assert.Equal(t, false, len(highestAt) <= 0, "Got empty highest at slice") - assert.Equal(t, true, proto.Equal(block2, highestAt[0].Proto()), "Wanted: %v, received: %v", block2, highestAt[0]) - highestAt, err = db.HighestSlotBlocksBelow(ctx, 101) - require.NoError(t, err) - assert.Equal(t, false, len(highestAt) <= 0, "Got empty highest at slice") - assert.Equal(t, true, proto.Equal(block3, highestAt[0].Proto()), "Wanted: %v, received: %v", block3, highestAt[0]) - - r3, err := block3.Block.HashTreeRoot() - require.NoError(t, err) - require.NoError(t, db.deleteBlock(ctx, r3)) - - highestAt, err = db.HighestSlotBlocksBelow(ctx, 101) - require.NoError(t, err) - assert.Equal(t, true, proto.Equal(block2, highestAt[0].Proto()), "Wanted: %v, received: %v", block2, highestAt[0]) -} - -func TestStore_GenesisBellatrixBlock_CanGetHighestAt(t *testing.T) { - db := setupDB(t) - ctx := context.Background() - - genesisBlock := util.NewBeaconBlockMerge() - genesisRoot, err := genesisBlock.Block.HashTreeRoot() - require.NoError(t, err) - require.NoError(t, db.SaveGenesisBlockRoot(ctx, genesisRoot)) - wsb, err := wrapper.WrappedMergeSignedBeaconBlock(genesisBlock) - require.NoError(t, err) - require.NoError(t, db.SaveBlock(ctx, wsb)) - block1 := util.NewBeaconBlockMerge() - block1.Block.Slot = 1 - wsb, err = wrapper.WrappedMergeSignedBeaconBlock(block1) - require.NoError(t, err) - require.NoError(t, db.SaveBlock(ctx, wsb)) - - highestAt, err := db.HighestSlotBlocksBelow(ctx, 2) - require.NoError(t, err) - assert.Equal(t, true, proto.Equal(block1, highestAt[0].Proto()), "Wanted: %v, received: %v", block1, highestAt[0]) - highestAt, err = db.HighestSlotBlocksBelow(ctx, 1) - require.NoError(t, err) - assert.Equal(t, true, proto.Equal(genesisBlock, highestAt[0].Proto()), "Wanted: %v, received: %v", genesisBlock, highestAt[0]) - highestAt, err = db.HighestSlotBlocksBelow(ctx, 0) - require.NoError(t, err) - assert.Equal(t, true, proto.Equal(genesisBlock, highestAt[0].Proto()), "Wanted: %v, received: %v", genesisBlock, highestAt[0]) -} - -func TestStore_SaveBellatrixBlocks_HasCachedBlocks(t *testing.T) { - db := setupDB(t) - ctx := context.Background() - - var err error - b := make([]block.SignedBeaconBlock, 500) - for i := 0; i < 500; i++ { - blk := util.NewBeaconBlockMerge() - blk.Block.ParentRoot = bytesutil.PadTo([]byte("parent"), 32) - blk.Block.Slot = types.Slot(i) - b[i], err = wrapper.WrappedMergeSignedBeaconBlock(blk) - require.NoError(t, err) - } - - require.NoError(t, db.SaveBlock(ctx, b[0])) - require.NoError(t, db.SaveBlocks(ctx, b)) - f := filters.NewFilter().SetStartSlot(0).SetEndSlot(500) - - blks, _, err := db.Blocks(ctx, f) - require.NoError(t, err) - assert.Equal(t, 500, len(blks), "Did not get wanted blocks") -} - -func TestStore_SaveBellatrixBlocks_HasRootsMatched(t *testing.T) { - db := setupDB(t) - ctx := context.Background() - - var err error - b := make([]block.SignedBeaconBlock, 500) - for i := 0; i < 500; i++ { - blk := util.NewBeaconBlockMerge() - blk.Block.ParentRoot = bytesutil.PadTo([]byte("parent"), 32) - blk.Block.Slot = types.Slot(i) - b[i], err = wrapper.WrappedMergeSignedBeaconBlock(blk) - require.NoError(t, err) - } - - require.NoError(t, db.SaveBlocks(ctx, b)) - f := filters.NewFilter().SetStartSlot(0).SetEndSlot(500) - - blks, roots, err := db.Blocks(ctx, f) - require.NoError(t, err) - assert.Equal(t, 500, len(blks), "Did not get wanted blocks") - - for i, blk := range blks { - rt, err := blk.Block().HashTreeRoot() - require.NoError(t, err) - assert.Equal(t, roots[i], rt, "mismatch of block roots") - } -} - -func TestStore_BellatrixBlocksBySlot_BlockRootsBySlot(t *testing.T) { - db := setupDB(t) - ctx := context.Background() - - b1 := util.NewBeaconBlockMerge() - b1.Block.Slot = 20 - b2 := util.NewBeaconBlockMerge() - b2.Block.Slot = 100 - b2.Block.ParentRoot = bytesutil.PadTo([]byte("parent1"), 32) - b3 := util.NewBeaconBlockMerge() - b3.Block.Slot = 100 - b3.Block.ParentRoot = bytesutil.PadTo([]byte("parent2"), 32) - - for _, b := range []*v2.SignedBeaconBlockMerge{b1, b2, b3} { - wsb, err := wrapper.WrappedMergeSignedBeaconBlock(b) - require.NoError(t, err) - require.NoError(t, db.SaveBlock(ctx, wsb)) - } - - r1, err := b1.Block.HashTreeRoot() - require.NoError(t, err) - r2, err := b2.Block.HashTreeRoot() - require.NoError(t, err) - r3, err := b3.Block.HashTreeRoot() - require.NoError(t, err) - - hasBlocks, retrievedBlocks, err := db.BlocksBySlot(ctx, 1) - require.NoError(t, err) - assert.Equal(t, 0, len(retrievedBlocks), "Unexpected number of blocks received, expected none") - assert.Equal(t, false, hasBlocks, "Expected no blocks") - hasBlocks, retrievedBlocks, err = db.BlocksBySlot(ctx, 20) - require.NoError(t, err) - assert.Equal(t, true, proto.Equal(b1, retrievedBlocks[0].Proto()), "Wanted: %v, received: %v", b1, retrievedBlocks[0]) - assert.Equal(t, true, hasBlocks, "Expected to have blocks") - hasBlocks, retrievedBlocks, err = db.BlocksBySlot(ctx, 100) - require.NoError(t, err) - assert.Equal(t, true, proto.Equal(b2, retrievedBlocks[0].Proto()), "Wanted: %v, received: %v", b2, retrievedBlocks[0]) - assert.Equal(t, true, proto.Equal(b3, retrievedBlocks[1].Proto()), "Wanted: %v, received: %v", b3, retrievedBlocks[1]) - assert.Equal(t, true, hasBlocks, "Expected to have blocks") - - hasBlockRoots, retrievedBlockRoots, err := db.BlockRootsBySlot(ctx, 1) - require.NoError(t, err) - assert.DeepEqual(t, [][32]byte{}, retrievedBlockRoots) - assert.Equal(t, false, hasBlockRoots, "Expected no block roots") - hasBlockRoots, retrievedBlockRoots, err = db.BlockRootsBySlot(ctx, 20) - require.NoError(t, err) - assert.DeepEqual(t, [][32]byte{r1}, retrievedBlockRoots) - assert.Equal(t, true, hasBlockRoots, "Expected no block roots") - hasBlockRoots, retrievedBlockRoots, err = db.BlockRootsBySlot(ctx, 100) - require.NoError(t, err) - assert.DeepEqual(t, [][32]byte{r2, r3}, retrievedBlockRoots) - assert.Equal(t, true, hasBlockRoots, "Expected no block roots") -} diff --git a/beacon-chain/db/kv/blocks_test.go b/beacon-chain/db/kv/blocks_test.go index e34da53149..b80f7e6329 100644 --- a/beacon-chain/db/kv/blocks_test.go +++ b/beacon-chain/db/kv/blocks_test.go @@ -17,135 +17,193 @@ import ( "google.golang.org/protobuf/proto" ) +var blockTests = []struct { + name string + newBlock func(types.Slot, []byte) (block.SignedBeaconBlock, error) +}{ + { + name: "phase0", + newBlock: func(slot types.Slot, root []byte) (block.SignedBeaconBlock, error) { + b := util.NewBeaconBlock() + b.Block.Slot = slot + if root != nil { + b.Block.ParentRoot = root + } + return wrapper.WrappedPhase0SignedBeaconBlock(b), nil + }, + }, + { + name: "altair", + newBlock: func(slot types.Slot, root []byte) (block.SignedBeaconBlock, error) { + b := util.NewBeaconBlockAltair() + b.Block.Slot = slot + if root != nil { + b.Block.ParentRoot = root + } + return wrapper.WrappedAltairSignedBeaconBlock(b) + }, + }, + { + name: "bellatrix", + newBlock: func(slot types.Slot, root []byte) (block.SignedBeaconBlock, error) { + b := util.NewBeaconBlockMerge() + b.Block.Slot = slot + if root != nil { + b.Block.ParentRoot = root + } + return wrapper.WrappedMergeSignedBeaconBlock(b) + }, + }, +} + func TestStore_SaveBlock_NoDuplicates(t *testing.T) { BlockCacheSize = 1 - db := setupDB(t) slot := types.Slot(20) ctx := context.Background() - // First we save a previous block to ensure the cache max size is reached. - prevBlock := util.NewBeaconBlock() - prevBlock.Block.Slot = slot - 1 - prevBlock.Block.ParentRoot = bytesutil.PadTo([]byte{1, 2, 3}, 32) - require.NoError(t, db.SaveBlock(ctx, wrapper.WrappedPhase0SignedBeaconBlock(prevBlock))) - block := util.NewBeaconBlock() - block.Block.Slot = slot - block.Block.ParentRoot = bytesutil.PadTo([]byte{1, 2, 3}, 32) - // Even with a full cache, saving new blocks should not cause - // duplicated blocks in the DB. - for i := 0; i < 100; i++ { - require.NoError(t, db.SaveBlock(ctx, wrapper.WrappedPhase0SignedBeaconBlock(block))) + for _, tt := range blockTests { + t.Run(tt.name, func(t *testing.T) { + db := setupDB(t) + + // First we save a previous block to ensure the cache max size is reached. + prevBlock, err := tt.newBlock(slot-1, bytesutil.PadTo([]byte{1, 2, 3}, 32)) + require.NoError(t, err) + require.NoError(t, db.SaveBlock(ctx, prevBlock)) + + blk, err := tt.newBlock(slot, bytesutil.PadTo([]byte{1, 2, 3}, 32)) + require.NoError(t, err) + + // Even with a full cache, saving new blocks should not cause + // duplicated blocks in the DB. + for i := 0; i < 100; i++ { + require.NoError(t, db.SaveBlock(ctx, blk)) + } + + f := filters.NewFilter().SetStartSlot(slot).SetEndSlot(slot) + retrieved, _, err := db.Blocks(ctx, f) + require.NoError(t, err) + assert.Equal(t, 1, len(retrieved)) + }) } - f := filters.NewFilter().SetStartSlot(slot).SetEndSlot(slot) - retrieved, _, err := db.Blocks(ctx, f) - require.NoError(t, err) - assert.Equal(t, 1, len(retrieved)) // We reset the block cache size. BlockCacheSize = 256 } func TestStore_BlocksCRUD(t *testing.T) { - db := setupDB(t) ctx := context.Background() - block := util.NewBeaconBlock() - block.Block.Slot = 20 - block.Block.ParentRoot = bytesutil.PadTo([]byte{1, 2, 3}, 32) + for _, tt := range blockTests { + t.Run(tt.name, func(t *testing.T) { + db := setupDB(t) - blockRoot, err := block.Block.HashTreeRoot() - require.NoError(t, err) - retrievedBlock, err := db.Block(ctx, blockRoot) - require.NoError(t, err) - assert.DeepEqual(t, nil, retrievedBlock, "Expected nil block") - require.NoError(t, db.SaveBlock(ctx, wrapper.WrappedPhase0SignedBeaconBlock(block))) - assert.Equal(t, true, db.HasBlock(ctx, blockRoot), "Expected block to exist in the db") - retrievedBlock, err = db.Block(ctx, blockRoot) - require.NoError(t, err) - assert.Equal(t, true, proto.Equal(block, retrievedBlock.Proto()), "Wanted: %v, received: %v", block, retrievedBlock) - require.NoError(t, db.deleteBlock(ctx, blockRoot)) - assert.Equal(t, false, db.HasBlock(ctx, blockRoot), "Expected block to have been deleted from the db") + blk, err := tt.newBlock(types.Slot(20), bytesutil.PadTo([]byte{1, 2, 3}, 32)) + require.NoError(t, err) + blockRoot, err := blk.Block().HashTreeRoot() + require.NoError(t, err) + + retrievedBlock, err := db.Block(ctx, blockRoot) + require.NoError(t, err) + assert.DeepEqual(t, nil, retrievedBlock, "Expected nil block") + require.NoError(t, db.SaveBlock(ctx, blk)) + assert.Equal(t, true, db.HasBlock(ctx, blockRoot), "Expected block to exist in the db") + retrievedBlock, err = db.Block(ctx, blockRoot) + require.NoError(t, err) + assert.Equal(t, true, proto.Equal(blk.Proto(), retrievedBlock.Proto()), "Wanted: %v, received: %v", blk, retrievedBlock) + require.NoError(t, db.deleteBlock(ctx, blockRoot)) + assert.Equal(t, false, db.HasBlock(ctx, blockRoot), "Expected block to have been deleted from the db") + }) + } } func TestStore_BlocksBatchDelete(t *testing.T) { - db := setupDB(t) - ctx := context.Background() - numBlocks := 10 - totalBlocks := make([]block.SignedBeaconBlock, numBlocks) - blockRoots := make([][32]byte, 0) - oddBlocks := make([]block.SignedBeaconBlock, 0) - for i := 0; i < len(totalBlocks); i++ { - b := util.NewBeaconBlock() - b.Block.Slot = types.Slot(i) - b.Block.ParentRoot = bytesutil.PadTo([]byte("parent"), 32) - totalBlocks[i] = wrapper.WrappedPhase0SignedBeaconBlock(b) - if i%2 == 0 { - r, err := totalBlocks[i].Block().HashTreeRoot() + for _, tt := range blockTests { + t.Run(tt.name, func(t *testing.T) { + db := setupDB(t) + ctx := context.Background() + numBlocks := 10 + totalBlocks := make([]block.SignedBeaconBlock, numBlocks) + blockRoots := make([][32]byte, 0) + oddBlocks := make([]block.SignedBeaconBlock, 0) + for i := 0; i < len(totalBlocks); i++ { + b, err := tt.newBlock(types.Slot(i), bytesutil.PadTo([]byte("parent"), 32)) + require.NoError(t, err) + totalBlocks[i] = b + if i%2 == 0 { + r, err := totalBlocks[i].Block().HashTreeRoot() + require.NoError(t, err) + blockRoots = append(blockRoots, r) + } else { + oddBlocks = append(oddBlocks, totalBlocks[i]) + } + } + require.NoError(t, db.SaveBlocks(ctx, totalBlocks)) + retrieved, _, err := db.Blocks(ctx, filters.NewFilter().SetParentRoot(bytesutil.PadTo([]byte("parent"), 32))) require.NoError(t, err) - blockRoots = append(blockRoots, r) - } else { - oddBlocks = append(oddBlocks, totalBlocks[i]) - } - } - require.NoError(t, db.SaveBlocks(ctx, totalBlocks)) - retrieved, _, err := db.Blocks(ctx, filters.NewFilter().SetParentRoot(bytesutil.PadTo([]byte("parent"), 32))) - require.NoError(t, err) - assert.Equal(t, numBlocks, len(retrieved), "Unexpected number of blocks received") - // We delete all even indexed blocks. - require.NoError(t, db.deleteBlocks(ctx, blockRoots)) - // When we retrieve the data, only the odd indexed blocks should remain. - retrieved, _, err = db.Blocks(ctx, filters.NewFilter().SetParentRoot(bytesutil.PadTo([]byte("parent"), 32))) - require.NoError(t, err) - sort.Slice(retrieved, func(i, j int) bool { - return retrieved[i].Block().Slot() < retrieved[j].Block().Slot() - }) - for i, block := range retrieved { - assert.Equal(t, true, proto.Equal(block.Proto(), oddBlocks[i].Proto()), "Wanted: %v, received: %v", block, oddBlocks[i]) + assert.Equal(t, numBlocks, len(retrieved), "Unexpected number of blocks received") + // We delete all even indexed blocks. + require.NoError(t, db.deleteBlocks(ctx, blockRoots)) + // When we retrieve the data, only the odd indexed blocks should remain. + retrieved, _, err = db.Blocks(ctx, filters.NewFilter().SetParentRoot(bytesutil.PadTo([]byte("parent"), 32))) + require.NoError(t, err) + sort.Slice(retrieved, func(i, j int) bool { + return retrieved[i].Block().Slot() < retrieved[j].Block().Slot() + }) + for i, blk := range retrieved { + assert.Equal(t, true, proto.Equal(blk.Proto(), oddBlocks[i].Proto()), "Wanted: %v, received: %v", blk, oddBlocks[i]) + } + }) } } func TestStore_BlocksHandleZeroCase(t *testing.T) { - db := setupDB(t) - ctx := context.Background() - numBlocks := 10 - totalBlocks := make([]block.SignedBeaconBlock, numBlocks) - for i := 0; i < len(totalBlocks); i++ { - b := util.NewBeaconBlock() - b.Block.Slot = types.Slot(i) - b.Block.ParentRoot = bytesutil.PadTo([]byte("parent"), 32) - totalBlocks[i] = wrapper.WrappedPhase0SignedBeaconBlock(b) - _, err := totalBlocks[i].Block().HashTreeRoot() - require.NoError(t, err) + for _, tt := range blockTests { + t.Run(tt.name, func(t *testing.T) { + db := setupDB(t) + ctx := context.Background() + numBlocks := 10 + totalBlocks := make([]block.SignedBeaconBlock, numBlocks) + for i := 0; i < len(totalBlocks); i++ { + b, err := tt.newBlock(types.Slot(i), bytesutil.PadTo([]byte("parent"), 32)) + require.NoError(t, err) + totalBlocks[i] = b + _, err = totalBlocks[i].Block().HashTreeRoot() + require.NoError(t, err) + } + require.NoError(t, db.SaveBlocks(ctx, totalBlocks)) + zeroFilter := filters.NewFilter().SetStartSlot(0).SetEndSlot(0) + retrieved, _, err := db.Blocks(ctx, zeroFilter) + require.NoError(t, err) + assert.Equal(t, 1, len(retrieved), "Unexpected number of blocks received, expected one") + }) } - require.NoError(t, db.SaveBlocks(ctx, totalBlocks)) - zeroFilter := filters.NewFilter().SetStartSlot(0).SetEndSlot(0) - retrieved, _, err := db.Blocks(ctx, zeroFilter) - require.NoError(t, err) - assert.Equal(t, 1, len(retrieved), "Unexpected number of blocks received, expected one") } func TestStore_BlocksHandleInvalidEndSlot(t *testing.T) { - db := setupDB(t) - ctx := context.Background() - numBlocks := 10 - totalBlocks := make([]block.SignedBeaconBlock, numBlocks) - // Save blocks from slot 1 onwards. - for i := 0; i < len(totalBlocks); i++ { - b := util.NewBeaconBlock() - b.Block.Slot = types.Slot(i) + 1 - b.Block.ParentRoot = bytesutil.PadTo([]byte("parent"), 32) - totalBlocks[i] = wrapper.WrappedPhase0SignedBeaconBlock(b) - _, err := totalBlocks[i].Block().HashTreeRoot() - require.NoError(t, err) - } - require.NoError(t, db.SaveBlocks(ctx, totalBlocks)) - badFilter := filters.NewFilter().SetStartSlot(5).SetEndSlot(1) - _, _, err := db.Blocks(ctx, badFilter) - require.ErrorContains(t, errInvalidSlotRange.Error(), err) + for _, tt := range blockTests { + t.Run(tt.name, func(t *testing.T) { + db := setupDB(t) + ctx := context.Background() + numBlocks := 10 + totalBlocks := make([]block.SignedBeaconBlock, numBlocks) + // Save blocks from slot 1 onwards. + for i := 0; i < len(totalBlocks); i++ { + b, err := tt.newBlock(types.Slot(i+1), bytesutil.PadTo([]byte("parent"), 32)) + require.NoError(t, err) + totalBlocks[i] = b + _, err = totalBlocks[i].Block().HashTreeRoot() + require.NoError(t, err) + } + require.NoError(t, db.SaveBlocks(ctx, totalBlocks)) + badFilter := filters.NewFilter().SetStartSlot(5).SetEndSlot(1) + _, _, err := db.Blocks(ctx, badFilter) + require.ErrorContains(t, errInvalidSlotRange.Error(), err) - goodFilter := filters.NewFilter().SetStartSlot(0).SetEndSlot(1) - requested, _, err := db.Blocks(ctx, goodFilter) - require.NoError(t, err) - assert.Equal(t, 1, len(requested), "Unexpected number of blocks received, only expected two") + goodFilter := filters.NewFilter().SetStartSlot(0).SetEndSlot(1) + requested, _, err := db.Blocks(ctx, goodFilter) + require.NoError(t, err) + assert.Equal(t, 1, len(requested), "Unexpected number of blocks received, only expected two") + }) + } } func TestStore_GenesisBlock(t *testing.T) { @@ -163,349 +221,385 @@ func TestStore_GenesisBlock(t *testing.T) { } func TestStore_BlocksCRUD_NoCache(t *testing.T) { - db := setupDB(t) - ctx := context.Background() - block := util.NewBeaconBlock() - block.Block.Slot = 20 - block.Block.ParentRoot = bytesutil.PadTo([]byte{1, 2, 3}, 32) - blockRoot, err := block.Block.HashTreeRoot() - require.NoError(t, err) - retrievedBlock, err := db.Block(ctx, blockRoot) - require.NoError(t, err) - require.DeepEqual(t, nil, retrievedBlock, "Expected nil block") - require.NoError(t, db.SaveBlock(ctx, wrapper.WrappedPhase0SignedBeaconBlock(block))) - db.blockCache.Del(string(blockRoot[:])) - assert.Equal(t, true, db.HasBlock(ctx, blockRoot), "Expected block to exist in the db") - retrievedBlock, err = db.Block(ctx, blockRoot) - require.NoError(t, err) - assert.Equal(t, true, proto.Equal(block, retrievedBlock.Proto()), "Wanted: %v, received: %v", block, retrievedBlock) - require.NoError(t, db.deleteBlock(ctx, blockRoot)) - assert.Equal(t, false, db.HasBlock(ctx, blockRoot), "Expected block to have been deleted from the db") + for _, tt := range blockTests { + t.Run(tt.name, func(t *testing.T) { + db := setupDB(t) + ctx := context.Background() + blk, err := tt.newBlock(types.Slot(20), bytesutil.PadTo([]byte{1, 2, 3}, 32)) + require.NoError(t, err) + blockRoot, err := blk.Block().HashTreeRoot() + require.NoError(t, err) + retrievedBlock, err := db.Block(ctx, blockRoot) + require.NoError(t, err) + require.DeepEqual(t, nil, retrievedBlock, "Expected nil block") + require.NoError(t, db.SaveBlock(ctx, blk)) + db.blockCache.Del(string(blockRoot[:])) + assert.Equal(t, true, db.HasBlock(ctx, blockRoot), "Expected block to exist in the db") + retrievedBlock, err = db.Block(ctx, blockRoot) + require.NoError(t, err) + assert.Equal(t, true, proto.Equal(blk.Proto(), retrievedBlock.Proto()), "Wanted: %v, received: %v", blk, retrievedBlock) + require.NoError(t, db.deleteBlock(ctx, blockRoot)) + assert.Equal(t, false, db.HasBlock(ctx, blockRoot), "Expected block to have been deleted from the db") + }) + } } func TestStore_Blocks_FiltersCorrectly(t *testing.T) { - db := setupDB(t) - b4 := util.NewBeaconBlock() - b4.Block.Slot = 4 - b4.Block.ParentRoot = bytesutil.PadTo([]byte("parent"), 32) - b5 := util.NewBeaconBlock() - b5.Block.Slot = 5 - b5.Block.ParentRoot = bytesutil.PadTo([]byte("parent2"), 32) - b6 := util.NewBeaconBlock() - b6.Block.Slot = 6 - b6.Block.ParentRoot = bytesutil.PadTo([]byte("parent2"), 32) - b7 := util.NewBeaconBlock() - b7.Block.Slot = 7 - b7.Block.ParentRoot = bytesutil.PadTo([]byte("parent3"), 32) - b8 := util.NewBeaconBlock() - b8.Block.Slot = 8 - b8.Block.ParentRoot = bytesutil.PadTo([]byte("parent4"), 32) - blocks := []block.SignedBeaconBlock{ - wrapper.WrappedPhase0SignedBeaconBlock(b4), - wrapper.WrappedPhase0SignedBeaconBlock(b5), - wrapper.WrappedPhase0SignedBeaconBlock(b6), - wrapper.WrappedPhase0SignedBeaconBlock(b7), - wrapper.WrappedPhase0SignedBeaconBlock(b8), - } - ctx := context.Background() - require.NoError(t, db.SaveBlocks(ctx, blocks)) + for _, tt := range blockTests { + t.Run(tt.name, func(t *testing.T) { + db := setupDB(t) + b4, err := tt.newBlock(types.Slot(4), bytesutil.PadTo([]byte("parent"), 32)) + require.NoError(t, err) + b5, err := tt.newBlock(types.Slot(5), bytesutil.PadTo([]byte("parent2"), 32)) + require.NoError(t, err) + b6, err := tt.newBlock(types.Slot(6), bytesutil.PadTo([]byte("parent2"), 32)) + require.NoError(t, err) + b7, err := tt.newBlock(types.Slot(7), bytesutil.PadTo([]byte("parent3"), 32)) + require.NoError(t, err) + b8, err := tt.newBlock(types.Slot(8), bytesutil.PadTo([]byte("parent4"), 32)) + require.NoError(t, err) + blocks := []block.SignedBeaconBlock{ + b4, + b5, + b6, + b7, + b8, + } + ctx := context.Background() + require.NoError(t, db.SaveBlocks(ctx, blocks)) - tests := []struct { - filter *filters.QueryFilter - expectedNumBlocks int - }{ - { - filter: filters.NewFilter().SetParentRoot(bytesutil.PadTo([]byte("parent2"), 32)), - expectedNumBlocks: 2, - }, - { - // No block meets the criteria below. - filter: filters.NewFilter().SetParentRoot(bytesutil.PadTo([]byte{3, 4, 5}, 32)), - expectedNumBlocks: 0, - }, - { - // Block slot range filter criteria. - filter: filters.NewFilter().SetStartSlot(5).SetEndSlot(7), - expectedNumBlocks: 3, - }, - { - filter: filters.NewFilter().SetStartSlot(7).SetEndSlot(7), - expectedNumBlocks: 1, - }, - { - filter: filters.NewFilter().SetStartSlot(4).SetEndSlot(8), - expectedNumBlocks: 5, - }, - { - filter: filters.NewFilter().SetStartSlot(4).SetEndSlot(5), - expectedNumBlocks: 2, - }, - { - filter: filters.NewFilter().SetStartSlot(5).SetEndSlot(9), - expectedNumBlocks: 4, - }, - { - filter: filters.NewFilter().SetEndSlot(7), - expectedNumBlocks: 4, - }, - { - filter: filters.NewFilter().SetEndSlot(8), - expectedNumBlocks: 5, - }, - { - filter: filters.NewFilter().SetStartSlot(5).SetEndSlot(10), - expectedNumBlocks: 4, - }, - { - // Composite filter criteria. - filter: filters.NewFilter(). - SetParentRoot(bytesutil.PadTo([]byte("parent2"), 32)). - SetStartSlot(6). - SetEndSlot(8), - expectedNumBlocks: 1, - }, - } - for _, tt := range tests { - retrievedBlocks, _, err := db.Blocks(ctx, tt.filter) - require.NoError(t, err) - assert.Equal(t, tt.expectedNumBlocks, len(retrievedBlocks), "Unexpected number of blocks") + tests := []struct { + filter *filters.QueryFilter + expectedNumBlocks int + }{ + { + filter: filters.NewFilter().SetParentRoot(bytesutil.PadTo([]byte("parent2"), 32)), + expectedNumBlocks: 2, + }, + { + // No block meets the criteria below. + filter: filters.NewFilter().SetParentRoot(bytesutil.PadTo([]byte{3, 4, 5}, 32)), + expectedNumBlocks: 0, + }, + { + // Block slot range filter criteria. + filter: filters.NewFilter().SetStartSlot(5).SetEndSlot(7), + expectedNumBlocks: 3, + }, + { + filter: filters.NewFilter().SetStartSlot(7).SetEndSlot(7), + expectedNumBlocks: 1, + }, + { + filter: filters.NewFilter().SetStartSlot(4).SetEndSlot(8), + expectedNumBlocks: 5, + }, + { + filter: filters.NewFilter().SetStartSlot(4).SetEndSlot(5), + expectedNumBlocks: 2, + }, + { + filter: filters.NewFilter().SetStartSlot(5).SetEndSlot(9), + expectedNumBlocks: 4, + }, + { + filter: filters.NewFilter().SetEndSlot(7), + expectedNumBlocks: 4, + }, + { + filter: filters.NewFilter().SetEndSlot(8), + expectedNumBlocks: 5, + }, + { + filter: filters.NewFilter().SetStartSlot(5).SetEndSlot(10), + expectedNumBlocks: 4, + }, + { + // Composite filter criteria. + filter: filters.NewFilter(). + SetParentRoot(bytesutil.PadTo([]byte("parent2"), 32)). + SetStartSlot(6). + SetEndSlot(8), + expectedNumBlocks: 1, + }, + } + for _, tt2 := range tests { + retrievedBlocks, _, err := db.Blocks(ctx, tt2.filter) + require.NoError(t, err) + assert.Equal(t, tt2.expectedNumBlocks, len(retrievedBlocks), "Unexpected number of blocks") + } + }) } } func TestStore_Blocks_VerifyBlockRoots(t *testing.T) { - ctx := context.Background() - db := setupDB(t) - b1 := util.NewBeaconBlock() - b1.Block.Slot = 1 - r1, err := b1.Block.HashTreeRoot() - require.NoError(t, err) - b2 := util.NewBeaconBlock() - b2.Block.Slot = 2 - r2, err := b2.Block.HashTreeRoot() - require.NoError(t, err) + for _, tt := range blockTests { + t.Run(tt.name, func(t *testing.T) { + ctx := context.Background() + db := setupDB(t) + b1, err := tt.newBlock(types.Slot(1), nil) + require.NoError(t, err) + r1, err := b1.Block().HashTreeRoot() + require.NoError(t, err) + b2, err := tt.newBlock(types.Slot(2), nil) + require.NoError(t, err) + r2, err := b2.Block().HashTreeRoot() + require.NoError(t, err) - require.NoError(t, db.SaveBlock(ctx, wrapper.WrappedPhase0SignedBeaconBlock(b1))) - require.NoError(t, db.SaveBlock(ctx, wrapper.WrappedPhase0SignedBeaconBlock(b2))) + require.NoError(t, db.SaveBlock(ctx, b1)) + require.NoError(t, db.SaveBlock(ctx, b2)) - filter := filters.NewFilter().SetStartSlot(b1.Block.Slot).SetEndSlot(b2.Block.Slot) - roots, err := db.BlockRoots(ctx, filter) - require.NoError(t, err) + filter := filters.NewFilter().SetStartSlot(b1.Block().Slot()).SetEndSlot(b2.Block().Slot()) + roots, err := db.BlockRoots(ctx, filter) + require.NoError(t, err) - assert.DeepEqual(t, [][32]byte{r1, r2}, roots) + assert.DeepEqual(t, [][32]byte{r1, r2}, roots) + }) + } } func TestStore_Blocks_Retrieve_SlotRange(t *testing.T) { - db := setupDB(t) - totalBlocks := make([]block.SignedBeaconBlock, 500) - for i := 0; i < 500; i++ { - b := util.NewBeaconBlock() - b.Block.Slot = types.Slot(i) - b.Block.ParentRoot = bytesutil.PadTo([]byte("parent"), 32) - totalBlocks[i] = wrapper.WrappedPhase0SignedBeaconBlock(b) + for _, tt := range blockTests { + t.Run(tt.name, func(t *testing.T) { + db := setupDB(t) + totalBlocks := make([]block.SignedBeaconBlock, 500) + for i := 0; i < 500; i++ { + b, err := tt.newBlock(types.Slot(i), bytesutil.PadTo([]byte("parent"), 32)) + require.NoError(t, err) + totalBlocks[i] = b + } + ctx := context.Background() + require.NoError(t, db.SaveBlocks(ctx, totalBlocks)) + retrieved, _, err := db.Blocks(ctx, filters.NewFilter().SetStartSlot(100).SetEndSlot(399)) + require.NoError(t, err) + assert.Equal(t, 300, len(retrieved)) + }) } - ctx := context.Background() - require.NoError(t, db.SaveBlocks(ctx, totalBlocks)) - retrieved, _, err := db.Blocks(ctx, filters.NewFilter().SetStartSlot(100).SetEndSlot(399)) - require.NoError(t, err) - assert.Equal(t, 300, len(retrieved)) } func TestStore_Blocks_Retrieve_Epoch(t *testing.T) { - db := setupDB(t) - slots := params.BeaconConfig().SlotsPerEpoch.Mul(7) - totalBlocks := make([]block.SignedBeaconBlock, slots) - for i := types.Slot(0); i < slots; i++ { - b := util.NewBeaconBlock() - b.Block.Slot = i - b.Block.ParentRoot = bytesutil.PadTo([]byte("parent"), 32) - totalBlocks[i] = wrapper.WrappedPhase0SignedBeaconBlock(b) + for _, tt := range blockTests { + t.Run(tt.name, func(t *testing.T) { + db := setupDB(t) + slots := params.BeaconConfig().SlotsPerEpoch.Mul(7) + totalBlocks := make([]block.SignedBeaconBlock, slots) + for i := types.Slot(0); i < slots; i++ { + b, err := tt.newBlock(i, bytesutil.PadTo([]byte("parent"), 32)) + require.NoError(t, err) + totalBlocks[i] = b + } + ctx := context.Background() + require.NoError(t, db.SaveBlocks(ctx, totalBlocks)) + retrieved, _, err := db.Blocks(ctx, filters.NewFilter().SetStartEpoch(5).SetEndEpoch(6)) + require.NoError(t, err) + want := params.BeaconConfig().SlotsPerEpoch.Mul(2) + assert.Equal(t, uint64(want), uint64(len(retrieved))) + retrieved, _, err = db.Blocks(ctx, filters.NewFilter().SetStartEpoch(0).SetEndEpoch(0)) + require.NoError(t, err) + want = params.BeaconConfig().SlotsPerEpoch + assert.Equal(t, uint64(want), uint64(len(retrieved))) + }) } - ctx := context.Background() - require.NoError(t, db.SaveBlocks(ctx, totalBlocks)) - retrieved, _, err := db.Blocks(ctx, filters.NewFilter().SetStartEpoch(5).SetEndEpoch(6)) - require.NoError(t, err) - want := params.BeaconConfig().SlotsPerEpoch.Mul(2) - assert.Equal(t, uint64(want), uint64(len(retrieved))) - retrieved, _, err = db.Blocks(ctx, filters.NewFilter().SetStartEpoch(0).SetEndEpoch(0)) - require.NoError(t, err) - want = params.BeaconConfig().SlotsPerEpoch - assert.Equal(t, uint64(want), uint64(len(retrieved))) } func TestStore_Blocks_Retrieve_SlotRangeWithStep(t *testing.T) { - db := setupDB(t) - totalBlocks := make([]block.SignedBeaconBlock, 500) - for i := 0; i < 500; i++ { - b := util.NewBeaconBlock() - b.Block.Slot = types.Slot(i) - b.Block.ParentRoot = bytesutil.PadTo([]byte("parent"), 32) - totalBlocks[i] = wrapper.WrappedPhase0SignedBeaconBlock(b) - } - const step = 2 - ctx := context.Background() - require.NoError(t, db.SaveBlocks(ctx, totalBlocks)) - retrieved, _, err := db.Blocks(ctx, filters.NewFilter().SetStartSlot(100).SetEndSlot(399).SetSlotStep(step)) - require.NoError(t, err) - assert.Equal(t, 150, len(retrieved)) - for _, b := range retrieved { - assert.Equal(t, types.Slot(0), (b.Block().Slot()-100)%step, "Unexpect block slot %d", b.Block().Slot()) + for _, tt := range blockTests { + t.Run(tt.name, func(t *testing.T) { + db := setupDB(t) + totalBlocks := make([]block.SignedBeaconBlock, 500) + for i := 0; i < 500; i++ { + b, err := tt.newBlock(types.Slot(i), bytesutil.PadTo([]byte("parent"), 32)) + require.NoError(t, err) + totalBlocks[i] = b + } + const step = 2 + ctx := context.Background() + require.NoError(t, db.SaveBlocks(ctx, totalBlocks)) + retrieved, _, err := db.Blocks(ctx, filters.NewFilter().SetStartSlot(100).SetEndSlot(399).SetSlotStep(step)) + require.NoError(t, err) + assert.Equal(t, 150, len(retrieved)) + for _, b := range retrieved { + assert.Equal(t, types.Slot(0), (b.Block().Slot()-100)%step, "Unexpect block slot %d", b.Block().Slot()) + } + }) } } func TestStore_SaveBlock_CanGetHighestAt(t *testing.T) { - db := setupDB(t) - ctx := context.Background() + for _, tt := range blockTests { + t.Run(tt.name, func(t *testing.T) { + db := setupDB(t) + ctx := context.Background() - block1 := util.NewBeaconBlock() - block1.Block.Slot = 1 - require.NoError(t, db.SaveBlock(ctx, wrapper.WrappedPhase0SignedBeaconBlock(block1))) - block2 := util.NewBeaconBlock() - block2.Block.Slot = 10 - require.NoError(t, db.SaveBlock(ctx, wrapper.WrappedPhase0SignedBeaconBlock(block2))) - block3 := util.NewBeaconBlock() - block3.Block.Slot = 100 - require.NoError(t, db.SaveBlock(ctx, wrapper.WrappedPhase0SignedBeaconBlock(block3))) + block1, err := tt.newBlock(types.Slot(1), nil) + require.NoError(t, err) + block2, err := tt.newBlock(types.Slot(10), nil) + require.NoError(t, err) + block3, err := tt.newBlock(types.Slot(100), nil) + require.NoError(t, err) - highestAt, err := db.HighestSlotBlocksBelow(ctx, 2) - require.NoError(t, err) - assert.Equal(t, false, len(highestAt) <= 0, "Got empty highest at slice") - assert.Equal(t, true, proto.Equal(block1, highestAt[0].Proto()), "Wanted: %v, received: %v", block1, highestAt[0]) - highestAt, err = db.HighestSlotBlocksBelow(ctx, 11) - require.NoError(t, err) - assert.Equal(t, false, len(highestAt) <= 0, "Got empty highest at slice") - assert.Equal(t, true, proto.Equal(block2, highestAt[0].Proto()), "Wanted: %v, received: %v", block2, highestAt[0]) - highestAt, err = db.HighestSlotBlocksBelow(ctx, 101) - require.NoError(t, err) - assert.Equal(t, false, len(highestAt) <= 0, "Got empty highest at slice") - assert.Equal(t, true, proto.Equal(block3, highestAt[0].Proto()), "Wanted: %v, received: %v", block3, highestAt[0]) + require.NoError(t, db.SaveBlock(ctx, block1)) + require.NoError(t, db.SaveBlock(ctx, block2)) + require.NoError(t, db.SaveBlock(ctx, block3)) - r3, err := block3.Block.HashTreeRoot() - require.NoError(t, err) - require.NoError(t, db.deleteBlock(ctx, r3)) + highestAt, err := db.HighestSlotBlocksBelow(ctx, 2) + require.NoError(t, err) + assert.Equal(t, false, len(highestAt) <= 0, "Got empty highest at slice") + assert.Equal(t, true, proto.Equal(block1.Proto(), highestAt[0].Proto()), "Wanted: %v, received: %v", block1, highestAt[0]) + highestAt, err = db.HighestSlotBlocksBelow(ctx, 11) + require.NoError(t, err) + assert.Equal(t, false, len(highestAt) <= 0, "Got empty highest at slice") + assert.Equal(t, true, proto.Equal(block2.Proto(), highestAt[0].Proto()), "Wanted: %v, received: %v", block2, highestAt[0]) + highestAt, err = db.HighestSlotBlocksBelow(ctx, 101) + require.NoError(t, err) + assert.Equal(t, false, len(highestAt) <= 0, "Got empty highest at slice") + assert.Equal(t, true, proto.Equal(block3.Proto(), highestAt[0].Proto()), "Wanted: %v, received: %v", block3, highestAt[0]) - highestAt, err = db.HighestSlotBlocksBelow(ctx, 101) - require.NoError(t, err) - assert.Equal(t, true, proto.Equal(block2, highestAt[0].Proto()), "Wanted: %v, received: %v", block2, highestAt[0]) + r3, err := block3.Block().HashTreeRoot() + require.NoError(t, err) + require.NoError(t, db.deleteBlock(ctx, r3)) + + highestAt, err = db.HighestSlotBlocksBelow(ctx, 101) + require.NoError(t, err) + assert.Equal(t, true, proto.Equal(block2.Proto(), highestAt[0].Proto()), "Wanted: %v, received: %v", block2, highestAt[0]) + }) + } } func TestStore_GenesisBlock_CanGetHighestAt(t *testing.T) { - db := setupDB(t) - ctx := context.Background() + for _, tt := range blockTests { + t.Run(tt.name, func(t *testing.T) { + db := setupDB(t) + ctx := context.Background() - genesisBlock := util.NewBeaconBlock() - genesisRoot, err := genesisBlock.Block.HashTreeRoot() - require.NoError(t, err) - require.NoError(t, db.SaveGenesisBlockRoot(ctx, genesisRoot)) - require.NoError(t, db.SaveBlock(ctx, wrapper.WrappedPhase0SignedBeaconBlock(genesisBlock))) - block1 := util.NewBeaconBlock() - block1.Block.Slot = 1 - require.NoError(t, db.SaveBlock(ctx, wrapper.WrappedPhase0SignedBeaconBlock(block1))) + genesisBlock, err := tt.newBlock(types.Slot(0), nil) + require.NoError(t, err) + genesisRoot, err := genesisBlock.Block().HashTreeRoot() + require.NoError(t, err) + require.NoError(t, db.SaveGenesisBlockRoot(ctx, genesisRoot)) + require.NoError(t, db.SaveBlock(ctx, genesisBlock)) + block1, err := tt.newBlock(types.Slot(1), nil) + require.NoError(t, err) + require.NoError(t, db.SaveBlock(ctx, block1)) - highestAt, err := db.HighestSlotBlocksBelow(ctx, 2) - require.NoError(t, err) - assert.Equal(t, true, proto.Equal(block1, highestAt[0].Proto()), "Wanted: %v, received: %v", block1, highestAt[0]) - highestAt, err = db.HighestSlotBlocksBelow(ctx, 1) - require.NoError(t, err) - assert.Equal(t, true, proto.Equal(genesisBlock, highestAt[0].Proto()), "Wanted: %v, received: %v", genesisBlock, highestAt[0]) - highestAt, err = db.HighestSlotBlocksBelow(ctx, 0) - require.NoError(t, err) - assert.Equal(t, true, proto.Equal(genesisBlock, highestAt[0].Proto()), "Wanted: %v, received: %v", genesisBlock, highestAt[0]) + highestAt, err := db.HighestSlotBlocksBelow(ctx, 2) + require.NoError(t, err) + assert.Equal(t, true, proto.Equal(block1.Proto(), highestAt[0].Proto()), "Wanted: %v, received: %v", block1, highestAt[0]) + highestAt, err = db.HighestSlotBlocksBelow(ctx, 1) + require.NoError(t, err) + assert.Equal(t, true, proto.Equal(genesisBlock.Proto(), highestAt[0].Proto()), "Wanted: %v, received: %v", genesisBlock, highestAt[0]) + highestAt, err = db.HighestSlotBlocksBelow(ctx, 0) + require.NoError(t, err) + assert.Equal(t, true, proto.Equal(genesisBlock.Proto(), highestAt[0].Proto()), "Wanted: %v, received: %v", genesisBlock, highestAt[0]) + }) + } } func TestStore_SaveBlocks_HasCachedBlocks(t *testing.T) { - db := setupDB(t) - ctx := context.Background() + for _, tt := range blockTests { + t.Run(tt.name, func(t *testing.T) { + db := setupDB(t) + ctx := context.Background() - b := make([]block.SignedBeaconBlock, 500) - for i := 0; i < 500; i++ { - blk := util.NewBeaconBlock() - blk.Block.ParentRoot = bytesutil.PadTo([]byte("parent"), 32) - blk.Block.Slot = types.Slot(i) - b[i] = wrapper.WrappedPhase0SignedBeaconBlock(blk) + b := make([]block.SignedBeaconBlock, 500) + for i := 0; i < 500; i++ { + blk, err := tt.newBlock(types.Slot(i), bytesutil.PadTo([]byte("parent"), 32)) + require.NoError(t, err) + b[i] = blk + } + + require.NoError(t, db.SaveBlock(ctx, b[0])) + require.NoError(t, db.SaveBlocks(ctx, b)) + f := filters.NewFilter().SetStartSlot(0).SetEndSlot(500) + + blks, _, err := db.Blocks(ctx, f) + require.NoError(t, err) + assert.Equal(t, 500, len(blks), "Did not get wanted blocks") + }) } - - require.NoError(t, db.SaveBlock(ctx, b[0])) - require.NoError(t, db.SaveBlocks(ctx, b)) - f := filters.NewFilter().SetStartSlot(0).SetEndSlot(500) - - blks, _, err := db.Blocks(ctx, f) - require.NoError(t, err) - assert.Equal(t, 500, len(blks), "Did not get wanted blocks") } func TestStore_SaveBlocks_HasRootsMatched(t *testing.T) { - db := setupDB(t) - ctx := context.Background() + for _, tt := range blockTests { + t.Run(tt.name, func(t *testing.T) { + db := setupDB(t) + ctx := context.Background() - b := make([]block.SignedBeaconBlock, 500) - for i := 0; i < 500; i++ { - blk := util.NewBeaconBlock() - blk.Block.ParentRoot = bytesutil.PadTo([]byte("parent"), 32) - blk.Block.Slot = types.Slot(i) - b[i] = wrapper.WrappedPhase0SignedBeaconBlock(blk) - } + b := make([]block.SignedBeaconBlock, 500) + for i := 0; i < 500; i++ { + blk, err := tt.newBlock(types.Slot(i), bytesutil.PadTo([]byte("parent"), 32)) + require.NoError(t, err) + b[i] = blk + } - require.NoError(t, db.SaveBlocks(ctx, b)) - f := filters.NewFilter().SetStartSlot(0).SetEndSlot(500) + require.NoError(t, db.SaveBlocks(ctx, b)) + f := filters.NewFilter().SetStartSlot(0).SetEndSlot(500) - blks, roots, err := db.Blocks(ctx, f) - require.NoError(t, err) - assert.Equal(t, 500, len(blks), "Did not get wanted blocks") + blks, roots, err := db.Blocks(ctx, f) + require.NoError(t, err) + assert.Equal(t, 500, len(blks), "Did not get wanted blocks") - for i, blk := range blks { - rt, err := blk.Block().HashTreeRoot() - require.NoError(t, err) - assert.Equal(t, roots[i], rt, "mismatch of block roots") + for i, blk := range blks { + rt, err := blk.Block().HashTreeRoot() + require.NoError(t, err) + assert.Equal(t, roots[i], rt, "mismatch of block roots") + } + }) } } func TestStore_BlocksBySlot_BlockRootsBySlot(t *testing.T) { - db := setupDB(t) - ctx := context.Background() + for _, tt := range blockTests { + t.Run(tt.name, func(t *testing.T) { + db := setupDB(t) + ctx := context.Background() - b1 := util.NewBeaconBlock() - b1.Block.Slot = 20 - require.NoError(t, db.SaveBlock(ctx, wrapper.WrappedPhase0SignedBeaconBlock(b1))) - b2 := util.NewBeaconBlock() - b2.Block.Slot = 100 - b2.Block.ParentRoot = bytesutil.PadTo([]byte("parent1"), 32) - require.NoError(t, db.SaveBlock(ctx, wrapper.WrappedPhase0SignedBeaconBlock(b2))) - b3 := util.NewBeaconBlock() - b3.Block.Slot = 100 - b3.Block.ParentRoot = bytesutil.PadTo([]byte("parent2"), 32) - require.NoError(t, db.SaveBlock(ctx, wrapper.WrappedPhase0SignedBeaconBlock(b3))) + b1, err := tt.newBlock(types.Slot(20), nil) + require.NoError(t, err) + require.NoError(t, db.SaveBlock(ctx, b1)) + b2, err := tt.newBlock(types.Slot(100), bytesutil.PadTo([]byte("parent1"), 32)) + require.NoError(t, err) + require.NoError(t, db.SaveBlock(ctx, b2)) + b3, err := tt.newBlock(types.Slot(100), bytesutil.PadTo([]byte("parent2"), 32)) + require.NoError(t, err) + require.NoError(t, db.SaveBlock(ctx, b3)) - r1, err := b1.Block.HashTreeRoot() - require.NoError(t, err) - r2, err := b2.Block.HashTreeRoot() - require.NoError(t, err) - r3, err := b3.Block.HashTreeRoot() - require.NoError(t, err) + r1, err := b1.Block().HashTreeRoot() + require.NoError(t, err) + r2, err := b2.Block().HashTreeRoot() + require.NoError(t, err) + r3, err := b3.Block().HashTreeRoot() + require.NoError(t, err) - hasBlocks, retrievedBlocks, err := db.BlocksBySlot(ctx, 1) - require.NoError(t, err) - assert.Equal(t, 0, len(retrievedBlocks), "Unexpected number of blocks received, expected none") - assert.Equal(t, false, hasBlocks, "Expected no blocks") - hasBlocks, retrievedBlocks, err = db.BlocksBySlot(ctx, 20) - require.NoError(t, err) - assert.Equal(t, true, proto.Equal(b1, retrievedBlocks[0].Proto()), "Wanted: %v, received: %v", b1, retrievedBlocks[0]) - assert.Equal(t, true, hasBlocks, "Expected to have blocks") - hasBlocks, retrievedBlocks, err = db.BlocksBySlot(ctx, 100) - require.NoError(t, err) - assert.Equal(t, true, proto.Equal(b2, retrievedBlocks[0].Proto()), "Wanted: %v, received: %v", b2, retrievedBlocks[0]) - assert.Equal(t, true, proto.Equal(b3, retrievedBlocks[1].Proto()), "Wanted: %v, received: %v", b3, retrievedBlocks[1]) - assert.Equal(t, true, hasBlocks, "Expected to have blocks") + hasBlocks, retrievedBlocks, err := db.BlocksBySlot(ctx, 1) + require.NoError(t, err) + assert.Equal(t, 0, len(retrievedBlocks), "Unexpected number of blocks received, expected none") + assert.Equal(t, false, hasBlocks, "Expected no blocks") + hasBlocks, retrievedBlocks, err = db.BlocksBySlot(ctx, 20) + require.NoError(t, err) + assert.Equal(t, true, proto.Equal(b1.Proto(), retrievedBlocks[0].Proto()), "Wanted: %v, received: %v", b1, retrievedBlocks[0]) + assert.Equal(t, true, hasBlocks, "Expected to have blocks") + hasBlocks, retrievedBlocks, err = db.BlocksBySlot(ctx, 100) + require.NoError(t, err) + if len(retrievedBlocks) != 2 { + t.Fatalf("Expected 2 blocks, received %d blocks", len(retrievedBlocks)) + } + assert.Equal(t, true, proto.Equal(b2.Proto(), retrievedBlocks[0].Proto()), "Wanted: %v, received: %v", b2, retrievedBlocks[0]) + assert.Equal(t, true, proto.Equal(b3.Proto(), retrievedBlocks[1].Proto()), "Wanted: %v, received: %v", b3, retrievedBlocks[1]) + assert.Equal(t, true, hasBlocks, "Expected to have blocks") - hasBlockRoots, retrievedBlockRoots, err := db.BlockRootsBySlot(ctx, 1) - require.NoError(t, err) - assert.DeepEqual(t, [][32]byte{}, retrievedBlockRoots) - assert.Equal(t, false, hasBlockRoots, "Expected no block roots") - hasBlockRoots, retrievedBlockRoots, err = db.BlockRootsBySlot(ctx, 20) - require.NoError(t, err) - assert.DeepEqual(t, [][32]byte{r1}, retrievedBlockRoots) - assert.Equal(t, true, hasBlockRoots, "Expected no block roots") - hasBlockRoots, retrievedBlockRoots, err = db.BlockRootsBySlot(ctx, 100) - require.NoError(t, err) - assert.DeepEqual(t, [][32]byte{r2, r3}, retrievedBlockRoots) - assert.Equal(t, true, hasBlockRoots, "Expected no block roots") + hasBlockRoots, retrievedBlockRoots, err := db.BlockRootsBySlot(ctx, 1) + require.NoError(t, err) + assert.DeepEqual(t, [][32]byte{}, retrievedBlockRoots) + assert.Equal(t, false, hasBlockRoots, "Expected no block roots") + hasBlockRoots, retrievedBlockRoots, err = db.BlockRootsBySlot(ctx, 20) + require.NoError(t, err) + assert.DeepEqual(t, [][32]byte{r1}, retrievedBlockRoots) + assert.Equal(t, true, hasBlockRoots, "Expected no block roots") + hasBlockRoots, retrievedBlockRoots, err = db.BlockRootsBySlot(ctx, 100) + require.NoError(t, err) + assert.DeepEqual(t, [][32]byte{r2, r3}, retrievedBlockRoots) + assert.Equal(t, true, hasBlockRoots, "Expected no block roots") + }) + } } diff --git a/beacon-chain/db/kv/finalized_block_roots_test.go b/beacon-chain/db/kv/finalized_block_roots_test.go index 1b4d67b861..98a01608b1 100644 --- a/beacon-chain/db/kv/finalized_block_roots_test.go +++ b/beacon-chain/db/kv/finalized_block_roots_test.go @@ -136,76 +136,57 @@ func TestStore_IsFinalized_ForkEdgeCase(t *testing.T) { func TestStore_IsFinalizedChildBlock(t *testing.T) { slotsPerEpoch := uint64(params.BeaconConfig().SlotsPerEpoch) - db := setupDB(t) ctx := context.Background() - 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) - - 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() + eval := func(t testing.TB, ctx context.Context, db *Store, blks []block.SignedBeaconBlock) { + require.NoError(t, db.SaveBlocks(ctx, blks)) + root, err := blks[slotsPerEpoch].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.") + + 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.") + } } } -} -func TestStore_IsFinalizedChildBlockAltair(t *testing.T) { - slotsPerEpoch := uint64(params.BeaconConfig().SlotsPerEpoch) - db := setupDB(t) - ctx := context.Background() + setup := func(t testing.TB) *Store { + db := setupDB(t) + require.NoError(t, db.SaveGenesisBlockRoot(ctx, genesisBlockRoot)) - require.NoError(t, db.SaveGenesisBlockRoot(ctx, genesisBlockRoot)) - - blks := makeBlocksAltair(t, 0, slotsPerEpoch*3, 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[:], + return db } - 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)) + t.Run("phase0", func(t *testing.T) { + db := setup(t) - // 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*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 block.SignedBeaconBlock) []byte { diff --git a/beacon-chain/rpc/eth/beacon/sync_committee.go b/beacon-chain/rpc/eth/beacon/sync_committee.go index 1ad1260ada..65df6fbc33 100644 --- a/beacon-chain/rpc/eth/beacon/sync_committee.go +++ b/beacon-chain/rpc/eth/beacon/sync_committee.go @@ -99,14 +99,7 @@ func (bs *Server) ListSyncCommittees(ctx context.Context, req *ethpbv2.StateSync }, nil } -func currentCommitteeIndicesFromState(st state.BeaconState) ([]types.ValidatorIndex, *ethpbalpha.SyncCommittee, error) { - committee, err := st.CurrentSyncCommittee() - if err != nil { - return nil, nil, fmt.Errorf( - "could not get sync committee: %v", err, - ) - } - +func committeeIndicesFromState(st state.BeaconState, committee *ethpbalpha.SyncCommittee) ([]types.ValidatorIndex, *ethpbalpha.SyncCommittee, error) { committeeIndices := make([]types.ValidatorIndex, len(committee.Pubkeys)) for i, key := range committee.Pubkeys { index, ok := st.ValidatorIndexByPubkey(bytesutil.ToBytes48(key)) @@ -121,6 +114,17 @@ func currentCommitteeIndicesFromState(st state.BeaconState) ([]types.ValidatorIn return committeeIndices, committee, nil } +func currentCommitteeIndicesFromState(st state.BeaconState) ([]types.ValidatorIndex, *ethpbalpha.SyncCommittee, error) { + committee, err := st.CurrentSyncCommittee() + if err != nil { + return nil, nil, fmt.Errorf( + "could not get sync committee: %v", err, + ) + } + + return committeeIndicesFromState(st, committee) +} + func nextCommitteeIndicesFromState(st state.BeaconState) ([]types.ValidatorIndex, *ethpbalpha.SyncCommittee, error) { committee, err := st.NextSyncCommittee() if err != nil { @@ -129,18 +133,7 @@ func nextCommitteeIndicesFromState(st state.BeaconState) ([]types.ValidatorIndex ) } - committeeIndices := make([]types.ValidatorIndex, len(committee.Pubkeys)) - for i, key := range committee.Pubkeys { - index, ok := st.ValidatorIndexByPubkey(bytesutil.ToBytes48(key)) - if !ok { - return nil, nil, fmt.Errorf( - "validator index not found for pubkey %#x", - bytesutil.Trunc(key), - ) - } - committeeIndices[i] = index - } - return committeeIndices, committee, nil + return committeeIndicesFromState(st, committee) } func extractSyncSubcommittees(st state.BeaconState, committee *ethpbalpha.SyncCommittee) ([]*ethpbv2.SyncSubcommitteeValidators, error) { diff --git a/beacon-chain/rpc/prysm/v1alpha1/beacon/blocks.go b/beacon-chain/rpc/prysm/v1alpha1/beacon/blocks.go index 81cbc271c3..d097fa0d95 100644 --- a/beacon-chain/rpc/prysm/v1alpha1/beacon/blocks.go +++ b/beacon-chain/rpc/prysm/v1alpha1/beacon/blocks.go @@ -41,75 +41,20 @@ type blockContainer struct { func (bs *Server) ListBlocks( ctx context.Context, req *ethpb.ListBlocksRequest, ) (*ethpb.ListBlocksResponse, error) { - if int(req.PageSize) > cmd.Get().MaxRPCPageSize { - return nil, status.Errorf(codes.InvalidArgument, "Requested page size %d can not be greater than max size %d", - req.PageSize, cmd.Get().MaxRPCPageSize) + ctrs, numBlks, nextPageToken, err := bs.listBlocks(ctx, req) + if err != nil { + return nil, err + } + blkContainers, err := convertToProto(ctrs) + if err != nil { + return nil, err } - switch q := req.QueryFilter.(type) { - case *ethpb.ListBlocksRequest_Epoch: - ctrs, numBlks, nextPageToken, err := bs.listBlocksForEpoch(ctx, req, q) - if err != nil { - return nil, err - } - blkContainers, err := convertToProto(ctrs) - if err != nil { - return nil, err - } - - return ðpb.ListBlocksResponse{ - BlockContainers: blkContainers, - TotalSize: int32(numBlks), - NextPageToken: nextPageToken, - }, nil - case *ethpb.ListBlocksRequest_Root: - ctrs, numBlks, nextPageToken, err := bs.listBlocksForRoot(ctx, req, q) - if err != nil { - return nil, err - } - blkContainers, err := convertToProto(ctrs) - if err != nil { - return nil, err - } - - return ðpb.ListBlocksResponse{ - BlockContainers: blkContainers, - TotalSize: int32(numBlks), - NextPageToken: nextPageToken, - }, nil - - case *ethpb.ListBlocksRequest_Slot: - ctrs, numBlks, nextPageToken, err := bs.listBlocksForSlot(ctx, req, q) - if err != nil { - return nil, err - } - blkContainers, err := convertToProto(ctrs) - if err != nil { - return nil, err - } - - return ðpb.ListBlocksResponse{ - BlockContainers: blkContainers, - TotalSize: int32(numBlks), - NextPageToken: nextPageToken, - }, nil - case *ethpb.ListBlocksRequest_Genesis: - ctrs, numBlks, nextPageToken, err := bs.listBlocksForGenesis(ctx, req, q) - if err != nil { - return nil, err - } - blkContainers, err := convertToProto(ctrs) - if err != nil { - return nil, err - } - return ðpb.ListBlocksResponse{ - BlockContainers: blkContainers, - TotalSize: int32(numBlks), - NextPageToken: nextPageToken, - }, nil - } - - return nil, status.Error(codes.InvalidArgument, "Must specify a filter criteria for fetching blocks") + return ðpb.ListBlocksResponse{ + BlockContainers: blkContainers, + TotalSize: int32(numBlks), + NextPageToken: nextPageToken, + }, nil } // ListBeaconBlocks retrieves blocks by root, slot, or epoch. @@ -121,72 +66,39 @@ func (bs *Server) ListBlocks( func (bs *Server) ListBeaconBlocks( ctx context.Context, req *ethpb.ListBlocksRequest, ) (*ethpb.ListBeaconBlocksResponse, error) { + ctrs, numBlks, nextPageToken, err := bs.listBlocks(ctx, req) + if err != nil { + return nil, err + } + altCtrs, err := convertFromV1Containers(ctrs) + if err != nil { + return nil, err + } + return ðpb.ListBeaconBlocksResponse{ + BlockContainers: altCtrs, + TotalSize: int32(numBlks), + NextPageToken: nextPageToken, + }, nil +} + +func (bs *Server) listBlocks(ctx context.Context, req *ethpb.ListBlocksRequest) ([]blockContainer, int, string, error) { if int(req.PageSize) > cmd.Get().MaxRPCPageSize { - return nil, status.Errorf(codes.InvalidArgument, "Requested page size %d can not be greater than max size %d", + return nil, 0, "", status.Errorf(codes.InvalidArgument, "Requested page size %d can not be greater than max size %d", req.PageSize, cmd.Get().MaxRPCPageSize) } switch q := req.QueryFilter.(type) { case *ethpb.ListBlocksRequest_Epoch: - ctrs, numBlks, nextPageToken, err := bs.listBlocksForEpoch(ctx, req, q) - if err != nil { - return nil, err - } - altCtrs, err := convertFromV1Containers(ctrs) - if err != nil { - return nil, err - } - return ðpb.ListBeaconBlocksResponse{ - BlockContainers: altCtrs, - TotalSize: int32(numBlks), - NextPageToken: nextPageToken, - }, nil + return bs.listBlocksForEpoch(ctx, req, q) case *ethpb.ListBlocksRequest_Root: - ctrs, numBlks, nextPageToken, err := bs.listBlocksForRoot(ctx, req, q) - if err != nil { - return nil, err - } - altCtrs, err := convertFromV1Containers(ctrs) - if err != nil { - return nil, err - } - return ðpb.ListBeaconBlocksResponse{ - BlockContainers: altCtrs, - TotalSize: int32(numBlks), - NextPageToken: nextPageToken, - }, nil - + return bs.listBlocksForRoot(ctx, req, q) case *ethpb.ListBlocksRequest_Slot: - ctrs, numBlks, nextPageToken, err := bs.listBlocksForSlot(ctx, req, q) - if err != nil { - return nil, err - } - altCtrs, err := convertFromV1Containers(ctrs) - if err != nil { - return nil, err - } - return ðpb.ListBeaconBlocksResponse{ - BlockContainers: altCtrs, - TotalSize: int32(numBlks), - NextPageToken: nextPageToken, - }, nil + return bs.listBlocksForSlot(ctx, req, q) case *ethpb.ListBlocksRequest_Genesis: - ctrs, numBlks, nextPageToken, err := bs.listBlocksForGenesis(ctx, req, q) - if err != nil { - return nil, err - } - altCtrs, err := convertFromV1Containers(ctrs) - if err != nil { - return nil, err - } - return ðpb.ListBeaconBlocksResponse{ - BlockContainers: altCtrs, - TotalSize: int32(numBlks), - NextPageToken: nextPageToken, - }, nil + return bs.listBlocksForGenesis(ctx, req, q) + default: + return nil, 0, "", status.Errorf(codes.InvalidArgument, "Must specify a filter criteria for fetching blocks. Criteria %T not supported", q) } - - return nil, status.Error(codes.InvalidArgument, "Must specify a filter criteria for fetching blocks") } func convertFromV1Containers(ctrs []blockContainer) ([]*ethpb.BeaconBlockContainer, error) { diff --git a/config/fieldparams/BUILD.bazel b/config/fieldparams/BUILD.bazel index cfa5162a2e..1e65c64b2b 100644 --- a/config/fieldparams/BUILD.bazel +++ b/config/fieldparams/BUILD.bazel @@ -12,7 +12,10 @@ go_library( go_test( name = "go_default_test", - srcs = ["mainnet_test.go"], + srcs = [ + "common_test.go", + "mainnet_test.go", + ], deps = [ ":go_default_library", "//config/params:go_default_library", @@ -22,7 +25,10 @@ go_test( go_test( name = "go_minimal_test", - srcs = ["minimal_test.go"], + srcs = [ + "common_test.go", + "minimal_test.go", + ], eth_network = "minimal", deps = [ ":go_default_library", diff --git a/config/fieldparams/common_test.go b/config/fieldparams/common_test.go new file mode 100644 index 0000000000..9da99f8e82 --- /dev/null +++ b/config/fieldparams/common_test.go @@ -0,0 +1,22 @@ +package field_params_test + +import ( + "testing" + + fieldparams "github.com/prysmaticlabs/prysm/config/fieldparams" + "github.com/prysmaticlabs/prysm/config/params" + "github.com/prysmaticlabs/prysm/testing/assert" +) + +func testFieldParametersMatchConfig(t *testing.T) { + assert.Equal(t, uint64(params.BeaconConfig().SlotsPerHistoricalRoot), uint64(fieldparams.BlockRootsLength)) + assert.Equal(t, uint64(params.BeaconConfig().SlotsPerHistoricalRoot), uint64(fieldparams.StateRootsLength)) + assert.Equal(t, params.BeaconConfig().HistoricalRootsLimit, uint64(fieldparams.HistoricalRootsLength)) + assert.Equal(t, uint64(params.BeaconConfig().EpochsPerHistoricalVector), uint64(fieldparams.RandaoMixesLength)) + assert.Equal(t, params.BeaconConfig().ValidatorRegistryLimit, uint64(fieldparams.ValidatorRegistryLimit)) + assert.Equal(t, uint64(params.BeaconConfig().SlotsPerEpoch.Mul(uint64(params.BeaconConfig().EpochsPerEth1VotingPeriod))), uint64(fieldparams.Eth1DataVotesLength)) + assert.Equal(t, uint64(params.BeaconConfig().SlotsPerEpoch.Mul(params.BeaconConfig().MaxAttestations)), uint64(fieldparams.PreviousEpochAttestationsLength)) + assert.Equal(t, uint64(params.BeaconConfig().SlotsPerEpoch.Mul(params.BeaconConfig().MaxAttestations)), uint64(fieldparams.CurrentEpochAttestationsLength)) + assert.Equal(t, uint64(params.BeaconConfig().EpochsPerSlashingsVector), uint64(fieldparams.SlashingsLength)) + assert.Equal(t, params.BeaconConfig().SyncCommitteeSize, uint64(fieldparams.SyncCommitteeLength)) +} diff --git a/config/fieldparams/mainnet_test.go b/config/fieldparams/mainnet_test.go index a307d97799..1b24877106 100644 --- a/config/fieldparams/mainnet_test.go +++ b/config/fieldparams/mainnet_test.go @@ -5,21 +5,10 @@ package field_params_test import ( "testing" - fieldparams "github.com/prysmaticlabs/prysm/config/fieldparams" "github.com/prysmaticlabs/prysm/config/params" - "github.com/prysmaticlabs/prysm/testing/assert" ) func TestFieldParametersValues(t *testing.T) { params.UseMainnetConfig() - assert.Equal(t, uint64(params.BeaconConfig().SlotsPerHistoricalRoot), uint64(fieldparams.BlockRootsLength)) - assert.Equal(t, uint64(params.BeaconConfig().SlotsPerHistoricalRoot), uint64(fieldparams.StateRootsLength)) - assert.Equal(t, params.BeaconConfig().HistoricalRootsLimit, uint64(fieldparams.HistoricalRootsLength)) - assert.Equal(t, uint64(params.BeaconConfig().EpochsPerHistoricalVector), uint64(fieldparams.RandaoMixesLength)) - assert.Equal(t, params.BeaconConfig().ValidatorRegistryLimit, uint64(fieldparams.ValidatorRegistryLimit)) - assert.Equal(t, uint64(params.BeaconConfig().SlotsPerEpoch.Mul(uint64(params.BeaconConfig().EpochsPerEth1VotingPeriod))), uint64(fieldparams.Eth1DataVotesLength)) - assert.Equal(t, uint64(params.BeaconConfig().SlotsPerEpoch.Mul(params.BeaconConfig().MaxAttestations)), uint64(fieldparams.PreviousEpochAttestationsLength)) - assert.Equal(t, uint64(params.BeaconConfig().SlotsPerEpoch.Mul(params.BeaconConfig().MaxAttestations)), uint64(fieldparams.CurrentEpochAttestationsLength)) - assert.Equal(t, uint64(params.BeaconConfig().EpochsPerSlashingsVector), uint64(fieldparams.SlashingsLength)) - assert.Equal(t, params.BeaconConfig().SyncCommitteeSize, uint64(fieldparams.SyncCommitteeLength)) + testFieldParametersMatchConfig(t) } diff --git a/config/fieldparams/minimal_test.go b/config/fieldparams/minimal_test.go index d1a952440f..b59426eea0 100644 --- a/config/fieldparams/minimal_test.go +++ b/config/fieldparams/minimal_test.go @@ -5,21 +5,10 @@ package field_params_test import ( "testing" - fieldparams "github.com/prysmaticlabs/prysm/config/fieldparams" "github.com/prysmaticlabs/prysm/config/params" - "github.com/prysmaticlabs/prysm/testing/assert" ) func TestFieldParametersValues(t *testing.T) { params.UseMinimalConfig() - assert.Equal(t, uint64(params.BeaconConfig().SlotsPerHistoricalRoot), uint64(fieldparams.BlockRootsLength)) - assert.Equal(t, uint64(params.BeaconConfig().SlotsPerHistoricalRoot), uint64(fieldparams.StateRootsLength)) - assert.Equal(t, params.BeaconConfig().HistoricalRootsLimit, uint64(fieldparams.HistoricalRootsLength)) - assert.Equal(t, uint64(params.BeaconConfig().EpochsPerHistoricalVector), uint64(fieldparams.RandaoMixesLength)) - assert.Equal(t, params.BeaconConfig().ValidatorRegistryLimit, uint64(fieldparams.ValidatorRegistryLimit)) - assert.Equal(t, uint64(params.BeaconConfig().SlotsPerEpoch.Mul(uint64(params.BeaconConfig().EpochsPerEth1VotingPeriod))), uint64(fieldparams.Eth1DataVotesLength)) - assert.Equal(t, uint64(params.BeaconConfig().SlotsPerEpoch.Mul(params.BeaconConfig().MaxAttestations)), uint64(fieldparams.PreviousEpochAttestationsLength)) - assert.Equal(t, uint64(params.BeaconConfig().SlotsPerEpoch.Mul(params.BeaconConfig().MaxAttestations)), uint64(fieldparams.CurrentEpochAttestationsLength)) - assert.Equal(t, uint64(params.BeaconConfig().EpochsPerSlashingsVector), uint64(fieldparams.SlashingsLength)) - assert.Equal(t, params.BeaconConfig().SyncCommitteeSize, uint64(fieldparams.SyncCommitteeLength)) + testFieldParametersMatchConfig(t) } diff --git a/proto/prysm/v1alpha1/wrapper/beacon_block.go b/proto/prysm/v1alpha1/wrapper/beacon_block.go index ea31eea003..ccb31e77db 100644 --- a/proto/prysm/v1alpha1/wrapper/beacon_block.go +++ b/proto/prysm/v1alpha1/wrapper/beacon_block.go @@ -13,8 +13,27 @@ var ( _ = block.SignedBeaconBlock(&altairSignedBeaconBlock{}) _ = block.BeaconBlock(&altairBeaconBlock{}) _ = block.BeaconBlockBody(&altairBeaconBlockBody{}) + + // ErrUnsupportedSignedBeaconBlock is returned when the struct type is not a supported signed + // beacon block type. + ErrUnsupportedSignedBeaconBlock = errors.New("unsupported signed beacon block") ) +// WrappedSignedBeaconBlock will wrap a signed beacon block to conform to the +// signed beacon block interface. +func WrappedSignedBeaconBlock(i interface{}) (block.SignedBeaconBlock, error) { + switch b := i.(type) { + case *eth.SignedBeaconBlock: + return WrappedPhase0SignedBeaconBlock(b), nil + case *eth.SignedBeaconBlockAltair: + return WrappedAltairSignedBeaconBlock(b) + case *eth.SignedBeaconBlockMerge: + return WrappedMergeSignedBeaconBlock(b) + default: + return nil, errors.Wrapf(ErrUnsupportedSignedBeaconBlock, "unable to wrap block of type %T", i) + } +} + // Phase0SignedBeaconBlock is a convenience wrapper around a phase 0 beacon block // object. This wrapper allows us to conform to a common interface so that beacon // blocks for future forks can also be applied across prysm without issues. @@ -24,6 +43,7 @@ type Phase0SignedBeaconBlock struct { // WrappedPhase0SignedBeaconBlock is constructor which wraps a protobuf phase 0 block // with the block wrapper. +// Deprecated: use WrappedSignedBeaconBlock instead. func WrappedPhase0SignedBeaconBlock(b *eth.SignedBeaconBlock) block.SignedBeaconBlock { return Phase0SignedBeaconBlock{b: b} } @@ -291,6 +311,7 @@ type altairSignedBeaconBlock struct { // WrappedAltairSignedBeaconBlock is constructor which wraps a protobuf altair block // with the block wrapper. +// Deprecated: use WrappedSignedBeaconBlock instead. func WrappedAltairSignedBeaconBlock(b *eth.SignedBeaconBlockAltair) (block.SignedBeaconBlock, error) { w := altairSignedBeaconBlock{b: b} if w.IsNil() { @@ -561,6 +582,7 @@ type mergeSignedBeaconBlock struct { } // WrappedMergeSignedBeaconBlock is constructor which wraps a protobuf merge block with the block wrapper. +// Deprecated: use WrappedSignedBeaconBlock instead. func WrappedMergeSignedBeaconBlock(b *eth.SignedBeaconBlockMerge) (block.SignedBeaconBlock, error) { w := mergeSignedBeaconBlock{b: b} if w.IsNil() { diff --git a/proto/prysm/v1alpha1/wrapper/beacon_block_test.go b/proto/prysm/v1alpha1/wrapper/beacon_block_test.go index fea23ace2e..6d29ccda10 100644 --- a/proto/prysm/v1alpha1/wrapper/beacon_block_test.go +++ b/proto/prysm/v1alpha1/wrapper/beacon_block_test.go @@ -14,6 +14,42 @@ import ( "github.com/prysmaticlabs/prysm/testing/util" ) +func TestWrappedSignedBeaconBlock(t *testing.T) { + tests := []struct { + name string + blk interface{} + wantErr bool + }{ + { + name: "unsupported type", + blk: "not a beacon block", + wantErr: true, + }, + { + name: "phase0", + blk: util.NewBeaconBlock(), + }, + { + name: "altair", + blk: util.NewBeaconBlockAltair(), + }, + { + name: "bellatrix", + blk: util.NewBeaconBlockMerge(), + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + _, err := wrapper.WrappedSignedBeaconBlock(tt.blk) + if tt.wantErr { + require.ErrorIs(t, err, wrapper.ErrUnsupportedSignedBeaconBlock) + } else { + require.NoError(t, err) + } + }) + } +} + func TestAltairSignedBeaconBlock_Signature(t *testing.T) { sig := []byte{0x11, 0x22} wsb, err := wrapper.WrappedAltairSignedBeaconBlock(ðpb.SignedBeaconBlockAltair{Block: ðpb.BeaconBlockAltair{}, Signature: sig})