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

     1  package beacon
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  	"sort"
     7  	"strconv"
     8  	"testing"
     9  	"time"
    10  
    11  	"github.com/golang/mock/gomock"
    12  	types "github.com/prysmaticlabs/eth2-types"
    13  	"github.com/prysmaticlabs/go-bitfield"
    14  	chainMock "github.com/prysmaticlabs/prysm/beacon-chain/blockchain/testing"
    15  	"github.com/prysmaticlabs/prysm/beacon-chain/core/feed"
    16  	"github.com/prysmaticlabs/prysm/beacon-chain/core/feed/operation"
    17  	"github.com/prysmaticlabs/prysm/beacon-chain/core/helpers"
    18  	dbTest "github.com/prysmaticlabs/prysm/beacon-chain/db/testing"
    19  	"github.com/prysmaticlabs/prysm/beacon-chain/operations/attestations"
    20  	"github.com/prysmaticlabs/prysm/beacon-chain/state/stategen"
    21  	"github.com/prysmaticlabs/prysm/beacon-chain/state/v1"
    22  	pbp2p "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1"
    23  	ethpb "github.com/prysmaticlabs/prysm/proto/eth/v1alpha1"
    24  	"github.com/prysmaticlabs/prysm/proto/eth/v1alpha1/wrapper"
    25  	"github.com/prysmaticlabs/prysm/proto/interfaces"
    26  	attaggregation "github.com/prysmaticlabs/prysm/shared/aggregation/attestations"
    27  	"github.com/prysmaticlabs/prysm/shared/attestationutil"
    28  	"github.com/prysmaticlabs/prysm/shared/bytesutil"
    29  	"github.com/prysmaticlabs/prysm/shared/cmd"
    30  	"github.com/prysmaticlabs/prysm/shared/mock"
    31  	"github.com/prysmaticlabs/prysm/shared/params"
    32  	"github.com/prysmaticlabs/prysm/shared/testutil"
    33  	"github.com/prysmaticlabs/prysm/shared/testutil/assert"
    34  	"github.com/prysmaticlabs/prysm/shared/testutil/require"
    35  	"google.golang.org/protobuf/proto"
    36  	"google.golang.org/protobuf/types/known/emptypb"
    37  )
    38  
    39  func TestServer_ListAttestations_NoResults(t *testing.T) {
    40  	db := dbTest.SetupDB(t)
    41  	ctx := context.Background()
    42  
    43  	st, err := v1.InitializeFromProto(&pbp2p.BeaconState{
    44  		Slot: 0,
    45  	})
    46  	require.NoError(t, err)
    47  	bs := &Server{
    48  		BeaconDB: db,
    49  		HeadFetcher: &chainMock.ChainService{
    50  			State: st,
    51  		},
    52  	}
    53  	wanted := &ethpb.ListAttestationsResponse{
    54  		Attestations:  make([]*ethpb.Attestation, 0),
    55  		TotalSize:     int32(0),
    56  		NextPageToken: strconv.Itoa(0),
    57  	}
    58  	res, err := bs.ListAttestations(ctx, &ethpb.ListAttestationsRequest{
    59  		QueryFilter: &ethpb.ListAttestationsRequest_GenesisEpoch{GenesisEpoch: true},
    60  	})
    61  	require.NoError(t, err)
    62  	if !proto.Equal(wanted, res) {
    63  		t.Errorf("Wanted %v, received %v", wanted, res)
    64  	}
    65  }
    66  
    67  func TestServer_ListAttestations_Genesis(t *testing.T) {
    68  	db := dbTest.SetupDB(t)
    69  	ctx := context.Background()
    70  
    71  	st, err := v1.InitializeFromProto(&pbp2p.BeaconState{
    72  		Slot: 0,
    73  	})
    74  	require.NoError(t, err)
    75  	bs := &Server{
    76  		BeaconDB: db,
    77  		HeadFetcher: &chainMock.ChainService{
    78  			State: st,
    79  		},
    80  	}
    81  
    82  	att := testutil.HydrateAttestation(&ethpb.Attestation{
    83  		AggregationBits: bitfield.NewBitlist(0),
    84  		Data: &ethpb.AttestationData{
    85  			Slot:           2,
    86  			CommitteeIndex: 1,
    87  		},
    88  	})
    89  
    90  	parentRoot := [32]byte{1, 2, 3}
    91  	signedBlock := testutil.NewBeaconBlock()
    92  	signedBlock.Block.ParentRoot = bytesutil.PadTo(parentRoot[:], 32)
    93  	signedBlock.Block.Body.Attestations = []*ethpb.Attestation{att}
    94  	root, err := signedBlock.Block.HashTreeRoot()
    95  	require.NoError(t, err)
    96  	require.NoError(t, db.SaveBlock(ctx, wrapper.WrappedPhase0SignedBeaconBlock(signedBlock)))
    97  	require.NoError(t, db.SaveGenesisBlockRoot(ctx, root))
    98  	wanted := &ethpb.ListAttestationsResponse{
    99  		Attestations:  []*ethpb.Attestation{att},
   100  		NextPageToken: "",
   101  		TotalSize:     1,
   102  	}
   103  
   104  	res, err := bs.ListAttestations(ctx, &ethpb.ListAttestationsRequest{
   105  		QueryFilter: &ethpb.ListAttestationsRequest_GenesisEpoch{
   106  			GenesisEpoch: true,
   107  		},
   108  	})
   109  	require.NoError(t, err)
   110  	require.DeepSSZEqual(t, wanted, res)
   111  }
   112  
   113  func TestServer_ListAttestations_NoPagination(t *testing.T) {
   114  	db := dbTest.SetupDB(t)
   115  	ctx := context.Background()
   116  
   117  	count := types.Slot(8)
   118  	atts := make([]*ethpb.Attestation, 0, count)
   119  	for i := types.Slot(0); i < count; i++ {
   120  		blockExample := testutil.NewBeaconBlock()
   121  		blockExample.Block.Body.Attestations = []*ethpb.Attestation{
   122  			{
   123  				Signature: make([]byte, 96),
   124  				Data: &ethpb.AttestationData{
   125  					Target:          &ethpb.Checkpoint{Root: bytesutil.PadTo([]byte("root"), 32)},
   126  					Source:          &ethpb.Checkpoint{Root: bytesutil.PadTo([]byte("root"), 32)},
   127  					BeaconBlockRoot: bytesutil.PadTo([]byte("root"), 32),
   128  					Slot:            i,
   129  				},
   130  				AggregationBits: bitfield.Bitlist{0b11},
   131  			},
   132  		}
   133  		require.NoError(t, db.SaveBlock(ctx, wrapper.WrappedPhase0SignedBeaconBlock(blockExample)))
   134  		atts = append(atts, blockExample.Block.Body.Attestations...)
   135  	}
   136  
   137  	bs := &Server{
   138  		BeaconDB: db,
   139  	}
   140  
   141  	received, err := bs.ListAttestations(ctx, &ethpb.ListAttestationsRequest{
   142  		QueryFilter: &ethpb.ListAttestationsRequest_GenesisEpoch{
   143  			GenesisEpoch: true,
   144  		},
   145  	})
   146  	require.NoError(t, err)
   147  	require.DeepEqual(t, atts, received.Attestations, "Incorrect attestations response")
   148  }
   149  
   150  func TestServer_ListAttestations_FiltersCorrectly(t *testing.T) {
   151  	db := dbTest.SetupDB(t)
   152  	ctx := context.Background()
   153  
   154  	someRoot := [32]byte{1, 2, 3}
   155  	sourceRoot := [32]byte{4, 5, 6}
   156  	sourceEpoch := types.Epoch(5)
   157  	targetRoot := [32]byte{7, 8, 9}
   158  	targetEpoch := types.Epoch(7)
   159  
   160  	blocks := []interfaces.SignedBeaconBlock{
   161  		wrapper.WrappedPhase0SignedBeaconBlock(
   162  			testutil.HydrateSignedBeaconBlock(
   163  				&ethpb.SignedBeaconBlock{
   164  					Block: &ethpb.BeaconBlock{
   165  						Slot: 4,
   166  						Body: &ethpb.BeaconBlockBody{
   167  							Attestations: []*ethpb.Attestation{
   168  								{
   169  									Data: &ethpb.AttestationData{
   170  										BeaconBlockRoot: someRoot[:],
   171  										Source: &ethpb.Checkpoint{
   172  											Root:  sourceRoot[:],
   173  											Epoch: sourceEpoch,
   174  										},
   175  										Target: &ethpb.Checkpoint{
   176  											Root:  targetRoot[:],
   177  											Epoch: targetEpoch,
   178  										},
   179  										Slot: 3,
   180  									},
   181  									AggregationBits: bitfield.Bitlist{0b11},
   182  									Signature:       bytesutil.PadTo([]byte("sig"), 96),
   183  								},
   184  							},
   185  						},
   186  					},
   187  				})),
   188  		wrapper.WrappedPhase0SignedBeaconBlock(
   189  			testutil.HydrateSignedBeaconBlock(&ethpb.SignedBeaconBlock{
   190  				Block: &ethpb.BeaconBlock{
   191  					Slot: 5 + params.BeaconConfig().SlotsPerEpoch,
   192  					Body: &ethpb.BeaconBlockBody{
   193  						Attestations: []*ethpb.Attestation{
   194  							{
   195  								Data: &ethpb.AttestationData{
   196  									BeaconBlockRoot: someRoot[:],
   197  									Source: &ethpb.Checkpoint{
   198  										Root:  sourceRoot[:],
   199  										Epoch: sourceEpoch,
   200  									},
   201  									Target: &ethpb.Checkpoint{
   202  										Root:  targetRoot[:],
   203  										Epoch: targetEpoch,
   204  									},
   205  									Slot: 4 + params.BeaconConfig().SlotsPerEpoch,
   206  								},
   207  								AggregationBits: bitfield.Bitlist{0b11},
   208  								Signature:       bytesutil.PadTo([]byte("sig"), 96),
   209  							},
   210  						},
   211  					},
   212  				},
   213  			})),
   214  		wrapper.WrappedPhase0SignedBeaconBlock(
   215  			testutil.HydrateSignedBeaconBlock(
   216  				&ethpb.SignedBeaconBlock{
   217  					Block: &ethpb.BeaconBlock{
   218  						Slot: 5,
   219  						Body: &ethpb.BeaconBlockBody{
   220  							Attestations: []*ethpb.Attestation{
   221  								{
   222  									Data: &ethpb.AttestationData{
   223  										BeaconBlockRoot: someRoot[:],
   224  										Source: &ethpb.Checkpoint{
   225  											Root:  sourceRoot[:],
   226  											Epoch: sourceEpoch,
   227  										},
   228  										Target: &ethpb.Checkpoint{
   229  											Root:  targetRoot[:],
   230  											Epoch: targetEpoch,
   231  										},
   232  										Slot: 4,
   233  									},
   234  									AggregationBits: bitfield.Bitlist{0b11},
   235  									Signature:       bytesutil.PadTo([]byte("sig"), 96),
   236  								},
   237  							},
   238  						},
   239  					},
   240  				})),
   241  	}
   242  
   243  	require.NoError(t, db.SaveBlocks(ctx, blocks))
   244  
   245  	bs := &Server{
   246  		BeaconDB: db,
   247  	}
   248  
   249  	received, err := bs.ListAttestations(ctx, &ethpb.ListAttestationsRequest{
   250  		QueryFilter: &ethpb.ListAttestationsRequest_Epoch{Epoch: 1},
   251  	})
   252  	require.NoError(t, err)
   253  	assert.Equal(t, 1, len(received.Attestations))
   254  	received, err = bs.ListAttestations(ctx, &ethpb.ListAttestationsRequest{
   255  		QueryFilter: &ethpb.ListAttestationsRequest_GenesisEpoch{GenesisEpoch: true},
   256  	})
   257  	require.NoError(t, err)
   258  	assert.Equal(t, 2, len(received.Attestations))
   259  }
   260  
   261  func TestServer_ListAttestations_Pagination_CustomPageParameters(t *testing.T) {
   262  	db := dbTest.SetupDB(t)
   263  	ctx := context.Background()
   264  
   265  	count := params.BeaconConfig().SlotsPerEpoch * 4
   266  	atts := make([]*ethpb.Attestation, 0, count)
   267  	for i := types.Slot(0); i < params.BeaconConfig().SlotsPerEpoch; i++ {
   268  		for s := types.CommitteeIndex(0); s < 4; s++ {
   269  			blockExample := testutil.NewBeaconBlock()
   270  			blockExample.Block.Slot = i
   271  			blockExample.Block.Body.Attestations = []*ethpb.Attestation{
   272  				testutil.HydrateAttestation(&ethpb.Attestation{
   273  					Data: &ethpb.AttestationData{
   274  						CommitteeIndex: s,
   275  						Slot:           i,
   276  					},
   277  					AggregationBits: bitfield.Bitlist{0b11},
   278  				}),
   279  			}
   280  			require.NoError(t, db.SaveBlock(ctx, wrapper.WrappedPhase0SignedBeaconBlock(blockExample)))
   281  			atts = append(atts, blockExample.Block.Body.Attestations...)
   282  		}
   283  	}
   284  	sort.Sort(sortableAttestations(atts))
   285  
   286  	bs := &Server{
   287  		BeaconDB: db,
   288  	}
   289  
   290  	tests := []struct {
   291  		name string
   292  		req  *ethpb.ListAttestationsRequest
   293  		res  *ethpb.ListAttestationsResponse
   294  	}{
   295  		{
   296  			name: "1st of 3 pages",
   297  			req: &ethpb.ListAttestationsRequest{
   298  				QueryFilter: &ethpb.ListAttestationsRequest_GenesisEpoch{
   299  					GenesisEpoch: true,
   300  				},
   301  				PageToken: strconv.Itoa(1),
   302  				PageSize:  3,
   303  			},
   304  			res: &ethpb.ListAttestationsResponse{
   305  				Attestations: []*ethpb.Attestation{
   306  					atts[3],
   307  					atts[4],
   308  					atts[5],
   309  				},
   310  				NextPageToken: strconv.Itoa(2),
   311  				TotalSize:     int32(count),
   312  			},
   313  		},
   314  		{
   315  			name: "10 of size 1",
   316  			req: &ethpb.ListAttestationsRequest{
   317  				QueryFilter: &ethpb.ListAttestationsRequest_GenesisEpoch{
   318  					GenesisEpoch: true,
   319  				},
   320  				PageToken: strconv.Itoa(10),
   321  				PageSize:  1,
   322  			},
   323  			res: &ethpb.ListAttestationsResponse{
   324  				Attestations: []*ethpb.Attestation{
   325  					atts[10],
   326  				},
   327  				NextPageToken: strconv.Itoa(11),
   328  				TotalSize:     int32(count),
   329  			},
   330  		},
   331  		{
   332  			name: "2 of size 8",
   333  			req: &ethpb.ListAttestationsRequest{
   334  				QueryFilter: &ethpb.ListAttestationsRequest_GenesisEpoch{
   335  					GenesisEpoch: true,
   336  				},
   337  				PageToken: strconv.Itoa(2),
   338  				PageSize:  8,
   339  			},
   340  			res: &ethpb.ListAttestationsResponse{
   341  				Attestations: []*ethpb.Attestation{
   342  					atts[16],
   343  					atts[17],
   344  					atts[18],
   345  					atts[19],
   346  					atts[20],
   347  					atts[21],
   348  					atts[22],
   349  					atts[23],
   350  				},
   351  				NextPageToken: strconv.Itoa(3),
   352  				TotalSize:     int32(count)},
   353  		},
   354  	}
   355  	for _, test := range tests {
   356  		t.Run(test.name, func(t *testing.T) {
   357  			res, err := bs.ListAttestations(ctx, test.req)
   358  			require.NoError(t, err)
   359  			require.DeepSSZEqual(t, res, test.res)
   360  		})
   361  	}
   362  }
   363  
   364  func TestServer_ListAttestations_Pagination_OutOfRange(t *testing.T) {
   365  	db := dbTest.SetupDB(t)
   366  	ctx := context.Background()
   367  	testutil.NewBeaconBlock()
   368  	count := types.Slot(1)
   369  	atts := make([]*ethpb.Attestation, 0, count)
   370  	for i := types.Slot(0); i < count; i++ {
   371  		blockExample := testutil.HydrateSignedBeaconBlock(&ethpb.SignedBeaconBlock{
   372  			Block: &ethpb.BeaconBlock{
   373  				Body: &ethpb.BeaconBlockBody{
   374  					Attestations: []*ethpb.Attestation{
   375  						{
   376  							Data: &ethpb.AttestationData{
   377  								BeaconBlockRoot: bytesutil.PadTo([]byte("root"), 32),
   378  								Source:          &ethpb.Checkpoint{Root: make([]byte, 32)},
   379  								Target:          &ethpb.Checkpoint{Root: make([]byte, 32)},
   380  								Slot:            i,
   381  							},
   382  							AggregationBits: bitfield.Bitlist{0b11},
   383  							Signature:       make([]byte, 96),
   384  						},
   385  					},
   386  				},
   387  			},
   388  		})
   389  		require.NoError(t, db.SaveBlock(ctx, wrapper.WrappedPhase0SignedBeaconBlock(blockExample)))
   390  		atts = append(atts, blockExample.Block.Body.Attestations...)
   391  	}
   392  
   393  	bs := &Server{
   394  		BeaconDB: db,
   395  	}
   396  
   397  	req := &ethpb.ListAttestationsRequest{
   398  		QueryFilter: &ethpb.ListAttestationsRequest_Epoch{
   399  			Epoch: 0,
   400  		},
   401  		PageToken: strconv.Itoa(1),
   402  		PageSize:  100,
   403  	}
   404  	wanted := fmt.Sprintf("page start %d >= list %d", req.PageSize, len(atts))
   405  	_, err := bs.ListAttestations(ctx, req)
   406  	assert.ErrorContains(t, wanted, err)
   407  }
   408  
   409  func TestServer_ListAttestations_Pagination_ExceedsMaxPageSize(t *testing.T) {
   410  	ctx := context.Background()
   411  	bs := &Server{}
   412  	exceedsMax := int32(cmd.Get().MaxRPCPageSize + 1)
   413  
   414  	wanted := fmt.Sprintf("Requested page size %d can not be greater than max size %d", exceedsMax, cmd.Get().MaxRPCPageSize)
   415  	req := &ethpb.ListAttestationsRequest{PageToken: strconv.Itoa(0), PageSize: exceedsMax}
   416  	_, err := bs.ListAttestations(ctx, req)
   417  	assert.ErrorContains(t, wanted, err)
   418  }
   419  
   420  func TestServer_ListAttestations_Pagination_DefaultPageSize(t *testing.T) {
   421  	db := dbTest.SetupDB(t)
   422  	ctx := context.Background()
   423  
   424  	count := types.Slot(params.BeaconConfig().DefaultPageSize)
   425  	atts := make([]*ethpb.Attestation, 0, count)
   426  	for i := types.Slot(0); i < count; i++ {
   427  		blockExample := testutil.NewBeaconBlock()
   428  		blockExample.Block.Body.Attestations = []*ethpb.Attestation{
   429  			{
   430  				Data: &ethpb.AttestationData{
   431  					BeaconBlockRoot: bytesutil.PadTo([]byte("root"), 32),
   432  					Target:          &ethpb.Checkpoint{Root: bytesutil.PadTo([]byte("root"), 32)},
   433  					Source:          &ethpb.Checkpoint{Root: bytesutil.PadTo([]byte("root"), 32)},
   434  					Slot:            i,
   435  				},
   436  				Signature:       bytesutil.PadTo([]byte("root"), 96),
   437  				AggregationBits: bitfield.Bitlist{0b11},
   438  			},
   439  		}
   440  		require.NoError(t, db.SaveBlock(ctx, wrapper.WrappedPhase0SignedBeaconBlock(blockExample)))
   441  		atts = append(atts, blockExample.Block.Body.Attestations...)
   442  	}
   443  
   444  	bs := &Server{
   445  		BeaconDB: db,
   446  	}
   447  
   448  	req := &ethpb.ListAttestationsRequest{
   449  		QueryFilter: &ethpb.ListAttestationsRequest_GenesisEpoch{
   450  			GenesisEpoch: true,
   451  		},
   452  	}
   453  	res, err := bs.ListAttestations(ctx, req)
   454  	require.NoError(t, err)
   455  
   456  	i := 0
   457  	j := params.BeaconConfig().DefaultPageSize
   458  	assert.DeepEqual(t, atts[i:j], res.Attestations, "Incorrect attestations response")
   459  }
   460  
   461  func TestServer_mapAttestationToTargetRoot(t *testing.T) {
   462  	count := types.Slot(100)
   463  	atts := make([]*ethpb.Attestation, count)
   464  	targetRoot1 := bytesutil.ToBytes32([]byte("root1"))
   465  	targetRoot2 := bytesutil.ToBytes32([]byte("root2"))
   466  
   467  	for i := types.Slot(0); i < count; i++ {
   468  		var targetRoot [32]byte
   469  		if i%2 == 0 {
   470  			targetRoot = targetRoot1
   471  		} else {
   472  			targetRoot = targetRoot2
   473  		}
   474  		atts[i] = &ethpb.Attestation{
   475  			Data: &ethpb.AttestationData{
   476  				Target: &ethpb.Checkpoint{
   477  					Root: targetRoot[:],
   478  				},
   479  			},
   480  			AggregationBits: bitfield.Bitlist{0b11},
   481  		}
   482  
   483  	}
   484  	mappedAtts := mapAttestationsByTargetRoot(atts)
   485  	wantedMapLen := 2
   486  	wantedMapNumberOfElements := 50
   487  	assert.Equal(t, wantedMapLen, len(mappedAtts), "Unexpected mapped attestations length")
   488  	assert.Equal(t, wantedMapNumberOfElements, len(mappedAtts[targetRoot1]), "Unexpected number of attestations per block root")
   489  	assert.Equal(t, wantedMapNumberOfElements, len(mappedAtts[targetRoot2]), "Unexpected number of attestations per block root")
   490  }
   491  
   492  func TestServer_ListIndexedAttestations_GenesisEpoch(t *testing.T) {
   493  	params.UseMainnetConfig()
   494  	db := dbTest.SetupDB(t)
   495  	helpers.ClearCache()
   496  	ctx := context.Background()
   497  	targetRoot1 := bytesutil.ToBytes32([]byte("root"))
   498  	targetRoot2 := bytesutil.ToBytes32([]byte("root2"))
   499  
   500  	count := params.BeaconConfig().SlotsPerEpoch
   501  	atts := make([]*ethpb.Attestation, 0, count)
   502  	atts2 := make([]*ethpb.Attestation, 0, count)
   503  
   504  	for i := types.Slot(0); i < count; i++ {
   505  		var targetRoot [32]byte
   506  		if i%2 == 0 {
   507  			targetRoot = targetRoot1
   508  		} else {
   509  			targetRoot = targetRoot2
   510  		}
   511  		blockExample := testutil.NewBeaconBlock()
   512  		blockExample.Block.Body.Attestations = []*ethpb.Attestation{
   513  			{
   514  				Signature: make([]byte, 96),
   515  				Data: &ethpb.AttestationData{
   516  					BeaconBlockRoot: make([]byte, 32),
   517  					Target: &ethpb.Checkpoint{
   518  						Root: targetRoot[:],
   519  					},
   520  					Source: &ethpb.Checkpoint{
   521  						Root: make([]byte, 32),
   522  					},
   523  					Slot:           i,
   524  					CommitteeIndex: 0,
   525  				},
   526  				AggregationBits: bitfield.NewBitlist(128 / uint64(params.BeaconConfig().SlotsPerEpoch)),
   527  			},
   528  		}
   529  		require.NoError(t, db.SaveBlock(ctx, wrapper.WrappedPhase0SignedBeaconBlock(blockExample)))
   530  		if i%2 == 0 {
   531  			atts = append(atts, blockExample.Block.Body.Attestations...)
   532  		} else {
   533  			atts2 = append(atts2, blockExample.Block.Body.Attestations...)
   534  		}
   535  
   536  	}
   537  
   538  	// We setup 128 validators.
   539  	numValidators := uint64(128)
   540  	state, _ := testutil.DeterministicGenesisState(t, numValidators)
   541  
   542  	// Next up we convert the test attestations to indexed form:
   543  	indexedAtts := make([]*ethpb.IndexedAttestation, len(atts)+len(atts2))
   544  	for i := 0; i < len(atts); i++ {
   545  		att := atts[i]
   546  		committee, err := helpers.BeaconCommitteeFromState(state, att.Data.Slot, att.Data.CommitteeIndex)
   547  		require.NoError(t, err)
   548  		idxAtt, err := attestationutil.ConvertToIndexed(ctx, atts[i], committee)
   549  		require.NoError(t, err, "Could not convert attestation to indexed")
   550  		indexedAtts[i] = idxAtt
   551  	}
   552  	for i := 0; i < len(atts2); i++ {
   553  		att := atts2[i]
   554  		committee, err := helpers.BeaconCommitteeFromState(state, att.Data.Slot, att.Data.CommitteeIndex)
   555  		require.NoError(t, err)
   556  		idxAtt, err := attestationutil.ConvertToIndexed(ctx, atts2[i], committee)
   557  		require.NoError(t, err, "Could not convert attestation to indexed")
   558  		indexedAtts[i+len(atts)] = idxAtt
   559  	}
   560  
   561  	bs := &Server{
   562  		BeaconDB:           db,
   563  		GenesisTimeFetcher: &chainMock.ChainService{State: state},
   564  		HeadFetcher:        &chainMock.ChainService{State: state},
   565  		StateGen:           stategen.New(db),
   566  	}
   567  	err := db.SaveStateSummary(ctx, &pbp2p.StateSummary{
   568  		Root: targetRoot1[:],
   569  		Slot: 1,
   570  	})
   571  	require.NoError(t, err)
   572  
   573  	err = db.SaveStateSummary(ctx, &pbp2p.StateSummary{
   574  		Root: targetRoot2[:],
   575  		Slot: 2,
   576  	})
   577  	require.NoError(t, err)
   578  
   579  	require.NoError(t, db.SaveState(ctx, state, bytesutil.ToBytes32(targetRoot1[:])))
   580  	require.NoError(t, state.SetSlot(state.Slot()+1))
   581  	require.NoError(t, db.SaveState(ctx, state, bytesutil.ToBytes32(targetRoot2[:])))
   582  	res, err := bs.ListIndexedAttestations(ctx, &ethpb.ListIndexedAttestationsRequest{
   583  		QueryFilter: &ethpb.ListIndexedAttestationsRequest_GenesisEpoch{
   584  			GenesisEpoch: true,
   585  		},
   586  	})
   587  	require.NoError(t, err)
   588  	assert.Equal(t, len(indexedAtts), len(res.IndexedAttestations), "Incorrect indexted attestations length")
   589  	sort.Slice(indexedAtts, func(i, j int) bool {
   590  		return indexedAtts[i].Data.Slot < indexedAtts[j].Data.Slot
   591  	})
   592  	sort.Slice(res.IndexedAttestations, func(i, j int) bool {
   593  		return res.IndexedAttestations[i].Data.Slot < res.IndexedAttestations[j].Data.Slot
   594  	})
   595  
   596  	assert.DeepEqual(t, indexedAtts, res.IndexedAttestations, "Incorrect list indexed attestations response")
   597  }
   598  
   599  func TestServer_ListIndexedAttestations_OldEpoch(t *testing.T) {
   600  	params.SetupTestConfigCleanup(t)
   601  	params.OverrideBeaconConfig(params.MainnetConfig())
   602  	db := dbTest.SetupDB(t)
   603  	helpers.ClearCache()
   604  	ctx := context.Background()
   605  
   606  	blockRoot := bytesutil.ToBytes32([]byte("root"))
   607  	count := params.BeaconConfig().SlotsPerEpoch
   608  	atts := make([]*ethpb.Attestation, 0, count)
   609  	epoch := types.Epoch(50)
   610  	startSlot, err := helpers.StartSlot(epoch)
   611  	require.NoError(t, err)
   612  
   613  	for i := startSlot; i < count; i++ {
   614  		blockExample := &ethpb.SignedBeaconBlock{
   615  			Block: &ethpb.BeaconBlock{
   616  				Body: &ethpb.BeaconBlockBody{
   617  					Attestations: []*ethpb.Attestation{
   618  						{
   619  							Data: &ethpb.AttestationData{
   620  								BeaconBlockRoot: blockRoot[:],
   621  								Slot:            i,
   622  								CommitteeIndex:  0,
   623  								Target: &ethpb.Checkpoint{
   624  									Epoch: epoch,
   625  									Root:  make([]byte, 32),
   626  								},
   627  							},
   628  							AggregationBits: bitfield.Bitlist{0b11},
   629  						},
   630  					},
   631  				},
   632  			},
   633  		}
   634  		require.NoError(t, db.SaveBlock(ctx, wrapper.WrappedPhase0SignedBeaconBlock(blockExample)))
   635  		atts = append(atts, blockExample.Block.Body.Attestations...)
   636  	}
   637  
   638  	// We setup 128 validators.
   639  	numValidators := uint64(128)
   640  	state, _ := testutil.DeterministicGenesisState(t, numValidators)
   641  
   642  	randaoMixes := make([][]byte, params.BeaconConfig().EpochsPerHistoricalVector)
   643  	for i := 0; i < len(randaoMixes); i++ {
   644  		randaoMixes[i] = make([]byte, 32)
   645  	}
   646  	require.NoError(t, state.SetRandaoMixes(randaoMixes))
   647  	require.NoError(t, state.SetSlot(startSlot))
   648  
   649  	// Next up we convert the test attestations to indexed form:
   650  	indexedAtts := make([]*ethpb.IndexedAttestation, len(atts))
   651  	for i := 0; i < len(atts); i++ {
   652  		att := atts[i]
   653  		committee, err := helpers.BeaconCommitteeFromState(state, att.Data.Slot, att.Data.CommitteeIndex)
   654  		require.NoError(t, err)
   655  		idxAtt, err := attestationutil.ConvertToIndexed(ctx, atts[i], committee)
   656  		require.NoError(t, err, "Could not convert attestation to indexed")
   657  		indexedAtts[i] = idxAtt
   658  	}
   659  
   660  	bs := &Server{
   661  		BeaconDB: db,
   662  		GenesisTimeFetcher: &chainMock.ChainService{
   663  			Genesis: time.Now(),
   664  		},
   665  		StateGen: stategen.New(db),
   666  	}
   667  	err = db.SaveStateSummary(ctx, &pbp2p.StateSummary{
   668  		Root: blockRoot[:],
   669  		Slot: params.BeaconConfig().SlotsPerEpoch.Mul(uint64(epoch)),
   670  	})
   671  	require.NoError(t, err)
   672  	require.NoError(t, db.SaveState(ctx, state, bytesutil.ToBytes32([]byte("root"))))
   673  	res, err := bs.ListIndexedAttestations(ctx, &ethpb.ListIndexedAttestationsRequest{
   674  		QueryFilter: &ethpb.ListIndexedAttestationsRequest_Epoch{
   675  			Epoch: epoch,
   676  		},
   677  	})
   678  	require.NoError(t, err)
   679  	require.DeepEqual(t, indexedAtts, res.IndexedAttestations, "Incorrect list indexed attestations response")
   680  }
   681  
   682  func TestServer_AttestationPool_Pagination_ExceedsMaxPageSize(t *testing.T) {
   683  	ctx := context.Background()
   684  	bs := &Server{}
   685  	exceedsMax := int32(cmd.Get().MaxRPCPageSize + 1)
   686  
   687  	wanted := fmt.Sprintf("Requested page size %d can not be greater than max size %d", exceedsMax, cmd.Get().MaxRPCPageSize)
   688  	req := &ethpb.AttestationPoolRequest{PageToken: strconv.Itoa(0), PageSize: exceedsMax}
   689  	_, err := bs.AttestationPool(ctx, req)
   690  	assert.ErrorContains(t, wanted, err)
   691  }
   692  
   693  func TestServer_AttestationPool_Pagination_OutOfRange(t *testing.T) {
   694  	ctx := context.Background()
   695  	bs := &Server{
   696  		AttestationsPool: attestations.NewPool(),
   697  	}
   698  
   699  	atts := []*ethpb.Attestation{
   700  		{
   701  			Data: &ethpb.AttestationData{
   702  				Slot:            1,
   703  				BeaconBlockRoot: bytesutil.PadTo([]byte{1}, 32),
   704  				Source:          &ethpb.Checkpoint{Root: bytesutil.PadTo([]byte{1}, 32)},
   705  				Target:          &ethpb.Checkpoint{Root: bytesutil.PadTo([]byte{1}, 32)},
   706  			},
   707  			AggregationBits: bitfield.Bitlist{0b1101},
   708  			Signature:       bytesutil.PadTo([]byte{1}, 96),
   709  		},
   710  		{
   711  			Data: &ethpb.AttestationData{
   712  				Slot:            2,
   713  				BeaconBlockRoot: bytesutil.PadTo([]byte{2}, 32),
   714  				Source:          &ethpb.Checkpoint{Root: bytesutil.PadTo([]byte{2}, 32)},
   715  				Target:          &ethpb.Checkpoint{Root: bytesutil.PadTo([]byte{2}, 32)},
   716  			},
   717  			AggregationBits: bitfield.Bitlist{0b1101},
   718  			Signature:       bytesutil.PadTo([]byte{2}, 96),
   719  		},
   720  		{
   721  			Data: &ethpb.AttestationData{
   722  				Slot:            3,
   723  				BeaconBlockRoot: bytesutil.PadTo([]byte{3}, 32),
   724  				Source:          &ethpb.Checkpoint{Root: bytesutil.PadTo([]byte{3}, 32)},
   725  				Target:          &ethpb.Checkpoint{Root: bytesutil.PadTo([]byte{3}, 32)},
   726  			},
   727  			AggregationBits: bitfield.Bitlist{0b1101},
   728  			Signature:       bytesutil.PadTo([]byte{3}, 96),
   729  		},
   730  	}
   731  	require.NoError(t, bs.AttestationsPool.SaveAggregatedAttestations(atts))
   732  
   733  	req := &ethpb.AttestationPoolRequest{
   734  		PageToken: strconv.Itoa(1),
   735  		PageSize:  100,
   736  	}
   737  	wanted := fmt.Sprintf("page start %d >= list %d", req.PageSize, len(atts))
   738  	_, err := bs.AttestationPool(ctx, req)
   739  	assert.ErrorContains(t, wanted, err)
   740  }
   741  
   742  func TestServer_AttestationPool_Pagination_DefaultPageSize(t *testing.T) {
   743  	ctx := context.Background()
   744  	bs := &Server{
   745  		AttestationsPool: attestations.NewPool(),
   746  	}
   747  
   748  	atts := make([]*ethpb.Attestation, params.BeaconConfig().DefaultPageSize+1)
   749  	for i := 0; i < len(atts); i++ {
   750  		att := testutil.NewAttestation()
   751  		att.Data.Slot = types.Slot(i)
   752  		atts[i] = att
   753  	}
   754  	require.NoError(t, bs.AttestationsPool.SaveAggregatedAttestations(atts))
   755  
   756  	req := &ethpb.AttestationPoolRequest{}
   757  	res, err := bs.AttestationPool(ctx, req)
   758  	require.NoError(t, err)
   759  	assert.Equal(t, params.BeaconConfig().DefaultPageSize, len(res.Attestations), "Unexpected number of attestations")
   760  	assert.Equal(t, params.BeaconConfig().DefaultPageSize+1, int(res.TotalSize), "Unexpected total size")
   761  }
   762  
   763  func TestServer_AttestationPool_Pagination_CustomPageSize(t *testing.T) {
   764  	ctx := context.Background()
   765  	bs := &Server{
   766  		AttestationsPool: attestations.NewPool(),
   767  	}
   768  
   769  	numAtts := 100
   770  	atts := make([]*ethpb.Attestation, numAtts)
   771  	for i := 0; i < len(atts); i++ {
   772  		att := testutil.NewAttestation()
   773  		att.Data.Slot = types.Slot(i)
   774  		atts[i] = att
   775  	}
   776  	require.NoError(t, bs.AttestationsPool.SaveAggregatedAttestations(atts))
   777  	tests := []struct {
   778  		req *ethpb.AttestationPoolRequest
   779  		res *ethpb.AttestationPoolResponse
   780  	}{
   781  		{
   782  			req: &ethpb.AttestationPoolRequest{
   783  				PageToken: strconv.Itoa(1),
   784  				PageSize:  3,
   785  			},
   786  			res: &ethpb.AttestationPoolResponse{
   787  				NextPageToken: "2",
   788  				TotalSize:     int32(numAtts),
   789  			},
   790  		},
   791  		{
   792  			req: &ethpb.AttestationPoolRequest{
   793  				PageToken: strconv.Itoa(3),
   794  				PageSize:  30,
   795  			},
   796  			res: &ethpb.AttestationPoolResponse{
   797  				NextPageToken: "",
   798  				TotalSize:     int32(numAtts),
   799  			},
   800  		},
   801  		{
   802  			req: &ethpb.AttestationPoolRequest{
   803  				PageToken: strconv.Itoa(0),
   804  				PageSize:  int32(numAtts),
   805  			},
   806  			res: &ethpb.AttestationPoolResponse{
   807  				NextPageToken: "",
   808  				TotalSize:     int32(numAtts),
   809  			},
   810  		},
   811  	}
   812  	for _, tt := range tests {
   813  		res, err := bs.AttestationPool(ctx, tt.req)
   814  		require.NoError(t, err)
   815  		assert.Equal(t, tt.res.TotalSize, res.TotalSize, "Unexpected total size")
   816  		assert.Equal(t, tt.res.NextPageToken, res.NextPageToken, "Unexpected next page token")
   817  	}
   818  }
   819  
   820  func TestServer_StreamIndexedAttestations_ContextCanceled(t *testing.T) {
   821  	ctx := context.Background()
   822  	ctx, cancel := context.WithCancel(ctx)
   823  	chainService := &chainMock.ChainService{}
   824  	server := &Server{
   825  		Ctx:                 ctx,
   826  		AttestationNotifier: chainService.OperationNotifier(),
   827  		GenesisTimeFetcher: &chainMock.ChainService{
   828  			Genesis: time.Now(),
   829  		},
   830  	}
   831  
   832  	exitRoutine := make(chan bool)
   833  	ctrl := gomock.NewController(t)
   834  	defer ctrl.Finish()
   835  	mockStream := mock.NewMockBeaconChain_StreamIndexedAttestationsServer(ctrl)
   836  	mockStream.EXPECT().Context().Return(ctx).AnyTimes()
   837  	go func(tt *testing.T) {
   838  		err := server.StreamIndexedAttestations(&emptypb.Empty{}, mockStream)
   839  		assert.ErrorContains(t, "Context canceled", err)
   840  		<-exitRoutine
   841  	}(t)
   842  	cancel()
   843  	exitRoutine <- true
   844  }
   845  
   846  func TestServer_StreamIndexedAttestations_OK(t *testing.T) {
   847  	params.SetupTestConfigCleanup(t)
   848  	params.OverrideBeaconConfig(params.MainnetConfig())
   849  	db := dbTest.SetupDB(t)
   850  	exitRoutine := make(chan bool)
   851  	ctrl := gomock.NewController(t)
   852  	defer ctrl.Finish()
   853  	ctx := context.Background()
   854  
   855  	numValidators := 64
   856  	headState, privKeys := testutil.DeterministicGenesisState(t, uint64(numValidators))
   857  	b := testutil.NewBeaconBlock()
   858  	require.NoError(t, db.SaveBlock(ctx, wrapper.WrappedPhase0SignedBeaconBlock(b)))
   859  	gRoot, err := b.Block.HashTreeRoot()
   860  	require.NoError(t, err)
   861  	require.NoError(t, db.SaveGenesisBlockRoot(ctx, gRoot))
   862  	require.NoError(t, db.SaveState(ctx, headState, gRoot))
   863  
   864  	activeIndices, err := helpers.ActiveValidatorIndices(headState, 0)
   865  	require.NoError(t, err)
   866  	epoch := types.Epoch(0)
   867  	attesterSeed, err := helpers.Seed(headState, epoch, params.BeaconConfig().DomainBeaconAttester)
   868  	require.NoError(t, err)
   869  	committees, err := computeCommittees(params.BeaconConfig().SlotsPerEpoch.Mul(uint64(epoch)), activeIndices, attesterSeed)
   870  	require.NoError(t, err)
   871  
   872  	count := params.BeaconConfig().SlotsPerEpoch
   873  	// We generate attestations for each validator per slot per epoch.
   874  	atts := make(map[[32]byte][]*ethpb.Attestation)
   875  	for i := types.Slot(0); i < count; i++ {
   876  		comms := committees[i].Committees
   877  		for j := 0; j < numValidators; j++ {
   878  			var indexInCommittee uint64
   879  			var committeeIndex types.CommitteeIndex
   880  			var committeeLength int
   881  			var found bool
   882  			for comIndex, item := range comms {
   883  				for n, idx := range item.ValidatorIndices {
   884  					if types.ValidatorIndex(j) == idx {
   885  						indexInCommittee = uint64(n)
   886  						committeeIndex = types.CommitteeIndex(comIndex)
   887  						committeeLength = len(item.ValidatorIndices)
   888  						found = true
   889  						break
   890  					}
   891  				}
   892  			}
   893  			if !found {
   894  				continue
   895  			}
   896  			attExample := &ethpb.Attestation{
   897  				Data: &ethpb.AttestationData{
   898  					BeaconBlockRoot: bytesutil.PadTo([]byte("root"), 32),
   899  					Slot:            i,
   900  					Source: &ethpb.Checkpoint{
   901  						Epoch: 0,
   902  						Root:  gRoot[:],
   903  					},
   904  					Target: &ethpb.Checkpoint{
   905  						Epoch: 0,
   906  						Root:  gRoot[:],
   907  					},
   908  				},
   909  			}
   910  			domain, err := helpers.Domain(headState.Fork(), 0, params.BeaconConfig().DomainBeaconAttester, headState.GenesisValidatorRoot())
   911  			require.NoError(t, err)
   912  			encoded, err := helpers.ComputeSigningRoot(attExample.Data, domain)
   913  			require.NoError(t, err)
   914  			sig := privKeys[j].Sign(encoded[:])
   915  			attExample.Signature = sig.Marshal()
   916  			attExample.Data.CommitteeIndex = committeeIndex
   917  			aggregationBitfield := bitfield.NewBitlist(uint64(committeeLength))
   918  			aggregationBitfield.SetBitAt(indexInCommittee, true)
   919  			attExample.AggregationBits = aggregationBitfield
   920  			atts[encoded] = append(atts[encoded], attExample)
   921  		}
   922  	}
   923  
   924  	chainService := &chainMock.ChainService{}
   925  	server := &Server{
   926  		BeaconDB: db,
   927  		Ctx:      context.Background(),
   928  		HeadFetcher: &chainMock.ChainService{
   929  			State: headState,
   930  		},
   931  		GenesisTimeFetcher: &chainMock.ChainService{
   932  			Genesis: time.Now(),
   933  		},
   934  		AttestationNotifier:         chainService.OperationNotifier(),
   935  		CollectedAttestationsBuffer: make(chan []*ethpb.Attestation, 1),
   936  		StateGen:                    stategen.New(db),
   937  	}
   938  
   939  	for dataRoot, sameDataAtts := range atts {
   940  		aggAtts, err := attaggregation.Aggregate(sameDataAtts)
   941  		require.NoError(t, err)
   942  		atts[dataRoot] = aggAtts
   943  	}
   944  
   945  	// Next up we convert the test attestations to indexed form.
   946  	attsByTarget := make(map[[32]byte][]*ethpb.Attestation)
   947  	for _, dataRootAtts := range atts {
   948  		targetRoot := bytesutil.ToBytes32(dataRootAtts[0].Data.Target.Root)
   949  		attsByTarget[targetRoot] = append(attsByTarget[targetRoot], dataRootAtts...)
   950  	}
   951  
   952  	allAtts := make([]*ethpb.Attestation, 0)
   953  	indexedAtts := make(map[[32]byte][]*ethpb.IndexedAttestation)
   954  	for dataRoot, aggAtts := range attsByTarget {
   955  		allAtts = append(allAtts, aggAtts...)
   956  		for _, att := range aggAtts {
   957  			committee := committees[att.Data.Slot].Committees[att.Data.CommitteeIndex]
   958  			idxAtt, err := attestationutil.ConvertToIndexed(ctx, att, committee.ValidatorIndices)
   959  			require.NoError(t, err)
   960  			indexedAtts[dataRoot] = append(indexedAtts[dataRoot], idxAtt)
   961  		}
   962  	}
   963  
   964  	attsSent := 0
   965  	mockStream := mock.NewMockBeaconChain_StreamIndexedAttestationsServer(ctrl)
   966  	for _, atts := range indexedAtts {
   967  		for _, att := range atts {
   968  			if attsSent == len(allAtts)-1 {
   969  				mockStream.EXPECT().Send(att).Do(func(arg0 interface{}) {
   970  					exitRoutine <- true
   971  				})
   972  				t.Log("cancelled")
   973  			} else {
   974  				mockStream.EXPECT().Send(att)
   975  				attsSent++
   976  			}
   977  		}
   978  	}
   979  	mockStream.EXPECT().Context().Return(ctx).AnyTimes()
   980  
   981  	go func(tt *testing.T) {
   982  		assert.NoError(tt, server.StreamIndexedAttestations(&emptypb.Empty{}, mockStream), "Could not call RPC method")
   983  	}(t)
   984  
   985  	server.CollectedAttestationsBuffer <- allAtts
   986  	<-exitRoutine
   987  }
   988  
   989  func TestServer_StreamAttestations_ContextCanceled(t *testing.T) {
   990  	ctx := context.Background()
   991  
   992  	ctx, cancel := context.WithCancel(ctx)
   993  	chainService := &chainMock.ChainService{}
   994  	server := &Server{
   995  		Ctx:                 ctx,
   996  		AttestationNotifier: chainService.OperationNotifier(),
   997  	}
   998  
   999  	exitRoutine := make(chan bool)
  1000  	ctrl := gomock.NewController(t)
  1001  	defer ctrl.Finish()
  1002  	mockStream := mock.NewMockBeaconChain_StreamAttestationsServer(ctrl)
  1003  	mockStream.EXPECT().Context().Return(ctx)
  1004  	go func(tt *testing.T) {
  1005  		err := server.StreamAttestations(
  1006  			&emptypb.Empty{},
  1007  			mockStream,
  1008  		)
  1009  		assert.ErrorContains(tt, "Context canceled", err)
  1010  		<-exitRoutine
  1011  	}(t)
  1012  	cancel()
  1013  	exitRoutine <- true
  1014  }
  1015  
  1016  func TestServer_StreamAttestations_OnSlotTick(t *testing.T) {
  1017  	exitRoutine := make(chan bool)
  1018  	ctrl := gomock.NewController(t)
  1019  	defer ctrl.Finish()
  1020  	ctx := context.Background()
  1021  	chainService := &chainMock.ChainService{}
  1022  	server := &Server{
  1023  		Ctx:                 ctx,
  1024  		AttestationNotifier: chainService.OperationNotifier(),
  1025  	}
  1026  
  1027  	atts := []*ethpb.Attestation{
  1028  		testutil.HydrateAttestation(&ethpb.Attestation{Data: &ethpb.AttestationData{Slot: 1}, AggregationBits: bitfield.Bitlist{0b1101}}),
  1029  		testutil.HydrateAttestation(&ethpb.Attestation{Data: &ethpb.AttestationData{Slot: 2}, AggregationBits: bitfield.Bitlist{0b1101}}),
  1030  		testutil.HydrateAttestation(&ethpb.Attestation{Data: &ethpb.AttestationData{Slot: 3}, AggregationBits: bitfield.Bitlist{0b1101}}),
  1031  	}
  1032  
  1033  	mockStream := mock.NewMockBeaconChain_StreamAttestationsServer(ctrl)
  1034  	mockStream.EXPECT().Send(atts[0])
  1035  	mockStream.EXPECT().Send(atts[1])
  1036  	mockStream.EXPECT().Send(atts[2]).Do(func(arg0 interface{}) {
  1037  		exitRoutine <- true
  1038  	})
  1039  	mockStream.EXPECT().Context().Return(ctx).AnyTimes()
  1040  
  1041  	go func(tt *testing.T) {
  1042  		assert.NoError(tt, server.StreamAttestations(&emptypb.Empty{}, mockStream), "Could not call RPC method")
  1043  	}(t)
  1044  	for i := 0; i < len(atts); i++ {
  1045  		// Send in a loop to ensure it is delivered (busy wait for the service to subscribe to the state feed).
  1046  		for sent := 0; sent == 0; {
  1047  			sent = server.AttestationNotifier.OperationFeed().Send(&feed.Event{
  1048  				Type: operation.UnaggregatedAttReceived,
  1049  				Data: &operation.UnAggregatedAttReceivedData{Attestation: atts[i]},
  1050  			})
  1051  		}
  1052  	}
  1053  	<-exitRoutine
  1054  }