mirror of
https://gitlab.com/pulsechaincom/prysm-pulse.git
synced 2025-01-10 11:41:21 +00:00
a9b003e1fe
* HTTP Beacon API: `/eth/v1/validator/contribution_and_proofs` * add comment to invalid test case * fix validation and test * review --------- Co-authored-by: james-prysm <90280386+james-prysm@users.noreply.github.com>
114 lines
4.0 KiB
Go
114 lines
4.0 KiB
Go
package validator
|
|
|
|
import (
|
|
"bytes"
|
|
"encoding/json"
|
|
"net/http"
|
|
"strconv"
|
|
|
|
"github.com/ethereum/go-ethereum/common/hexutil"
|
|
"github.com/go-playground/validator/v10"
|
|
"github.com/prysmaticlabs/prysm/v4/beacon-chain/rpc/core"
|
|
"github.com/prysmaticlabs/prysm/v4/beacon-chain/rpc/eth/shared"
|
|
"github.com/prysmaticlabs/prysm/v4/consensus-types/primitives"
|
|
http2 "github.com/prysmaticlabs/prysm/v4/network/http"
|
|
ethpbalpha "github.com/prysmaticlabs/prysm/v4/proto/prysm/v1alpha1"
|
|
)
|
|
|
|
// GetAggregateAttestation aggregates all attestations matching the given attestation data root and slot, returning the aggregated result.
|
|
func (s *Server) GetAggregateAttestation(w http.ResponseWriter, r *http.Request) {
|
|
attDataRoot := r.URL.Query().Get("attestation_data_root")
|
|
valid := shared.ValidateHex(w, "Attestation data root", attDataRoot)
|
|
if !valid {
|
|
return
|
|
}
|
|
rawSlot := r.URL.Query().Get("slot")
|
|
slot, valid := shared.ValidateUint(w, "Slot", rawSlot)
|
|
if !valid {
|
|
return
|
|
}
|
|
|
|
if err := s.AttestationsPool.AggregateUnaggregatedAttestations(r.Context()); err != nil {
|
|
http2.HandleError(w, "Could not aggregate unaggregated attestations: "+err.Error(), http.StatusBadRequest)
|
|
return
|
|
}
|
|
|
|
allAtts := s.AttestationsPool.AggregatedAttestations()
|
|
var bestMatchingAtt *ethpbalpha.Attestation
|
|
for _, att := range allAtts {
|
|
if att.Data.Slot == primitives.Slot(slot) {
|
|
root, err := att.Data.HashTreeRoot()
|
|
if err != nil {
|
|
http2.HandleError(w, "Could not get attestation data root: "+err.Error(), http.StatusInternalServerError)
|
|
return
|
|
}
|
|
attDataRootBytes, err := hexutil.Decode(attDataRoot)
|
|
if err != nil {
|
|
http2.HandleError(w, "Could not decode attestation data root into bytes: "+err.Error(), http.StatusBadRequest)
|
|
return
|
|
}
|
|
if bytes.Equal(root[:], attDataRootBytes) {
|
|
if bestMatchingAtt == nil || len(att.AggregationBits) > len(bestMatchingAtt.AggregationBits) {
|
|
bestMatchingAtt = att
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if bestMatchingAtt == nil {
|
|
http2.HandleError(w, "No matching attestation found", http.StatusNotFound)
|
|
return
|
|
}
|
|
|
|
response := &AggregateAttestationResponse{
|
|
Data: shared.Attestation{
|
|
AggregationBits: hexutil.Encode(bestMatchingAtt.AggregationBits),
|
|
Data: shared.AttestationData{
|
|
Slot: strconv.FormatUint(uint64(bestMatchingAtt.Data.Slot), 10),
|
|
CommitteeIndex: strconv.FormatUint(uint64(bestMatchingAtt.Data.CommitteeIndex), 10),
|
|
BeaconBlockRoot: hexutil.Encode(bestMatchingAtt.Data.BeaconBlockRoot),
|
|
Source: shared.Checkpoint{
|
|
Epoch: strconv.FormatUint(uint64(bestMatchingAtt.Data.Source.Epoch), 10),
|
|
Root: hexutil.Encode(bestMatchingAtt.Data.Source.Root),
|
|
},
|
|
Target: shared.Checkpoint{
|
|
Epoch: strconv.FormatUint(uint64(bestMatchingAtt.Data.Target.Epoch), 10),
|
|
Root: hexutil.Encode(bestMatchingAtt.Data.Target.Root),
|
|
},
|
|
},
|
|
Signature: hexutil.Encode(bestMatchingAtt.Signature),
|
|
}}
|
|
http2.WriteJson(w, response)
|
|
}
|
|
|
|
// SubmitContributionAndProofs publishes multiple signed sync committee contribution and proofs.
|
|
func (s *Server) SubmitContributionAndProofs(w http.ResponseWriter, r *http.Request) {
|
|
var req SubmitContributionAndProofsRequest
|
|
|
|
if r.Body == http.NoBody {
|
|
http2.HandleError(w, "No data submitted", http.StatusBadRequest)
|
|
return
|
|
}
|
|
|
|
if err := json.NewDecoder(r.Body).Decode(&req.Data); err != nil {
|
|
http2.HandleError(w, "Could not decode request body: "+err.Error(), http.StatusBadRequest)
|
|
return
|
|
}
|
|
|
|
validate := validator.New()
|
|
for _, item := range req.Data {
|
|
if err := validate.Struct(item); err != nil {
|
|
http2.HandleError(w, err.Error(), http.StatusBadRequest)
|
|
return
|
|
}
|
|
consensusItem, err := item.ToConsensus()
|
|
if err != nil {
|
|
http2.HandleError(w, "Could not convert request contribution to consensus contribution: "+err.Error(), http.StatusBadRequest)
|
|
return
|
|
}
|
|
rpcError := core.SubmitSignedContributionAndProof(r.Context(), consensusItem, s.Broadcaster, s.SyncCommitteePool, s.OperationNotifier)
|
|
if rpcError != nil {
|
|
http2.HandleError(w, rpcError.Err.Error(), core.ErrorReasonToHTTP(rpcError.Reason))
|
|
}
|
|
}
|
|
}
|