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

     1  package kv
     2  
     3  import (
     4  	"bytes"
     5  	"context"
     6  	"sort"
     7  	"testing"
     8  
     9  	fssz "github.com/ferranbt/fastssz"
    10  	c "github.com/patrickmn/go-cache"
    11  	"github.com/prysmaticlabs/go-bitfield"
    12  	ethpb "github.com/prysmaticlabs/prysm/proto/eth/v1alpha1"
    13  	"github.com/prysmaticlabs/prysm/shared/testutil"
    14  	"github.com/prysmaticlabs/prysm/shared/testutil/assert"
    15  	"github.com/prysmaticlabs/prysm/shared/testutil/require"
    16  )
    17  
    18  func TestKV_Unaggregated_SaveUnaggregatedAttestation(t *testing.T) {
    19  	tests := []struct {
    20  		name          string
    21  		att           *ethpb.Attestation
    22  		count         int
    23  		wantErrString string
    24  	}{
    25  		{
    26  			name: "nil attestation",
    27  			att:  nil,
    28  		},
    29  		{
    30  			name:          "already aggregated",
    31  			att:           &ethpb.Attestation{AggregationBits: bitfield.Bitlist{0b10101}, Data: &ethpb.AttestationData{Slot: 2}},
    32  			wantErrString: "attestation is aggregated",
    33  		},
    34  		{
    35  			name: "invalid hash",
    36  			att: &ethpb.Attestation{
    37  				Data: &ethpb.AttestationData{
    38  					BeaconBlockRoot: []byte{0b0},
    39  				},
    40  			},
    41  			wantErrString: fssz.ErrBytesLength.Error(),
    42  		},
    43  		{
    44  			name:  "normal save",
    45  			att:   testutil.HydrateAttestation(&ethpb.Attestation{AggregationBits: bitfield.Bitlist{0b0001}}),
    46  			count: 1,
    47  		},
    48  		{
    49  			name: "already seen",
    50  			att: testutil.HydrateAttestation(&ethpb.Attestation{
    51  				Data: &ethpb.AttestationData{
    52  					Slot: 100,
    53  				},
    54  				AggregationBits: bitfield.Bitlist{0b10000001},
    55  			}),
    56  			count: 0,
    57  		},
    58  	}
    59  	r, err := hashFn(testutil.HydrateAttestationData(&ethpb.AttestationData{Slot: 100}))
    60  	require.NoError(t, err)
    61  
    62  	for _, tt := range tests {
    63  		t.Run(tt.name, func(t *testing.T) {
    64  			cache := NewAttCaches()
    65  			cache.seenAtt.Set(string(r[:]), []bitfield.Bitlist{{0xff}}, c.DefaultExpiration)
    66  			assert.Equal(t, 0, len(cache.unAggregatedAtt), "Invalid start pool, atts: %d", len(cache.unAggregatedAtt))
    67  
    68  			if tt.att != nil && tt.att.Signature == nil {
    69  				tt.att.Signature = make([]byte, 96)
    70  			}
    71  
    72  			err := cache.SaveUnaggregatedAttestation(tt.att)
    73  			if tt.wantErrString != "" {
    74  				assert.ErrorContains(t, tt.wantErrString, err)
    75  			} else {
    76  				assert.NoError(t, err)
    77  			}
    78  			assert.Equal(t, tt.count, len(cache.unAggregatedAtt), "Wrong attestation count")
    79  			assert.Equal(t, tt.count, cache.UnaggregatedAttestationCount(), "Wrong attestation count")
    80  		})
    81  	}
    82  }
    83  
    84  func TestKV_Unaggregated_SaveUnaggregatedAttestations(t *testing.T) {
    85  	tests := []struct {
    86  		name          string
    87  		atts          []*ethpb.Attestation
    88  		count         int
    89  		wantErrString string
    90  	}{
    91  		{
    92  			name: "unaggregated only",
    93  			atts: []*ethpb.Attestation{
    94  				testutil.HydrateAttestation(&ethpb.Attestation{Data: &ethpb.AttestationData{Slot: 1}}),
    95  				testutil.HydrateAttestation(&ethpb.Attestation{Data: &ethpb.AttestationData{Slot: 2}}),
    96  				testutil.HydrateAttestation(&ethpb.Attestation{Data: &ethpb.AttestationData{Slot: 3}}),
    97  			},
    98  			count: 3,
    99  		},
   100  		{
   101  			name: "has aggregated",
   102  			atts: []*ethpb.Attestation{
   103  				testutil.HydrateAttestation(&ethpb.Attestation{Data: &ethpb.AttestationData{Slot: 1}}),
   104  				{AggregationBits: bitfield.Bitlist{0b1111}, Data: &ethpb.AttestationData{Slot: 2}},
   105  				testutil.HydrateAttestation(&ethpb.Attestation{Data: &ethpb.AttestationData{Slot: 3}}),
   106  			},
   107  			wantErrString: "attestation is aggregated",
   108  			count:         1,
   109  		},
   110  	}
   111  
   112  	for _, tt := range tests {
   113  		t.Run(tt.name, func(t *testing.T) {
   114  			cache := NewAttCaches()
   115  			assert.Equal(t, 0, len(cache.unAggregatedAtt), "Invalid start pool, atts: %d", len(cache.unAggregatedAtt))
   116  
   117  			err := cache.SaveUnaggregatedAttestations(tt.atts)
   118  			if tt.wantErrString != "" {
   119  				assert.ErrorContains(t, tt.wantErrString, err)
   120  			} else {
   121  				assert.NoError(t, err)
   122  			}
   123  			assert.Equal(t, tt.count, len(cache.unAggregatedAtt), "Wrong attestation count")
   124  			assert.Equal(t, tt.count, cache.UnaggregatedAttestationCount(), "Wrong attestation count")
   125  		})
   126  	}
   127  }
   128  
   129  func TestKV_Unaggregated_DeleteUnaggregatedAttestation(t *testing.T) {
   130  	t.Run("nil attestation", func(t *testing.T) {
   131  		cache := NewAttCaches()
   132  		assert.NoError(t, cache.DeleteUnaggregatedAttestation(nil))
   133  	})
   134  
   135  	t.Run("aggregated attestation", func(t *testing.T) {
   136  		cache := NewAttCaches()
   137  		att := &ethpb.Attestation{AggregationBits: bitfield.Bitlist{0b1111}, Data: &ethpb.AttestationData{Slot: 2}}
   138  		err := cache.DeleteUnaggregatedAttestation(att)
   139  		assert.ErrorContains(t, "attestation is aggregated", err)
   140  	})
   141  
   142  	t.Run("successful deletion", func(t *testing.T) {
   143  		cache := NewAttCaches()
   144  		att1 := testutil.HydrateAttestation(&ethpb.Attestation{Data: &ethpb.AttestationData{Slot: 1}, AggregationBits: bitfield.Bitlist{0b101}})
   145  		att2 := testutil.HydrateAttestation(&ethpb.Attestation{Data: &ethpb.AttestationData{Slot: 2}, AggregationBits: bitfield.Bitlist{0b110}})
   146  		att3 := testutil.HydrateAttestation(&ethpb.Attestation{Data: &ethpb.AttestationData{Slot: 3}, AggregationBits: bitfield.Bitlist{0b110}})
   147  		atts := []*ethpb.Attestation{att1, att2, att3}
   148  		require.NoError(t, cache.SaveUnaggregatedAttestations(atts))
   149  		for _, att := range atts {
   150  			assert.NoError(t, cache.DeleteUnaggregatedAttestation(att))
   151  		}
   152  		returned, err := cache.UnaggregatedAttestations()
   153  		require.NoError(t, err)
   154  		assert.DeepEqual(t, []*ethpb.Attestation{}, returned)
   155  	})
   156  }
   157  
   158  func TestKV_Unaggregated_DeleteSeenUnaggregatedAttestations(t *testing.T) {
   159  	d := testutil.HydrateAttestationData(&ethpb.AttestationData{})
   160  
   161  	t.Run("no attestations", func(t *testing.T) {
   162  		cache := NewAttCaches()
   163  		count, err := cache.DeleteSeenUnaggregatedAttestations()
   164  		assert.NoError(t, err)
   165  		assert.Equal(t, 0, count)
   166  	})
   167  
   168  	t.Run("none seen", func(t *testing.T) {
   169  		cache := NewAttCaches()
   170  		atts := []*ethpb.Attestation{
   171  			testutil.HydrateAttestation(&ethpb.Attestation{Data: d, AggregationBits: bitfield.Bitlist{0b1001}}),
   172  			testutil.HydrateAttestation(&ethpb.Attestation{Data: d, AggregationBits: bitfield.Bitlist{0b1010}}),
   173  			testutil.HydrateAttestation(&ethpb.Attestation{Data: d, AggregationBits: bitfield.Bitlist{0b1100}}),
   174  		}
   175  		require.NoError(t, cache.SaveUnaggregatedAttestations(atts))
   176  		assert.Equal(t, 3, cache.UnaggregatedAttestationCount())
   177  
   178  		// As none of attestations have been marked seen, nothing should be deleted.
   179  		count, err := cache.DeleteSeenUnaggregatedAttestations()
   180  		assert.NoError(t, err)
   181  		assert.Equal(t, 0, count)
   182  		assert.Equal(t, 3, cache.UnaggregatedAttestationCount())
   183  	})
   184  
   185  	t.Run("some seen", func(t *testing.T) {
   186  		cache := NewAttCaches()
   187  		atts := []*ethpb.Attestation{
   188  			testutil.HydrateAttestation(&ethpb.Attestation{Data: d, AggregationBits: bitfield.Bitlist{0b1001}}),
   189  			testutil.HydrateAttestation(&ethpb.Attestation{Data: d, AggregationBits: bitfield.Bitlist{0b1010}}),
   190  			testutil.HydrateAttestation(&ethpb.Attestation{Data: d, AggregationBits: bitfield.Bitlist{0b1100}}),
   191  		}
   192  		require.NoError(t, cache.SaveUnaggregatedAttestations(atts))
   193  		assert.Equal(t, 3, cache.UnaggregatedAttestationCount())
   194  
   195  		require.NoError(t, cache.insertSeenBit(atts[1]))
   196  
   197  		// Only seen attestations must be deleted.
   198  		count, err := cache.DeleteSeenUnaggregatedAttestations()
   199  		assert.NoError(t, err)
   200  		assert.Equal(t, 1, count)
   201  		assert.Equal(t, 2, cache.UnaggregatedAttestationCount())
   202  		returned, err := cache.UnaggregatedAttestations()
   203  		sort.Slice(returned, func(i, j int) bool {
   204  			return bytes.Compare(returned[i].AggregationBits, returned[j].AggregationBits) < 0
   205  		})
   206  		require.NoError(t, err)
   207  		assert.DeepEqual(t, []*ethpb.Attestation{atts[0], atts[2]}, returned)
   208  	})
   209  
   210  	t.Run("all seen", func(t *testing.T) {
   211  		cache := NewAttCaches()
   212  		atts := []*ethpb.Attestation{
   213  			testutil.HydrateAttestation(&ethpb.Attestation{Data: d, AggregationBits: bitfield.Bitlist{0b1001}}),
   214  			testutil.HydrateAttestation(&ethpb.Attestation{Data: d, AggregationBits: bitfield.Bitlist{0b1010}}),
   215  			testutil.HydrateAttestation(&ethpb.Attestation{Data: d, AggregationBits: bitfield.Bitlist{0b1100}}),
   216  		}
   217  		require.NoError(t, cache.SaveUnaggregatedAttestations(atts))
   218  		assert.Equal(t, 3, cache.UnaggregatedAttestationCount())
   219  
   220  		require.NoError(t, cache.insertSeenBit(atts[0]))
   221  		require.NoError(t, cache.insertSeenBit(atts[1]))
   222  		require.NoError(t, cache.insertSeenBit(atts[2]))
   223  
   224  		// All attestations have been processed -- all should be removed.
   225  		count, err := cache.DeleteSeenUnaggregatedAttestations()
   226  		assert.NoError(t, err)
   227  		assert.Equal(t, 3, count)
   228  		assert.Equal(t, 0, cache.UnaggregatedAttestationCount())
   229  		returned, err := cache.UnaggregatedAttestations()
   230  		require.NoError(t, err)
   231  		assert.DeepEqual(t, []*ethpb.Attestation{}, returned)
   232  	})
   233  }
   234  
   235  func TestKV_Unaggregated_UnaggregatedAttestationsBySlotIndex(t *testing.T) {
   236  	cache := NewAttCaches()
   237  
   238  	att1 := testutil.HydrateAttestation(&ethpb.Attestation{Data: &ethpb.AttestationData{Slot: 1, CommitteeIndex: 1}, AggregationBits: bitfield.Bitlist{0b101}})
   239  	att2 := testutil.HydrateAttestation(&ethpb.Attestation{Data: &ethpb.AttestationData{Slot: 1, CommitteeIndex: 2}, AggregationBits: bitfield.Bitlist{0b110}})
   240  	att3 := testutil.HydrateAttestation(&ethpb.Attestation{Data: &ethpb.AttestationData{Slot: 2, CommitteeIndex: 1}, AggregationBits: bitfield.Bitlist{0b110}})
   241  	atts := []*ethpb.Attestation{att1, att2, att3}
   242  
   243  	for _, att := range atts {
   244  		require.NoError(t, cache.SaveUnaggregatedAttestation(att))
   245  	}
   246  	ctx := context.Background()
   247  	returned := cache.UnaggregatedAttestationsBySlotIndex(ctx, 1, 1)
   248  	assert.DeepEqual(t, []*ethpb.Attestation{att1}, returned)
   249  	returned = cache.UnaggregatedAttestationsBySlotIndex(ctx, 1, 2)
   250  	assert.DeepEqual(t, []*ethpb.Attestation{att2}, returned)
   251  	returned = cache.UnaggregatedAttestationsBySlotIndex(ctx, 2, 1)
   252  	assert.DeepEqual(t, []*ethpb.Attestation{att3}, returned)
   253  }