From 2550a87ed35060467b66873ecc241199bffab7eb Mon Sep 17 00:00:00 2001 From: Alberto Benegiamo Date: Thu, 2 Nov 2023 00:20:18 +0100 Subject: [PATCH] nit --- .../state_sync_block_backfilling_test.go | 179 ++++++++++++++++-- 1 file changed, 158 insertions(+), 21 deletions(-) diff --git a/vms/proposervm/state_sync_block_backfilling_test.go b/vms/proposervm/state_sync_block_backfilling_test.go index d73895c4e7bd..05eb2bcd3456 100644 --- a/vms/proposervm/state_sync_block_backfilling_test.go +++ b/vms/proposervm/state_sync_block_backfilling_test.go @@ -106,7 +106,7 @@ func TestBlockBackfillEnabled(t *testing.T) { require.ErrorIs(err, block.ErrBlockBackfillingNotEnabled) } -func TestBlockBackfill(t *testing.T) { +func TestBlockBackfillSuccess(t *testing.T) { // setup VM with backfill enabled require := require.New(t) toEngineCh := make(chan common.Message) @@ -116,9 +116,11 @@ func TestBlockBackfill(t *testing.T) { }() var ( - forkHeight = uint64(100) - blkCount = 10 - startBlkHeight = uint64(1492) + forkHeight = uint64(100) + blkCount = 10 + startBlkHeight = uint64(1492) + + // create a list of consecutive blocks and build state summary of top of them proBlks, innerBlks = createTestBlocks(t, vm, blkCount, startBlkHeight) innerTopBlk = innerBlks[len(innerBlks)-1] @@ -173,30 +175,20 @@ func TestBlockBackfill(t *testing.T) { // Backfill some blocks innerVM.ParseBlockF = func(_ context.Context, b []byte) (snowman.Block, error) { - idx := -1 - for i, blk := range innerBlks { + for _, blk := range innerBlks { if bytes.Equal(b, blk.Bytes()) { - idx = i - break + return blk, nil } } - if idx == -1 { - return nil, database.ErrNotFound - } - return innerBlks[idx], nil + return nil, database.ErrNotFound } innerVM.GetBlockF = func(_ context.Context, blkID ids.ID) (snowman.Block, error) { - idx := -1 - for i, blk := range innerBlks { + for _, blk := range innerBlks { if blkID == blk.ID() { - idx = i - break + return blk, nil } } - if idx == -1 { - return nil, database.ErrNotFound - } - return innerBlks[idx], nil + return nil, database.ErrNotFound } innerVM.BackfillBlocksF = func(_ context.Context, b [][]byte) (ids.ID, uint64, error) { lowestblk := innerBlks[0] @@ -216,6 +208,144 @@ func TestBlockBackfill(t *testing.T) { require.NoError(err) require.Equal(proBlks[0].Parent(), nextBlkID) require.Equal(proBlks[0].Height()-1, nextBlkHeight) + + // check proBlocks have been indexed + for _, blk := range proBlks { + blkID, err := vm.GetBlockIDAtHeight(ctx, blk.Height()) + require.NoError(err) + require.Equal(blk.ID(), blkID) + + _, err = vm.GetBlock(ctx, blkID) + require.NoError(err) + } +} + +func TestBlockBackfillPartialSuccess(t *testing.T) { + // setup VM with backfill enabled + require := require.New(t) + toEngineCh := make(chan common.Message) + innerVM, vm, fromInnerVMCh := setupBlockBackfillingVM(t, toEngineCh) + defer func() { + require.NoError(vm.Shutdown(context.Background())) + }() + + var ( + forkHeight = uint64(100) + blkCount = 10 + startBlkHeight = uint64(1492) + + // create a list of consecutive blocks and build state summary of top of them + proBlks, innerBlks = createTestBlocks(t, vm, blkCount, startBlkHeight) + + innerTopBlk = innerBlks[len(innerBlks)-1] + proTopBlk = proBlks[len(proBlks)-1] + stateSummaryHeight = innerTopBlk.Height() + 1 + ) + + innerSummary := &block.TestStateSummary{ + IDV: ids.ID{'s', 'u', 'm', 'm', 'a', 'r', 'y', 'I', 'D'}, + HeightV: stateSummaryHeight, + BytesV: []byte{'i', 'n', 'n', 'e', 'r'}, + } + innerStateSyncedBlk := &snowman.TestBlock{ + TestDecidable: choices.TestDecidable{ + IDV: ids.ID{'i', 'n', 'n', 'e', 'r', 'S', 'y', 'n', 'c', 'e', 'd'}, + }, + ParentV: innerTopBlk.ID(), + HeightV: innerSummary.Height(), + BytesV: []byte("inner state synced block"), + } + stateSummary := createTestStateSummary(t, vm, proTopBlk.ID(), forkHeight, innerVM, innerSummary, innerStateSyncedBlk) + + innerSummary.AcceptF = func(ctx context.Context) (block.StateSyncMode, error) { + return block.StateSyncStatic, nil + } + + ctx := context.Background() + _, err := stateSummary.Accept(ctx) + require.NoError(err) + + innerVM.LastAcceptedF = func(context.Context) (ids.ID, error) { + return innerStateSyncedBlk.ID(), nil + } + innerVM.GetBlockF = func(_ context.Context, blkID ids.ID) (snowman.Block, error) { + switch blkID { + case innerStateSyncedBlk.ID(): + return innerStateSyncedBlk, nil + default: + return nil, database.ErrNotFound + } + } + + fromInnerVMCh <- common.StateSyncDone + <-toEngineCh + + innerVM.BackfillBlocksEnabledF = func(ctx context.Context) (ids.ID, uint64, error) { + return innerStateSyncedBlk.ID(), innerStateSyncedBlk.Height() - 1, nil + } + blkID, height, err := vm.BackfillBlocksEnabled(ctx) + require.NoError(err) + require.Equal(proTopBlk.ID(), blkID) + require.Equal(proTopBlk.Height(), height) + + // Backfill some blocks + innerVM.ParseBlockF = func(_ context.Context, b []byte) (snowman.Block, error) { + for _, blk := range innerBlks { + if bytes.Equal(b, blk.Bytes()) { + return blk, nil + } + } + return nil, database.ErrNotFound + } + + // simulate that lower half of backfilled blocks won't be accepted by innerVM + idx := len(innerBlks) / 2 + innerVM.GetBlockF = func(_ context.Context, blkID ids.ID) (snowman.Block, error) { + for _, blk := range innerBlks { + if blkID != blk.ID() { + continue + } + // if it's one of the lower half blocks, assume it's not stored + // since it was rejected + if blk.Height() <= innerBlks[idx].Height() { + return nil, database.ErrNotFound + } + return blk, nil + } + return nil, database.ErrNotFound + } + + innerVM.BackfillBlocksF = func(_ context.Context, b [][]byte) (ids.ID, uint64, error) { + // assume lowest half blocks fails verification + return innerBlks[idx].ID(), innerBlks[idx].Height(), nil + } + + blkBytes := make([][]byte, 0, len(proBlks)) + for _, blk := range proBlks { + blkBytes = append(blkBytes, blk.Bytes()) + } + nextBlkID, nextBlkHeight, err := vm.BackfillBlocks(ctx, blkBytes) + require.NoError(err) + require.Equal(proBlks[idx].ID(), nextBlkID) + require.Equal(proBlks[idx].Height(), nextBlkHeight) + + // check only upper half of blocks have been indexed + for i, blk := range proBlks { + if i <= idx { + _, err := vm.GetBlockIDAtHeight(ctx, blk.Height()) + require.ErrorIs(err, database.ErrNotFound) + + _, err = vm.GetBlock(ctx, blk.ID()) + require.ErrorIs(err, database.ErrNotFound) + } else { + blkID, err := vm.GetBlockIDAtHeight(ctx, blk.Height()) + require.NoError(err) + require.Equal(blk.ID(), blkID) + + _, err = vm.GetBlock(ctx, blkID) + require.NoError(err) + } + } } func createTestBlocks( @@ -311,7 +441,14 @@ func createTestStateSummary( return summary } -func setupBlockBackfillingVM(t *testing.T, toEngineCh chan<- common.Message) (*fullVM, *VM, chan<- common.Message) { +func setupBlockBackfillingVM( + t *testing.T, + toEngineCh chan<- common.Message, +) ( + *fullVM, + *VM, + chan<- common.Message, +) { require := require.New(t) innerVM := &fullVM{