2023-02-14 11:25:21 +00:00
package beacon_api
import (
"context"
"net/url"
"strconv"
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/pkg/errors"
2023-03-17 18:52:56 +00:00
"github.com/prysmaticlabs/prysm/v4/beacon-chain/core/helpers"
"github.com/prysmaticlabs/prysm/v4/beacon-chain/rpc/apimiddleware"
"github.com/prysmaticlabs/prysm/v4/consensus-types/primitives"
ethpb "github.com/prysmaticlabs/prysm/v4/proto/prysm/v1alpha1"
"github.com/prysmaticlabs/prysm/v4/time/slots"
2023-02-14 11:25:21 +00:00
)
func ( c * beaconApiValidatorClient ) submitAggregateSelectionProof ( ctx context . Context , in * ethpb . AggregateSelectionRequest ) ( * ethpb . AggregateSelectionResponse , error ) {
isOptimistic , err := c . isOptimistic ( ctx )
if err != nil {
return nil , err
}
// An optimistic validator MUST NOT participate in attestation. (i.e., sign across the DOMAIN_BEACON_ATTESTER, DOMAIN_SELECTION_PROOF or DOMAIN_AGGREGATE_AND_PROOF domains).
if isOptimistic {
return nil , errors . New ( "the node is currently optimistic and cannot serve validators" )
}
validatorIndexResponse , err := c . validatorIndex ( ctx , & ethpb . ValidatorIndexRequest { PublicKey : in . PublicKey } )
if err != nil {
return nil , errors . Wrap ( err , "failed to get validator index" )
}
attesterDuties , err := c . dutiesProvider . GetAttesterDuties ( ctx , slots . ToEpoch ( in . Slot ) , [ ] primitives . ValidatorIndex { validatorIndexResponse . Index } )
if err != nil {
return nil , errors . Wrap ( err , "failed to get attester duties" )
}
if len ( attesterDuties ) == 0 {
return nil , errors . Errorf ( "no attester duty for the given slot %d" , in . Slot )
}
// First attester duty is required since we requested attester duties for one validator index.
attesterDuty := attesterDuties [ 0 ]
committeeLen , err := strconv . ParseUint ( attesterDuty . CommitteeLength , 10 , 64 )
if err != nil {
return nil , errors . Wrap ( err , "failed to parse committee length" )
}
isAggregator , err := helpers . IsAggregator ( committeeLen , in . SlotSignature )
if err != nil {
return nil , errors . Wrap ( err , "failed to get aggregator status" )
}
if ! isAggregator {
return nil , errors . New ( "validator is not an aggregator" )
}
attestationData , err := c . getAttestationData ( ctx , in . Slot , in . CommitteeIndex )
if err != nil {
return nil , errors . Wrapf ( err , "failed to get attestation data for slot=%d and committee_index=%d" , in . Slot , in . CommitteeIndex )
}
attestationDataRoot , err := attestationData . HashTreeRoot ( )
if err != nil {
return nil , errors . Wrap ( err , "failed to calculate attestation data root" )
}
aggregateAttestationResponse , err := c . getAggregateAttestation ( ctx , in . Slot , attestationDataRoot [ : ] )
if err != nil {
return nil , err
}
aggregatedAttestation , err := convertAttestationToProto ( aggregateAttestationResponse . Data )
if err != nil {
return nil , errors . Wrap ( err , "failed to convert aggregate attestation json to proto" )
}
return & ethpb . AggregateSelectionResponse {
AggregateAndProof : & ethpb . AggregateAttestationAndProof {
AggregatorIndex : validatorIndexResponse . Index ,
Aggregate : aggregatedAttestation ,
SelectionProof : in . SlotSignature ,
} ,
} , nil
}
func ( c * beaconApiValidatorClient ) getAggregateAttestation ( ctx context . Context , slot primitives . Slot , attestationDataRoot [ ] byte ) ( * apimiddleware . AggregateAttestationResponseJson , error ) {
params := url . Values { }
params . Add ( "slot" , strconv . FormatUint ( uint64 ( slot ) , 10 ) )
params . Add ( "attestation_data_root" , hexutil . Encode ( attestationDataRoot ) )
endpoint := buildURL ( "/eth/v1/validator/aggregate_attestation" , params )
var aggregateAttestationResponse apimiddleware . AggregateAttestationResponseJson
if _ , err := c . jsonRestHandler . GetRestJsonResponse ( ctx , endpoint , & aggregateAttestationResponse ) ; err != nil {
return nil , errors . Wrap ( err , "failed to get aggregate attestation" )
}
return & aggregateAttestationResponse , nil
}