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

     1  package beacon
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  	"strconv"
     7  	"testing"
     8  
     9  	"github.com/golang/mock/gomock"
    10  	types "github.com/prysmaticlabs/eth2-types"
    11  	chainMock "github.com/prysmaticlabs/prysm/beacon-chain/blockchain/testing"
    12  	"github.com/prysmaticlabs/prysm/beacon-chain/core/feed"
    13  	blockfeed "github.com/prysmaticlabs/prysm/beacon-chain/core/feed/block"
    14  	statefeed "github.com/prysmaticlabs/prysm/beacon-chain/core/feed/state"
    15  	"github.com/prysmaticlabs/prysm/beacon-chain/core/helpers"
    16  	dbTest "github.com/prysmaticlabs/prysm/beacon-chain/db/testing"
    17  	"github.com/prysmaticlabs/prysm/beacon-chain/state/stategen"
    18  	"github.com/prysmaticlabs/prysm/beacon-chain/state/v1"
    19  	pbp2p "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1"
    20  	ethpb "github.com/prysmaticlabs/prysm/proto/eth/v1alpha1"
    21  	"github.com/prysmaticlabs/prysm/proto/eth/v1alpha1/wrapper"
    22  	"github.com/prysmaticlabs/prysm/proto/interfaces"
    23  	"github.com/prysmaticlabs/prysm/shared/bytesutil"
    24  	"github.com/prysmaticlabs/prysm/shared/cmd"
    25  	"github.com/prysmaticlabs/prysm/shared/mock"
    26  	"github.com/prysmaticlabs/prysm/shared/params"
    27  	"github.com/prysmaticlabs/prysm/shared/testutil"
    28  	"github.com/prysmaticlabs/prysm/shared/testutil/assert"
    29  	"github.com/prysmaticlabs/prysm/shared/testutil/require"
    30  	"google.golang.org/protobuf/proto"
    31  	"google.golang.org/protobuf/types/known/emptypb"
    32  )
    33  
    34  func TestServer_ListBlocks_NoResults(t *testing.T) {
    35  	db := dbTest.SetupDB(t)
    36  	ctx := context.Background()
    37  
    38  	bs := &Server{
    39  		BeaconDB: db,
    40  	}
    41  	wanted := &ethpb.ListBlocksResponse{
    42  		BlockContainers: make([]*ethpb.BeaconBlockContainer, 0),
    43  		TotalSize:       int32(0),
    44  		NextPageToken:   strconv.Itoa(0),
    45  	}
    46  	res, err := bs.ListBlocks(ctx, &ethpb.ListBlocksRequest{
    47  		QueryFilter: &ethpb.ListBlocksRequest_Slot{
    48  			Slot: 0,
    49  		},
    50  	})
    51  	require.NoError(t, err)
    52  	if !proto.Equal(wanted, res) {
    53  		t.Errorf("Wanted %v, received %v", wanted, res)
    54  	}
    55  	res, err = bs.ListBlocks(ctx, &ethpb.ListBlocksRequest{
    56  		QueryFilter: &ethpb.ListBlocksRequest_Slot{
    57  			Slot: 0,
    58  		},
    59  	})
    60  	require.NoError(t, err)
    61  	if !proto.Equal(wanted, res) {
    62  		t.Errorf("Wanted %v, received %v", wanted, res)
    63  	}
    64  	res, err = bs.ListBlocks(ctx, &ethpb.ListBlocksRequest{
    65  		QueryFilter: &ethpb.ListBlocksRequest_Root{
    66  			Root: make([]byte, 32),
    67  		},
    68  	})
    69  	require.NoError(t, err)
    70  	if !proto.Equal(wanted, res) {
    71  		t.Errorf("Wanted %v, received %v", wanted, res)
    72  	}
    73  }
    74  
    75  func TestServer_ListBlocks_Genesis(t *testing.T) {
    76  	db := dbTest.SetupDB(t)
    77  	ctx := context.Background()
    78  
    79  	bs := &Server{
    80  		BeaconDB: db,
    81  	}
    82  
    83  	// Should throw an error if no genesis block is found.
    84  	_, err := bs.ListBlocks(ctx, &ethpb.ListBlocksRequest{
    85  		QueryFilter: &ethpb.ListBlocksRequest_Genesis{
    86  			Genesis: true,
    87  		},
    88  	})
    89  	require.ErrorContains(t, "Could not find genesis", err)
    90  
    91  	// Should return the proper genesis block if it exists.
    92  	parentRoot := [32]byte{'a'}
    93  	blk := testutil.NewBeaconBlock()
    94  	blk.Block.ParentRoot = parentRoot[:]
    95  	root, err := blk.Block.HashTreeRoot()
    96  	require.NoError(t, err)
    97  	require.NoError(t, db.SaveBlock(ctx, wrapper.WrappedPhase0SignedBeaconBlock(blk)))
    98  	require.NoError(t, db.SaveGenesisBlockRoot(ctx, root))
    99  	wanted := &ethpb.ListBlocksResponse{
   100  		BlockContainers: []*ethpb.BeaconBlockContainer{
   101  			{
   102  				Block:     blk,
   103  				BlockRoot: root[:],
   104  				Canonical: true,
   105  			},
   106  		},
   107  		NextPageToken: "0",
   108  		TotalSize:     1,
   109  	}
   110  	res, err := bs.ListBlocks(ctx, &ethpb.ListBlocksRequest{
   111  		QueryFilter: &ethpb.ListBlocksRequest_Genesis{
   112  			Genesis: true,
   113  		},
   114  	})
   115  	require.NoError(t, err)
   116  	if !proto.Equal(wanted, res) {
   117  		t.Errorf("Wanted %v, received %v", wanted, res)
   118  	}
   119  }
   120  
   121  func TestServer_ListBlocks_Genesis_MultiBlocks(t *testing.T) {
   122  	db := dbTest.SetupDB(t)
   123  	ctx := context.Background()
   124  
   125  	bs := &Server{
   126  		BeaconDB: db,
   127  	}
   128  	// Should return the proper genesis block if it exists.
   129  	parentRoot := [32]byte{1, 2, 3}
   130  	blk := testutil.NewBeaconBlock()
   131  	blk.Block.ParentRoot = parentRoot[:]
   132  	root, err := blk.Block.HashTreeRoot()
   133  	require.NoError(t, err)
   134  	require.NoError(t, db.SaveBlock(ctx, wrapper.WrappedPhase0SignedBeaconBlock(blk)))
   135  	require.NoError(t, db.SaveGenesisBlockRoot(ctx, root))
   136  
   137  	count := types.Slot(100)
   138  	blks := make([]interfaces.SignedBeaconBlock, count)
   139  	for i := types.Slot(0); i < count; i++ {
   140  		b := testutil.NewBeaconBlock()
   141  		b.Block.Slot = i
   142  		require.NoError(t, err)
   143  		blks[i] = wrapper.WrappedPhase0SignedBeaconBlock(b)
   144  	}
   145  	require.NoError(t, db.SaveBlocks(ctx, blks))
   146  
   147  	// Should throw an error if more than one blk returned.
   148  	_, err = bs.ListBlocks(ctx, &ethpb.ListBlocksRequest{
   149  		QueryFilter: &ethpb.ListBlocksRequest_Genesis{
   150  			Genesis: true,
   151  		},
   152  	})
   153  	require.NoError(t, err)
   154  }
   155  
   156  func TestServer_ListBlocks_Pagination(t *testing.T) {
   157  	params.UseMinimalConfig()
   158  	defer params.UseMainnetConfig()
   159  
   160  	db := dbTest.SetupDB(t)
   161  	chain := &chainMock.ChainService{
   162  		CanonicalRoots: map[[32]byte]bool{},
   163  	}
   164  	ctx := context.Background()
   165  
   166  	count := types.Slot(100)
   167  	blks := make([]interfaces.SignedBeaconBlock, count)
   168  	blkContainers := make([]*ethpb.BeaconBlockContainer, count)
   169  	for i := types.Slot(0); i < count; i++ {
   170  		b := testutil.NewBeaconBlock()
   171  		b.Block.Slot = i
   172  		root, err := b.Block.HashTreeRoot()
   173  		require.NoError(t, err)
   174  		chain.CanonicalRoots[root] = true
   175  		blks[i] = wrapper.WrappedPhase0SignedBeaconBlock(b)
   176  		blkContainers[i] = &ethpb.BeaconBlockContainer{Block: b, BlockRoot: root[:], Canonical: true}
   177  	}
   178  	require.NoError(t, db.SaveBlocks(ctx, blks))
   179  
   180  	orphanedBlk := testutil.NewBeaconBlock()
   181  	orphanedBlk.Block.Slot = 300
   182  	orphanedBlkRoot, err := orphanedBlk.Block.HashTreeRoot()
   183  	require.NoError(t, err)
   184  	require.NoError(t, db.SaveBlock(ctx, wrapper.WrappedPhase0SignedBeaconBlock(orphanedBlk)))
   185  
   186  	bs := &Server{
   187  		BeaconDB:         db,
   188  		CanonicalFetcher: chain,
   189  	}
   190  
   191  	root6, err := blks[6].Block().HashTreeRoot()
   192  	require.NoError(t, err)
   193  
   194  	tests := []struct {
   195  		req *ethpb.ListBlocksRequest
   196  		res *ethpb.ListBlocksResponse
   197  	}{
   198  		{req: &ethpb.ListBlocksRequest{
   199  			PageToken:   strconv.Itoa(0),
   200  			QueryFilter: &ethpb.ListBlocksRequest_Slot{Slot: 5},
   201  			PageSize:    3},
   202  			res: &ethpb.ListBlocksResponse{
   203  				BlockContainers: []*ethpb.BeaconBlockContainer{{Block: testutil.HydrateSignedBeaconBlock(&ethpb.SignedBeaconBlock{
   204  					Block: &ethpb.BeaconBlock{
   205  						Slot: 5}}),
   206  					BlockRoot: blkContainers[5].BlockRoot,
   207  					Canonical: blkContainers[5].Canonical}},
   208  				NextPageToken: "",
   209  				TotalSize:     1}},
   210  		{req: &ethpb.ListBlocksRequest{
   211  			PageToken:   strconv.Itoa(0),
   212  			QueryFilter: &ethpb.ListBlocksRequest_Root{Root: root6[:]},
   213  			PageSize:    3},
   214  			res: &ethpb.ListBlocksResponse{
   215  				BlockContainers: []*ethpb.BeaconBlockContainer{{Block: testutil.HydrateSignedBeaconBlock(&ethpb.SignedBeaconBlock{
   216  					Block: &ethpb.BeaconBlock{
   217  						Slot: 6}}),
   218  					BlockRoot: blkContainers[6].BlockRoot,
   219  					Canonical: blkContainers[6].Canonical}},
   220  				TotalSize: 1}},
   221  		{req: &ethpb.ListBlocksRequest{QueryFilter: &ethpb.ListBlocksRequest_Root{Root: root6[:]}},
   222  			res: &ethpb.ListBlocksResponse{
   223  				BlockContainers: []*ethpb.BeaconBlockContainer{{Block: testutil.HydrateSignedBeaconBlock(&ethpb.SignedBeaconBlock{
   224  					Block: &ethpb.BeaconBlock{
   225  						Slot: 6}}),
   226  					BlockRoot: blkContainers[6].BlockRoot,
   227  					Canonical: blkContainers[6].Canonical}},
   228  				TotalSize: 1}},
   229  		{req: &ethpb.ListBlocksRequest{
   230  			PageToken:   strconv.Itoa(0),
   231  			QueryFilter: &ethpb.ListBlocksRequest_Epoch{Epoch: 0},
   232  			PageSize:    100},
   233  			res: &ethpb.ListBlocksResponse{
   234  				BlockContainers: blkContainers[0:params.BeaconConfig().SlotsPerEpoch],
   235  				NextPageToken:   "",
   236  				TotalSize:       int32(params.BeaconConfig().SlotsPerEpoch)}},
   237  		{req: &ethpb.ListBlocksRequest{
   238  			PageToken:   strconv.Itoa(1),
   239  			QueryFilter: &ethpb.ListBlocksRequest_Epoch{Epoch: 5},
   240  			PageSize:    3},
   241  			res: &ethpb.ListBlocksResponse{
   242  				BlockContainers: blkContainers[43:46],
   243  				NextPageToken:   "2",
   244  				TotalSize:       int32(params.BeaconConfig().SlotsPerEpoch)}},
   245  		{req: &ethpb.ListBlocksRequest{
   246  			PageToken:   strconv.Itoa(1),
   247  			QueryFilter: &ethpb.ListBlocksRequest_Epoch{Epoch: 11},
   248  			PageSize:    7},
   249  			res: &ethpb.ListBlocksResponse{
   250  				BlockContainers: blkContainers[95:96],
   251  				NextPageToken:   "",
   252  				TotalSize:       int32(params.BeaconConfig().SlotsPerEpoch)}},
   253  		{req: &ethpb.ListBlocksRequest{
   254  			PageToken:   strconv.Itoa(0),
   255  			QueryFilter: &ethpb.ListBlocksRequest_Epoch{Epoch: 12},
   256  			PageSize:    4},
   257  			res: &ethpb.ListBlocksResponse{
   258  				BlockContainers: blkContainers[96:100],
   259  				NextPageToken:   "",
   260  				TotalSize:       int32(params.BeaconConfig().SlotsPerEpoch / 2)}},
   261  		{req: &ethpb.ListBlocksRequest{
   262  			PageToken:   strconv.Itoa(0),
   263  			QueryFilter: &ethpb.ListBlocksRequest_Slot{Slot: 300},
   264  			PageSize:    3},
   265  			res: &ethpb.ListBlocksResponse{
   266  				BlockContainers: []*ethpb.BeaconBlockContainer{{Block: testutil.HydrateSignedBeaconBlock(&ethpb.SignedBeaconBlock{
   267  					Block: &ethpb.BeaconBlock{
   268  						Slot: 300}}),
   269  					BlockRoot: orphanedBlkRoot[:],
   270  					Canonical: false}},
   271  				NextPageToken: "",
   272  				TotalSize:     1}},
   273  	}
   274  
   275  	for i, test := range tests {
   276  		t.Run(fmt.Sprintf("test_%d", i), func(t *testing.T) {
   277  			res, err := bs.ListBlocks(ctx, test.req)
   278  			require.NoError(t, err)
   279  			require.DeepSSZEqual(t, res, test.res)
   280  		})
   281  	}
   282  }
   283  
   284  func TestServer_ListBlocks_Errors(t *testing.T) {
   285  	db := dbTest.SetupDB(t)
   286  	ctx := context.Background()
   287  
   288  	bs := &Server{BeaconDB: db}
   289  	exceedsMax := int32(cmd.Get().MaxRPCPageSize + 1)
   290  
   291  	wanted := fmt.Sprintf("Requested page size %d can not be greater than max size %d", exceedsMax, cmd.Get().MaxRPCPageSize)
   292  	req := &ethpb.ListBlocksRequest{PageToken: strconv.Itoa(0), PageSize: exceedsMax}
   293  	_, err := bs.ListBlocks(ctx, req)
   294  	assert.ErrorContains(t, wanted, err)
   295  
   296  	wanted = "Must specify a filter criteria for fetching"
   297  	req = &ethpb.ListBlocksRequest{}
   298  	_, err = bs.ListBlocks(ctx, req)
   299  	assert.ErrorContains(t, wanted, err)
   300  
   301  	req = &ethpb.ListBlocksRequest{QueryFilter: &ethpb.ListBlocksRequest_Slot{Slot: 0}}
   302  	res, err := bs.ListBlocks(ctx, req)
   303  	require.NoError(t, err)
   304  	assert.Equal(t, 0, len(res.BlockContainers), "Wanted empty list")
   305  	assert.Equal(t, int32(0), res.TotalSize, "Wanted total size 0")
   306  
   307  	req = &ethpb.ListBlocksRequest{QueryFilter: &ethpb.ListBlocksRequest_Slot{}}
   308  	res, err = bs.ListBlocks(ctx, req)
   309  	require.NoError(t, err)
   310  	assert.Equal(t, 0, len(res.BlockContainers), "Wanted empty list")
   311  	assert.Equal(t, int32(0), res.TotalSize, "Wanted total size 0")
   312  
   313  	req = &ethpb.ListBlocksRequest{QueryFilter: &ethpb.ListBlocksRequest_Root{Root: []byte{'A'}}}
   314  	res, err = bs.ListBlocks(ctx, req)
   315  	require.NoError(t, err)
   316  	assert.Equal(t, 0, len(res.BlockContainers), "Wanted empty list")
   317  	assert.Equal(t, int32(0), res.TotalSize, "Wanted total size 0")
   318  
   319  	req = &ethpb.ListBlocksRequest{QueryFilter: &ethpb.ListBlocksRequest_Root{Root: []byte{'A'}}}
   320  	res, err = bs.ListBlocks(ctx, req)
   321  	require.NoError(t, err)
   322  	assert.Equal(t, 0, len(res.BlockContainers), "Wanted empty list")
   323  	assert.Equal(t, int32(0), res.TotalSize, "Wanted total size 0")
   324  }
   325  
   326  func TestServer_GetChainHead_NoFinalizedBlock(t *testing.T) {
   327  	db := dbTest.SetupDB(t)
   328  
   329  	s, err := testutil.NewBeaconState()
   330  	require.NoError(t, err)
   331  	require.NoError(t, s.SetSlot(1))
   332  	require.NoError(t, s.SetPreviousJustifiedCheckpoint(&ethpb.Checkpoint{Epoch: 3, Root: bytesutil.PadTo([]byte{'A'}, 32)}))
   333  	require.NoError(t, s.SetCurrentJustifiedCheckpoint(&ethpb.Checkpoint{Epoch: 2, Root: bytesutil.PadTo([]byte{'B'}, 32)}))
   334  	require.NoError(t, s.SetFinalizedCheckpoint(&ethpb.Checkpoint{Epoch: 1, Root: bytesutil.PadTo([]byte{'C'}, 32)}))
   335  
   336  	genBlock := testutil.NewBeaconBlock()
   337  	genBlock.Block.ParentRoot = bytesutil.PadTo([]byte{'G'}, 32)
   338  	require.NoError(t, db.SaveBlock(context.Background(), wrapper.WrappedPhase0SignedBeaconBlock(genBlock)))
   339  	gRoot, err := genBlock.Block.HashTreeRoot()
   340  	require.NoError(t, err)
   341  	require.NoError(t, db.SaveGenesisBlockRoot(context.Background(), gRoot))
   342  
   343  	bs := &Server{
   344  		BeaconDB:    db,
   345  		HeadFetcher: &chainMock.ChainService{Block: wrapper.WrappedPhase0SignedBeaconBlock(genBlock), State: s},
   346  		FinalizationFetcher: &chainMock.ChainService{
   347  			FinalizedCheckPoint:         s.FinalizedCheckpoint(),
   348  			CurrentJustifiedCheckPoint:  s.CurrentJustifiedCheckpoint(),
   349  			PreviousJustifiedCheckPoint: s.PreviousJustifiedCheckpoint()},
   350  	}
   351  
   352  	_, err = bs.GetChainHead(context.Background(), nil)
   353  	require.ErrorContains(t, "Could not get finalized block", err)
   354  }
   355  
   356  func TestServer_GetChainHead_NoHeadBlock(t *testing.T) {
   357  	bs := &Server{
   358  		HeadFetcher: &chainMock.ChainService{Block: nil},
   359  	}
   360  	_, err := bs.GetChainHead(context.Background(), nil)
   361  	assert.ErrorContains(t, "Head block of chain was nil", err)
   362  }
   363  
   364  func TestServer_GetChainHead(t *testing.T) {
   365  	params.UseMinimalConfig()
   366  	defer params.UseMainnetConfig()
   367  
   368  	db := dbTest.SetupDB(t)
   369  	genBlock := testutil.NewBeaconBlock()
   370  	genBlock.Block.ParentRoot = bytesutil.PadTo([]byte{'G'}, 32)
   371  	require.NoError(t, db.SaveBlock(context.Background(), wrapper.WrappedPhase0SignedBeaconBlock(genBlock)))
   372  	gRoot, err := genBlock.Block.HashTreeRoot()
   373  	require.NoError(t, err)
   374  	require.NoError(t, db.SaveGenesisBlockRoot(context.Background(), gRoot))
   375  
   376  	finalizedBlock := testutil.NewBeaconBlock()
   377  	finalizedBlock.Block.Slot = 1
   378  	finalizedBlock.Block.ParentRoot = bytesutil.PadTo([]byte{'A'}, 32)
   379  	require.NoError(t, db.SaveBlock(context.Background(), wrapper.WrappedPhase0SignedBeaconBlock(finalizedBlock)))
   380  	fRoot, err := finalizedBlock.Block.HashTreeRoot()
   381  	require.NoError(t, err)
   382  
   383  	justifiedBlock := testutil.NewBeaconBlock()
   384  	justifiedBlock.Block.Slot = 2
   385  	justifiedBlock.Block.ParentRoot = bytesutil.PadTo([]byte{'B'}, 32)
   386  	require.NoError(t, db.SaveBlock(context.Background(), wrapper.WrappedPhase0SignedBeaconBlock(justifiedBlock)))
   387  	jRoot, err := justifiedBlock.Block.HashTreeRoot()
   388  	require.NoError(t, err)
   389  
   390  	prevJustifiedBlock := testutil.NewBeaconBlock()
   391  	prevJustifiedBlock.Block.Slot = 3
   392  	prevJustifiedBlock.Block.ParentRoot = bytesutil.PadTo([]byte{'C'}, 32)
   393  	require.NoError(t, db.SaveBlock(context.Background(), wrapper.WrappedPhase0SignedBeaconBlock(prevJustifiedBlock)))
   394  	pjRoot, err := prevJustifiedBlock.Block.HashTreeRoot()
   395  	require.NoError(t, err)
   396  
   397  	s, err := v1.InitializeFromProto(&pbp2p.BeaconState{
   398  		Slot:                        1,
   399  		PreviousJustifiedCheckpoint: &ethpb.Checkpoint{Epoch: 3, Root: pjRoot[:]},
   400  		CurrentJustifiedCheckpoint:  &ethpb.Checkpoint{Epoch: 2, Root: jRoot[:]},
   401  		FinalizedCheckpoint:         &ethpb.Checkpoint{Epoch: 1, Root: fRoot[:]},
   402  	})
   403  	require.NoError(t, err)
   404  
   405  	b := testutil.NewBeaconBlock()
   406  	b.Block.Slot, err = helpers.StartSlot(s.PreviousJustifiedCheckpoint().Epoch)
   407  	require.NoError(t, err)
   408  	b.Block.Slot++
   409  	bs := &Server{
   410  		BeaconDB:    db,
   411  		HeadFetcher: &chainMock.ChainService{Block: wrapper.WrappedPhase0SignedBeaconBlock(b), State: s},
   412  		FinalizationFetcher: &chainMock.ChainService{
   413  			FinalizedCheckPoint:         s.FinalizedCheckpoint(),
   414  			CurrentJustifiedCheckPoint:  s.CurrentJustifiedCheckpoint(),
   415  			PreviousJustifiedCheckPoint: s.PreviousJustifiedCheckpoint()},
   416  	}
   417  
   418  	head, err := bs.GetChainHead(context.Background(), nil)
   419  	require.NoError(t, err)
   420  	assert.Equal(t, types.Epoch(3), head.PreviousJustifiedEpoch, "Unexpected PreviousJustifiedEpoch")
   421  	assert.Equal(t, types.Epoch(2), head.JustifiedEpoch, "Unexpected JustifiedEpoch")
   422  	assert.Equal(t, types.Epoch(1), head.FinalizedEpoch, "Unexpected FinalizedEpoch")
   423  	assert.Equal(t, types.Slot(24), head.PreviousJustifiedSlot, "Unexpected PreviousJustifiedSlot")
   424  	assert.Equal(t, types.Slot(16), head.JustifiedSlot, "Unexpected JustifiedSlot")
   425  	assert.Equal(t, types.Slot(8), head.FinalizedSlot, "Unexpected FinalizedSlot")
   426  	assert.DeepEqual(t, pjRoot[:], head.PreviousJustifiedBlockRoot, "Unexpected PreviousJustifiedBlockRoot")
   427  	assert.DeepEqual(t, jRoot[:], head.JustifiedBlockRoot, "Unexpected JustifiedBlockRoot")
   428  	assert.DeepEqual(t, fRoot[:], head.FinalizedBlockRoot, "Unexpected FinalizedBlockRoot")
   429  }
   430  
   431  func TestServer_StreamChainHead_ContextCanceled(t *testing.T) {
   432  	db := dbTest.SetupDB(t)
   433  	ctx := context.Background()
   434  
   435  	ctx, cancel := context.WithCancel(ctx)
   436  	chainService := &chainMock.ChainService{}
   437  	server := &Server{
   438  		Ctx:           ctx,
   439  		StateNotifier: chainService.StateNotifier(),
   440  		BeaconDB:      db,
   441  	}
   442  
   443  	exitRoutine := make(chan bool)
   444  	ctrl := gomock.NewController(t)
   445  	defer ctrl.Finish()
   446  	mockStream := mock.NewMockBeaconChain_StreamChainHeadServer(ctrl)
   447  	mockStream.EXPECT().Context().Return(ctx)
   448  	go func(tt *testing.T) {
   449  		assert.ErrorContains(tt, "Context canceled", server.StreamChainHead(&emptypb.Empty{}, mockStream))
   450  		<-exitRoutine
   451  	}(t)
   452  	cancel()
   453  	exitRoutine <- true
   454  }
   455  
   456  func TestServer_StreamChainHead_OnHeadUpdated(t *testing.T) {
   457  	db := dbTest.SetupDB(t)
   458  	params.UseMainnetConfig()
   459  	genBlock := testutil.NewBeaconBlock()
   460  	genBlock.Block.ParentRoot = bytesutil.PadTo([]byte{'G'}, 32)
   461  	require.NoError(t, db.SaveBlock(context.Background(), wrapper.WrappedPhase0SignedBeaconBlock(genBlock)))
   462  	gRoot, err := genBlock.Block.HashTreeRoot()
   463  	require.NoError(t, err)
   464  	require.NoError(t, db.SaveGenesisBlockRoot(context.Background(), gRoot))
   465  
   466  	finalizedBlock := testutil.NewBeaconBlock()
   467  	finalizedBlock.Block.Slot = 32
   468  	finalizedBlock.Block.ParentRoot = bytesutil.PadTo([]byte{'A'}, 32)
   469  	require.NoError(t, db.SaveBlock(context.Background(), wrapper.WrappedPhase0SignedBeaconBlock(finalizedBlock)))
   470  	fRoot, err := finalizedBlock.Block.HashTreeRoot()
   471  	require.NoError(t, err)
   472  
   473  	justifiedBlock := testutil.NewBeaconBlock()
   474  	justifiedBlock.Block.Slot = 64
   475  	justifiedBlock.Block.ParentRoot = bytesutil.PadTo([]byte{'B'}, 32)
   476  	require.NoError(t, db.SaveBlock(context.Background(), wrapper.WrappedPhase0SignedBeaconBlock(justifiedBlock)))
   477  	jRoot, err := justifiedBlock.Block.HashTreeRoot()
   478  	require.NoError(t, err)
   479  
   480  	prevJustifiedBlock := testutil.NewBeaconBlock()
   481  	prevJustifiedBlock.Block.Slot = 96
   482  	prevJustifiedBlock.Block.ParentRoot = bytesutil.PadTo([]byte{'C'}, 32)
   483  	require.NoError(t, db.SaveBlock(context.Background(), wrapper.WrappedPhase0SignedBeaconBlock(prevJustifiedBlock)))
   484  	pjRoot, err := prevJustifiedBlock.Block.HashTreeRoot()
   485  	require.NoError(t, err)
   486  
   487  	s, err := v1.InitializeFromProto(&pbp2p.BeaconState{
   488  		Slot:                        1,
   489  		PreviousJustifiedCheckpoint: &ethpb.Checkpoint{Epoch: 3, Root: pjRoot[:]},
   490  		CurrentJustifiedCheckpoint:  &ethpb.Checkpoint{Epoch: 2, Root: jRoot[:]},
   491  		FinalizedCheckpoint:         &ethpb.Checkpoint{Epoch: 1, Root: fRoot[:]},
   492  	})
   493  	require.NoError(t, err)
   494  
   495  	b := testutil.NewBeaconBlock()
   496  	b.Block.Slot, err = helpers.StartSlot(s.PreviousJustifiedCheckpoint().Epoch)
   497  	require.NoError(t, err)
   498  
   499  	hRoot, err := b.Block.HashTreeRoot()
   500  	require.NoError(t, err)
   501  
   502  	chainService := &chainMock.ChainService{}
   503  	ctx := context.Background()
   504  	server := &Server{
   505  		Ctx:           ctx,
   506  		HeadFetcher:   &chainMock.ChainService{Block: wrapper.WrappedPhase0SignedBeaconBlock(b), State: s},
   507  		BeaconDB:      db,
   508  		StateNotifier: chainService.StateNotifier(),
   509  		FinalizationFetcher: &chainMock.ChainService{
   510  			FinalizedCheckPoint:         s.FinalizedCheckpoint(),
   511  			CurrentJustifiedCheckPoint:  s.CurrentJustifiedCheckpoint(),
   512  			PreviousJustifiedCheckPoint: s.PreviousJustifiedCheckpoint()},
   513  	}
   514  	exitRoutine := make(chan bool)
   515  	ctrl := gomock.NewController(t)
   516  	defer ctrl.Finish()
   517  	mockStream := mock.NewMockBeaconChain_StreamChainHeadServer(ctrl)
   518  	mockStream.EXPECT().Send(
   519  		&ethpb.ChainHead{
   520  			HeadSlot:                   b.Block.Slot,
   521  			HeadEpoch:                  helpers.SlotToEpoch(b.Block.Slot),
   522  			HeadBlockRoot:              hRoot[:],
   523  			FinalizedSlot:              32,
   524  			FinalizedEpoch:             1,
   525  			FinalizedBlockRoot:         fRoot[:],
   526  			JustifiedSlot:              64,
   527  			JustifiedEpoch:             2,
   528  			JustifiedBlockRoot:         jRoot[:],
   529  			PreviousJustifiedSlot:      96,
   530  			PreviousJustifiedEpoch:     3,
   531  			PreviousJustifiedBlockRoot: pjRoot[:],
   532  		},
   533  	).Do(func(arg0 interface{}) {
   534  		exitRoutine <- true
   535  	})
   536  	mockStream.EXPECT().Context().Return(ctx).AnyTimes()
   537  
   538  	go func(tt *testing.T) {
   539  		assert.NoError(tt, server.StreamChainHead(&emptypb.Empty{}, mockStream), "Could not call RPC method")
   540  	}(t)
   541  
   542  	// Send in a loop to ensure it is delivered (busy wait for the service to subscribe to the state feed).
   543  	for sent := 0; sent == 0; {
   544  		sent = server.StateNotifier.StateFeed().Send(&feed.Event{
   545  			Type: statefeed.BlockProcessed,
   546  			Data: &statefeed.BlockProcessedData{},
   547  		})
   548  	}
   549  	<-exitRoutine
   550  }
   551  
   552  func TestServer_StreamBlocksVerified_ContextCanceled(t *testing.T) {
   553  	db := dbTest.SetupDB(t)
   554  	ctx := context.Background()
   555  
   556  	chainService := &chainMock.ChainService{}
   557  	ctx, cancel := context.WithCancel(ctx)
   558  	server := &Server{
   559  		Ctx:           ctx,
   560  		StateNotifier: chainService.StateNotifier(),
   561  		HeadFetcher:   chainService,
   562  		BeaconDB:      db,
   563  	}
   564  
   565  	exitRoutine := make(chan bool)
   566  	ctrl := gomock.NewController(t)
   567  	defer ctrl.Finish()
   568  	mockStream := mock.NewMockBeaconChain_StreamBlocksServer(ctrl)
   569  	mockStream.EXPECT().Context().Return(ctx)
   570  	go func(tt *testing.T) {
   571  		assert.ErrorContains(tt, "Context canceled", server.StreamBlocks(&ethpb.StreamBlocksRequest{
   572  			VerifiedOnly: true,
   573  		}, mockStream))
   574  		<-exitRoutine
   575  	}(t)
   576  	cancel()
   577  	exitRoutine <- true
   578  }
   579  
   580  func TestServer_StreamBlocks_ContextCanceled(t *testing.T) {
   581  	db := dbTest.SetupDB(t)
   582  	ctx := context.Background()
   583  
   584  	chainService := &chainMock.ChainService{}
   585  	ctx, cancel := context.WithCancel(ctx)
   586  	server := &Server{
   587  		Ctx:           ctx,
   588  		BlockNotifier: chainService.BlockNotifier(),
   589  		HeadFetcher:   chainService,
   590  		BeaconDB:      db,
   591  	}
   592  
   593  	exitRoutine := make(chan bool)
   594  	ctrl := gomock.NewController(t)
   595  	defer ctrl.Finish()
   596  	mockStream := mock.NewMockBeaconChain_StreamBlocksServer(ctrl)
   597  	mockStream.EXPECT().Context().Return(ctx)
   598  	go func(tt *testing.T) {
   599  		assert.ErrorContains(tt, "Context canceled", server.StreamBlocks(&ethpb.StreamBlocksRequest{}, mockStream))
   600  		<-exitRoutine
   601  	}(t)
   602  	cancel()
   603  	exitRoutine <- true
   604  }
   605  
   606  func TestServer_StreamBlocks_OnHeadUpdated(t *testing.T) {
   607  	ctx := context.Background()
   608  	beaconState, privs := testutil.DeterministicGenesisState(t, 32)
   609  	b, err := testutil.GenerateFullBlock(beaconState, privs, testutil.DefaultBlockGenConfig(), 1)
   610  	require.NoError(t, err)
   611  	chainService := &chainMock.ChainService{State: beaconState}
   612  	server := &Server{
   613  		Ctx:           ctx,
   614  		BlockNotifier: chainService.BlockNotifier(),
   615  		HeadFetcher:   chainService,
   616  	}
   617  	exitRoutine := make(chan bool)
   618  	ctrl := gomock.NewController(t)
   619  	defer ctrl.Finish()
   620  	mockStream := mock.NewMockBeaconChain_StreamBlocksServer(ctrl)
   621  	mockStream.EXPECT().Send(b).Do(func(arg0 interface{}) {
   622  		exitRoutine <- true
   623  	})
   624  	mockStream.EXPECT().Context().Return(ctx).AnyTimes()
   625  
   626  	go func(tt *testing.T) {
   627  		assert.NoError(tt, server.StreamBlocks(&ethpb.StreamBlocksRequest{}, mockStream), "Could not call RPC method")
   628  	}(t)
   629  
   630  	// Send in a loop to ensure it is delivered (busy wait for the service to subscribe to the state feed).
   631  	for sent := 0; sent == 0; {
   632  		sent = server.BlockNotifier.BlockFeed().Send(&feed.Event{
   633  			Type: blockfeed.ReceivedBlock,
   634  			Data: &blockfeed.ReceivedBlockData{SignedBlock: wrapper.WrappedPhase0SignedBeaconBlock(b)},
   635  		})
   636  	}
   637  	<-exitRoutine
   638  }
   639  
   640  func TestServer_StreamBlocksVerified_OnHeadUpdated(t *testing.T) {
   641  	db := dbTest.SetupDB(t)
   642  	ctx := context.Background()
   643  	beaconState, privs := testutil.DeterministicGenesisState(t, 32)
   644  	b, err := testutil.GenerateFullBlock(beaconState, privs, testutil.DefaultBlockGenConfig(), 1)
   645  	require.NoError(t, err)
   646  	r, err := b.Block.HashTreeRoot()
   647  	require.NoError(t, err)
   648  	require.NoError(t, db.SaveBlock(ctx, wrapper.WrappedPhase0SignedBeaconBlock(b)))
   649  	chainService := &chainMock.ChainService{State: beaconState}
   650  	server := &Server{
   651  		Ctx:           ctx,
   652  		StateNotifier: chainService.StateNotifier(),
   653  		HeadFetcher:   chainService,
   654  		BeaconDB:      db,
   655  	}
   656  	exitRoutine := make(chan bool)
   657  	ctrl := gomock.NewController(t)
   658  	defer ctrl.Finish()
   659  	mockStream := mock.NewMockBeaconChain_StreamBlocksServer(ctrl)
   660  	mockStream.EXPECT().Send(b).Do(func(arg0 interface{}) {
   661  		exitRoutine <- true
   662  	})
   663  	mockStream.EXPECT().Context().Return(ctx).AnyTimes()
   664  
   665  	go func(tt *testing.T) {
   666  		assert.NoError(tt, server.StreamBlocks(&ethpb.StreamBlocksRequest{
   667  			VerifiedOnly: true,
   668  		}, mockStream), "Could not call RPC method")
   669  	}(t)
   670  
   671  	// Send in a loop to ensure it is delivered (busy wait for the service to subscribe to the state feed).
   672  	for sent := 0; sent == 0; {
   673  		sent = server.StateNotifier.StateFeed().Send(&feed.Event{
   674  			Type: statefeed.BlockProcessed,
   675  			Data: &statefeed.BlockProcessedData{Slot: b.Block.Slot, BlockRoot: r, SignedBlock: wrapper.WrappedPhase0SignedBeaconBlock(b)},
   676  		})
   677  	}
   678  	<-exitRoutine
   679  }
   680  
   681  func TestServer_GetWeakSubjectivityCheckpoint(t *testing.T) {
   682  	params.UseMainnetConfig()
   683  
   684  	db := dbTest.SetupDB(t)
   685  	ctx := context.Background()
   686  
   687  	// Beacon state.
   688  	beaconState, err := testutil.NewBeaconState()
   689  	require.NoError(t, err)
   690  	require.NoError(t, beaconState.SetSlot(10))
   691  
   692  	// Active validator set is used for computing the weak subjectivity period.
   693  	numVals := 256 // Works with params.BeaconConfig().MinGenesisActiveValidatorCount as well, but takes longer.
   694  	validators := make([]*ethpb.Validator, numVals)
   695  	balances := make([]uint64, len(validators))
   696  	for i := 0; i < len(validators); i++ {
   697  		validators[i] = &ethpb.Validator{
   698  			PublicKey:             make([]byte, params.BeaconConfig().BLSPubkeyLength),
   699  			WithdrawalCredentials: make([]byte, 32),
   700  			EffectiveBalance:      28 * 1e9,
   701  			ExitEpoch:             params.BeaconConfig().FarFutureEpoch,
   702  		}
   703  		balances[i] = validators[i].EffectiveBalance
   704  	}
   705  	require.NoError(t, beaconState.SetValidators(validators))
   706  	require.NoError(t, beaconState.SetBalances(balances))
   707  
   708  	// Genesis block.
   709  	genesisBlock := testutil.NewBeaconBlock()
   710  	genesisBlockRoot, err := genesisBlock.Block.HashTreeRoot()
   711  	require.NoError(t, err)
   712  	require.NoError(t, db.SaveBlock(ctx, wrapper.WrappedPhase0SignedBeaconBlock(genesisBlock)))
   713  	require.NoError(t, db.SaveState(ctx, beaconState, genesisBlockRoot))
   714  	require.NoError(t, db.SaveGenesisBlockRoot(ctx, genesisBlockRoot))
   715  
   716  	// Finalized checkpoint.
   717  	finalizedEpoch := types.Epoch(1020)
   718  	require.NoError(t, beaconState.SetSlot(types.Slot(finalizedEpoch.Mul(uint64(params.BeaconConfig().SlotsPerEpoch)))))
   719  	require.NoError(t, beaconState.SetCurrentJustifiedCheckpoint(&ethpb.Checkpoint{
   720  		Epoch: finalizedEpoch - 1,
   721  		Root:  bytesutil.PadTo([]byte{'A'}, 32),
   722  	}))
   723  	require.NoError(t, beaconState.SetFinalizedCheckpoint(&ethpb.Checkpoint{
   724  		Epoch: finalizedEpoch,
   725  		Root:  bytesutil.PadTo([]byte{'B'}, 32),
   726  	}))
   727  
   728  	chainService := &chainMock.ChainService{State: beaconState}
   729  	server := &Server{
   730  		Ctx:           ctx,
   731  		BlockNotifier: chainService.BlockNotifier(),
   732  		HeadFetcher:   chainService,
   733  		BeaconDB:      db,
   734  		StateGen:      stategen.New(db),
   735  	}
   736  
   737  	wsEpoch, err := helpers.ComputeWeakSubjectivityPeriod(beaconState)
   738  	require.NoError(t, err)
   739  
   740  	c, err := server.GetWeakSubjectivityCheckpoint(ctx, &emptypb.Empty{})
   741  	require.NoError(t, err)
   742  	e := finalizedEpoch - (finalizedEpoch % wsEpoch)
   743  	require.Equal(t, e, c.Epoch)
   744  	wsState, err := server.StateGen.StateBySlot(ctx, params.BeaconConfig().SlotsPerEpoch.Mul(uint64(e)))
   745  	require.NoError(t, err)
   746  	sRoot, err := wsState.HashTreeRoot(ctx)
   747  	require.NoError(t, err)
   748  	require.DeepEqual(t, sRoot[:], c.StateRoot)
   749  }