Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions beacon-chain/core/helpers/attestation.go
Original file line number Diff line number Diff line change
Expand Up @@ -58,14 +58,14 @@ func ValidateSlotTargetEpoch(data *ethpb.AttestationData) error {
// committee = get_beacon_committee(state, slot, index)
// modulo = max(1, len(committee) // TARGET_AGGREGATORS_PER_COMMITTEE)
// return bytes_to_uint64(hash(slot_signature)[0:8]) % modulo == 0
func IsAggregator(committeeCount uint64, slotSig []byte) (bool, error) {
func IsAggregator(committeeCount uint64, slotSig []byte) bool {
modulo := uint64(1)
if committeeCount/params.BeaconConfig().TargetAggregatorsPerCommittee > 1 {
modulo = committeeCount / params.BeaconConfig().TargetAggregatorsPerCommittee
}

b := hash.Hash(slotSig)
return binary.LittleEndian.Uint64(b[:8])%modulo == 0, nil
return binary.LittleEndian.Uint64(b[:8])%modulo == 0
}

// ComputeSubnetForAttestation returns the subnet for which the provided attestation will be broadcasted to.
Expand Down
6 changes: 2 additions & 4 deletions beacon-chain/core/helpers/attestation_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,7 @@ func TestAttestation_IsAggregator(t *testing.T) {
committee, err := helpers.BeaconCommitteeFromState(t.Context(), beaconState, 0, 0)
require.NoError(t, err)
sig := privKeys[0].Sign([]byte{'A'})
agg, err := helpers.IsAggregator(uint64(len(committee)), sig.Marshal())
require.NoError(t, err)
agg := helpers.IsAggregator(uint64(len(committee)), sig.Marshal())
assert.Equal(t, true, agg, "Wanted aggregator true")
})

Expand All @@ -40,8 +39,7 @@ func TestAttestation_IsAggregator(t *testing.T) {
committee, err := helpers.BeaconCommitteeFromState(t.Context(), beaconState, 0, 0)
require.NoError(t, err)
sig := privKeys[0].Sign([]byte{'A'})
agg, err := helpers.IsAggregator(uint64(len(committee)), sig.Marshal())
require.NoError(t, err)
agg := helpers.IsAggregator(uint64(len(committee)), sig.Marshal())
assert.Equal(t, false, agg, "Wanted aggregator false")
})
}
Expand Down
6 changes: 1 addition & 5 deletions beacon-chain/rpc/prysm/v1alpha1/validator/aggregator.go
Original file line number Diff line number Diff line change
Expand Up @@ -132,11 +132,7 @@ func (vs *Server) processAggregateSelection(ctx context.Context, req *ethpb.Aggr
}

