github.com/prysmaticlabs/prysm@v1.4.4/slasher/db/kv/indexed_attestations_test.go (about)

     1  package kv
     2  
     3  import (
     4  	"context"
     5  	"testing"
     6  
     7  	types "github.com/prysmaticlabs/eth2-types"
     8  	ethpb "github.com/prysmaticlabs/prysm/proto/eth/v1alpha1"
     9  	"github.com/prysmaticlabs/prysm/shared/testutil/require"
    10  )
    11  
    12  type testStruct struct {
    13  	idxAtt *ethpb.IndexedAttestation
    14  }
    15  
    16  var tests []testStruct
    17  
    18  func init() {
    19  	tests = []testStruct{
    20  		{
    21  			idxAtt: &ethpb.IndexedAttestation{
    22  				AttestingIndices: []uint64{0},
    23  				Data: &ethpb.AttestationData{
    24  					Source: &ethpb.Checkpoint{Epoch: 0, Root: make([]byte, 32)},
    25  					Target: &ethpb.Checkpoint{Epoch: 1, Root: make([]byte, 32)},
    26  				},
    27  				Signature: []byte{1, 2},
    28  			},
    29  		},
    30  		{
    31  			idxAtt: &ethpb.IndexedAttestation{
    32  				AttestingIndices: []uint64{1, 2},
    33  				Data: &ethpb.AttestationData{
    34  					Source: &ethpb.Checkpoint{Epoch: 0, Root: make([]byte, 32)},
    35  					Target: &ethpb.Checkpoint{Epoch: 2, Root: make([]byte, 32)},
    36  				},
    37  				Signature: []byte{3, 4},
    38  			},
    39  		},
    40  		{
    41  			idxAtt: &ethpb.IndexedAttestation{
    42  				AttestingIndices: []uint64{0},
    43  				Data: &ethpb.AttestationData{
    44  					Source: &ethpb.Checkpoint{Epoch: 1, Root: make([]byte, 32)},
    45  					Target: &ethpb.Checkpoint{Epoch: 2, Root: make([]byte, 32)},
    46  				},
    47  				Signature: []byte{5, 6},
    48  			},
    49  		},
    50  		{
    51  			idxAtt: &ethpb.IndexedAttestation{
    52  				AttestingIndices: []uint64{0},
    53  				Data: &ethpb.AttestationData{
    54  					Source: &ethpb.Checkpoint{Epoch: 1, Root: make([]byte, 32)},
    55  					Target: &ethpb.Checkpoint{Epoch: 3, Root: make([]byte, 32)},
    56  				},
    57  				Signature: []byte{5, 6},
    58  			},
    59  		},
    60  	}
    61  }
    62  
    63  func TestHasIndexedAttestation_NilDB(t *testing.T) {
    64  	db := setupDB(t)
    65  	ctx := context.Background()
    66  
    67  	hasIdxAtt, err := db.HasIndexedAttestation(ctx, tests[0].idxAtt)
    68  	require.NoError(t, err)
    69  	require.Equal(t, false, hasIdxAtt)
    70  }
    71  
    72  func TestSaveIndexedAttestation(t *testing.T) {
    73  	db := setupDB(t)
    74  	ctx := context.Background()
    75  
    76  	for _, tt := range tests {
    77  		require.NoError(t, db.SaveIndexedAttestation(ctx, tt.idxAtt), "Save indexed attestation failed")
    78  
    79  		exists, err := db.HasIndexedAttestation(ctx, tt.idxAtt)
    80  		require.NoError(t, err, "Failed to get indexed attestation")
    81  		require.Equal(t, true, exists, "Expected to find saved attestation in DB")
    82  	}
    83  }
    84  
    85  func TestIndexedAttestationsWithPrefix(t *testing.T) {
    86  	type prefixTestStruct struct {
    87  		name           string
    88  		attsInDB       []*ethpb.IndexedAttestation
    89  		targetEpoch    types.Epoch
    90  		searchPrefix   []byte
    91  		expectedResult []*ethpb.IndexedAttestation
    92  	}
    93  	prefixTests := []prefixTestStruct{
    94  		{
    95  			name: "single item, same sig, should find one",
    96  			attsInDB: []*ethpb.IndexedAttestation{
    97  				{
    98  					AttestingIndices: []uint64{0},
    99  					Data: &ethpb.AttestationData{
   100  						Source: &ethpb.Checkpoint{Epoch: 0, Root: make([]byte, 32)},
   101  						Target: &ethpb.Checkpoint{Epoch: 1, Root: make([]byte, 32)},
   102  					},
   103  					Signature: []byte{1, 2},
   104  				},
   105  			},
   106  			searchPrefix: []byte{1, 2},
   107  			targetEpoch:  1,
   108  			expectedResult: []*ethpb.IndexedAttestation{
   109  				{
   110  					AttestingIndices: []uint64{0},
   111  					Data: &ethpb.AttestationData{
   112  						Source: &ethpb.Checkpoint{Epoch: 0, Root: make([]byte, 32)},
   113  						Target: &ethpb.Checkpoint{Epoch: 1, Root: make([]byte, 32)},
   114  					},
   115  					Signature: []byte{1, 2},
   116  				},
   117  			},
   118  		},
   119  		{
   120  			name: "multiple item, same sig, should find 3",
   121  			attsInDB: []*ethpb.IndexedAttestation{
   122  				{
   123  					AttestingIndices: []uint64{0},
   124  					Data: &ethpb.AttestationData{
   125  						Source:          &ethpb.Checkpoint{Epoch: 0, Root: make([]byte, 32)},
   126  						Target:          &ethpb.Checkpoint{Epoch: 1, Root: make([]byte, 32)},
   127  						BeaconBlockRoot: []byte("hi there"),
   128  					},
   129  					Signature: []byte{1, 2, 3},
   130  				},
   131  				{
   132  					AttestingIndices: []uint64{1},
   133  					Data: &ethpb.AttestationData{
   134  						Source:          &ethpb.Checkpoint{Epoch: 0, Root: make([]byte, 32)},
   135  						Target:          &ethpb.Checkpoint{Epoch: 1, Root: make([]byte, 32)},
   136  						BeaconBlockRoot: []byte("hi there 2"),
   137  					},
   138  					Signature: []byte{1, 2, 4},
   139  				},
   140  				{
   141  					AttestingIndices: []uint64{0},
   142  					Data: &ethpb.AttestationData{
   143  						Source:          &ethpb.Checkpoint{Epoch: 0, Root: make([]byte, 32)},
   144  						Target:          &ethpb.Checkpoint{Epoch: 1, Root: make([]byte, 32)},
   145  						BeaconBlockRoot: []byte("hi there 3"),
   146  					},
   147  					Signature: []byte{1, 2, 5},
   148  				},
   149  			},
   150  			searchPrefix: []byte{1, 2},
   151  			targetEpoch:  1,
   152  			expectedResult: []*ethpb.IndexedAttestation{
   153  				{
   154  					AttestingIndices: []uint64{0},
   155  					Data: &ethpb.AttestationData{
   156  						Source:          &ethpb.Checkpoint{Epoch: 0, Root: make([]byte, 32)},
   157  						Target:          &ethpb.Checkpoint{Epoch: 1, Root: make([]byte, 32)},
   158  						BeaconBlockRoot: []byte("hi there"),
   159  					},
   160  					Signature: []byte{1, 2, 3},
   161  				},
   162  				{
   163  					AttestingIndices: []uint64{1},
   164  					Data: &ethpb.AttestationData{
   165  						Source:          &ethpb.Checkpoint{Epoch: 0, Root: make([]byte, 32)},
   166  						Target:          &ethpb.Checkpoint{Epoch: 1, Root: make([]byte, 32)},
   167  						BeaconBlockRoot: []byte("hi there 2"),
   168  					},
   169  					Signature: []byte{1, 2, 4},
   170  				},
   171  				{
   172  					AttestingIndices: []uint64{0},
   173  					Data: &ethpb.AttestationData{
   174  						Source:          &ethpb.Checkpoint{Epoch: 0, Root: make([]byte, 32)},
   175  						Target:          &ethpb.Checkpoint{Epoch: 1, Root: make([]byte, 32)},
   176  						BeaconBlockRoot: []byte("hi there 3"),
   177  					},
   178  					Signature: []byte{1, 2, 5},
   179  				},
   180  			},
   181  		},
   182  		{
   183  			name: "multiple items, different sig and epoch, should find 2",
   184  			attsInDB: []*ethpb.IndexedAttestation{
   185  				{
   186  					AttestingIndices: []uint64{0},
   187  					Data: &ethpb.AttestationData{
   188  						Source:          &ethpb.Checkpoint{Epoch: 0, Root: make([]byte, 32)},
   189  						Target:          &ethpb.Checkpoint{Epoch: 1, Root: make([]byte, 32)},
   190  						BeaconBlockRoot: []byte("hi there"),
   191  					},
   192  					Signature: []byte{1, 2, 3},
   193  				},
   194  				{
   195  					AttestingIndices: []uint64{1},
   196  					Data: &ethpb.AttestationData{
   197  						Source:          &ethpb.Checkpoint{Epoch: 0, Root: make([]byte, 32)},
   198  						Target:          &ethpb.Checkpoint{Epoch: 2, Root: make([]byte, 32)},
   199  						BeaconBlockRoot: []byte("hi there"),
   200  					},
   201  					Signature: []byte{1, 2, 4},
   202  				},
   203  				{
   204  					AttestingIndices: []uint64{0},
   205  					Data: &ethpb.AttestationData{
   206  						Source:          &ethpb.Checkpoint{Epoch: 0, Root: make([]byte, 32)},
   207  						Target:          &ethpb.Checkpoint{Epoch: 3, Root: make([]byte, 32)},
   208  						BeaconBlockRoot: []byte("hi there 3"),
   209  					},
   210  					Signature: []byte{1, 2, 5},
   211  				},
   212  				{
   213  					AttestingIndices: []uint64{1},
   214  					Data: &ethpb.AttestationData{
   215  						Source:          &ethpb.Checkpoint{Epoch: 0, Root: make([]byte, 32)},
   216  						Target:          &ethpb.Checkpoint{Epoch: 3, Root: make([]byte, 32)},
   217  						BeaconBlockRoot: []byte("hi there 2"),
   218  					},
   219  					Signature: []byte{1, 3, 1},
   220  				},
   221  				{
   222  					AttestingIndices: []uint64{1},
   223  					Data: &ethpb.AttestationData{
   224  						Source:          &ethpb.Checkpoint{Epoch: 0, Root: make([]byte, 32)},
   225  						Target:          &ethpb.Checkpoint{Epoch: 2, Root: make([]byte, 32)},
   226  						BeaconBlockRoot: []byte("hi there 2"),
   227  					},
   228  					Signature: []byte{0, 2, 4},
   229  				},
   230  				{
   231  					AttestingIndices: []uint64{4},
   232  					Data: &ethpb.AttestationData{
   233  						Source:          &ethpb.Checkpoint{Epoch: 0, Root: make([]byte, 32)},
   234  						Target:          &ethpb.Checkpoint{Epoch: 2, Root: make([]byte, 32)},
   235  						BeaconBlockRoot: []byte("hi there 2"),
   236  					},
   237  					Signature: []byte{1, 2, 9},
   238  				},
   239  			},
   240  			searchPrefix: []byte{1, 2},
   241  			targetEpoch:  2,
   242  			expectedResult: []*ethpb.IndexedAttestation{
   243  				{
   244  					AttestingIndices: []uint64{1},
   245  					Data: &ethpb.AttestationData{
   246  						Source:          &ethpb.Checkpoint{Epoch: 0, Root: make([]byte, 32)},
   247  						Target:          &ethpb.Checkpoint{Epoch: 2, Root: make([]byte, 32)},
   248  						BeaconBlockRoot: []byte("hi there"),
   249  					},
   250  					Signature: []byte{1, 2, 4},
   251  				},
   252  				{
   253  					AttestingIndices: []uint64{4},
   254  					Data: &ethpb.AttestationData{
   255  						Source:          &ethpb.Checkpoint{Epoch: 0, Root: make([]byte, 32)},
   256  						Target:          &ethpb.Checkpoint{Epoch: 2, Root: make([]byte, 32)},
   257  						BeaconBlockRoot: []byte("hi there 2"),
   258  					},
   259  					Signature: []byte{1, 2, 9},
   260  				},
   261  			},
   262  		},
   263  		{
   264  			name: "multiple items, different sigs, should not find any atts",
   265  			attsInDB: []*ethpb.IndexedAttestation{
   266  				{
   267  					AttestingIndices: []uint64{0},
   268  					Data: &ethpb.AttestationData{
   269  						Source:          &ethpb.Checkpoint{Epoch: 0, Root: make([]byte, 32)},
   270  						Target:          &ethpb.Checkpoint{Epoch: 2, Root: make([]byte, 32)},
   271  						BeaconBlockRoot: []byte("hi there"),
   272  					},
   273  					Signature: []byte{3, 5, 3},
   274  				},
   275  				{
   276  					AttestingIndices: []uint64{0},
   277  					Data: &ethpb.AttestationData{
   278  						Source:          &ethpb.Checkpoint{Epoch: 0, Root: make([]byte, 32)},
   279  						Target:          &ethpb.Checkpoint{Epoch: 2, Root: make([]byte, 32)},
   280  						BeaconBlockRoot: []byte("hi there"),
   281  					},
   282  					Signature: []byte{3, 5, 3},
   283  				},
   284  				{
   285  					AttestingIndices: []uint64{1},
   286  					Data: &ethpb.AttestationData{
   287  						Source:          &ethpb.Checkpoint{Epoch: 0, Root: make([]byte, 32)},
   288  						Target:          &ethpb.Checkpoint{Epoch: 1, Root: make([]byte, 32)},
   289  						BeaconBlockRoot: []byte("hi there 2"),
   290  					},
   291  					Signature: []byte{1, 2, 4},
   292  				},
   293  				{
   294  					AttestingIndices: []uint64{0},
   295  					Data: &ethpb.AttestationData{
   296  						Source:          &ethpb.Checkpoint{Epoch: 0, Root: make([]byte, 32)},
   297  						Target:          &ethpb.Checkpoint{Epoch: 1, Root: make([]byte, 32)},
   298  						BeaconBlockRoot: []byte("hi there 3"),
   299  					},
   300  					Signature: []byte{1, 2, 5},
   301  				},
   302  			},
   303  			searchPrefix: []byte{3, 5},
   304  			targetEpoch:  1,
   305  		},
   306  	}
   307  	for _, tt := range prefixTests {
   308  		t.Run(tt.name, func(t *testing.T) {
   309  			db := setupDB(t)
   310  			ctx := context.Background()
   311  
   312  			require.NoError(t, db.SaveIndexedAttestations(ctx, tt.attsInDB), "Save indexed attestation failed")
   313  			for _, att := range tt.attsInDB {
   314  				found, err := db.HasIndexedAttestation(ctx, att)
   315  				require.NoError(t, err)
   316  				require.Equal(t, true, found, "Expected to save %v", att)
   317  			}
   318  
   319  			idxAtts, err := db.IndexedAttestationsWithPrefix(ctx, tt.targetEpoch, tt.searchPrefix)
   320  			require.NoError(t, err, "Failed to get indexed attestation")
   321  			require.DeepSSZEqual(t, tt.expectedResult, idxAtts)
   322  		})
   323  	}
   324  }
   325  
   326  func TestIndexedAttestationsForTarget(t *testing.T) {
   327  	type prefixTestStruct struct {
   328  		name           string
   329  		attsInDB       []*ethpb.IndexedAttestation
   330  		targetEpoch    types.Epoch
   331  		expectedResult []*ethpb.IndexedAttestation
   332  	}
   333  	prefixTests := []prefixTestStruct{
   334  		{
   335  			name: "single item, should find one",
   336  			attsInDB: []*ethpb.IndexedAttestation{
   337  				{
   338  					AttestingIndices: []uint64{0},
   339  					Data: &ethpb.AttestationData{
   340  						Source: &ethpb.Checkpoint{Epoch: 0, Root: make([]byte, 32)},
   341  						Target: &ethpb.Checkpoint{Epoch: 1, Root: make([]byte, 32)},
   342  					},
   343  					Signature: []byte{1, 2},
   344  				},
   345  			},
   346  			targetEpoch: 1,
   347  			expectedResult: []*ethpb.IndexedAttestation{
   348  				{
   349  					AttestingIndices: []uint64{0},
   350  					Data: &ethpb.AttestationData{
   351  						Source: &ethpb.Checkpoint{Epoch: 0, Root: make([]byte, 32)},
   352  						Target: &ethpb.Checkpoint{Epoch: 1, Root: make([]byte, 32)},
   353  					},
   354  					Signature: []byte{1, 2},
   355  				},
   356  			},
   357  		},
   358  		{
   359  			name: "multiple items, same epoch, should find 3",
   360  			attsInDB: []*ethpb.IndexedAttestation{
   361  				{
   362  					AttestingIndices: []uint64{0},
   363  					Data: &ethpb.AttestationData{
   364  						Source:          &ethpb.Checkpoint{Epoch: 0, Root: make([]byte, 32)},
   365  						Target:          &ethpb.Checkpoint{Epoch: 3, Root: make([]byte, 32)},
   366  						BeaconBlockRoot: []byte("hi there"),
   367  					},
   368  					Signature: []byte{1, 2, 3},
   369  				},
   370  				{
   371  					AttestingIndices: []uint64{1},
   372  					Data: &ethpb.AttestationData{
   373  						Source:          &ethpb.Checkpoint{Epoch: 0, Root: make([]byte, 32)},
   374  						Target:          &ethpb.Checkpoint{Epoch: 3, Root: make([]byte, 32)},
   375  						BeaconBlockRoot: []byte("hi there 2"),
   376  					},
   377  					Signature: []byte{1, 5, 4},
   378  				},
   379  				{
   380  					AttestingIndices: []uint64{0},
   381  					Data: &ethpb.AttestationData{
   382  						Source:          &ethpb.Checkpoint{Epoch: 0, Root: make([]byte, 32)},
   383  						Target:          &ethpb.Checkpoint{Epoch: 3, Root: make([]byte, 32)},
   384  						BeaconBlockRoot: []byte("hi there 3"),
   385  					},
   386  					Signature: []byte{8, 2, 5},
   387  				},
   388  			},
   389  			targetEpoch: 3,
   390  			expectedResult: []*ethpb.IndexedAttestation{
   391  				{
   392  					AttestingIndices: []uint64{0},
   393  					Data: &ethpb.AttestationData{
   394  						Source:          &ethpb.Checkpoint{Epoch: 0, Root: make([]byte, 32)},
   395  						Target:          &ethpb.Checkpoint{Epoch: 3, Root: make([]byte, 32)},
   396  						BeaconBlockRoot: []byte("hi there"),
   397  					},
   398  					Signature: []byte{1, 2, 3},
   399  				},
   400  				{
   401  					AttestingIndices: []uint64{1},
   402  					Data: &ethpb.AttestationData{
   403  						Source:          &ethpb.Checkpoint{Epoch: 0, Root: make([]byte, 32)},
   404  						Target:          &ethpb.Checkpoint{Epoch: 3, Root: make([]byte, 32)},
   405  						BeaconBlockRoot: []byte("hi there 2"),
   406  					},
   407  					Signature: []byte{1, 5, 4},
   408  				},
   409  				{
   410  					AttestingIndices: []uint64{0},
   411  					Data: &ethpb.AttestationData{
   412  						Source:          &ethpb.Checkpoint{Epoch: 0, Root: make([]byte, 32)},
   413  						Target:          &ethpb.Checkpoint{Epoch: 3, Root: make([]byte, 32)},
   414  						BeaconBlockRoot: []byte("hi there 3"),
   415  					},
   416  					Signature: []byte{8, 2, 5},
   417  				},
   418  			},
   419  		},
   420  		{
   421  			name: "multiple items, different epochs, should not find any atts",
   422  			attsInDB: []*ethpb.IndexedAttestation{
   423  				{
   424  					AttestingIndices: []uint64{0},
   425  					Data: &ethpb.AttestationData{
   426  						Source:          &ethpb.Checkpoint{Epoch: 0, Root: make([]byte, 32)},
   427  						Target:          &ethpb.Checkpoint{Epoch: 1, Root: make([]byte, 32)},
   428  						BeaconBlockRoot: []byte("hi there"),
   429  					},
   430  					Signature: []byte{3, 5, 3},
   431  				},
   432  				{
   433  					AttestingIndices: []uint64{0},
   434  					Data: &ethpb.AttestationData{
   435  						Source:          &ethpb.Checkpoint{Epoch: 0, Root: make([]byte, 32)},
   436  						Target:          &ethpb.Checkpoint{Epoch: 2, Root: make([]byte, 32)},
   437  						BeaconBlockRoot: []byte("hi there"),
   438  					},
   439  					Signature: []byte{3, 5, 3},
   440  				},
   441  				{
   442  					AttestingIndices: []uint64{1},
   443  					Data: &ethpb.AttestationData{
   444  						Source:          &ethpb.Checkpoint{Epoch: 0, Root: make([]byte, 32)},
   445  						Target:          &ethpb.Checkpoint{Epoch: 3, Root: make([]byte, 32)},
   446  						BeaconBlockRoot: []byte("hi there 2"),
   447  					},
   448  					Signature: []byte{1, 2, 4},
   449  				},
   450  				{
   451  					AttestingIndices: []uint64{0},
   452  					Data: &ethpb.AttestationData{
   453  						Source:          &ethpb.Checkpoint{Epoch: 0, Root: make([]byte, 32)},
   454  						Target:          &ethpb.Checkpoint{Epoch: 5, Root: make([]byte, 32)},
   455  						BeaconBlockRoot: []byte("hi there 3"),
   456  					},
   457  					Signature: []byte{1, 2, 5},
   458  				},
   459  			},
   460  			targetEpoch: 4,
   461  		},
   462  	}
   463  	for _, tt := range prefixTests {
   464  		t.Run(tt.name, func(t *testing.T) {
   465  			db := setupDB(t)
   466  			ctx := context.Background()
   467  
   468  			require.NoError(t, db.SaveIndexedAttestations(ctx, tt.attsInDB), "Save indexed attestation failed")
   469  			for _, att := range tt.attsInDB {
   470  				found, err := db.HasIndexedAttestation(ctx, att)
   471  				require.NoError(t, err)
   472  				require.Equal(t, true, found, "Expected to save %v", att)
   473  			}
   474  
   475  			idxAtts, err := db.IndexedAttestationsForTarget(ctx, tt.targetEpoch)
   476  			require.NoError(t, err, "Failed to get indexed attestation: %v", err)
   477  			require.DeepSSZEqual(t, tt.expectedResult, idxAtts)
   478  		})
   479  	}
   480  }
   481  
   482  func TestDeleteIndexedAttestation(t *testing.T) {
   483  	type deleteTestStruct struct {
   484  		name       string
   485  		attsInDB   []*ethpb.IndexedAttestation
   486  		deleteAtts []*ethpb.IndexedAttestation
   487  		foundArray []bool
   488  	}
   489  	deleteTests := []deleteTestStruct{
   490  		{
   491  			name: "single item, should delete all",
   492  			attsInDB: []*ethpb.IndexedAttestation{
   493  				{
   494  					AttestingIndices: []uint64{0},
   495  					Data: &ethpb.AttestationData{
   496  						Source: &ethpb.Checkpoint{Epoch: 0, Root: make([]byte, 32)},
   497  						Target: &ethpb.Checkpoint{Epoch: 1, Root: make([]byte, 32)},
   498  					},
   499  					Signature: []byte{1, 2},
   500  				},
   501  			},
   502  			deleteAtts: []*ethpb.IndexedAttestation{
   503  				{
   504  					AttestingIndices: []uint64{0},
   505  					Data: &ethpb.AttestationData{
   506  						Source: &ethpb.Checkpoint{Epoch: 0, Root: make([]byte, 32)},
   507  						Target: &ethpb.Checkpoint{Epoch: 1, Root: make([]byte, 32)},
   508  					},
   509  					Signature: []byte{1, 2},
   510  				},
   511  			},
   512  			foundArray: []bool{false},
   513  		},
   514  		{
   515  			name: "multiple items, should delete 2",
   516  			attsInDB: []*ethpb.IndexedAttestation{
   517  				{
   518  					AttestingIndices: []uint64{0},
   519  					Data: &ethpb.AttestationData{
   520  						Source: &ethpb.Checkpoint{Epoch: 0, Root: make([]byte, 32)},
   521  						Target: &ethpb.Checkpoint{Epoch: 1, Root: make([]byte, 32)},
   522  					},
   523  					Signature: []byte{1, 2},
   524  				},
   525  				{
   526  					AttestingIndices: []uint64{0},
   527  					Data: &ethpb.AttestationData{
   528  						Source: &ethpb.Checkpoint{Epoch: 0, Root: make([]byte, 32)},
   529  						Target: &ethpb.Checkpoint{Epoch: 3, Root: make([]byte, 32)},
   530  					},
   531  					Signature: []byte{2, 4},
   532  				},
   533  				{
   534  					AttestingIndices: []uint64{0},
   535  					Data: &ethpb.AttestationData{
   536  						Source: &ethpb.Checkpoint{Epoch: 0, Root: make([]byte, 32)},
   537  						Target: &ethpb.Checkpoint{Epoch: 4, Root: make([]byte, 32)},
   538  					},
   539  					Signature: []byte{3, 5},
   540  				},
   541  			},
   542  			deleteAtts: []*ethpb.IndexedAttestation{
   543  				{
   544  					AttestingIndices: []uint64{0},
   545  					Data: &ethpb.AttestationData{
   546  						Source: &ethpb.Checkpoint{Epoch: 0, Root: make([]byte, 32)},
   547  						Target: &ethpb.Checkpoint{Epoch: 1, Root: make([]byte, 32)},
   548  					},
   549  					Signature: []byte{1, 2},
   550  				},
   551  				{
   552  					AttestingIndices: []uint64{0},
   553  					Data: &ethpb.AttestationData{
   554  						Source: &ethpb.Checkpoint{Epoch: 0, Root: make([]byte, 32)},
   555  						Target: &ethpb.Checkpoint{Epoch: 4, Root: make([]byte, 32)},
   556  					},
   557  					Signature: []byte{3, 5},
   558  				},
   559  			},
   560  			foundArray: []bool{false, true, false},
   561  		},
   562  		{
   563  			name: "multiple similar items, should delete 1",
   564  			attsInDB: []*ethpb.IndexedAttestation{
   565  				{
   566  					AttestingIndices: []uint64{0},
   567  					Data: &ethpb.AttestationData{
   568  						Source: &ethpb.Checkpoint{Epoch: 0, Root: make([]byte, 32)},
   569  						Target: &ethpb.Checkpoint{Epoch: 1, Root: make([]byte, 32)},
   570  					},
   571  					Signature: []byte{1, 2, 2},
   572  				},
   573  				{
   574  					AttestingIndices: []uint64{0},
   575  					Data: &ethpb.AttestationData{
   576  						Source: &ethpb.Checkpoint{Epoch: 0, Root: make([]byte, 32)},
   577  						Target: &ethpb.Checkpoint{Epoch: 1, Root: make([]byte, 32)},
   578  					},
   579  					Signature: []byte{1, 2, 3},
   580  				},
   581  				{
   582  					AttestingIndices: []uint64{0},
   583  					Data: &ethpb.AttestationData{
   584  						Source: &ethpb.Checkpoint{Epoch: 0, Root: make([]byte, 32)},
   585  						Target: &ethpb.Checkpoint{Epoch: 1, Root: make([]byte, 32)},
   586  					},
   587  					Signature: []byte{1, 2, 4},
   588  				},
   589  			},
   590  			deleteAtts: []*ethpb.IndexedAttestation{
   591  				{
   592  					AttestingIndices: []uint64{0},
   593  					Data: &ethpb.AttestationData{
   594  						Source: &ethpb.Checkpoint{Epoch: 0, Root: make([]byte, 32)},
   595  						Target: &ethpb.Checkpoint{Epoch: 1, Root: make([]byte, 32)},
   596  					},
   597  					Signature: []byte{1, 2, 3},
   598  				},
   599  			},
   600  			foundArray: []bool{true, false, true},
   601  		},
   602  		{
   603  			name: "should not delete any if not in list",
   604  			attsInDB: []*ethpb.IndexedAttestation{
   605  				{
   606  					AttestingIndices: []uint64{0},
   607  					Data: &ethpb.AttestationData{
   608  						Source: &ethpb.Checkpoint{Epoch: 0, Root: make([]byte, 32)},
   609  						Target: &ethpb.Checkpoint{Epoch: 1, Root: make([]byte, 32)},
   610  					},
   611  					Signature: []byte{1, 2, 2},
   612  				},
   613  				{
   614  					AttestingIndices: []uint64{0},
   615  					Data: &ethpb.AttestationData{
   616  						Source: &ethpb.Checkpoint{Epoch: 0, Root: make([]byte, 32)},
   617  						Target: &ethpb.Checkpoint{Epoch: 1, Root: make([]byte, 32)},
   618  					},
   619  					Signature: []byte{1, 2, 3},
   620  				},
   621  				{
   622  					AttestingIndices: []uint64{0},
   623  					Data: &ethpb.AttestationData{
   624  						Source: &ethpb.Checkpoint{Epoch: 0, Root: make([]byte, 32)},
   625  						Target: &ethpb.Checkpoint{Epoch: 1, Root: make([]byte, 32)},
   626  					},
   627  					Signature: []byte{1, 2, 4},
   628  				},
   629  			},
   630  			deleteAtts: []*ethpb.IndexedAttestation{
   631  				{
   632  					AttestingIndices: []uint64{3},
   633  					Data: &ethpb.AttestationData{
   634  						Source: &ethpb.Checkpoint{Epoch: 0, Root: make([]byte, 32)},
   635  						Target: &ethpb.Checkpoint{Epoch: 1, Root: make([]byte, 32)},
   636  					},
   637  					Signature: []byte{1, 2, 6},
   638  				},
   639  			},
   640  			foundArray: []bool{true, true, true},
   641  		},
   642  	}
   643  	for _, tt := range deleteTests {
   644  		t.Run(tt.name, func(t *testing.T) {
   645  			db := setupDB(t)
   646  			ctx := context.Background()
   647  
   648  			require.NoError(t, db.SaveIndexedAttestations(ctx, tt.attsInDB), "Save indexed attestation failed")
   649  
   650  			for _, att := range tt.attsInDB {
   651  				found, err := db.HasIndexedAttestation(ctx, att)
   652  				require.NoError(t, err)
   653  				require.Equal(t, true, found, "Expected to save %v", att)
   654  			}
   655  
   656  			for _, att := range tt.deleteAtts {
   657  				require.NoError(t, db.DeleteIndexedAttestation(ctx, att))
   658  			}
   659  
   660  			for i, att := range tt.attsInDB {
   661  				found, err := db.HasIndexedAttestation(ctx, att)
   662  				require.NoError(t, err)
   663  				require.Equal(t, tt.foundArray[i], found)
   664  			}
   665  		})
   666  	}
   667  }
   668  
   669  func TestHasIndexedAttestation(t *testing.T) {
   670  	db := setupDB(t)
   671  	ctx := context.Background()
   672  
   673  	for _, tt := range tests {
   674  		exists, err := db.HasIndexedAttestation(ctx, tt.idxAtt)
   675  		require.NoError(t, err)
   676  		require.Equal(t, false, exists, "has indexed attestation should return false for indexed attestations that are not in db")
   677  
   678  		require.NoError(t, db.SaveIndexedAttestation(ctx, tt.idxAtt), "Save indexed attestation failed")
   679  	}
   680  
   681  	for _, tt := range tests {
   682  		exists, err := db.HasIndexedAttestation(ctx, tt.idxAtt)
   683  		require.NoError(t, err)
   684  		require.Equal(t, true, exists)
   685  	}
   686  }
   687  
   688  func TestPruneHistoryIndexedAttestation(t *testing.T) {
   689  	db := setupDB(t)
   690  	ctx := context.Background()
   691  
   692  	for _, tt := range tests {
   693  		require.NoError(t, db.SaveIndexedAttestation(ctx, tt.idxAtt), "Save indexed attestation failed")
   694  
   695  		found, err := db.HasIndexedAttestation(ctx, tt.idxAtt)
   696  		require.NoError(t, err, "Failed to get indexed attestation")
   697  		require.Equal(t, true, found, "Expected to find attestation in DB")
   698  	}
   699  	currentEpoch := types.Epoch(2)
   700  	historyToKeep := types.Epoch(1)
   701  	require.NoError(t, db.PruneAttHistory(ctx, currentEpoch, historyToKeep), "Failed to prune")
   702  
   703  	for _, tt := range tests {
   704  		exists, err := db.HasIndexedAttestation(ctx, tt.idxAtt)
   705  		require.NoError(t, err)
   706  
   707  		if tt.idxAtt.Data.Target.Epoch > currentEpoch-historyToKeep {
   708  			require.Equal(t, true, exists, "Expected to find attestation newer than prune age in DB")
   709  		} else {
   710  			require.Equal(t, false, exists, "Expected to not find attestation older than prune age in DB")
   711  		}
   712  	}
   713  }