Move attestation's source checkpoint validation to VerifyAttestationNoVerifySignature (#8598)

* Move attestation's source checkpoint validation to VerifyAttestationNoVerifySignature

* change parameter type to ReadOnlyBeaconState

Co-authored-by: terence tsao <terence@prysmaticlabs.com>
This commit is contained in:
Radosław Kapka 2021-03-12 22:43:20 +01:00 committed by GitHub
parent dc6dee3f4e
commit c577fbd772
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 65 additions and 24 deletions

View File

@ -103,35 +103,46 @@ func ProcessAttestationsNoVerifySignature(
// used before processing attestation with the beacon state. // used before processing attestation with the beacon state.
func VerifyAttestationNoVerifySignature( func VerifyAttestationNoVerifySignature(
ctx context.Context, ctx context.Context,
beaconState iface.BeaconState, beaconState iface.ReadOnlyBeaconState,
att *ethpb.Attestation, att *ethpb.Attestation,
) (iface.BeaconState, error) { ) error {
ctx, span := trace.StartSpan(ctx, "core.VerifyAttestationNoVerifySignature") ctx, span := trace.StartSpan(ctx, "core.VerifyAttestationNoVerifySignature")
defer span.End() defer span.End()
if err := helpers.ValidateNilAttestation(att); err != nil { if err := helpers.ValidateNilAttestation(att); err != nil {
return nil, err return err
} }
currEpoch := helpers.CurrentEpoch(beaconState) currEpoch := helpers.CurrentEpoch(beaconState)
prevEpoch := helpers.PrevEpoch(beaconState) prevEpoch := helpers.PrevEpoch(beaconState)
data := att.Data data := att.Data
if data.Target.Epoch != prevEpoch && data.Target.Epoch != currEpoch { if data.Target.Epoch != prevEpoch && data.Target.Epoch != currEpoch {
return nil, fmt.Errorf( return fmt.Errorf(
"expected target epoch (%d) to be the previous epoch (%d) or the current epoch (%d)", "expected target epoch (%d) to be the previous epoch (%d) or the current epoch (%d)",
data.Target.Epoch, data.Target.Epoch,
prevEpoch, prevEpoch,
currEpoch, currEpoch,
) )
} }
if data.Target.Epoch == currEpoch {
if !beaconState.MatchCurrentJustifiedCheckpoint(data.Source) {
return errors.New("source check point not equal to current justified checkpoint")
}
} else {
if !beaconState.MatchPreviousJustifiedCheckpoint(data.Source) {
return errors.New("source check point not equal to previous justified checkpoint")
}
}
if err := helpers.ValidateSlotTargetEpoch(att.Data); err != nil { if err := helpers.ValidateSlotTargetEpoch(att.Data); err != nil {
return nil, err return err
} }
s := att.Data.Slot s := att.Data.Slot
minInclusionCheck := s+params.BeaconConfig().MinAttestationInclusionDelay <= beaconState.Slot() minInclusionCheck := s+params.BeaconConfig().MinAttestationInclusionDelay <= beaconState.Slot()
epochInclusionCheck := beaconState.Slot() <= s+params.BeaconConfig().SlotsPerEpoch epochInclusionCheck := beaconState.Slot() <= s+params.BeaconConfig().SlotsPerEpoch
if !minInclusionCheck { if !minInclusionCheck {
return nil, fmt.Errorf( return fmt.Errorf(
"attestation slot %d + inclusion delay %d > state slot %d", "attestation slot %d + inclusion delay %d > state slot %d",
s, s,
params.BeaconConfig().MinAttestationInclusionDelay, params.BeaconConfig().MinAttestationInclusionDelay,
@ -139,7 +150,7 @@ func VerifyAttestationNoVerifySignature(
) )
} }
if !epochInclusionCheck { if !epochInclusionCheck {
return nil, fmt.Errorf( return fmt.Errorf(
"state slot %d > attestation slot %d + SLOTS_PER_EPOCH %d", "state slot %d > attestation slot %d + SLOTS_PER_EPOCH %d",
beaconState.Slot(), beaconState.Slot(),
s, s,
@ -148,28 +159,28 @@ func VerifyAttestationNoVerifySignature(
} }
activeValidatorCount, err := helpers.ActiveValidatorCount(beaconState, att.Data.Target.Epoch) activeValidatorCount, err := helpers.ActiveValidatorCount(beaconState, att.Data.Target.Epoch)
if err != nil { if err != nil {
return nil, err return err
} }
c := helpers.SlotCommitteeCount(activeValidatorCount) c := helpers.SlotCommitteeCount(activeValidatorCount)
if uint64(att.Data.CommitteeIndex) >= c { if uint64(att.Data.CommitteeIndex) >= c {
return nil, fmt.Errorf("committee index %d >= committee count %d", att.Data.CommitteeIndex, c) return fmt.Errorf("committee index %d >= committee count %d", att.Data.CommitteeIndex, c)
} }
if err := helpers.VerifyAttestationBitfieldLengths(beaconState, att); err != nil { if err := helpers.VerifyAttestationBitfieldLengths(beaconState, att); err != nil {
return nil, errors.Wrap(err, "could not verify attestation bitfields") return errors.Wrap(err, "could not verify attestation bitfields")
} }
// Verify attesting indices are correct. // Verify attesting indices are correct.
committee, err := helpers.BeaconCommitteeFromState(beaconState, att.Data.Slot, att.Data.CommitteeIndex) committee, err := helpers.BeaconCommitteeFromState(beaconState, att.Data.Slot, att.Data.CommitteeIndex)
if err != nil { if err != nil {
return nil, err return err
} }
indexedAtt, err := attestationutil.ConvertToIndexed(ctx, att, committee) indexedAtt, err := attestationutil.ConvertToIndexed(ctx, att, committee)
if err != nil { if err != nil {
return nil, err return err
} }
return nil, attestationutil.IsValidAttestationIndices(ctx, indexedAtt) return attestationutil.IsValidAttestationIndices(ctx, indexedAtt)
} }
// ProcessAttestationNoVerifySignature processes the attestation without verifying the attestation signature. This // ProcessAttestationNoVerifySignature processes the attestation without verifying the attestation signature. This
@ -182,7 +193,7 @@ func ProcessAttestationNoVerifySignature(
ctx, span := trace.StartSpan(ctx, "core.ProcessAttestationNoVerifySignature") ctx, span := trace.StartSpan(ctx, "core.ProcessAttestationNoVerifySignature")
defer span.End() defer span.End()
if _, err := VerifyAttestationNoVerifySignature(ctx, beaconState, att); err != nil { if err := VerifyAttestationNoVerifySignature(ctx, beaconState, att); err != nil {
return nil, err return nil, err
} }
@ -201,16 +212,10 @@ func ProcessAttestationNoVerifySignature(
} }
if data.Target.Epoch == currEpoch { if data.Target.Epoch == currEpoch {
if !beaconState.MatchCurrentJustifiedCheckpoint(data.Source) {
return nil, errors.New("source check point not equal to current justified checkpoint")
}
if err := beaconState.AppendCurrentEpochAttestations(pendingAtt); err != nil { if err := beaconState.AppendCurrentEpochAttestations(pendingAtt); err != nil {
return nil, err return nil, err
} }
} else { } else {
if !beaconState.MatchPreviousJustifiedCheckpoint(data.Source) {
return nil, errors.New("source check point not equal to previous justified checkpoint")
}
if err := beaconState.AppendPreviousEpochAttestations(pendingAtt); err != nil { if err := beaconState.AppendPreviousEpochAttestations(pendingAtt); err != nil {
return nil, err return nil, err
} }

View File

@ -6,9 +6,13 @@ import (
"testing" "testing"
ethpb "github.com/prysmaticlabs/ethereumapis/eth/v1alpha1" ethpb "github.com/prysmaticlabs/ethereumapis/eth/v1alpha1"
"github.com/prysmaticlabs/go-bitfield"
"github.com/prysmaticlabs/prysm/beacon-chain/core/blocks" "github.com/prysmaticlabs/prysm/beacon-chain/core/blocks"
"github.com/prysmaticlabs/prysm/beacon-chain/state" "github.com/prysmaticlabs/prysm/beacon-chain/state"
pb "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1" pb "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1"
"github.com/prysmaticlabs/prysm/shared/params"
"github.com/prysmaticlabs/prysm/shared/testutil"
"github.com/prysmaticlabs/prysm/shared/testutil/assert"
"github.com/prysmaticlabs/prysm/shared/testutil/require" "github.com/prysmaticlabs/prysm/shared/testutil/require"
) )
@ -42,3 +46,35 @@ func TestProcessAttestationNoVerifySignature_BeaconFuzzIssue78(t *testing.T) {
_, err = blocks.ProcessAttestationNoVerifySignature(ctx, st, att) _, err = blocks.ProcessAttestationNoVerifySignature(ctx, st, att)
require.ErrorContains(t, "committee index 1 >= committee count 1", err) require.ErrorContains(t, "committee index 1 >= committee count 1", err)
} }
// Regression introduced in https://github.com/prysmaticlabs/prysm/pull/8566.
func TestVerifyAttestationNoVerifySignature_IncorrectSourceEpoch(t *testing.T) {
// Attestation with an empty signature
beaconState, _ := testutil.DeterministicGenesisState(t, 100)
aggBits := bitfield.NewBitlist(3)
aggBits.SetBitAt(1, true)
var mockRoot [32]byte
copy(mockRoot[:], "hello-world")
att := &ethpb.Attestation{
Data: &ethpb.AttestationData{
Source: &ethpb.Checkpoint{Epoch: 99, Root: mockRoot[:]},
Target: &ethpb.Checkpoint{Epoch: 0, Root: make([]byte, 32)},
},
AggregationBits: aggBits,
}
zeroSig := [96]byte{}
att.Signature = zeroSig[:]
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.SetCurrentEpochAttestations([]*pb.PendingAttestation{}))
err = blocks.VerifyAttestationNoVerifySignature(context.TODO(), beaconState, att)
assert.NotEqual(t, nil, err)
}

View File

@ -366,7 +366,7 @@ func TestVerifyAttestationNoVerifySignature_IncorrectSlotTargetEpoch(t *testing.
}, },
}) })
wanted := "slot 32 does not match target epoch 0" wanted := "slot 32 does not match target epoch 0"
_, err := blocks.VerifyAttestationNoVerifySignature(context.TODO(), beaconState, att) err := blocks.VerifyAttestationNoVerifySignature(context.TODO(), beaconState, att)
assert.ErrorContains(t, wanted, err) assert.ErrorContains(t, wanted, err)
} }
@ -428,7 +428,7 @@ func TestVerifyAttestationNoVerifySignature_OK(t *testing.T) {
require.NoError(t, beaconState.SetCurrentJustifiedCheckpoint(ckp)) require.NoError(t, beaconState.SetCurrentJustifiedCheckpoint(ckp))
require.NoError(t, beaconState.SetCurrentEpochAttestations([]*pb.PendingAttestation{})) require.NoError(t, beaconState.SetCurrentEpochAttestations([]*pb.PendingAttestation{}))
_, err = blocks.VerifyAttestationNoVerifySignature(context.TODO(), beaconState, att) err = blocks.VerifyAttestationNoVerifySignature(context.TODO(), beaconState, att)
assert.NoError(t, err) assert.NoError(t, err)
} }
@ -453,7 +453,7 @@ func TestVerifyAttestationNoVerifySignature_BadAttIdx(t *testing.T) {
copy(ckp.Root, "hello-world") copy(ckp.Root, "hello-world")
require.NoError(t, beaconState.SetCurrentJustifiedCheckpoint(ckp)) require.NoError(t, beaconState.SetCurrentJustifiedCheckpoint(ckp))
require.NoError(t, beaconState.SetCurrentEpochAttestations([]*pb.PendingAttestation{})) require.NoError(t, beaconState.SetCurrentEpochAttestations([]*pb.PendingAttestation{}))
_, err := blocks.VerifyAttestationNoVerifySignature(context.TODO(), beaconState, att) err := blocks.VerifyAttestationNoVerifySignature(context.TODO(), beaconState, att)
require.ErrorContains(t, "committee index 100 >= committee count 1", err) require.ErrorContains(t, "committee index 100 >= committee count 1", err)
} }

View File

@ -35,7 +35,7 @@ func (bs *Server) SubmitAttestations(ctx context.Context, req *ethpb.SubmitAttes
var validAttestations []*ethpb_alpha.Attestation var validAttestations []*ethpb_alpha.Attestation
for _, sourceAtt := range req.Data { for _, sourceAtt := range req.Data {
att := migration.V1AttToV1Alpha1(sourceAtt) att := migration.V1AttToV1Alpha1(sourceAtt)
_, err = blocks.VerifyAttestationNoVerifySignature(ctx, headState, att) err = blocks.VerifyAttestationNoVerifySignature(ctx, headState, att)
if err != nil { if err != nil {
continue continue
} }