Guard against no attesters within committee in VerifyAttestationNoVerifySignature (#15169)

* Guard against no attesters within committee in `VerifyAttestationNoVerifySignature`

* changelog fragment
This commit is contained in:
Radosław Kapka
2025-04-14 16:46:38 +02:00
committed by GitHub
parent cd87082f25
commit 6180b5a560
5 changed files with 52 additions and 8 deletions

View File

@@ -106,7 +106,7 @@ func VerifyAttestationNoVerifySignature(
if err != nil { if err != nil {
return err return err
} }
c := helpers.SlotCommitteeCount(activeValidatorCount) committeeCount := helpers.SlotCommitteeCount(activeValidatorCount)
var indexedAtt ethpb.IndexedAtt var indexedAtt ethpb.IndexedAtt
@@ -115,13 +115,14 @@ func VerifyAttestationNoVerifySignature(
return errors.New("committee index must be 0 post-Electra") return errors.New("committee index must be 0 post-Electra")
} }
aggBits := att.GetAggregationBits()
committeeIndices := att.CommitteeBitsVal().BitIndices() committeeIndices := att.CommitteeBitsVal().BitIndices()
committees := make([][]primitives.ValidatorIndex, len(committeeIndices)) committees := make([][]primitives.ValidatorIndex, len(committeeIndices))
participantsCount := 0 participantsCount := 0
var err error var err error
for i, ci := range committeeIndices { for i, ci := range committeeIndices {
if uint64(ci) >= c { if uint64(ci) >= committeeCount {
return fmt.Errorf("committee index %d >= committee count %d", ci, c) return fmt.Errorf("committee index %d >= committee count %d", ci, committeeCount)
} }
committees[i], err = helpers.BeaconCommitteeFromState(ctx, beaconState, att.GetData().Slot, primitives.CommitteeIndex(ci)) committees[i], err = helpers.BeaconCommitteeFromState(ctx, beaconState, att.GetData().Slot, primitives.CommitteeIndex(ci))
if err != nil { if err != nil {
@@ -129,16 +130,32 @@ func VerifyAttestationNoVerifySignature(
} }
participantsCount += len(committees[i]) participantsCount += len(committees[i])
} }
if att.GetAggregationBits().Len() != uint64(participantsCount) { if aggBits.Len() != uint64(participantsCount) {
return fmt.Errorf("aggregation bits count %d is different than participant count %d", att.GetAggregationBits().Len(), participantsCount) return fmt.Errorf("aggregation bits count %d is different than participant count %d", att.GetAggregationBits().Len(), participantsCount)
} }
committeeOffset := 0
for ci, c := range committees {
attesterFound := false
for i := range c {
if aggBits.BitAt(uint64(committeeOffset + i)) {
attesterFound = true
break
}
}
if !attesterFound {
return fmt.Errorf("no attesting indices found for committee index %d", ci)
}
committeeOffset += len(c)
}
indexedAtt, err = attestation.ConvertToIndexed(ctx, att, committees...) indexedAtt, err = attestation.ConvertToIndexed(ctx, att, committees...)
if err != nil { if err != nil {
return err return err
} }
} else { } else {
if uint64(att.GetData().CommitteeIndex) >= c { if uint64(att.GetData().CommitteeIndex) >= committeeCount {
return fmt.Errorf("committee index %d >= committee count %d", att.GetData().CommitteeIndex, c) return fmt.Errorf("committee index %d >= committee count %d", att.GetData().CommitteeIndex, committeeCount)
} }
// Verify attesting indices are correct. // Verify attesting indices are correct.

View File

@@ -296,6 +296,22 @@ func TestVerifyAttestationNoVerifySignature_Electra(t *testing.T) {
err = blocks.VerifyAttestationNoVerifySignature(context.TODO(), beaconState, att) err = blocks.VerifyAttestationNoVerifySignature(context.TODO(), beaconState, att)
assert.ErrorContains(t, "aggregation bits count 123 is different than participant count 3", err) assert.ErrorContains(t, "aggregation bits count 123 is different than participant count 3", err)
}) })
t.Run("no attester in committee", func(t *testing.T) {
aggBits := bitfield.NewBitlist(3)
committeeBits := bitfield.NewBitvector64()
committeeBits.SetBitAt(0, true)
att := &ethpb.AttestationElectra{
Data: &ethpb.AttestationData{
Source: &ethpb.Checkpoint{Epoch: 0, Root: mockRoot[:]},
Target: &ethpb.Checkpoint{Epoch: 0, Root: make([]byte, 32)},
},
AggregationBits: aggBits,
CommitteeBits: committeeBits,
}
att.Signature = zeroSig[:]
err = blocks.VerifyAttestationNoVerifySignature(context.TODO(), beaconState, att)
assert.ErrorContains(t, "no attesting indices found for committee index 0", err)
})
} }
func TestConvertToIndexed_OK(t *testing.T) { func TestConvertToIndexed_OK(t *testing.T) {

View File

@@ -0,0 +1,3 @@
### Fixed
- Guard against no attesters within committee in `VerifyAttestationNoVerifySignature`.

View File

@@ -111,7 +111,7 @@ func AttestingIndices(att ethpb.Att, committees ...[]primitives.ValidatorIndex)
attesters := make([]uint64, 0, aggBits.Count()) attesters := make([]uint64, 0, aggBits.Count())
committeeOffset := 0 committeeOffset := 0
for _, c := range committees { for ci, c := range committees {
committeeAttesters := make([]uint64, 0, len(c)) committeeAttesters := make([]uint64, 0, len(c))
for i, vi := range c { for i, vi := range c {
if aggBits.BitAt(uint64(committeeOffset + i)) { if aggBits.BitAt(uint64(committeeOffset + i)) {
@@ -119,7 +119,7 @@ func AttestingIndices(att ethpb.Att, committees ...[]primitives.ValidatorIndex)
} }
} }
if len(committeeAttesters) == 0 { if len(committeeAttesters) == 0 {
return nil, fmt.Errorf("no attesting indices found in committee %v", c) return nil, fmt.Errorf("no attesting indices found for committee index %d", ci)
} }
attesters = append(attesters, committeeAttesters...) attesters = append(attesters, committeeAttesters...)
committeeOffset += len(c) committeeOffset += len(c)

View File

@@ -81,6 +81,14 @@ func TestAttestingIndices(t *testing.T) {
}, },
want: []uint64{0, 1}, want: []uint64{0, 1},
}, },
{
name: "Electra - No attester in committee",
args: args{
att: &eth.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 { for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) { t.Run(tt.name, func(t *testing.T) {