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

     1  package attestations
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  	"sort"
     7  	"testing"
     8  
     9  	"github.com/prysmaticlabs/go-bitfield"
    10  	ethpb "github.com/prysmaticlabs/prysm/proto/eth/v1alpha1"
    11  	attaggregation "github.com/prysmaticlabs/prysm/shared/aggregation/attestations"
    12  	"github.com/prysmaticlabs/prysm/shared/bls"
    13  	"github.com/prysmaticlabs/prysm/shared/testutil"
    14  	"github.com/prysmaticlabs/prysm/shared/testutil/assert"
    15  	"github.com/prysmaticlabs/prysm/shared/testutil/require"
    16  	"google.golang.org/protobuf/proto"
    17  )
    18  
    19  func TestBatchAttestations_Multiple(t *testing.T) {
    20  	s, err := NewService(context.Background(), &Config{Pool: NewPool()})
    21  	require.NoError(t, err)
    22  
    23  	priv, err := bls.RandKey()
    24  	require.NoError(t, err)
    25  	sig := priv.Sign([]byte("dummy_test_data"))
    26  	var mockRoot [32]byte
    27  
    28  	unaggregatedAtts := []*ethpb.Attestation{
    29  		{Data: &ethpb.AttestationData{
    30  			Slot:            2,
    31  			BeaconBlockRoot: mockRoot[:],
    32  			Source:          &ethpb.Checkpoint{Root: mockRoot[:]},
    33  			Target:          &ethpb.Checkpoint{Root: mockRoot[:]}}, AggregationBits: bitfield.Bitlist{0b100100}, Signature: sig.Marshal()},
    34  		{Data: &ethpb.AttestationData{
    35  			Slot:            1,
    36  			BeaconBlockRoot: mockRoot[:],
    37  			Source:          &ethpb.Checkpoint{Root: mockRoot[:]},
    38  			Target:          &ethpb.Checkpoint{Root: mockRoot[:]}}, AggregationBits: bitfield.Bitlist{0b101000}, Signature: sig.Marshal()},
    39  		{Data: &ethpb.AttestationData{
    40  			Slot:            0,
    41  			BeaconBlockRoot: mockRoot[:],
    42  			Source:          &ethpb.Checkpoint{Root: mockRoot[:]},
    43  			Target:          &ethpb.Checkpoint{Root: mockRoot[:]}}, AggregationBits: bitfield.Bitlist{0b100010}, Signature: sig.Marshal()},
    44  	}
    45  	aggregatedAtts := []*ethpb.Attestation{
    46  		{Data: &ethpb.AttestationData{
    47  			Slot:            2,
    48  			BeaconBlockRoot: mockRoot[:],
    49  			Source:          &ethpb.Checkpoint{Root: mockRoot[:]},
    50  			Target:          &ethpb.Checkpoint{Root: mockRoot[:]}}, AggregationBits: bitfield.Bitlist{0b111000}, Signature: sig.Marshal()},
    51  		{Data: &ethpb.AttestationData{
    52  			Slot:            1,
    53  			BeaconBlockRoot: mockRoot[:],
    54  			Source:          &ethpb.Checkpoint{Root: mockRoot[:]},
    55  			Target:          &ethpb.Checkpoint{Root: mockRoot[:]}}, AggregationBits: bitfield.Bitlist{0b100011}, Signature: sig.Marshal()},
    56  		{Data: &ethpb.AttestationData{
    57  			Slot:            0,
    58  			BeaconBlockRoot: mockRoot[:],
    59  			Source:          &ethpb.Checkpoint{Root: mockRoot[:]},
    60  			Target:          &ethpb.Checkpoint{Root: mockRoot[:]}}, AggregationBits: bitfield.Bitlist{0b110001}, Signature: sig.Marshal()},
    61  	}
    62  	blockAtts := []*ethpb.Attestation{
    63  		{Data: &ethpb.AttestationData{
    64  			Slot:            2,
    65  			BeaconBlockRoot: mockRoot[:],
    66  			Source:          &ethpb.Checkpoint{Root: mockRoot[:]},
    67  			Target:          &ethpb.Checkpoint{Root: mockRoot[:]}}, AggregationBits: bitfield.Bitlist{0b100001}, Signature: sig.Marshal()},
    68  		{Data: &ethpb.AttestationData{
    69  			Slot:            1,
    70  			BeaconBlockRoot: mockRoot[:],
    71  			Source:          &ethpb.Checkpoint{Root: mockRoot[:]},
    72  			Target:          &ethpb.Checkpoint{Root: mockRoot[:]}}, AggregationBits: bitfield.Bitlist{0b100100}, Signature: sig.Marshal()},
    73  		{Data: &ethpb.AttestationData{
    74  			Slot:            0,
    75  			BeaconBlockRoot: mockRoot[:],
    76  			Source:          &ethpb.Checkpoint{Root: mockRoot[:]},
    77  			Target:          &ethpb.Checkpoint{Root: mockRoot[:]}}, AggregationBits: bitfield.Bitlist{0b100100}, Signature: sig.Marshal()},
    78  		{Data: &ethpb.AttestationData{
    79  			Slot:            2,
    80  			BeaconBlockRoot: mockRoot[:],
    81  			Source:          &ethpb.Checkpoint{Root: mockRoot[:]},
    82  			Target:          &ethpb.Checkpoint{Root: mockRoot[:]}}, AggregationBits: bitfield.Bitlist{0b111000}, Signature: sig.Marshal()}, // Duplicated
    83  		{Data: &ethpb.AttestationData{
    84  			Slot:            1,
    85  			BeaconBlockRoot: mockRoot[:],
    86  			Source:          &ethpb.Checkpoint{Root: mockRoot[:]},
    87  			Target:          &ethpb.Checkpoint{Root: mockRoot[:]}}, AggregationBits: bitfield.Bitlist{0b100011}, Signature: sig.Marshal()}, // Duplicated
    88  	}
    89  	require.NoError(t, s.cfg.Pool.SaveUnaggregatedAttestations(unaggregatedAtts))
    90  	require.NoError(t, s.cfg.Pool.SaveAggregatedAttestations(aggregatedAtts))
    91  	require.NoError(t, s.cfg.Pool.SaveBlockAttestations(blockAtts))
    92  	require.NoError(t, s.batchForkChoiceAtts(context.Background()))
    93  
    94  	wanted, err := attaggregation.Aggregate([]*ethpb.Attestation{aggregatedAtts[0], blockAtts[0]})
    95  	require.NoError(t, err)
    96  	aggregated, err := attaggregation.Aggregate([]*ethpb.Attestation{aggregatedAtts[1], blockAtts[1]})
    97  	require.NoError(t, err)
    98  	wanted = append(wanted, aggregated...)
    99  	aggregated, err = attaggregation.Aggregate([]*ethpb.Attestation{aggregatedAtts[2], blockAtts[2]})
   100  	require.NoError(t, err)
   101  
   102  	wanted = append(wanted, aggregated...)
   103  	require.NoError(t, s.cfg.Pool.AggregateUnaggregatedAttestations(context.Background()))
   104  	received := s.cfg.Pool.ForkchoiceAttestations()
   105  
   106  	sort.Slice(received, func(i, j int) bool {
   107  		return received[i].Data.Slot < received[j].Data.Slot
   108  	})
   109  	sort.Slice(wanted, func(i, j int) bool {
   110  		return wanted[i].Data.Slot < wanted[j].Data.Slot
   111  	})
   112  
   113  	assert.DeepSSZEqual(t, wanted, received)
   114  }
   115  
   116  func TestBatchAttestations_Single(t *testing.T) {
   117  	s, err := NewService(context.Background(), &Config{Pool: NewPool()})
   118  	require.NoError(t, err)
   119  
   120  	priv, err := bls.RandKey()
   121  	require.NoError(t, err)
   122  	sig := priv.Sign([]byte("dummy_test_data"))
   123  	mockRoot := [32]byte{}
   124  	d := &ethpb.AttestationData{
   125  		BeaconBlockRoot: mockRoot[:],
   126  		Source:          &ethpb.Checkpoint{Root: mockRoot[:]},
   127  		Target:          &ethpb.Checkpoint{Root: mockRoot[:]},
   128  	}
   129  
   130  	unaggregatedAtts := []*ethpb.Attestation{
   131  		{Data: d, AggregationBits: bitfield.Bitlist{0b101000}, Signature: sig.Marshal()},
   132  		{Data: d, AggregationBits: bitfield.Bitlist{0b100100}, Signature: sig.Marshal()},
   133  	}
   134  	aggregatedAtts := []*ethpb.Attestation{
   135  		{Data: d, AggregationBits: bitfield.Bitlist{0b101100}, Signature: sig.Marshal()},
   136  		{Data: d, AggregationBits: bitfield.Bitlist{0b110010}, Signature: sig.Marshal()},
   137  	}
   138  	blockAtts := []*ethpb.Attestation{
   139  		{Data: d, AggregationBits: bitfield.Bitlist{0b110010}, Signature: sig.Marshal()},
   140  		{Data: d, AggregationBits: bitfield.Bitlist{0b100010}, Signature: sig.Marshal()},
   141  		{Data: d, AggregationBits: bitfield.Bitlist{0b110010}, Signature: sig.Marshal()}, // Duplicated
   142  	}
   143  	require.NoError(t, s.cfg.Pool.SaveUnaggregatedAttestations(unaggregatedAtts))
   144  	require.NoError(t, s.cfg.Pool.SaveAggregatedAttestations(aggregatedAtts))
   145  	require.NoError(t, s.cfg.Pool.SaveBlockAttestations(blockAtts))
   146  	require.NoError(t, s.batchForkChoiceAtts(context.Background()))
   147  
   148  	wanted, err := attaggregation.Aggregate(append(aggregatedAtts, unaggregatedAtts...))
   149  	require.NoError(t, err)
   150  
   151  	wanted, err = attaggregation.Aggregate(append(wanted, blockAtts...))
   152  	require.NoError(t, err)
   153  
   154  	got := s.cfg.Pool.ForkchoiceAttestations()
   155  	assert.DeepEqual(t, wanted, got)
   156  }
   157  
   158  func TestAggregateAndSaveForkChoiceAtts_Single(t *testing.T) {
   159  	s, err := NewService(context.Background(), &Config{Pool: NewPool()})
   160  	require.NoError(t, err)
   161  
   162  	priv, err := bls.RandKey()
   163  	require.NoError(t, err)
   164  	sig := priv.Sign([]byte("dummy_test_data"))
   165  	mockRoot := [32]byte{}
   166  	d := &ethpb.AttestationData{
   167  		BeaconBlockRoot: mockRoot[:],
   168  		Source:          &ethpb.Checkpoint{Root: mockRoot[:]},
   169  		Target:          &ethpb.Checkpoint{Root: mockRoot[:]},
   170  	}
   171  
   172  	atts := []*ethpb.Attestation{
   173  		{Data: d, AggregationBits: bitfield.Bitlist{0b101}, Signature: sig.Marshal()},
   174  		{Data: d, AggregationBits: bitfield.Bitlist{0b110}, Signature: sig.Marshal()}}
   175  	require.NoError(t, s.aggregateAndSaveForkChoiceAtts(atts))
   176  
   177  	wanted, err := attaggregation.Aggregate(atts)
   178  	require.NoError(t, err)
   179  	assert.DeepEqual(t, wanted, s.cfg.Pool.ForkchoiceAttestations())
   180  }
   181  
   182  func TestAggregateAndSaveForkChoiceAtts_Multiple(t *testing.T) {
   183  	s, err := NewService(context.Background(), &Config{Pool: NewPool()})
   184  	require.NoError(t, err)
   185  
   186  	priv, err := bls.RandKey()
   187  	require.NoError(t, err)
   188  	sig := priv.Sign([]byte("dummy_test_data"))
   189  	mockRoot := [32]byte{}
   190  	d := &ethpb.AttestationData{
   191  		BeaconBlockRoot: mockRoot[:],
   192  		Source:          &ethpb.Checkpoint{Root: mockRoot[:]},
   193  		Target:          &ethpb.Checkpoint{Root: mockRoot[:]},
   194  	}
   195  	d1, ok := proto.Clone(d).(*ethpb.AttestationData)
   196  	require.Equal(t, true, ok, "Entity is not of type *ethpb.AttestationData")
   197  	d1.Slot = 1
   198  	d2, ok := proto.Clone(d).(*ethpb.AttestationData)
   199  	require.Equal(t, true, ok, "Entity is not of type *ethpb.AttestationData")
   200  	d2.Slot = 2
   201  
   202  	atts1 := []*ethpb.Attestation{
   203  		{Data: d, AggregationBits: bitfield.Bitlist{0b101}, Signature: sig.Marshal()},
   204  		{Data: d, AggregationBits: bitfield.Bitlist{0b110}, Signature: sig.Marshal()},
   205  	}
   206  	require.NoError(t, s.aggregateAndSaveForkChoiceAtts(atts1))
   207  	atts2 := []*ethpb.Attestation{
   208  		{Data: d1, AggregationBits: bitfield.Bitlist{0b10110}, Signature: sig.Marshal()},
   209  		{Data: d1, AggregationBits: bitfield.Bitlist{0b11100}, Signature: sig.Marshal()},
   210  		{Data: d1, AggregationBits: bitfield.Bitlist{0b11000}, Signature: sig.Marshal()},
   211  	}
   212  	require.NoError(t, s.aggregateAndSaveForkChoiceAtts(atts2))
   213  	att3 := []*ethpb.Attestation{
   214  		{Data: d2, AggregationBits: bitfield.Bitlist{0b1100}, Signature: sig.Marshal()},
   215  	}
   216  	require.NoError(t, s.aggregateAndSaveForkChoiceAtts(att3))
   217  
   218  	wanted, err := attaggregation.Aggregate(atts1)
   219  	require.NoError(t, err)
   220  	aggregated, err := attaggregation.Aggregate(atts2)
   221  	require.NoError(t, err)
   222  
   223  	wanted = append(wanted, aggregated...)
   224  	wanted = append(wanted, att3...)
   225  
   226  	received := s.cfg.Pool.ForkchoiceAttestations()
   227  	sort.Slice(received, func(i, j int) bool {
   228  		return received[i].Data.Slot < received[j].Data.Slot
   229  	})
   230  	assert.DeepEqual(t, wanted, received)
   231  }
   232  
   233  func TestSeenAttestations_PresentInCache(t *testing.T) {
   234  	s, err := NewService(context.Background(), &Config{Pool: NewPool()})
   235  	require.NoError(t, err)
   236  
   237  	ad1 := testutil.HydrateAttestationData(&ethpb.AttestationData{})
   238  	att1 := &ethpb.Attestation{Data: ad1, Signature: []byte{'A'}, AggregationBits: bitfield.Bitlist{0x13} /* 0b00010011 */}
   239  	got, err := s.seen(att1)
   240  	require.NoError(t, err)
   241  	assert.Equal(t, false, got)
   242  
   243  	att2 := &ethpb.Attestation{Data: ad1, Signature: []byte{'A'}, AggregationBits: bitfield.Bitlist{0x17} /* 0b00010111 */}
   244  	got, err = s.seen(att2)
   245  	require.NoError(t, err)
   246  	assert.Equal(t, false, got)
   247  
   248  	att3 := &ethpb.Attestation{Data: ad1, Signature: []byte{'A'}, AggregationBits: bitfield.Bitlist{0x17} /* 0b00010111 */}
   249  	got, err = s.seen(att3)
   250  	require.NoError(t, err)
   251  	assert.Equal(t, true, got)
   252  }
   253  
   254  func TestService_seen(t *testing.T) {
   255  	ad1 := testutil.HydrateAttestationData(&ethpb.AttestationData{Slot: 1})
   256  
   257  	ad2 := testutil.HydrateAttestationData(&ethpb.AttestationData{Slot: 2})
   258  
   259  	// Attestation are checked in order of this list.
   260  	tests := []struct {
   261  		att  *ethpb.Attestation
   262  		want bool
   263  	}{
   264  		{
   265  			att: &ethpb.Attestation{
   266  				AggregationBits: bitfield.Bitlist{0b11011},
   267  				Data:            ad1,
   268  			},
   269  			want: false,
   270  		},
   271  		{
   272  			att: &ethpb.Attestation{
   273  				AggregationBits: bitfield.Bitlist{0b11011},
   274  				Data:            ad1,
   275  			},
   276  			want: true, // Exact same attestation should return true
   277  		},
   278  		{
   279  			att: &ethpb.Attestation{
   280  				AggregationBits: bitfield.Bitlist{0b10101},
   281  				Data:            ad1,
   282  			},
   283  			want: false, // Haven't seen the bit at index 2 yet.
   284  		},
   285  		{
   286  			att: &ethpb.Attestation{
   287  				AggregationBits: bitfield.Bitlist{0b11111},
   288  				Data:            ad1,
   289  			},
   290  			want: true, // We've full committee at this point.
   291  		},
   292  		{
   293  			att: &ethpb.Attestation{
   294  				AggregationBits: bitfield.Bitlist{0b11111},
   295  				Data:            ad2,
   296  			},
   297  			want: false, // Different root is different bitlist.
   298  		},
   299  		{
   300  			att: &ethpb.Attestation{
   301  				AggregationBits: bitfield.Bitlist{0b11111001},
   302  				Data:            ad1,
   303  			},
   304  			want: false, // Sanity test that an attestation of different lengths does not panic.
   305  		},
   306  	}
   307  
   308  	s, err := NewService(context.Background(), &Config{Pool: NewPool()})
   309  	require.NoError(t, err)
   310  
   311  	for i, tt := range tests {
   312  		t.Run(fmt.Sprintf("%d", i), func(t *testing.T) {
   313  			got, err := s.seen(tt.att)
   314  			require.NoError(t, err)
   315  			assert.Equal(t, tt.want, got)
   316  		})
   317  	}
   318  }