github.com/prysmaticlabs/prysm@v1.4.4/shared/attestationutil/attestation_utils_test.go (about)

     1  package attestationutil_test
     2  
     3  import (
     4  	"context"
     5  	"testing"
     6  
     7  	types "github.com/prysmaticlabs/eth2-types"
     8  	"github.com/prysmaticlabs/go-bitfield"
     9  	eth "github.com/prysmaticlabs/prysm/proto/eth/v1alpha1"
    10  	"github.com/prysmaticlabs/prysm/shared/attestationutil"
    11  	"github.com/prysmaticlabs/prysm/shared/params"
    12  	"github.com/prysmaticlabs/prysm/shared/testutil/assert"
    13  	"github.com/prysmaticlabs/prysm/shared/testutil/require"
    14  )
    15  
    16  func TestAttestingIndices(t *testing.T) {
    17  	type args struct {
    18  		bf        bitfield.Bitfield
    19  		committee []types.ValidatorIndex
    20  	}
    21  	tests := []struct {
    22  		name string
    23  		args args
    24  		want []uint64
    25  		err  string
    26  	}{
    27  		{
    28  			name: "Full committee attested",
    29  			args: args{
    30  				bf:        bitfield.Bitlist{0b1111},
    31  				committee: []types.ValidatorIndex{0, 1, 2},
    32  			},
    33  			want: []uint64{0, 1, 2},
    34  		},
    35  		{
    36  			name: "Partial committee attested",
    37  			args: args{
    38  				bf:        bitfield.Bitlist{0b1101},
    39  				committee: []types.ValidatorIndex{0, 1, 2},
    40  			},
    41  			want: []uint64{0, 2},
    42  		},
    43  		{
    44  			name: "Invalid bit length",
    45  			args: args{
    46  				bf:        bitfield.Bitlist{0b11111},
    47  				committee: []types.ValidatorIndex{0, 1, 2},
    48  			},
    49  			err: "bitfield length 4 is not equal to committee length 3",
    50  		},
    51  	}
    52  	for _, tt := range tests {
    53  		t.Run(tt.name, func(t *testing.T) {
    54  			got, err := attestationutil.AttestingIndices(tt.args.bf, tt.args.committee)
    55  			if tt.err == "" {
    56  				require.NoError(t, err)
    57  				assert.DeepEqual(t, tt.want, got)
    58  			} else {
    59  				require.ErrorContains(t, tt.err, err)
    60  			}
    61  		})
    62  	}
    63  }
    64  
    65  func TestIsValidAttestationIndices(t *testing.T) {
    66  	tests := []struct {
    67  		name      string
    68  		att       *eth.IndexedAttestation
    69  		wantedErr string
    70  	}{
    71  		{
    72  			name: "Indices should not be nil",
    73  			att: &eth.IndexedAttestation{
    74  				Data: &eth.AttestationData{
    75  					Target: &eth.Checkpoint{},
    76  				},
    77  				Signature: make([]byte, 96),
    78  			},
    79  			wantedErr: "nil or missing indexed attestation data",
    80  		},
    81  		{
    82  			name: "Indices should be non-empty",
    83  			att: &eth.IndexedAttestation{
    84  				AttestingIndices: []uint64{},
    85  				Data: &eth.AttestationData{
    86  					Target: &eth.Checkpoint{},
    87  				},
    88  				Signature: make([]byte, 96),
    89  			},
    90  			wantedErr: "expected non-empty",
    91  		},
    92  		{
    93  			name: "Greater than max validators per committee",
    94  			att: &eth.IndexedAttestation{
    95  				AttestingIndices: make([]uint64, params.BeaconConfig().MaxValidatorsPerCommittee+1),
    96  				Data: &eth.AttestationData{
    97  					Target: &eth.Checkpoint{},
    98  				},
    99  				Signature: make([]byte, 96),
   100  			},
   101  			wantedErr: "indices count exceeds",
   102  		},
   103  		{
   104  			name: "Needs to be sorted",
   105  			att: &eth.IndexedAttestation{
   106  				AttestingIndices: []uint64{3, 2, 1},
   107  				Data: &eth.AttestationData{
   108  					Target: &eth.Checkpoint{},
   109  				},
   110  				Signature: make([]byte, 96),
   111  			},
   112  			wantedErr: "not uniquely sorted",
   113  		},
   114  		{
   115  			name: "Valid indices",
   116  			att: &eth.IndexedAttestation{
   117  				AttestingIndices: []uint64{1, 2, 3},
   118  				Data: &eth.AttestationData{
   119  					Target: &eth.Checkpoint{},
   120  				},
   121  				Signature: make([]byte, 96),
   122  			},
   123  		},
   124  		{
   125  			name: "Valid indices with length of 2",
   126  			att: &eth.IndexedAttestation{
   127  				AttestingIndices: []uint64{1, 2},
   128  				Data: &eth.AttestationData{
   129  					Target: &eth.Checkpoint{},
   130  				},
   131  				Signature: make([]byte, 96),
   132  			},
   133  		},
   134  		{
   135  			name: "Valid indices with length of 1",
   136  			att: &eth.IndexedAttestation{
   137  				AttestingIndices: []uint64{1},
   138  				Data: &eth.AttestationData{
   139  					Target: &eth.Checkpoint{},
   140  				},
   141  				Signature: make([]byte, 96),
   142  			},
   143  		},
   144  	}
   145  	for _, tt := range tests {
   146  		t.Run(tt.name, func(t *testing.T) {
   147  			err := attestationutil.IsValidAttestationIndices(context.Background(), tt.att)
   148  			if tt.wantedErr != "" {
   149  				assert.ErrorContains(t, tt.wantedErr, err)
   150  			} else {
   151  				assert.NoError(t, err)
   152  			}
   153  		})
   154  	}
   155  }
   156  
   157  func BenchmarkAttestingIndices_PartialCommittee(b *testing.B) {
   158  	bf := bitfield.Bitlist{0b11111111, 0b11111111, 0b10000111, 0b11111111, 0b100}
   159  	committee := []types.ValidatorIndex{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34}
   160  
   161  	b.ResetTimer()
   162  	for i := 0; i < b.N; i++ {
   163  		_, err := attestationutil.AttestingIndices(bf, committee)
   164  		require.NoError(b, err)
   165  	}
   166  }
   167  
   168  func BenchmarkIsValidAttestationIndices(b *testing.B) {
   169  	indices := make([]uint64, params.BeaconConfig().MaxValidatorsPerCommittee)
   170  	for i := 0; i < len(indices); i++ {
   171  		indices[i] = uint64(i)
   172  	}
   173  	att := &eth.IndexedAttestation{
   174  		AttestingIndices: indices,
   175  		Data: &eth.AttestationData{
   176  			Target: &eth.Checkpoint{},
   177  		},
   178  		Signature: make([]byte, 96),
   179  	}
   180  	b.ResetTimer()
   181  	for i := 0; i < b.N; i++ {
   182  		if err := attestationutil.IsValidAttestationIndices(context.Background(), att); err != nil {
   183  			require.NoError(b, err)
   184  		}
   185  	}
   186  }
   187  
   188  func TestAttDataIsEqual(t *testing.T) {
   189  	type test struct {
   190  		name     string
   191  		attData1 *eth.AttestationData
   192  		attData2 *eth.AttestationData
   193  		equal    bool
   194  	}
   195  	tests := []test{
   196  		{
   197  			name: "same",
   198  			attData1: &eth.AttestationData{
   199  				Slot:            5,
   200  				CommitteeIndex:  2,
   201  				BeaconBlockRoot: []byte("great block"),
   202  				Source: &eth.Checkpoint{
   203  					Epoch: 4,
   204  					Root:  []byte("good source"),
   205  				},
   206  				Target: &eth.Checkpoint{
   207  					Epoch: 10,
   208  					Root:  []byte("good target"),
   209  				},
   210  			},
   211  			attData2: &eth.AttestationData{
   212  				Slot:            5,
   213  				CommitteeIndex:  2,
   214  				BeaconBlockRoot: []byte("great block"),
   215  				Source: &eth.Checkpoint{
   216  					Epoch: 4,
   217  					Root:  []byte("good source"),
   218  				},
   219  				Target: &eth.Checkpoint{
   220  					Epoch: 10,
   221  					Root:  []byte("good target"),
   222  				},
   223  			},
   224  			equal: true,
   225  		},
   226  		{
   227  			name: "diff slot",
   228  			attData1: &eth.AttestationData{
   229  				Slot:            5,
   230  				CommitteeIndex:  2,
   231  				BeaconBlockRoot: []byte("great block"),
   232  				Source: &eth.Checkpoint{
   233  					Epoch: 4,
   234  					Root:  []byte("good source"),
   235  				},
   236  				Target: &eth.Checkpoint{
   237  					Epoch: 10,
   238  					Root:  []byte("good target"),
   239  				},
   240  			},
   241  			attData2: &eth.AttestationData{
   242  				Slot:            4,
   243  				CommitteeIndex:  2,
   244  				BeaconBlockRoot: []byte("great block"),
   245  				Source: &eth.Checkpoint{
   246  					Epoch: 4,
   247  					Root:  []byte("good source"),
   248  				},
   249  				Target: &eth.Checkpoint{
   250  					Epoch: 10,
   251  					Root:  []byte("good target"),
   252  				},
   253  			},
   254  		},
   255  		{
   256  			name: "diff block",
   257  			attData1: &eth.AttestationData{
   258  				Slot:            5,
   259  				CommitteeIndex:  2,
   260  				BeaconBlockRoot: []byte("good block"),
   261  				Source: &eth.Checkpoint{
   262  					Epoch: 4,
   263  					Root:  []byte("good source"),
   264  				},
   265  				Target: &eth.Checkpoint{
   266  					Epoch: 10,
   267  					Root:  []byte("good target"),
   268  				},
   269  			},
   270  			attData2: &eth.AttestationData{
   271  				Slot:            5,
   272  				CommitteeIndex:  2,
   273  				BeaconBlockRoot: []byte("great block"),
   274  				Source: &eth.Checkpoint{
   275  					Epoch: 4,
   276  					Root:  []byte("good source"),
   277  				},
   278  				Target: &eth.Checkpoint{
   279  					Epoch: 10,
   280  					Root:  []byte("good target"),
   281  				},
   282  			},
   283  		},
   284  		{
   285  			name: "diff source root",
   286  			attData1: &eth.AttestationData{
   287  				Slot:            5,
   288  				CommitteeIndex:  2,
   289  				BeaconBlockRoot: []byte("great block"),
   290  				Source: &eth.Checkpoint{
   291  					Epoch: 4,
   292  					Root:  []byte("good source"),
   293  				},
   294  				Target: &eth.Checkpoint{
   295  					Epoch: 10,
   296  					Root:  []byte("good target"),
   297  				},
   298  			},
   299  			attData2: &eth.AttestationData{
   300  				Slot:            5,
   301  				CommitteeIndex:  2,
   302  				BeaconBlockRoot: []byte("great block"),
   303  				Source: &eth.Checkpoint{
   304  					Epoch: 4,
   305  					Root:  []byte("bad source"),
   306  				},
   307  				Target: &eth.Checkpoint{
   308  					Epoch: 10,
   309  					Root:  []byte("good target"),
   310  				},
   311  			},
   312  		},
   313  	}
   314  	for _, tt := range tests {
   315  		t.Run(tt.name, func(t *testing.T) {
   316  			assert.Equal(t, tt.equal, attestationutil.AttDataIsEqual(tt.attData1, tt.attData2))
   317  		})
   318  	}
   319  }
   320  
   321  func TestCheckPtIsEqual(t *testing.T) {
   322  	type test struct {
   323  		name     string
   324  		checkPt1 *eth.Checkpoint
   325  		checkPt2 *eth.Checkpoint
   326  		equal    bool
   327  	}
   328  	tests := []test{
   329  		{
   330  			name: "same",
   331  			checkPt1: &eth.Checkpoint{
   332  				Epoch: 4,
   333  				Root:  []byte("good source"),
   334  			},
   335  			checkPt2: &eth.Checkpoint{
   336  				Epoch: 4,
   337  				Root:  []byte("good source"),
   338  			},
   339  			equal: true,
   340  		},
   341  		{
   342  			name: "diff epoch",
   343  			checkPt1: &eth.Checkpoint{
   344  				Epoch: 4,
   345  				Root:  []byte("good source"),
   346  			},
   347  			checkPt2: &eth.Checkpoint{
   348  				Epoch: 5,
   349  				Root:  []byte("good source"),
   350  			},
   351  			equal: false,
   352  		},
   353  		{
   354  			name: "diff root",
   355  			checkPt1: &eth.Checkpoint{
   356  				Epoch: 4,
   357  				Root:  []byte("good source"),
   358  			},
   359  			checkPt2: &eth.Checkpoint{
   360  				Epoch: 4,
   361  				Root:  []byte("bad source"),
   362  			},
   363  			equal: false,
   364  		},
   365  	}
   366  	for _, tt := range tests {
   367  		t.Run(tt.name, func(t *testing.T) {
   368  			assert.Equal(t, tt.equal, attestationutil.CheckPointIsEqual(tt.checkPt1, tt.checkPt2))
   369  		})
   370  	}
   371  }
   372  
   373  func BenchmarkAttDataIsEqual(b *testing.B) {
   374  	attData1 := &eth.AttestationData{
   375  		Slot:            5,
   376  		CommitteeIndex:  2,
   377  		BeaconBlockRoot: []byte("great block"),
   378  		Source: &eth.Checkpoint{
   379  			Epoch: 4,
   380  			Root:  []byte("good source"),
   381  		},
   382  		Target: &eth.Checkpoint{
   383  			Epoch: 10,
   384  			Root:  []byte("good target"),
   385  		},
   386  	}
   387  	attData2 := &eth.AttestationData{
   388  		Slot:            5,
   389  		CommitteeIndex:  2,
   390  		BeaconBlockRoot: []byte("great block"),
   391  		Source: &eth.Checkpoint{
   392  			Epoch: 4,
   393  			Root:  []byte("good source"),
   394  		},
   395  		Target: &eth.Checkpoint{
   396  			Epoch: 10,
   397  			Root:  []byte("good target"),
   398  		},
   399  	}
   400  
   401  	b.Run("fast", func(b *testing.B) {
   402  		b.ReportAllocs()
   403  		for i := 0; i < b.N; i++ {
   404  			assert.Equal(b, true, attestationutil.AttDataIsEqual(attData1, attData2))
   405  		}
   406  	})
   407  
   408  	b.Run("proto.Equal", func(b *testing.B) {
   409  		b.ReportAllocs()
   410  		for i := 0; i < b.N; i++ {
   411  			assert.Equal(b, true, attestationutil.AttDataIsEqual(attData1, attData2))
   412  		}
   413  	})
   414  }