// Check if the validator is an aggregator
isAggregator, err := helpers.IsAggregator(uint64(len(committee)), req.SlotSignature)
if err != nil {
return 0, 0, status.Errorf(codes.Internal, "Could not get aggregator status: %v", err)
}
if !isAggregator {
if !helpers.IsAggregator(uint64(len(committee)), req.SlotSignature) {
return 0, 0, status.Errorf(codes.InvalidArgument, "Validator is not an aggregator")
}

Expand Down
4 changes: 2 additions & 2 deletions beacon-chain/sync/batch_verifier.go
Original file line number Diff line number Diff line change
Expand Up @@ -93,12 +93,12 @@ func (s *Service) validateWithBatchVerifier(ctx context.Context, message string,
// If verification fails we fallback to individual verification
// of each signature set.
if resErr != nil {
log.WithError(resErr).Tracef("Could not perform batch verification of %s", message)
log.WithError(resErr).WithField("message", message).Trace("Could not perform batch verification")
verified, err := set.Verify()
if err != nil {
verErr := errors.Wrapf(err, "Could not verify %s", message)
tracing.AnnotateError(span, verErr)
return pubsub.ValidationReject, verErr
return pubsub.ValidationIgnore, verErr
}
if !verified {
verErr := errors.Errorf("Verification of %s failed", message)
Expand Down
2 changes: 1 addition & 1 deletion beacon-chain/sync/initial-sync/blocks_queue.go
Original file line number Diff line number Diff line change
Expand Up @@ -346,7 +346,7 @@ func (q *blocksQueue) onDataReceivedEvent(ctx context.Context) eventHandlerFn {
q.downscorePeer(response.blocksFrom, "invalidBlocks")
}

if errors.Is(response.err, verification.ErrBlobInvalid) {
if errors.Is(response.err, verification.ErrSidecarInvalid) {
q.downscorePeer(response.blobsFrom, "invalidBlobs")
}

Expand Down
4 changes: 2 additions & 2 deletions beacon-chain/sync/initial-sync/downscore_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,7 @@ func TestOnDataReceivedDownscore(t *testing.T) {
},
{
name: "invalid blob",
err: errors.Wrap(verification.ErrBlobInvalid, "test"),
err: errors.Wrap(verification.ErrSidecarInvalid, "test"),
downPeer: testDownscoreBlob,
},
{
Expand All @@ -149,7 +149,7 @@ func TestOnDataReceivedDownscore(t *testing.T) {
err: c.err,
}
if c.downPeer == testDownscoreBlob {
require.Equal(t, true, verification.IsBlobValidationFailure(c.err))
require.Equal(t, true, verification.IsSidecarValidationFailure(c.err))
}
ctx := t.Context()
p2p := p2pt.NewTestP2P(t)
Expand Down
2 changes: 1 addition & 1 deletion beacon-chain/sync/initial-sync/round_robin.go
Original file line number Diff line number Diff line change
Expand Up @@ -463,7 +463,7 @@ func isPunishableError(err error) bool {
// updatePeerScorerStats adjusts monitored metrics for a peer.
func (s *Service) updatePeerScorerStats(data *blocksQueueFetchedData, count uint64, err error) {
if isPunishableError(err) {
if verification.IsBlobValidationFailure(err) {
if verification.IsSidecarValidationFailure(err) {
s.downscorePeer(data.blobsFrom, "invalidBlobs")
} else {
s.downscorePeer(data.blocksFrom, "invalidBlocks")
Expand Down
16 changes: 8 additions & 8 deletions beacon-chain/sync/rpc_send_request.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,14 +35,14 @@ var errBlobUnmarshal = errors.New("Could not unmarshal chunk-encoded blob")
var (
// ErrInvalidFetchedData is used to signal that an error occurred which should result in peer downscoring.
ErrInvalidFetchedData = errors.New("invalid data returned from peer")
errBlobIndexOutOfBounds = errors.Wrap(verification.ErrBlobInvalid, "blob index out of range")
errMaxRequestBlobSidecarsExceeded = errors.Wrap(verification.ErrBlobInvalid, "peer exceeded req blob chunk tx limit")
errChunkResponseSlotNotAsc = errors.Wrap(verification.ErrBlobInvalid, "blob slot not higher than previous block root")
errChunkResponseIndexNotAsc = errors.Wrap(verification.ErrBlobInvalid, "blob indices for a block must start at 0 and increase by 1")
errUnrequested = errors.Wrap(verification.ErrBlobInvalid, "received BlobSidecar in response that was not requested")
errBlobResponseOutOfBounds = errors.Wrap(verification.ErrBlobInvalid, "received BlobSidecar with slot outside BlobSidecarsByRangeRequest bounds")
errChunkResponseBlockMismatch = errors.Wrap(verification.ErrBlobInvalid, "blob block details do not match")
errChunkResponseParentMismatch = errors.Wrap(verification.ErrBlobInvalid, "parent root for response element doesn't match previous element root")
errBlobIndexOutOfBounds = errors.Wrap(verification.ErrSidecarInvalid, "blob index out of range")
errMaxRequestBlobSidecarsExceeded = errors.Wrap(verification.ErrSidecarInvalid, "peer exceeded req blob chunk tx limit")
errChunkResponseSlotNotAsc = errors.Wrap(verification.ErrSidecarInvalid, "blob slot not higher than previous block root")
errChunkResponseIndexNotAsc = errors.Wrap(verification.ErrSidecarInvalid, "blob indices for a block must start at 0 and increase by 1")
errUnrequested = errors.Wrap(verification.ErrSidecarInvalid, "received BlobSidecar in response that was not requested")
errBlobResponseOutOfBounds = errors.Wrap(verification.ErrSidecarInvalid, "received BlobSidecar with slot outside BlobSidecarsByRangeRequest bounds")
errChunkResponseBlockMismatch = errors.Wrap(verification.ErrSidecarInvalid, "blob block details do not match")
errChunkResponseParentMismatch = errors.Wrap(verification.ErrSidecarInvalid, "parent root for response element doesn't match previous element root")
errDataColumnChunkedReadFailure = errors.New("failed to read stream of chunk-encoded data columns")
errMaxRequestDataColumnSidecarsExceeded = errors.New("count of requested data column sidecars exceeds MAX_REQUEST_DATA_COLUMN_SIDECARS")
errMaxResponseDataColumnSidecarsExceeded = errors.New("peer returned more data column sidecars than requested")
Expand Down
2 changes: 1 addition & 1 deletion beacon-chain/sync/rpc_send_request_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -884,7 +884,7 @@ func TestSendBlobsByRangeRequest(t *testing.T) {
}

func TestErrInvalidFetchedDataDistinction(t *testing.T) {
require.Equal(t, false, errors.Is(ErrInvalidFetchedData, verification.ErrBlobInvalid))
require.Equal(t, false, errors.Is(ErrInvalidFetchedData, verification.ErrSidecarInvalid))
}

func TestSendDataColumnSidecarsByRangeRequest(t *testing.T) {
Expand Down
30 changes: 18 additions & 12 deletions beacon-chain/sync/validate_aggregate_proof.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ import (
"github.com/pkg/errors"
)

var errInvalidAggregator = errors.New("invalid aggregator")

// validateAggregateAndProof verifies the aggregated signature and the selection proof is valid before forwarding to the
// network and downstream services.
func (s *Service) validateAggregateAndProof(ctx context.Context, pid peer.ID, msg *pubsub.Message) (pubsub.ValidationResult, error) {
Expand Down Expand Up @@ -212,11 +214,16 @@ func (s *Service) validateAggregatedAtt(ctx context.Context, signed ethpb.Signed
aggregatorIndex,
aggregateAndProof.GetSelectionProof(),
)

if errors.Is(err, errInvalidAggregator) {
attBadSelectionProofCount.Inc()
return pubsub.ValidationReject, nil
}

if err != nil {
wrappedErr := errors.Wrapf(err, "could not validate selection for validator %d", aggregateAndProof.GetAggregatorIndex())
tracing.AnnotateError(span, wrappedErr)
attBadSelectionProofCount.Inc()
return pubsub.ValidationReject, wrappedErr
return pubsub.ValidationIgnore, wrappedErr
}

// Verify selection signature, aggregator signature and attestation signature are valid.
Expand Down Expand Up @@ -316,36 +323,35 @@ func validateSelectionIndex(
_, span := trace.StartSpan(ctx, "sync.validateSelectionIndex")
defer span.End()

aggregator, err := helpers.IsAggregator(uint64(len(committee)), proof)
if err != nil {
return nil, err
}
if !aggregator {
return nil, fmt.Errorf("validator is not an aggregator for slot %d", slot)
if !helpers.IsAggregator(uint64(len(committee)), proof) {
return nil, errInvalidAggregator
}

domain := params.BeaconConfig().DomainSelectionProof
epoch := slots.ToEpoch(slot)

v, err := bs.ValidatorAtIndexReadOnly(validatorIndex)
if err != nil {
return nil, err
return nil, errors.Wrap(err, "validator at index read only")
}

pk := v.PublicKey()
publicKey, err := bls.PublicKeyFromBytes(pk[:])
if err != nil {
return nil, err
return nil, errors.Wrap(err, "public key from bytes")
}

d, err := signing.Domain(bs.Fork(), epoch, domain, bs.GenesisValidatorsRoot())
if err != nil {
return nil, err
return nil, errors.Wrap(err, "domain")
}

sszUint := primitives.SSZUint64(slot)
root, err := signing.ComputeSigningRoot(&sszUint, d)
if err != nil {
return nil, err
return nil, errors.Wrap(err, "compute signing root")
}

return &bls.SignatureBatch{
Signatures: [][]byte{proof},
PublicKeys: []bls.PublicKey{publicKey},
Expand Down
3 changes: 1 addition & 2 deletions beacon-chain/sync/validate_aggregate_proof_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -188,8 +188,7 @@ func TestVerifySelection_NotAnAggregator(t *testing.T) {
committee, err := helpers.BeaconCommitteeFromState(ctx, beaconState, data.Slot, data.CommitteeIndex)
require.NoError(t, err)
_, err = validateSelectionIndex(ctx, beaconState, data.Slot, committee, 0, sig.Marshal())
wanted := "validator is not an aggregator for slot"
assert.ErrorContains(t, wanted, err)
require.ErrorIs(t, err, errInvalidAggregator)
}

func TestValidateAggregateAndProof_NoBlock(t *testing.T) {
Expand Down
27 changes: 18 additions & 9 deletions beacon-chain/sync/validate_blob.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,12 +50,12 @@ func (s *Service) validateBlob(ctx context.Context, pid peer.ID, msg *pubsub.Mes
}
blob, err := blocks.NewROBlob(bpb)
if err != nil {
return pubsub.ValidationReject, errors.Wrap(err, "roblob conversion failure")
return pubsub.ValidationIgnore, errors.Wrap(err, "roblob conversion failure")
}
vf := s.newBlobVerifier(blob, verification.GossipBlobSidecarRequirements)

if err := vf.BlobIndexInBounds(); err != nil {
return pubsub.ValidationReject, err
return rejectOrIgnore(err)
}

// [REJECT] The sidecar is for the correct subnet -- i.e. compute_subnet_for_blob_sidecar(sidecar.index) == subnet_id.
Expand Down Expand Up @@ -94,32 +94,32 @@ func (s *Service) validateBlob(ctx context.Context, pid peer.ID, msg *pubsub.Mes
}

if err := vf.SidecarParentValid(s.hasBadBlock); err != nil {
return pubsub.ValidationReject, err
return rejectOrIgnore(err)
}

if err := vf.ValidProposerSignature(ctx); err != nil {
return pubsub.ValidationReject, err
return rejectOrIgnore(err)
}

if err := vf.SidecarParentSlotLower(); err != nil {
return pubsub.ValidationReject, err
return rejectOrIgnore(err)
}

if err := vf.SidecarDescendsFromFinalized(); err != nil {
return pubsub.ValidationReject, err
return rejectOrIgnore(err)
}

if err := vf.SidecarInclusionProven(); err != nil {
return pubsub.ValidationReject, err
return rejectOrIgnore(err)
}

if err := vf.SidecarKzgProofVerified(); err != nil {
saveInvalidBlobToTemp(blob)
return pubsub.ValidationReject, err
return rejectOrIgnore(err)
}

if err := vf.SidecarProposerExpected(ctx); err != nil {
return pubsub.ValidationReject, err
return rejectOrIgnore(err)
}

fields := blobFields(blob)
Expand Down Expand Up @@ -195,3 +195,12 @@ func saveInvalidBlobToTemp(b blocks.ROBlob) {
log.WithError(err).Error("Failed to write to disk")
}
}

// rejectOrIgnore returns ValidationReject if the error is a verification.ErrSidecarInvalid, otherwise
// it returns ValidationIgnore.
func rejectOrIgnore(err error) (pubsub.ValidationResult, error) {
if errors.Is(err, verification.ErrSidecarInvalid) {
return pubsub.ValidationReject, err
}
return pubsub.ValidationIgnore, err
}
Loading
Loading