Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

validator REST: attestation v2 #14633

Open
wants to merge 17 commits into
base: develop
Choose a base branch
from
Open
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
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ The format is based on Keep a Changelog, and this project adheres to Semantic Ve
- Added GetAggregatedAttestationV2 endpoint.
- Added SubmitAttestationsV2 endpoint.
- Validator REST mode Electra block support
- Added Validator REST mode use of Attestation V2 endpoints and Electra attestations

### Changed

Expand Down
16 changes: 16 additions & 0 deletions proto/prysm/v1alpha1/attestation.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ type Att interface {
CommitteeBitsVal() bitfield.Bitfield
GetSignature() []byte
GetCommitteeIndex() (primitives.CommitteeIndex, error)
IsNil() bool
}

// IndexedAtt defines common functionality for all indexed attestation types.
Expand Down Expand Up @@ -103,6 +104,11 @@ func (a *Attestation) Version() int {
return version.Phase0
}

// IsNil --
func (a *Attestation) IsNil() bool {
return a == nil || a.Data == nil
}

// Clone --
func (a *Attestation) Clone() Att {
return a.Copy()
Expand Down Expand Up @@ -140,6 +146,11 @@ func (a *PendingAttestation) Version() int {
return version.Phase0
}

// IsNil --
func (a *PendingAttestation) IsNil() bool {
return a == nil || a.Data == nil
}

// Clone --
func (a *PendingAttestation) Clone() Att {
return a.Copy()
Expand Down Expand Up @@ -181,6 +192,11 @@ func (a *AttestationElectra) Version() int {
return version.Electra
}

// IsNil --
func (a *AttestationElectra) IsNil() bool {
return a == nil || a.Data == nil
}

// Clone --
func (a *AttestationElectra) Clone() Att {
return a.Copy()
Expand Down
21 changes: 18 additions & 3 deletions validator/client/beacon-api/beacon_api_validator_client.go
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,12 @@ func (c *beaconApiValidatorClient) ProposeAttestation(ctx context.Context, in *e
}

func (c *beaconApiValidatorClient) ProposeAttestationElectra(ctx context.Context, in *ethpb.AttestationElectra) (*ethpb.AttestResponse, error) {
return nil, errors.New("ProposeAttestationElectra is not implemented")
ctx, span := trace.StartSpan(ctx, "beacon-api.ProposeAttestationElectra")
defer span.End()

return wrapInMetrics[*ethpb.AttestResponse]("ProposeAttestationElectra", func() (*ethpb.AttestResponse, error) {
return c.proposeAttestationElectra(ctx, in)
})
}

func (c *beaconApiValidatorClient) ProposeBeaconBlock(ctx context.Context, in *ethpb.GenericSignedBeaconBlock) (*ethpb.ProposeResponse, error) {
Expand Down Expand Up @@ -190,7 +195,12 @@ func (c *beaconApiValidatorClient) SubmitAggregateSelectionProof(ctx context.Con
}

func (c *beaconApiValidatorClient) SubmitAggregateSelectionProofElectra(ctx context.Context, in *ethpb.AggregateSelectionRequest, index primitives.ValidatorIndex, committeeLength uint64) (*ethpb.AggregateSelectionElectraResponse, error) {
return nil, errors.New("SubmitAggregateSelectionProofElectra is not implemented")
ctx, span := trace.StartSpan(ctx, "beacon-api.SubmitAggregateSelectionProofElectra")
defer span.End()

return wrapInMetrics[*ethpb.AggregateSelectionElectraResponse]("SubmitAggregateSelectionProofElectra", func() (*ethpb.AggregateSelectionElectraResponse, error) {
return c.submitAggregateSelectionProofElectra(ctx, in, index, committeeLength)
})
}

func (c *beaconApiValidatorClient) SubmitSignedAggregateSelectionProof(ctx context.Context, in *ethpb.SignedAggregateSubmitRequest) (*ethpb.SignedAggregateSubmitResponse, error) {
Expand All @@ -203,7 +213,12 @@ func (c *beaconApiValidatorClient) SubmitSignedAggregateSelectionProof(ctx conte
}

func (c *beaconApiValidatorClient) SubmitSignedAggregateSelectionProofElectra(ctx context.Context, in *ethpb.SignedAggregateSubmitElectraRequest) (*ethpb.SignedAggregateSubmitResponse, error) {
return nil, errors.New("SubmitSignedAggregateSelectionProofElectra is not implemented")
ctx, span := trace.StartSpan(ctx, "beacon-api.SubmitSignedAggregateSelectionProofElectra")
defer span.End()

return wrapInMetrics[*ethpb.SignedAggregateSubmitResponse]("SubmitSignedAggregateSelectionProofElectra", func() (*ethpb.SignedAggregateSubmitResponse, error) {
return c.submitSignedAggregateSelectionProofElectra(ctx, in)
})
}

func (c *beaconApiValidatorClient) SubmitSignedContributionAndProof(ctx context.Context, in *ethpb.SignedContributionAndProof) (*empty.Empty, error) {
Expand Down
28 changes: 28 additions & 0 deletions validator/client/beacon-api/beacon_block_json_helpers.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,14 @@ func jsonifyAttestations(attestations []*ethpb.Attestation) []*structs.Attestati
return jsonAttestations
}

func jsonifyAttestationsElectra(attestations []*ethpb.AttestationElectra) []*structs.AttestationElectra {
jsonAttestations := make([]*structs.AttestationElectra, len(attestations))
for index, attestation := range attestations {
jsonAttestations[index] = jsonifyAttestationElectra(attestation)
}
return jsonAttestations
}

func jsonifyAttesterSlashings(attesterSlashings []*ethpb.AttesterSlashing) []*structs.AttesterSlashing {
jsonAttesterSlashings := make([]*structs.AttesterSlashing, len(attesterSlashings))
for index, attesterSlashing := range attesterSlashings {
Expand Down Expand Up @@ -164,6 +172,15 @@ func jsonifyAttestation(attestation *ethpb.Attestation) *structs.Attestation {
}
}

func jsonifyAttestationElectra(attestation *ethpb.AttestationElectra) *structs.AttestationElectra {
return &structs.AttestationElectra{
AggregationBits: hexutil.Encode(attestation.AggregationBits),
Data: jsonifyAttestationData(attestation.Data),
Signature: hexutil.Encode(attestation.Signature),
CommitteeBits: hexutil.Encode(attestation.CommitteeBits),
}
}

func jsonifySignedAggregateAndProof(signedAggregateAndProof *ethpb.SignedAggregateAttestationAndProof) *structs.SignedAggregateAttestationAndProof {
return &structs.SignedAggregateAttestationAndProof{
Message: &structs.AggregateAttestationAndProof{
Expand All @@ -175,6 +192,17 @@ func jsonifySignedAggregateAndProof(signedAggregateAndProof *ethpb.SignedAggrega
}
}

func jsonifySignedAggregateAndProofElectra(signedAggregateAndProof *ethpb.SignedAggregateAttestationAndProofElectra) *structs.SignedAggregateAttestationAndProofElectra {
return &structs.SignedAggregateAttestationAndProofElectra{
Message: &structs.AggregateAttestationAndProofElectra{
AggregatorIndex: uint64ToString(signedAggregateAndProof.Message.AggregatorIndex),
Aggregate: jsonifyAttestationElectra(signedAggregateAndProof.Message.Aggregate),
SelectionProof: hexutil.Encode(signedAggregateAndProof.Message.SelectionProof),
},
Signature: hexutil.Encode(signedAggregateAndProof.Signature),
}
}

func jsonifyWithdrawals(withdrawals []*enginev1.Withdrawal) []*structs.Withdrawal {
jsonWithdrawals := make([]*structs.Withdrawal, len(withdrawals))
for index, withdrawal := range withdrawals {
Expand Down
33 changes: 33 additions & 0 deletions validator/client/beacon-api/beacon_block_proto_helpers.go
Original file line number Diff line number Diff line change
Expand Up @@ -197,6 +197,39 @@ func convertAttestationToProto(jsonAttestation *structs.Attestation) (*ethpb.Att
}, nil
}

func convertAttestationElectraToProto(jsonAttestation *structs.AttestationElectra) (*ethpb.AttestationElectra, error) {
if jsonAttestation == nil {
return nil, errors.New("json attestation is nil")
}

aggregationBits, err := hexutil.Decode(jsonAttestation.AggregationBits)
if err != nil {
return nil, errors.Wrapf(err, "failed to decode aggregation bits `%s`", jsonAttestation.AggregationBits)
}

attestationData, err := convertAttestationDataToProto(jsonAttestation.Data)
if err != nil {
return nil, errors.Wrap(err, "failed to get attestation data")
}

signature, err := hexutil.Decode(jsonAttestation.Signature)
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should we be checking for lengths?

if err != nil {
return nil, errors.Wrapf(err, "failed to decode attestation signature `%s`", jsonAttestation.Signature)
}

committeeBits, err := hexutil.Decode(jsonAttestation.CommitteeBits)
if err != nil {
return nil, errors.Wrapf(err, "failed to decode committee bits `%s`", jsonAttestation.CommitteeBits)
}

return &ethpb.AttestationElectra{
AggregationBits: aggregationBits,
Data: attestationData,
Signature: signature,
CommitteeBits: committeeBits,
}, nil
}

func convertAttestationsToProto(jsonAttestations []*structs.Attestation) ([]*ethpb.Attestation, error) {
var attestations []*ethpb.Attestation
for index, jsonAttestation := range jsonAttestations {
Expand Down
54 changes: 39 additions & 15 deletions validator/client/beacon-api/propose_attestation.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,9 @@ import (
)

func (c *beaconApiValidatorClient) proposeAttestation(ctx context.Context, attestation *ethpb.Attestation) (*ethpb.AttestResponse, error) {
if err := checkNilAttestation(attestation); err != nil {
if err := validateNilAttestation(attestation); err != nil {
return nil, err
}

marshalledAttestation, err := json.Marshal(jsonifyAttestations([]*ethpb.Attestation{attestation}))
if err != nil {
return nil, err
Expand All @@ -37,27 +36,52 @@ func (c *beaconApiValidatorClient) proposeAttestation(ctx context.Context, attes
return &ethpb.AttestResponse{AttestationDataRoot: attestationDataRoot[:]}, nil
}

// checkNilAttestation returns error if attestation or any field of attestation is nil.
func checkNilAttestation(attestation *ethpb.Attestation) error {
if attestation == nil {
return errors.New("attestation is nil")
func (c *beaconApiValidatorClient) proposeAttestationElectra(ctx context.Context, attestation *ethpb.AttestationElectra) (*ethpb.AttestResponse, error) {
if err := validateNilAttestation(attestation); err != nil {
return nil, err
}

if attestation.Data == nil {
return errors.New("attestation data is nil")
if len(attestation.CommitteeBits) == 0 {
return nil, errors.New("attestation committee bits is empty")
}

if attestation.Data.Source == nil || attestation.Data.Target == nil {
return errors.New("source/target in attestation data is nil")
marshalledAttestation, err := json.Marshal(jsonifyAttestationsElectra([]*ethpb.AttestationElectra{attestation}))
if err != nil {
return nil, err
}

if len(attestation.AggregationBits) == 0 {
return errors.New("attestation aggregation bits is empty")
if err = c.jsonRestHandler.Post(
ctx,
"/eth/v2/beacon/pool/attestations",
nil,
bytes.NewBuffer(marshalledAttestation),
nil,
); err != nil {
return nil, err
}

if len(attestation.Signature) == 0 {
return errors.New("attestation signature is empty")
attestationDataRoot, err := attestation.Data.HashTreeRoot()
if err != nil {
return nil, errors.Wrap(err, "failed to compute attestation data root")
}

return &ethpb.AttestResponse{AttestationDataRoot: attestationDataRoot[:]}, nil
}

func validateNilAttestation(attestation ethpb.Att) error {
if attestation == nil || attestation.IsNil() {
return errors.New("attestation can't be nil")
}
if attestation.GetData().Source == nil {
return errors.New("attestation's source can't be nil")
}
if attestation.GetData().Target == nil {
return errors.New("attestation's target can't be nil")
}
if len(attestation.GetAggregationBits()) == 0 {
return errors.New("attestation's bitfield can't be nil")
}
if len(attestation.GetSignature()) == 0 {
return errors.New("attestation signature can't be nil")
}
return nil
}
Loading
Loading