github.com/prysmaticlabs/prysm@v1.4.4/beacon-chain/operations/attestations/kv/aggregated_test.go (about)

     1  package kv
     2  
     3  import (
     4  	"context"
     5  	"sort"
     6  	"testing"
     7  
     8  	fssz "github.com/ferranbt/fastssz"
     9  	c "github.com/patrickmn/go-cache"
    10  	"github.com/pkg/errors"
    11  	types "github.com/prysmaticlabs/eth2-types"
    12  	"github.com/prysmaticlabs/go-bitfield"
    13  	ethpb "github.com/prysmaticlabs/prysm/proto/eth/v1alpha1"
    14  	"github.com/prysmaticlabs/prysm/shared/bls"
    15  	"github.com/prysmaticlabs/prysm/shared/testutil"
    16  	"github.com/prysmaticlabs/prysm/shared/testutil/assert"
    17  	"github.com/prysmaticlabs/prysm/shared/testutil/require"
    18  )
    19  
    20  func TestKV_Aggregated_AggregateUnaggregatedAttestations(t *testing.T) {
    21  	cache := NewAttCaches()
    22  	priv, err := bls.RandKey()
    23  	require.NoError(t, err)
    24  	sig1 := priv.Sign([]byte{'a'})
    25  	sig2 := priv.Sign([]byte{'b'})
    26  	att1 := testutil.HydrateAttestation(&ethpb.Attestation{Data: &ethpb.AttestationData{Slot: 1}, AggregationBits: bitfield.Bitlist{0b1001}, Signature: sig1.Marshal()})
    27  	att2 := testutil.HydrateAttestation(&ethpb.Attestation{Data: &ethpb.AttestationData{Slot: 1}, AggregationBits: bitfield.Bitlist{0b1010}, Signature: sig1.Marshal()})
    28  	att3 := testutil.HydrateAttestation(&ethpb.Attestation{Data: &ethpb.AttestationData{Slot: 1}, AggregationBits: bitfield.Bitlist{0b1100}, Signature: sig1.Marshal()})
    29  	att4 := testutil.HydrateAttestation(&ethpb.Attestation{Data: &ethpb.AttestationData{Slot: 1}, AggregationBits: bitfield.Bitlist{0b1001}, Signature: sig2.Marshal()})
    30  	att5 := testutil.HydrateAttestation(&ethpb.Attestation{Data: &ethpb.AttestationData{Slot: 2}, AggregationBits: bitfield.Bitlist{0b1001}, Signature: sig1.Marshal()})
    31  	att6 := testutil.HydrateAttestation(&ethpb.Attestation{Data: &ethpb.AttestationData{Slot: 2}, AggregationBits: bitfield.Bitlist{0b1010}, Signature: sig1.Marshal()})
    32  	att7 := testutil.HydrateAttestation(&ethpb.Attestation{Data: &ethpb.AttestationData{Slot: 2}, AggregationBits: bitfield.Bitlist{0b1100}, Signature: sig1.Marshal()})
    33  	att8 := testutil.HydrateAttestation(&ethpb.Attestation{Data: &ethpb.AttestationData{Slot: 2}, AggregationBits: bitfield.Bitlist{0b1001}, Signature: sig2.Marshal()})
    34  	atts := []*ethpb.Attestation{att1, att2, att3, att4, att5, att6, att7, att8}
    35  	require.NoError(t, cache.SaveUnaggregatedAttestations(atts))
    36  	require.NoError(t, cache.AggregateUnaggregatedAttestations(context.Background()))
    37  
    38  	require.Equal(t, 1, len(cache.AggregatedAttestationsBySlotIndex(context.Background(), 1, 0)), "Did not aggregate correctly")
    39  	require.Equal(t, 1, len(cache.AggregatedAttestationsBySlotIndex(context.Background(), 2, 0)), "Did not aggregate correctly")
    40  }
    41  
    42  func TestKV_Aggregated_AggregateUnaggregatedAttestationsBySlotIndex(t *testing.T) {
    43  	cache := NewAttCaches()
    44  	genData := func(slot types.Slot, committeeIndex types.CommitteeIndex) *ethpb.AttestationData {
    45  		return testutil.HydrateAttestationData(&ethpb.AttestationData{
    46  			Slot:           slot,
    47  			CommitteeIndex: committeeIndex,
    48  		})
    49  	}
    50  	genSign := func() []byte {
    51  		priv, err := bls.RandKey()
    52  		require.NoError(t, err)
    53  		return priv.Sign([]byte{'a'}).Marshal()
    54  	}
    55  
    56  	atts := []*ethpb.Attestation{
    57  		// The first slot.
    58  		{AggregationBits: bitfield.Bitlist{0b1001}, Data: genData(1, 2), Signature: genSign()},
    59  		{AggregationBits: bitfield.Bitlist{0b1010}, Data: genData(1, 2), Signature: genSign()},
    60  		{AggregationBits: bitfield.Bitlist{0b1100}, Data: genData(1, 2), Signature: genSign()},
    61  		{AggregationBits: bitfield.Bitlist{0b1001}, Data: genData(1, 3), Signature: genSign()},
    62  		{AggregationBits: bitfield.Bitlist{0b1100}, Data: genData(1, 3), Signature: genSign()},
    63  		// The second slot.
    64  		{AggregationBits: bitfield.Bitlist{0b1001}, Data: genData(2, 3), Signature: genSign()},
    65  		{AggregationBits: bitfield.Bitlist{0b1010}, Data: genData(2, 3), Signature: genSign()},
    66  		{AggregationBits: bitfield.Bitlist{0b1100}, Data: genData(2, 4), Signature: genSign()},
    67  	}
    68  	ctx := context.Background()
    69  
    70  	// Make sure that no error is produced if aggregation is requested on empty unaggregated list.
    71  	require.NoError(t, cache.AggregateUnaggregatedAttestationsBySlotIndex(ctx, 1, 2))
    72  	require.NoError(t, cache.AggregateUnaggregatedAttestationsBySlotIndex(ctx, 2, 3))
    73  	require.Equal(t, 0, len(cache.UnaggregatedAttestationsBySlotIndex(ctx, 1, 2)))
    74  	require.Equal(t, 0, len(cache.AggregatedAttestationsBySlotIndex(ctx, 1, 2)), "Did not aggregate correctly")
    75  	require.Equal(t, 0, len(cache.UnaggregatedAttestationsBySlotIndex(ctx, 1, 3)))
    76  	require.Equal(t, 0, len(cache.AggregatedAttestationsBySlotIndex(ctx, 1, 3)), "Did not aggregate correctly")
    77  
    78  	// Persist unaggregated attestations, and aggregate on per slot/committee index base.
    79  	require.NoError(t, cache.SaveUnaggregatedAttestations(atts))
    80  	require.NoError(t, cache.AggregateUnaggregatedAttestationsBySlotIndex(ctx, 1, 2))
    81  	require.NoError(t, cache.AggregateUnaggregatedAttestationsBySlotIndex(ctx, 2, 3))
    82  
    83  	// Committee attestations at a slot should be aggregated.
    84  	require.Equal(t, 0, len(cache.UnaggregatedAttestationsBySlotIndex(ctx, 1, 2)))
    85  	require.Equal(t, 1, len(cache.AggregatedAttestationsBySlotIndex(ctx, 1, 2)), "Did not aggregate correctly")
    86  	// Committee attestations haven't been aggregated.
    87  	require.Equal(t, 2, len(cache.UnaggregatedAttestationsBySlotIndex(ctx, 1, 3)))
    88  	require.Equal(t, 0, len(cache.AggregatedAttestationsBySlotIndex(ctx, 1, 3)), "Did not aggregate correctly")
    89  	// Committee at a second slot is aggregated.
    90  	require.Equal(t, 0, len(cache.UnaggregatedAttestationsBySlotIndex(ctx, 2, 3)))
    91  	require.Equal(t, 1, len(cache.AggregatedAttestationsBySlotIndex(ctx, 2, 3)), "Did not aggregate correctly")
    92  	// The second committee at second slot is not aggregated.
    93  	require.Equal(t, 1, len(cache.UnaggregatedAttestationsBySlotIndex(ctx, 2, 4)))
    94  	require.Equal(t, 0, len(cache.AggregatedAttestationsBySlotIndex(ctx, 2, 4)), "Did not aggregate correctly")
    95  }
    96  
    97  func TestKV_Aggregated_SaveAggregatedAttestation(t *testing.T) {
    98  	tests := []struct {
    99  		name          string
   100  		att           *ethpb.Attestation
   101  		count         int
   102  		wantErrString string
   103  	}{
   104  		{
   105  			name:          "nil attestation",
   106  			att:           nil,
   107  			wantErrString: "attestation can't be nil",
   108  		},
   109  		{
   110  			name:          "nil attestation data",
   111  			att:           &ethpb.Attestation{},
   112  			wantErrString: "attestation's data can't be nil",
   113  		},
   114  		{
   115  			name: "not aggregated",
   116  			att: testutil.HydrateAttestation(&ethpb.Attestation{
   117  				Data: &ethpb.AttestationData{}, AggregationBits: bitfield.Bitlist{0b10100}}),
   118  			wantErrString: "attestation is not aggregated",
   119  		},
   120  		{
   121  			name: "invalid hash",
   122  			att: &ethpb.Attestation{
   123  				Data: testutil.HydrateAttestationData(&ethpb.AttestationData{
   124  					BeaconBlockRoot: []byte{0b0},
   125  				}),
   126  				AggregationBits: bitfield.Bitlist{0b10111},
   127  			},
   128  			wantErrString: "could not tree hash attestation: " + fssz.ErrBytesLength.Error(),
   129  		},
   130  		{
   131  			name: "already seen",
   132  			att: testutil.HydrateAttestation(&ethpb.Attestation{
   133  				Data: &ethpb.AttestationData{
   134  					Slot: 100,
   135  				},
   136  				AggregationBits: bitfield.Bitlist{0b11101001},
   137  			}),
   138  			count: 0,
   139  		},
   140  		{
   141  			name: "normal save",
   142  			att: testutil.HydrateAttestation(&ethpb.Attestation{
   143  				Data: &ethpb.AttestationData{
   144  					Slot: 1,
   145  				},
   146  				AggregationBits: bitfield.Bitlist{0b1101},
   147  			}),
   148  			count: 1,
   149  		},
   150  	}
   151  	r, err := hashFn(testutil.HydrateAttestationData(&ethpb.AttestationData{
   152  		Slot: 100,
   153  	}))
   154  	require.NoError(t, err)
   155  
   156  	for _, tt := range tests {
   157  		t.Run(tt.name, func(t *testing.T) {
   158  			cache := NewAttCaches()
   159  			cache.seenAtt.Set(string(r[:]), []bitfield.Bitlist{{0xff}}, c.DefaultExpiration)
   160  			assert.Equal(t, 0, len(cache.unAggregatedAtt), "Invalid start pool, atts: %d", len(cache.unAggregatedAtt))
   161  
   162  			err := cache.SaveAggregatedAttestation(tt.att)
   163  			if tt.wantErrString != "" {
   164  				assert.ErrorContains(t, tt.wantErrString, err)
   165  			} else {
   166  				assert.NoError(t, err)
   167  			}
   168  			assert.Equal(t, tt.count, len(cache.aggregatedAtt), "Wrong attestation count")
   169  			assert.Equal(t, tt.count, cache.AggregatedAttestationCount(), "Wrong attestation count")
   170  		})
   171  	}
   172  }
   173  
   174  func TestKV_Aggregated_SaveAggregatedAttestations(t *testing.T) {
   175  	tests := []struct {
   176  		name          string
   177  		atts          []*ethpb.Attestation
   178  		count         int
   179  		wantErrString string
   180  	}{
   181  		{
   182  			name: "no duplicates",
   183  			atts: []*ethpb.Attestation{
   184  				testutil.HydrateAttestation(&ethpb.Attestation{Data: &ethpb.AttestationData{Slot: 1},
   185  					AggregationBits: bitfield.Bitlist{0b1101}}),
   186  				testutil.HydrateAttestation(&ethpb.Attestation{Data: &ethpb.AttestationData{Slot: 1},
   187  					AggregationBits: bitfield.Bitlist{0b1101}}),
   188  			},
   189  			count: 1,
   190  		},
   191  	}
   192  
   193  	for _, tt := range tests {
   194  		t.Run(tt.name, func(t *testing.T) {
   195  			cache := NewAttCaches()
   196  			assert.Equal(t, 0, len(cache.aggregatedAtt), "Invalid start pool, atts: %d", len(cache.unAggregatedAtt))
   197  			err := cache.SaveAggregatedAttestations(tt.atts)
   198  			if tt.wantErrString != "" {
   199  				assert.ErrorContains(t, tt.wantErrString, err)
   200  			} else {
   201  				assert.NoError(t, err)
   202  			}
   203  			assert.Equal(t, tt.count, len(cache.aggregatedAtt), "Wrong attestation count")
   204  			assert.Equal(t, tt.count, cache.AggregatedAttestationCount(), "Wrong attestation count")
   205  		})
   206  	}
   207  }
   208  
   209  func TestKV_Aggregated_SaveAggregatedAttestations_SomeGoodSomeBad(t *testing.T) {
   210  	tests := []struct {
   211  		name          string
   212  		atts          []*ethpb.Attestation
   213  		count         int
   214  		wantErrString string
   215  	}{
   216  		{
   217  			name: "the first attestation is bad",
   218  			atts: []*ethpb.Attestation{
   219  				testutil.HydrateAttestation(&ethpb.Attestation{Data: &ethpb.AttestationData{Slot: 1},
   220  					AggregationBits: bitfield.Bitlist{0b1100}}),
   221  				testutil.HydrateAttestation(&ethpb.Attestation{Data: &ethpb.AttestationData{Slot: 1},
   222  					AggregationBits: bitfield.Bitlist{0b1101}}),
   223  			},
   224  			count: 1,
   225  		},
   226  	}
   227  
   228  	for _, tt := range tests {
   229  		t.Run(tt.name, func(t *testing.T) {
   230  			cache := NewAttCaches()
   231  			assert.Equal(t, 0, len(cache.aggregatedAtt), "Invalid start pool, atts: %d", len(cache.unAggregatedAtt))
   232  			err := cache.SaveAggregatedAttestations(tt.atts)
   233  			if tt.wantErrString != "" {
   234  				assert.ErrorContains(t, tt.wantErrString, err)
   235  			} else {
   236  				assert.NoError(t, err)
   237  			}
   238  			assert.Equal(t, tt.count, len(cache.aggregatedAtt), "Wrong attestation count")
   239  			assert.Equal(t, tt.count, cache.AggregatedAttestationCount(), "Wrong attestation count")
   240  		})
   241  	}
   242  }
   243  
   244  func TestKV_Aggregated_AggregatedAttestations(t *testing.T) {
   245  	cache := NewAttCaches()
   246  
   247  	att1 := testutil.HydrateAttestation(&ethpb.Attestation{Data: &ethpb.AttestationData{Slot: 1}, AggregationBits: bitfield.Bitlist{0b1101}})
   248  	att2 := testutil.HydrateAttestation(&ethpb.Attestation{Data: &ethpb.AttestationData{Slot: 2}, AggregationBits: bitfield.Bitlist{0b1101}})
   249  	att3 := testutil.HydrateAttestation(&ethpb.Attestation{Data: &ethpb.AttestationData{Slot: 3}, AggregationBits: bitfield.Bitlist{0b1101}})
   250  	atts := []*ethpb.Attestation{att1, att2, att3}
   251  
   252  	for _, att := range atts {
   253  		require.NoError(t, cache.SaveAggregatedAttestation(att))
   254  	}
   255  
   256  	returned := cache.AggregatedAttestations()
   257  	sort.Slice(returned, func(i, j int) bool {
   258  		return returned[i].Data.Slot < returned[j].Data.Slot
   259  	})
   260  	assert.DeepSSZEqual(t, atts, returned)
   261  }
   262  
   263  func TestKV_Aggregated_DeleteAggregatedAttestation(t *testing.T) {
   264  	t.Run("nil attestation", func(t *testing.T) {
   265  		cache := NewAttCaches()
   266  		assert.ErrorContains(t, "attestation can't be nil", cache.DeleteAggregatedAttestation(nil))
   267  		att := testutil.HydrateAttestation(&ethpb.Attestation{AggregationBits: bitfield.Bitlist{0b10101}, Data: &ethpb.AttestationData{Slot: 2}})
   268  		assert.NoError(t, cache.DeleteAggregatedAttestation(att))
   269  	})
   270  
   271  	t.Run("non aggregated attestation", func(t *testing.T) {
   272  		cache := NewAttCaches()
   273  		att := testutil.HydrateAttestation(&ethpb.Attestation{AggregationBits: bitfield.Bitlist{0b1001}, Data: &ethpb.AttestationData{Slot: 2}})
   274  		err := cache.DeleteAggregatedAttestation(att)
   275  		assert.ErrorContains(t, "attestation is not aggregated", err)
   276  	})
   277  
   278  	t.Run("invalid hash", func(t *testing.T) {
   279  		cache := NewAttCaches()
   280  		att := &ethpb.Attestation{
   281  			AggregationBits: bitfield.Bitlist{0b1111},
   282  			Data: &ethpb.AttestationData{
   283  				Slot:   2,
   284  				Source: &ethpb.Checkpoint{},
   285  				Target: &ethpb.Checkpoint{},
   286  			},
   287  		}
   288  		err := cache.DeleteAggregatedAttestation(att)
   289  		wantErr := "could not tree hash attestation data: " + fssz.ErrBytesLength.Error()
   290  		assert.ErrorContains(t, wantErr, err)
   291  	})
   292  
   293  	t.Run("nonexistent attestation", func(t *testing.T) {
   294  		cache := NewAttCaches()
   295  		att := testutil.HydrateAttestation(&ethpb.Attestation{AggregationBits: bitfield.Bitlist{0b1111}, Data: &ethpb.AttestationData{Slot: 2}})
   296  		assert.NoError(t, cache.DeleteAggregatedAttestation(att))
   297  	})
   298  
   299  	t.Run("non-filtered deletion", func(t *testing.T) {
   300  		cache := NewAttCaches()
   301  		att1 := testutil.HydrateAttestation(&ethpb.Attestation{Data: &ethpb.AttestationData{Slot: 1}, AggregationBits: bitfield.Bitlist{0b11010}})
   302  		att2 := testutil.HydrateAttestation(&ethpb.Attestation{Data: &ethpb.AttestationData{Slot: 2}, AggregationBits: bitfield.Bitlist{0b11010}})
   303  		att3 := testutil.HydrateAttestation(&ethpb.Attestation{Data: &ethpb.AttestationData{Slot: 3}, AggregationBits: bitfield.Bitlist{0b11010}})
   304  		att4 := testutil.HydrateAttestation(&ethpb.Attestation{Data: &ethpb.AttestationData{Slot: 3}, AggregationBits: bitfield.Bitlist{0b10101}})
   305  		atts := []*ethpb.Attestation{att1, att2, att3, att4}
   306  		require.NoError(t, cache.SaveAggregatedAttestations(atts))
   307  		require.NoError(t, cache.DeleteAggregatedAttestation(att1))
   308  		require.NoError(t, cache.DeleteAggregatedAttestation(att3))
   309  
   310  		returned := cache.AggregatedAttestations()
   311  		wanted := []*ethpb.Attestation{att2}
   312  		assert.DeepEqual(t, wanted, returned)
   313  	})
   314  
   315  	t.Run("filtered deletion", func(t *testing.T) {
   316  		cache := NewAttCaches()
   317  		att1 := testutil.HydrateAttestation(&ethpb.Attestation{Data: &ethpb.AttestationData{Slot: 1}, AggregationBits: bitfield.Bitlist{0b110101}})
   318  		att2 := testutil.HydrateAttestation(&ethpb.Attestation{Data: &ethpb.AttestationData{Slot: 2}, AggregationBits: bitfield.Bitlist{0b110111}})
   319  		att3 := testutil.HydrateAttestation(&ethpb.Attestation{Data: &ethpb.AttestationData{Slot: 2}, AggregationBits: bitfield.Bitlist{0b110100}})
   320  		att4 := testutil.HydrateAttestation(&ethpb.Attestation{Data: &ethpb.AttestationData{Slot: 2}, AggregationBits: bitfield.Bitlist{0b110101}})
   321  		atts := []*ethpb.Attestation{att1, att2, att3, att4}
   322  		require.NoError(t, cache.SaveAggregatedAttestations(atts))
   323  
   324  		assert.Equal(t, 2, cache.AggregatedAttestationCount(), "Unexpected number of atts")
   325  		require.NoError(t, cache.DeleteAggregatedAttestation(att4))
   326  
   327  		returned := cache.AggregatedAttestations()
   328  		wanted := []*ethpb.Attestation{att1, att2}
   329  		sort.Slice(returned, func(i, j int) bool {
   330  			return string(returned[i].AggregationBits) < string(returned[j].AggregationBits)
   331  		})
   332  		assert.DeepEqual(t, wanted, returned)
   333  	})
   334  }
   335  
   336  func TestKV_Aggregated_HasAggregatedAttestation(t *testing.T) {
   337  	tests := []struct {
   338  		name     string
   339  		existing []*ethpb.Attestation
   340  		input    *ethpb.Attestation
   341  		want     bool
   342  		err      error
   343  	}{
   344  		{
   345  			name:  "nil attestation",
   346  			input: nil,
   347  			want:  false,
   348  			err:   errors.New("can't be nil"),
   349  		},
   350  		{
   351  			name: "nil attestation data",
   352  			input: &ethpb.Attestation{
   353  				AggregationBits: bitfield.Bitlist{0b1111},
   354  			},
   355  			want: false,
   356  			err:  errors.New("can't be nil"),
   357  		},
   358  		{
   359  			name: "empty cache aggregated",
   360  			input: testutil.HydrateAttestation(&ethpb.Attestation{
   361  				Data: &ethpb.AttestationData{
   362  					Slot: 1,
   363  				},
   364  				AggregationBits: bitfield.Bitlist{0b1111}}),
   365  			want: false,
   366  		},
   367  		{
   368  			name: "empty cache unaggregated",
   369  			input: testutil.HydrateAttestation(&ethpb.Attestation{
   370  				Data: &ethpb.AttestationData{
   371  					Slot: 1,
   372  				},
   373  				AggregationBits: bitfield.Bitlist{0b1001}}),
   374  			want: false,
   375  		},
   376  		{
   377  			name: "single attestation in cache with exact match",
   378  			existing: []*ethpb.Attestation{{
   379  				Data: testutil.HydrateAttestationData(&ethpb.AttestationData{
   380  					Slot: 1,
   381  				}),
   382  				AggregationBits: bitfield.Bitlist{0b1111}},
   383  			},
   384  			input: &ethpb.Attestation{
   385  				Data: testutil.HydrateAttestationData(&ethpb.AttestationData{
   386  					Slot: 1,
   387  				}),
   388  				AggregationBits: bitfield.Bitlist{0b1111}},
   389  			want: true,
   390  		},
   391  		{
   392  			name: "single attestation in cache with subset aggregation",
   393  			existing: []*ethpb.Attestation{{
   394  				Data: testutil.HydrateAttestationData(&ethpb.AttestationData{
   395  					Slot: 1,
   396  				}),
   397  				AggregationBits: bitfield.Bitlist{0b1111}},
   398  			},
   399  			input: &ethpb.Attestation{
   400  				Data: testutil.HydrateAttestationData(&ethpb.AttestationData{
   401  					Slot: 1,
   402  				}),
   403  				AggregationBits: bitfield.Bitlist{0b1110}},
   404  			want: true,
   405  		},
   406  		{
   407  			name: "single attestation in cache with superset aggregation",
   408  			existing: []*ethpb.Attestation{{
   409  				Data: testutil.HydrateAttestationData(&ethpb.AttestationData{
   410  					Slot: 1,
   411  				}),
   412  				AggregationBits: bitfield.Bitlist{0b1110}},
   413  			},
   414  			input: &ethpb.Attestation{
   415  				Data: testutil.HydrateAttestationData(&ethpb.AttestationData{
   416  					Slot: 1,
   417  				}),
   418  				AggregationBits: bitfield.Bitlist{0b1111}},
   419  			want: false,
   420  		},
   421  		{
   422  			name: "multiple attestations with same data in cache with overlapping aggregation, input is subset",
   423  			existing: []*ethpb.Attestation{
   424  				{
   425  					Data: testutil.HydrateAttestationData(&ethpb.AttestationData{
   426  						Slot: 1,
   427  					}),
   428  					AggregationBits: bitfield.Bitlist{0b1111000},
   429  				},
   430  				{
   431  					Data: testutil.HydrateAttestationData(&ethpb.AttestationData{
   432  						Slot: 1,
   433  					}),
   434  					AggregationBits: bitfield.Bitlist{0b1100111},
   435  				},
   436  			},
   437  			input: &ethpb.Attestation{
   438  				Data: testutil.HydrateAttestationData(&ethpb.AttestationData{
   439  					Slot: 1,
   440  				}),
   441  				AggregationBits: bitfield.Bitlist{0b1100000}},
   442  			want: true,
   443  		},
   444  		{
   445  			name: "multiple attestations with same data in cache with overlapping aggregation and input is superset",
   446  			existing: []*ethpb.Attestation{
   447  				{
   448  					Data: testutil.HydrateAttestationData(&ethpb.AttestationData{
   449  						Slot: 1,
   450  					}),
   451  					AggregationBits: bitfield.Bitlist{0b1111000},
   452  				},
   453  				{
   454  					Data: testutil.HydrateAttestationData(&ethpb.AttestationData{
   455  						Slot: 1,
   456  					}),
   457  					AggregationBits: bitfield.Bitlist{0b1100111},
   458  				},
   459  			},
   460  			input: &ethpb.Attestation{
   461  				Data: testutil.HydrateAttestationData(&ethpb.AttestationData{
   462  					Slot: 1,
   463  				}),
   464  				AggregationBits: bitfield.Bitlist{0b1111111}},
   465  			want: false,
   466  		},
   467  		{
   468  			name: "multiple attestations with different data in cache",
   469  			existing: []*ethpb.Attestation{
   470  				{
   471  					Data: testutil.HydrateAttestationData(&ethpb.AttestationData{
   472  						Slot: 2,
   473  					}),
   474  					AggregationBits: bitfield.Bitlist{0b1111000},
   475  				},
   476  				{
   477  					Data: testutil.HydrateAttestationData(&ethpb.AttestationData{
   478  						Slot: 3,
   479  					}),
   480  					AggregationBits: bitfield.Bitlist{0b1100111},
   481  				},
   482  			},
   483  			input: &ethpb.Attestation{
   484  				Data: testutil.HydrateAttestationData(&ethpb.AttestationData{
   485  					Slot: 1,
   486  				}),
   487  				AggregationBits: bitfield.Bitlist{0b1111111}},
   488  			want: false,
   489  		},
   490  		{
   491  			name: "attestations with different bitlist lengths",
   492  			existing: []*ethpb.Attestation{
   493  				{
   494  					Data: testutil.HydrateAttestationData(&ethpb.AttestationData{
   495  						Slot: 2,
   496  					}),
   497  					AggregationBits: bitfield.Bitlist{0b1111000},
   498  				},
   499  			},
   500  			input: &ethpb.Attestation{
   501  				Data: testutil.HydrateAttestationData(&ethpb.AttestationData{
   502  					Slot: 2,
   503  				}),
   504  				AggregationBits: bitfield.Bitlist{0b1111},
   505  			},
   506  			want: false,
   507  			err:  bitfield.ErrBitlistDifferentLength,
   508  		},
   509  	}
   510  
   511  	for _, tt := range tests {
   512  		t.Run(tt.name, func(t *testing.T) {
   513  			cache := NewAttCaches()
   514  			require.NoError(t, cache.SaveAggregatedAttestations(tt.existing))
   515  
   516  			if tt.input != nil && tt.input.Signature == nil {
   517  				tt.input.Signature = make([]byte, 96)
   518  			}
   519  
   520  			if tt.err != nil {
   521  				_, err := cache.HasAggregatedAttestation(tt.input)
   522  				require.ErrorContains(t, tt.err.Error(), err)
   523  			} else {
   524  				result, err := cache.HasAggregatedAttestation(tt.input)
   525  				require.NoError(t, err)
   526  				assert.Equal(t, tt.want, result)
   527  
   528  				// Same test for block attestations
   529  				cache = NewAttCaches()
   530  				assert.NoError(t, cache.SaveBlockAttestations(tt.existing))
   531  
   532  				result, err = cache.HasAggregatedAttestation(tt.input)
   533  				require.NoError(t, err)
   534  				assert.Equal(t, tt.want, result)
   535  			}
   536  		})
   537  	}
   538  }
   539  
   540  func TestKV_Aggregated_DuplicateAggregatedAttestations(t *testing.T) {
   541  	cache := NewAttCaches()
   542  
   543  	att1 := testutil.HydrateAttestation(&ethpb.Attestation{Data: &ethpb.AttestationData{Slot: 1}, AggregationBits: bitfield.Bitlist{0b1101}})
   544  	att2 := testutil.HydrateAttestation(&ethpb.Attestation{Data: &ethpb.AttestationData{Slot: 1}, AggregationBits: bitfield.Bitlist{0b1111}})
   545  	atts := []*ethpb.Attestation{att1, att2}
   546  
   547  	for _, att := range atts {
   548  		require.NoError(t, cache.SaveAggregatedAttestation(att))
   549  	}
   550  
   551  	returned := cache.AggregatedAttestations()
   552  
   553  	// It should have only returned att2.
   554  	assert.DeepSSZEqual(t, att2, returned[0], "Did not receive correct aggregated atts")
   555  	assert.Equal(t, 1, len(returned), "Did not receive correct aggregated atts")
   556  }