Skip to content

Commit

Permalink
EIP-7549 beacon spec (#13946)
Browse files Browse the repository at this point in the history
* EIP-7549 beacon spec

* reviews

* change signature of AttestingIndices
  • Loading branch information
rkapka authored May 7, 2024
1 parent 49f3531 commit 5f1b903
Show file tree
Hide file tree
Showing 22 changed files with 321 additions and 77 deletions.
2 changes: 1 addition & 1 deletion beacon-chain/blockchain/process_block.go
Original file line number Diff line number Diff line change
Expand Up @@ -370,7 +370,7 @@ func (s *Service) handleBlockAttestations(ctx context.Context, blk interfaces.Re
if err != nil {
return err
}
indices, err := attestation.AttestingIndices(a.GetAggregationBits(), committee)
indices, err := attestation.AttestingIndices(a, committee)
if err != nil {
return err
}
Expand Down
2 changes: 1 addition & 1 deletion beacon-chain/core/altair/attestation.go
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ func ProcessAttestationNoVerifySignature(
if err != nil {
return nil, err
}
indices, err := attestation.AttestingIndices(att.GetAggregationBits(), committee)
indices, err := attestation.AttestingIndices(att, committee)
if err != nil {
return nil, err
}
Expand Down
4 changes: 2 additions & 2 deletions beacon-chain/core/altair/attestation_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -215,7 +215,7 @@ func TestProcessAttestations_OK(t *testing.T) {

committee, err := helpers.BeaconCommitteeFromState(context.Background(), beaconState, att.Data.Slot, att.Data.CommitteeIndex)
require.NoError(t, err)
attestingIndices, err := attestation.AttestingIndices(att.AggregationBits, committee)
attestingIndices, err := attestation.AttestingIndices(att, committee)
require.NoError(t, err)
sigs := make([]bls.Signature, len(attestingIndices))
for i, indice := range attestingIndices {
Expand Down Expand Up @@ -273,7 +273,7 @@ func TestProcessAttestationNoVerify_SourceTargetHead(t *testing.T) {

committee, err := helpers.BeaconCommitteeFromState(context.Background(), beaconState, att.Data.Slot, att.Data.CommitteeIndex)
require.NoError(t, err)
indices, err := attestation.AttestingIndices(att.AggregationBits, committee)
indices, err := attestation.AttestingIndices(att, committee)
require.NoError(t, err)
for _, index := range indices {
has, err := altair.HasValidatorFlag(p[index], params.BeaconConfig().TimelyHeadFlagIndex)
Expand Down
2 changes: 1 addition & 1 deletion beacon-chain/core/altair/upgrade.go
Original file line number Diff line number Diff line change
Expand Up @@ -158,7 +158,7 @@ func TranslateParticipation(ctx context.Context, state state.BeaconState, atts [
if err != nil {
return nil, err
}
indices, err := attestation.AttestingIndices(att.AggregationBits, committee)
indices, err := attestation.AttestingIndices(att, committee)
if err != nil {
return nil, err
}
Expand Down
2 changes: 1 addition & 1 deletion beacon-chain/core/altair/upgrade_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ func TestTranslateParticipation(t *testing.T) {

committee, err := helpers.BeaconCommitteeFromState(ctx, s, pendingAtts[0].Data.Slot, pendingAtts[0].Data.CommitteeIndex)
require.NoError(t, err)
indices, err := attestation.AttestingIndices(pendingAtts[0].AggregationBits, committee)
indices, err := attestation.AttestingIndices(pendingAtts[0], committee)
require.NoError(t, err)
for _, index := range indices {
has, err := altair.HasValidatorFlag(participation[index], params.BeaconConfig().TimelySourceFlagIndex)
Expand Down
59 changes: 45 additions & 14 deletions beacon-chain/core/blocks/attestation.go
Original file line number Diff line number Diff line change
Expand Up @@ -107,22 +107,53 @@ func VerifyAttestationNoVerifySignature(
return err
}
c := helpers.SlotCommitteeCount(activeValidatorCount)
if uint64(att.GetData().CommitteeIndex) >= c {
return fmt.Errorf("committee index %d >= committee count %d", att.GetData().CommitteeIndex, c)
}

if err := helpers.VerifyAttestationBitfieldLengths(ctx, beaconState, att); err != nil {
return errors.Wrap(err, "could not verify attestation bitfields")
}
var indexedAtt ethpb.IndexedAtt

// Verify attesting indices are correct.
committee, err := helpers.BeaconCommitteeFromState(ctx, beaconState, att.GetData().Slot, att.GetData().CommitteeIndex)
if err != nil {
return err
}
indexedAtt, err := attestation.ConvertToIndexed(ctx, att, committee)
if err != nil {
return err
if att.Version() < version.Electra {
if uint64(att.GetData().CommitteeIndex) >= c {
return fmt.Errorf("committee index %d >= committee count %d", att.GetData().CommitteeIndex, c)
}

if err = helpers.VerifyAttestationBitfieldLengths(ctx, beaconState, att); err != nil {
return errors.Wrap(err, "could not verify attestation bitfields")
}

// Verify attesting indices are correct.
committee, err := helpers.BeaconCommitteeFromState(ctx, beaconState, att.GetData().Slot, att.GetData().CommitteeIndex)
if err != nil {
return err
}
indexedAtt, err = attestation.ConvertToIndexed(ctx, att, committee)
if err != nil {
return err
}
} else {
if att.GetData().CommitteeIndex != 0 {
return errors.New("committee index must be 0 post-Electra")
}

committeeIndices := att.GetCommitteeBitsVal().BitIndices()
committees := make([][]primitives.ValidatorIndex, len(committeeIndices))
participantsCount := 0
var err error
for i, ci := range committeeIndices {
if uint64(ci) >= c {
return fmt.Errorf("committee index %d >= committee count %d", ci, c)
}
committees[i], err = helpers.BeaconCommitteeFromState(ctx, beaconState, att.GetData().Slot, primitives.CommitteeIndex(ci))
if err != nil {
return err
}
participantsCount += len(committees[i])
}
if att.GetAggregationBits().Len() != uint64(participantsCount) {
return fmt.Errorf("aggregation bits count %d is different than participant count %d", att.GetAggregationBits().Len(), participantsCount)
}
indexedAtt, err = attestation.ConvertToIndexed(ctx, att, committees...)
if err != nil {
return err
}
}

return attestation.IsValidAttestationIndices(ctx, indexedAtt)
Expand Down
81 changes: 79 additions & 2 deletions beacon-chain/core/blocks/attestation_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ func TestProcessAggregatedAttestation_OverlappingBits(t *testing.T) {

committee, err := helpers.BeaconCommitteeFromState(context.Background(), beaconState, att1.Data.Slot, att1.Data.CommitteeIndex)
require.NoError(t, err)
attestingIndices1, err := attestation.AttestingIndices(att1.AggregationBits, committee)
attestingIndices1, err := attestation.AttestingIndices(att1, committee)
require.NoError(t, err)
sigs := make([]bls.Signature, len(attestingIndices1))
for i, indice := range attestingIndices1 {
Expand All @@ -67,7 +67,7 @@ func TestProcessAggregatedAttestation_OverlappingBits(t *testing.T) {

committee, err = helpers.BeaconCommitteeFromState(context.Background(), beaconState, att2.Data.Slot, att2.Data.CommitteeIndex)
require.NoError(t, err)
attestingIndices2, err := attestation.AttestingIndices(att2.AggregationBits, committee)
attestingIndices2, err := attestation.AttestingIndices(att2, committee)
require.NoError(t, err)
sigs = make([]bls.Signature, len(attestingIndices2))
for i, indice := range attestingIndices2 {
Expand Down Expand Up @@ -222,6 +222,83 @@ func TestVerifyAttestationNoVerifySignature_BadAttIdx(t *testing.T) {
require.ErrorContains(t, "committee index 100 >= committee count 1", err)
}

func TestVerifyAttestationNoVerifySignature_Electra(t *testing.T) {
var mockRoot [32]byte
copy(mockRoot[:], "hello-world")
var zeroSig [fieldparams.BLSSignatureLength]byte

beaconState, _ := util.DeterministicGenesisState(t, 100)
err := beaconState.SetSlot(beaconState.Slot() + params.BeaconConfig().MinAttestationInclusionDelay)
require.NoError(t, err)
ckp := beaconState.CurrentJustifiedCheckpoint()
copy(ckp.Root, "hello-world")
require.NoError(t, beaconState.SetCurrentJustifiedCheckpoint(ckp))
require.NoError(t, beaconState.AppendCurrentEpochAttestations(&ethpb.PendingAttestation{}))

t.Run("ok", func(t *testing.T) {
aggBits := bitfield.NewBitlist(3)
aggBits.SetBitAt(1, true)
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.NoError(t, err)
})
t.Run("non-zero committee index", func(t *testing.T) {
att := &ethpb.AttestationElectra{
Data: &ethpb.AttestationData{
Source: &ethpb.Checkpoint{Epoch: 0, Root: mockRoot[:]},
Target: &ethpb.Checkpoint{Epoch: 0, Root: make([]byte, 32)},
CommitteeIndex: 1,
},
AggregationBits: bitfield.NewBitlist(1),
CommitteeBits: bitfield.NewBitvector64(),
}
err = blocks.VerifyAttestationNoVerifySignature(context.TODO(), beaconState, att)
assert.ErrorContains(t, "committee index must be 0 post-Electra", err)
})
t.Run("index of committee too big", func(t *testing.T) {
aggBits := bitfield.NewBitlist(3)
committeeBits := bitfield.NewBitvector64()
committeeBits.SetBitAt(63, 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, "committee index 63 >= committee count 1", err)
})
t.Run("wrong aggregation bits count", func(t *testing.T) {
aggBits := bitfield.NewBitlist(123)
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, "aggregation bits count 123 is different than participant count 3", err)
})
}

func TestConvertToIndexed_OK(t *testing.T) {
helpers.ClearCache()
validators := make([]*ethpb.Validator, 2*params.BeaconConfig().SlotsPerEpoch)
Expand Down
2 changes: 1 addition & 1 deletion beacon-chain/core/epoch/epoch_processing.go
Original file line number Diff line number Diff line change
Expand Up @@ -474,7 +474,7 @@ func UnslashedAttestingIndices(ctx context.Context, state state.ReadOnlyBeaconSt
if err != nil {
return nil, err
}
attestingIndices, err := attestation.AttestingIndices(att.AggregationBits, committee)
attestingIndices, err := attestation.AttestingIndices(att, committee)
if err != nil {
return nil, err
}
Expand Down
2 changes: 1 addition & 1 deletion beacon-chain/core/epoch/precompute/attestation.go
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ func ProcessAttestations(
if err != nil {
return nil, nil, err
}
indices, err := attestation.AttestingIndices(a.AggregationBits, committee)
indices, err := attestation.AttestingIndices(a, committee)
if err != nil {
return nil, nil, err
}
Expand Down
4 changes: 2 additions & 2 deletions beacon-chain/core/epoch/precompute/attestation_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -211,7 +211,7 @@ func TestProcessAttestations(t *testing.T) {

committee, err := helpers.BeaconCommitteeFromState(context.Background(), beaconState, att1.Data.Slot, att1.Data.CommitteeIndex)
require.NoError(t, err)
indices, err := attestation.AttestingIndices(att1.AggregationBits, committee)
indices, err := attestation.AttestingIndices(att1, committee)
require.NoError(t, err)
for _, i := range indices {
if !pVals[i].IsPrevEpochAttester {
Expand All @@ -220,7 +220,7 @@ func TestProcessAttestations(t *testing.T) {
}
committee, err = helpers.BeaconCommitteeFromState(context.Background(), beaconState, att2.Data.Slot, att2.Data.CommitteeIndex)
require.NoError(t, err)
indices, err = attestation.AttestingIndices(att2.AggregationBits, committee)
indices, err = attestation.AttestingIndices(att2, committee)
require.NoError(t, err)
for _, i := range indices {
assert.Equal(t, true, pVals[i].IsPrevEpochAttester, "Not a prev epoch attester")
Expand Down
15 changes: 15 additions & 0 deletions beacon-chain/core/helpers/beacon_committee.go
Original file line number Diff line number Diff line change
Expand Up @@ -295,6 +295,21 @@ func ShuffledIndices(s state.ReadOnlyBeaconState, epoch primitives.Epoch) ([]pri
return UnshuffleList(indices, seed)
}

// CommitteeIndices return beacon committee indices corresponding to bits that are set on the argument bitfield.
//
// Spec pseudocode definition:
//
// def get_committee_indices(committee_bits: Bitvector) -> Sequence[CommitteeIndex]:
// return [CommitteeIndex(index) for index, bit in enumerate(committee_bits) if bit]
func CommitteeIndices(committeeBits bitfield.Bitfield) []primitives.CommitteeIndex {
indices := committeeBits.BitIndices()
committeeIndices := make([]primitives.CommitteeIndex, len(indices))
for i, ix := range indices {
committeeIndices[i] = primitives.CommitteeIndex(uint64(ix))
}
return committeeIndices
}

// UpdateCommitteeCache gets called at the beginning of every epoch to cache the committee shuffled indices
// list with committee index and epoch number. It caches the shuffled indices for the input epoch.
func UpdateCommitteeCache(ctx context.Context, state state.ReadOnlyBeaconState, e primitives.Epoch) error {
Expand Down
9 changes: 9 additions & 0 deletions beacon-chain/core/helpers/beacon_committee_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -699,3 +699,12 @@ func TestPrecomputeProposerIndices_Ok(t *testing.T) {
}
assert.DeepEqual(t, wantedProposerIndices, proposerIndices, "Did not precompute proposer indices correctly")
}

func TestCommitteeIndices(t *testing.T) {
bitfield := bitfield.NewBitvector4()
bitfield.SetBitAt(0, true)
bitfield.SetBitAt(1, true)
bitfield.SetBitAt(3, true)
indices := helpers.CommitteeIndices(bitfield)
assert.DeepEqual(t, []primitives.CommitteeIndex{0, 1, 3}, indices)
}
2 changes: 1 addition & 1 deletion beacon-chain/core/transition/transition_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -311,7 +311,7 @@ func createFullBlockWithOperations(t *testing.T) (state.BeaconState,

committee, err := helpers.BeaconCommitteeFromState(context.Background(), beaconState, blockAtt.Data.Slot, blockAtt.Data.CommitteeIndex)
assert.NoError(t, err)
attestingIndices, err := attestation.AttestingIndices(blockAtt.AggregationBits, committee)
attestingIndices, err := attestation.AttestingIndices(blockAtt, committee)
require.NoError(t, err)
assert.NoError(t, err)
hashTreeRoot, err = signing.ComputeSigningRoot(blockAtt.Data, domain)
Expand Down
2 changes: 1 addition & 1 deletion beacon-chain/monitor/process_attestation.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ func attestingIndices(ctx context.Context, state state.BeaconState, att interfac
if err != nil {
return nil, err
}
return attestation.AttestingIndices(att.GetAggregationBits(), committee)
return attestation.AttestingIndices(att, committee)
}

// logMessageTimelyFlagsForIndex returns the log message with performance info for the attestation (head, source, target)
Expand Down
2 changes: 1 addition & 1 deletion beacon-chain/rpc/prysm/v1alpha1/debug/block.go
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ func (ds *Server) GetInclusionSlot(ctx context.Context, req *pbrpc.InclusionSlot
if err != nil {
return nil, status.Errorf(codes.Internal, "Could not get committee: %v", err)
}
indices, err := attestation.AttestingIndices(a.GetAggregationBits(), c)
indices, err := attestation.AttestingIndices(a, c)
if err != nil {
return nil, err
}
Expand Down
4 changes: 2 additions & 2 deletions beacon-chain/rpc/prysm/v1alpha1/validator/aggregator_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -227,7 +227,7 @@ func generateAtt(state state.ReadOnlyBeaconState, index uint64, privKeys []bls.S
if err != nil {
return nil, err
}
attestingIndices, err := attestation.AttestingIndices(att.AggregationBits, committee)
attestingIndices, err := attestation.AttestingIndices(att, committee)
if err != nil {
return nil, err
}
Expand Down Expand Up @@ -266,7 +266,7 @@ func generateUnaggregatedAtt(state state.ReadOnlyBeaconState, index uint64, priv
if err != nil {
return nil, err
}
attestingIndices, err := attestation.AttestingIndices(att.AggregationBits, committee)
attestingIndices, err := attestation.AttestingIndices(att, committee)
if err != nil {
return nil, err
}
Expand Down
2 changes: 1 addition & 1 deletion beacon-chain/rpc/prysm/v1alpha1/validator/proposer_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2440,7 +2440,7 @@ func TestProposer_FilterAttestation(t *testing.T) {
})
committee, err := helpers.BeaconCommitteeFromState(context.Background(), st, atts[i].GetData().Slot, atts[i].GetData().CommitteeIndex)
assert.NoError(t, err)
attestingIndices, err := attestation.AttestingIndices(atts[i].GetAggregationBits(), committee)
attestingIndices, err := attestation.AttestingIndices(atts[i], committee)
require.NoError(t, err)
assert.NoError(t, err)
domain, err := signing.Domain(st.Fork(), 0, params.BeaconConfig().DomainBeaconAttester, params.BeaconConfig().ZeroHash[:])
Expand Down
6 changes: 3 additions & 3 deletions beacon-chain/sync/pending_attestations_queue_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ func TestProcessPendingAtts_HasBlockSaveUnAggregatedAtt(t *testing.T) {

committee, err := helpers.BeaconCommitteeFromState(context.Background(), beaconState, att.Data.Slot, att.Data.CommitteeIndex)
assert.NoError(t, err)
attestingIndices, err := attestation.AttestingIndices(att.AggregationBits, committee)
attestingIndices, err := attestation.AttestingIndices(att, committee)
require.NoError(t, err)
attesterDomain, err := signing.Domain(beaconState.Fork(), 0, params.BeaconConfig().DomainBeaconAttester, beaconState.GenesisValidatorsRoot())
require.NoError(t, err)
Expand Down Expand Up @@ -205,7 +205,7 @@ func TestProcessPendingAtts_NoBroadcastWithBadSignature(t *testing.T) {
}
committee, err := helpers.BeaconCommitteeFromState(context.Background(), s, att.Data.Slot, att.Data.CommitteeIndex)
assert.NoError(t, err)
attestingIndices, err := attestation.AttestingIndices(att.AggregationBits, committee)
attestingIndices, err := attestation.AttestingIndices(att, committee)
require.NoError(t, err)
attesterDomain, err := signing.Domain(s.Fork(), 0, params.BeaconConfig().DomainBeaconAttester, s.GenesisValidatorsRoot())
require.NoError(t, err)
Expand Down Expand Up @@ -285,7 +285,7 @@ func TestProcessPendingAtts_HasBlockSaveAggregatedAtt(t *testing.T) {

committee, err := helpers.BeaconCommitteeFromState(context.Background(), beaconState, att.Data.Slot, att.Data.CommitteeIndex)
assert.NoError(t, err)
attestingIndices, err := attestation.AttestingIndices(att.AggregationBits, committee)
attestingIndices, err := attestation.AttestingIndices(att, committee)
require.NoError(t, err)
attesterDomain, err := signing.Domain(beaconState.Fork(), 0, params.BeaconConfig().DomainBeaconAttester, beaconState.GenesisValidatorsRoot())
require.NoError(t, err)
Expand Down
Loading

0 comments on commit 5f1b903

Please sign in to comment.