mirror of
https://github.com/OffchainLabs/prysm.git
synced 2026-01-09 23:48:06 -05:00
* Ran gopls modernize to fix everything go run golang.org/x/tools/gopls/internal/analysis/modernize/cmd/modernize@latest -fix -test ./... * Override rules_go provided dependency for golang.org/x/tools to v0.38.0. To update this, checked out rules_go, then ran `bazel run //go/tools/releaser -- upgrade-dep -mirror=false org_golang_x_tools` and copied the patches. * Fix buildtag violations and ignore buildtag violations in external * Introduce modernize analyzer package. * Add modernize "any" analyzer. * Fix violations of any analyzer * Add modernize "appendclipped" analyzer. * Fix violations of appendclipped * Add modernize "bloop" analyzer. * Add modernize "fmtappendf" analyzer. * Add modernize "forvar" analyzer. * Add modernize "mapsloop" analyzer. * Add modernize "minmax" analyzer. * Fix violations of minmax analyzer * Add modernize "omitzero" analyzer. * Add modernize "rangeint" analyzer. * Fix violations of rangeint. * Add modernize "reflecttypefor" analyzer. * Fix violations of reflecttypefor analyzer. * Add modernize "slicescontains" analyzer. * Add modernize "slicessort" analyzer. * Add modernize "slicesdelete" analyzer. This is disabled by default for now. See https://go.dev/issue/73686. * Add modernize "stringscutprefix" analyzer. * Add modernize "stringsbuilder" analyzer. * Fix violations of stringsbuilder analyzer. * Add modernize "stringsseq" analyzer. * Add modernize "testingcontext" analyzer. * Add modernize "waitgroup" analyzer. * Changelog fragment * gofmt * gazelle * Add modernize "newexpr" analyzer. * Disable newexpr until go1.26 * Add more details in WORKSPACE on how to update the override * @nalepae feedback on min() * gofmt * Fix violations of forvar
474 lines
12 KiB
Go
474 lines
12 KiB
Go
package attestation_test
|
|
|
|
import (
|
|
"testing"
|
|
|
|
"github.com/OffchainLabs/go-bitfield"
|
|
fieldparams "github.com/OffchainLabs/prysm/v7/config/fieldparams"
|
|
"github.com/OffchainLabs/prysm/v7/config/params"
|
|
"github.com/OffchainLabs/prysm/v7/consensus-types/primitives"
|
|
eth "github.com/OffchainLabs/prysm/v7/proto/prysm/v1alpha1"
|
|
"github.com/OffchainLabs/prysm/v7/proto/prysm/v1alpha1/attestation"
|
|
"github.com/OffchainLabs/prysm/v7/testing/assert"
|
|
"github.com/OffchainLabs/prysm/v7/testing/require"
|
|
)
|
|
|
|
func TestAttestingIndices(t *testing.T) {
|
|
type args struct {
|
|
att eth.Att
|
|
committees [][]primitives.ValidatorIndex
|
|
}
|
|
tests := []struct {
|
|
name string
|
|
args args
|
|
want []uint64
|
|
err string
|
|
}{
|
|
{
|
|
name: "Full committee attested",
|
|
args: args{
|
|
att: ð.Attestation{AggregationBits: bitfield.Bitlist{0b1111}},
|
|
committees: [][]primitives.ValidatorIndex{{0, 1, 2}},
|
|
},
|
|
want: []uint64{0, 1, 2},
|
|
},
|
|
{
|
|
name: "Partial committee attested",
|
|
args: args{
|
|
att: ð.Attestation{AggregationBits: bitfield.Bitlist{0b1101}},
|
|
committees: [][]primitives.ValidatorIndex{{0, 1, 2}},
|
|
},
|
|
want: []uint64{0, 2},
|
|
},
|
|
{
|
|
name: "Invalid bit length",
|
|
args: args{
|
|
att: ð.Attestation{AggregationBits: bitfield.Bitlist{0b11111}},
|
|
committees: [][]primitives.ValidatorIndex{{0, 1, 2}},
|
|
},
|
|
err: "bitfield length 4 is not equal to committee length 3",
|
|
},
|
|
{
|
|
name: "Electra - Full committee attested",
|
|
args: args{
|
|
att: ð.AttestationElectra{AggregationBits: bitfield.Bitlist{0b11111}},
|
|
committees: [][]primitives.ValidatorIndex{{0, 1}, {2, 3}},
|
|
},
|
|
want: []uint64{0, 1, 2, 3},
|
|
},
|
|
{
|
|
name: "Electra - Partial committee attested",
|
|
args: args{
|
|
att: ð.AttestationElectra{AggregationBits: bitfield.Bitlist{0b10110}},
|
|
committees: [][]primitives.ValidatorIndex{{0, 1}, {2, 3}},
|
|
},
|
|
want: []uint64{1, 2},
|
|
},
|
|
{
|
|
name: "Electra - Invalid bit length",
|
|
args: args{
|
|
att: ð.AttestationElectra{AggregationBits: bitfield.Bitlist{0b111111}},
|
|
committees: [][]primitives.ValidatorIndex{{0, 1}, {2, 3}},
|
|
},
|
|
err: "bitfield length 5 is not equal to committee length 4",
|
|
},
|
|
{
|
|
name: "Electra - No duplicates",
|
|
args: args{
|
|
att: ð.AttestationElectra{AggregationBits: bitfield.Bitlist{0b11111}},
|
|
committees: [][]primitives.ValidatorIndex{{0, 1}, {0, 1}},
|
|
},
|
|
want: []uint64{0, 1},
|
|
},
|
|
{
|
|
name: "Electra - No attester in committee",
|
|
args: args{
|
|
att: ð.AttestationElectra{AggregationBits: bitfield.Bitlist{0b11100}},
|
|
committees: [][]primitives.ValidatorIndex{{0, 1}, {0, 1}},
|
|
},
|
|
err: "no attesting indices found for committee index 0",
|
|
},
|
|
}
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
got, err := attestation.AttestingIndices(tt.args.att, tt.args.committees...)
|
|
if tt.err == "" {
|
|
require.NoError(t, err)
|
|
assert.DeepEqual(t, tt.want, got)
|
|
} else {
|
|
require.ErrorContains(t, tt.err, err)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestIsValidAttestationIndices(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
att eth.IndexedAtt
|
|
wantedErr string
|
|
}{
|
|
{
|
|
name: "Indices should not be nil",
|
|
att: ð.IndexedAttestation{
|
|
Data: ð.AttestationData{
|
|
Target: ð.Checkpoint{},
|
|
Source: ð.Checkpoint{},
|
|
},
|
|
Signature: make([]byte, fieldparams.BLSSignatureLength),
|
|
},
|
|
wantedErr: "expected non-empty attesting indices",
|
|
},
|
|
{
|
|
name: "Indices should be non-empty",
|
|
att: ð.IndexedAttestation{
|
|
AttestingIndices: []uint64{},
|
|
Data: ð.AttestationData{
|
|
Target: ð.Checkpoint{},
|
|
Source: ð.Checkpoint{},
|
|
},
|
|
Signature: make([]byte, fieldparams.BLSSignatureLength),
|
|
},
|
|
wantedErr: "expected non-empty",
|
|
},
|
|
{
|
|
name: "Greater than max validators per committee",
|
|
att: ð.IndexedAttestation{
|
|
AttestingIndices: make([]uint64, params.BeaconConfig().MaxValidatorsPerCommittee+1),
|
|
Data: ð.AttestationData{
|
|
Target: ð.Checkpoint{},
|
|
Source: ð.Checkpoint{},
|
|
},
|
|
Signature: make([]byte, fieldparams.BLSSignatureLength),
|
|
},
|
|
wantedErr: "indices count exceeds",
|
|
},
|
|
{
|
|
name: "Needs to be sorted",
|
|
att: ð.IndexedAttestation{
|
|
AttestingIndices: []uint64{3, 2, 1},
|
|
Data: ð.AttestationData{
|
|
Target: ð.Checkpoint{},
|
|
Source: ð.Checkpoint{},
|
|
},
|
|
Signature: make([]byte, fieldparams.BLSSignatureLength),
|
|
},
|
|
wantedErr: "not uniquely sorted",
|
|
},
|
|
{
|
|
name: "Valid indices",
|
|
att: ð.IndexedAttestation{
|
|
AttestingIndices: []uint64{1, 2, 3},
|
|
Data: ð.AttestationData{
|
|
Target: ð.Checkpoint{},
|
|
Source: ð.Checkpoint{},
|
|
},
|
|
Signature: make([]byte, fieldparams.BLSSignatureLength),
|
|
},
|
|
},
|
|
{
|
|
name: "Valid indices with length of 2",
|
|
att: ð.IndexedAttestation{
|
|
AttestingIndices: []uint64{1, 2},
|
|
Data: ð.AttestationData{
|
|
Target: ð.Checkpoint{},
|
|
Source: ð.Checkpoint{},
|
|
},
|
|
Signature: make([]byte, fieldparams.BLSSignatureLength),
|
|
},
|
|
},
|
|
{
|
|
name: "Valid indices with length of 1",
|
|
att: ð.IndexedAttestation{
|
|
AttestingIndices: []uint64{1},
|
|
Data: ð.AttestationData{
|
|
Target: ð.Checkpoint{},
|
|
Source: ð.Checkpoint{},
|
|
},
|
|
Signature: make([]byte, fieldparams.BLSSignatureLength),
|
|
},
|
|
},
|
|
{
|
|
name: "Electra - Greater than max validators per slot",
|
|
att: ð.IndexedAttestationElectra{
|
|
AttestingIndices: make([]uint64, params.BeaconConfig().MaxValidatorsPerCommittee*params.BeaconConfig().MaxCommitteesPerSlot+1),
|
|
Data: ð.AttestationData{
|
|
Target: ð.Checkpoint{},
|
|
Source: ð.Checkpoint{},
|
|
},
|
|
Signature: make([]byte, fieldparams.BLSSignatureLength),
|
|
},
|
|
wantedErr: "indices count exceeds",
|
|
},
|
|
}
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
err := attestation.IsValidAttestationIndices(t.Context(), tt.att, params.BeaconConfig().MaxValidatorsPerCommittee, params.BeaconConfig().MaxCommitteesPerSlot)
|
|
if tt.wantedErr != "" {
|
|
assert.ErrorContains(t, tt.wantedErr, err)
|
|
} else {
|
|
assert.NoError(t, err)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func BenchmarkAttestingIndices_PartialCommittee(b *testing.B) {
|
|
bf := bitfield.Bitlist{0b11111111, 0b11111111, 0b10000111, 0b11111111, 0b100}
|
|
committee := []primitives.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}
|
|
|
|
for b.Loop() {
|
|
_, err := attestation.AttestingIndices(ð.Attestation{AggregationBits: bf}, committee)
|
|
require.NoError(b, err)
|
|
}
|
|
}
|
|
|
|
func BenchmarkIsValidAttestationIndices(b *testing.B) {
|
|
indices := make([]uint64, params.BeaconConfig().MaxValidatorsPerCommittee)
|
|
for i := range indices {
|
|
indices[i] = uint64(i)
|
|
}
|
|
att := ð.IndexedAttestation{
|
|
AttestingIndices: indices,
|
|
Data: ð.AttestationData{
|
|
Target: ð.Checkpoint{},
|
|
Source: ð.Checkpoint{},
|
|
},
|
|
Signature: make([]byte, fieldparams.BLSSignatureLength),
|
|
}
|
|
|
|
for b.Loop() {
|
|
if err := attestation.IsValidAttestationIndices(b.Context(), att, params.BeaconConfig().MaxValidatorsPerCommittee, params.BeaconConfig().MaxCommitteesPerSlot); err != nil {
|
|
require.NoError(b, err)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestAttDataIsEqual(t *testing.T) {
|
|
type test struct {
|
|
name string
|
|
attData1 *eth.AttestationData
|
|
attData2 *eth.AttestationData
|
|
equal bool
|
|
}
|
|
tests := []test{
|
|
{
|
|
name: "same",
|
|
attData1: ð.AttestationData{
|
|
Slot: 5,
|
|
CommitteeIndex: 2,
|
|
BeaconBlockRoot: []byte("great block"),
|
|
Source: ð.Checkpoint{
|
|
Epoch: 4,
|
|
Root: []byte("good source"),
|
|
},
|
|
Target: ð.Checkpoint{
|
|
Epoch: 10,
|
|
Root: []byte("good target"),
|
|
},
|
|
},
|
|
attData2: ð.AttestationData{
|
|
Slot: 5,
|
|
CommitteeIndex: 2,
|
|
BeaconBlockRoot: []byte("great block"),
|
|
Source: ð.Checkpoint{
|
|
Epoch: 4,
|
|
Root: []byte("good source"),
|
|
},
|
|
Target: ð.Checkpoint{
|
|
Epoch: 10,
|
|
Root: []byte("good target"),
|
|
},
|
|
},
|
|
equal: true,
|
|
},
|
|
{
|
|
name: "diff slot",
|
|
attData1: ð.AttestationData{
|
|
Slot: 5,
|
|
CommitteeIndex: 2,
|
|
BeaconBlockRoot: []byte("great block"),
|
|
Source: ð.Checkpoint{
|
|
Epoch: 4,
|
|
Root: []byte("good source"),
|
|
},
|
|
Target: ð.Checkpoint{
|
|
Epoch: 10,
|
|
Root: []byte("good target"),
|
|
},
|
|
},
|
|
attData2: ð.AttestationData{
|
|
Slot: 4,
|
|
CommitteeIndex: 2,
|
|
BeaconBlockRoot: []byte("great block"),
|
|
Source: ð.Checkpoint{
|
|
Epoch: 4,
|
|
Root: []byte("good source"),
|
|
},
|
|
Target: ð.Checkpoint{
|
|
Epoch: 10,
|
|
Root: []byte("good target"),
|
|
},
|
|
},
|
|
},
|
|
{
|
|
name: "diff block",
|
|
attData1: ð.AttestationData{
|
|
Slot: 5,
|
|
CommitteeIndex: 2,
|
|
BeaconBlockRoot: []byte("good block"),
|
|
Source: ð.Checkpoint{
|
|
Epoch: 4,
|
|
Root: []byte("good source"),
|
|
},
|
|
Target: ð.Checkpoint{
|
|
Epoch: 10,
|
|
Root: []byte("good target"),
|
|
},
|
|
},
|
|
attData2: ð.AttestationData{
|
|
Slot: 5,
|
|
CommitteeIndex: 2,
|
|
BeaconBlockRoot: []byte("great block"),
|
|
Source: ð.Checkpoint{
|
|
Epoch: 4,
|
|
Root: []byte("good source"),
|
|
},
|
|
Target: ð.Checkpoint{
|
|
Epoch: 10,
|
|
Root: []byte("good target"),
|
|
},
|
|
},
|
|
},
|
|
{
|
|
name: "diff source root",
|
|
attData1: ð.AttestationData{
|
|
Slot: 5,
|
|
CommitteeIndex: 2,
|
|
BeaconBlockRoot: []byte("great block"),
|
|
Source: ð.Checkpoint{
|
|
Epoch: 4,
|
|
Root: []byte("good source"),
|
|
},
|
|
Target: ð.Checkpoint{
|
|
Epoch: 10,
|
|
Root: []byte("good target"),
|
|
},
|
|
},
|
|
attData2: ð.AttestationData{
|
|
Slot: 5,
|
|
CommitteeIndex: 2,
|
|
BeaconBlockRoot: []byte("great block"),
|
|
Source: ð.Checkpoint{
|
|
Epoch: 4,
|
|
Root: []byte("bad source"),
|
|
},
|
|
Target: ð.Checkpoint{
|
|
Epoch: 10,
|
|
Root: []byte("good target"),
|
|
},
|
|
},
|
|
},
|
|
}
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
assert.Equal(t, tt.equal, attestation.AttDataIsEqual(tt.attData1, tt.attData2))
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestCheckPtIsEqual(t *testing.T) {
|
|
type test struct {
|
|
name string
|
|
checkPt1 *eth.Checkpoint
|
|
checkPt2 *eth.Checkpoint
|
|
equal bool
|
|
}
|
|
tests := []test{
|
|
{
|
|
name: "same",
|
|
checkPt1: ð.Checkpoint{
|
|
Epoch: 4,
|
|
Root: []byte("good source"),
|
|
},
|
|
checkPt2: ð.Checkpoint{
|
|
Epoch: 4,
|
|
Root: []byte("good source"),
|
|
},
|
|
equal: true,
|
|
},
|
|
{
|
|
name: "diff epoch",
|
|
checkPt1: ð.Checkpoint{
|
|
Epoch: 4,
|
|
Root: []byte("good source"),
|
|
},
|
|
checkPt2: ð.Checkpoint{
|
|
Epoch: 5,
|
|
Root: []byte("good source"),
|
|
},
|
|
equal: false,
|
|
},
|
|
{
|
|
name: "diff root",
|
|
checkPt1: ð.Checkpoint{
|
|
Epoch: 4,
|
|
Root: []byte("good source"),
|
|
},
|
|
checkPt2: ð.Checkpoint{
|
|
Epoch: 4,
|
|
Root: []byte("bad source"),
|
|
},
|
|
equal: false,
|
|
},
|
|
}
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
assert.Equal(t, tt.equal, attestation.CheckPointIsEqual(tt.checkPt1, tt.checkPt2))
|
|
})
|
|
}
|
|
}
|
|
|
|
func BenchmarkAttDataIsEqual(b *testing.B) {
|
|
attData1 := ð.AttestationData{
|
|
Slot: 5,
|
|
CommitteeIndex: 2,
|
|
BeaconBlockRoot: []byte("great block"),
|
|
Source: ð.Checkpoint{
|
|
Epoch: 4,
|
|
Root: []byte("good source"),
|
|
},
|
|
Target: ð.Checkpoint{
|
|
Epoch: 10,
|
|
Root: []byte("good target"),
|
|
},
|
|
}
|
|
attData2 := ð.AttestationData{
|
|
Slot: 5,
|
|
CommitteeIndex: 2,
|
|
BeaconBlockRoot: []byte("great block"),
|
|
Source: ð.Checkpoint{
|
|
Epoch: 4,
|
|
Root: []byte("good source"),
|
|
},
|
|
Target: ð.Checkpoint{
|
|
Epoch: 10,
|
|
Root: []byte("good target"),
|
|
},
|
|
}
|
|
|
|
b.Run("fast", func(b *testing.B) {
|
|
b.ReportAllocs()
|
|
for b.Loop() {
|
|
assert.Equal(b, true, attestation.AttDataIsEqual(attData1, attData2))
|
|
}
|
|
})
|
|
|
|
b.Run("proto.Equal", func(b *testing.B) {
|
|
b.ReportAllocs()
|
|
for b.Loop() {
|
|
assert.Equal(b, true, attestation.AttDataIsEqual(attData1, attData2))
|
|
}
|
|
})
|
|
}
|