-
Notifications
You must be signed in to change notification settings - Fork 1.3k
fix gloas proposal endpoint support #16818
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
Changes from 2 commits
505b458
d099a7d
01839f4
25f7246
b644330
b46ab77
50aee36
a508cd3
a299148
cbbb87b
9e81229
aebb6fe
e87e9c3
9ddc67e
76bdd01
f774a0e
6daf544
969294f
fb3b1c0
80b8ccf
cfca674
02d55e2
7df1423
f55d283
f641f7d
75f0026
c1633d7
0d5cb60
b72deaa
271b0dc
86e4b7b
6dc65e8
d3323c8
432041d
c957444
7b0affd
5a7c178
9cc939b
b95871b
d4f0f07
02023db
8a1a608
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,6 +1,7 @@ | ||
| package beacon | ||
|
|
||
| import ( | ||
| "bytes" | ||
| "context" | ||
| "encoding/json" | ||
| "io" | ||
|
|
@@ -9,6 +10,7 @@ import ( | |
| "github.com/OffchainLabs/prysm/v7/api" | ||
| "github.com/OffchainLabs/prysm/v7/api/server/structs" | ||
| "github.com/OffchainLabs/prysm/v7/beacon-chain/blockchain/kzg" | ||
| "github.com/OffchainLabs/prysm/v7/beacon-chain/core/gloas" | ||
| "github.com/OffchainLabs/prysm/v7/beacon-chain/core/peerdas" | ||
| "github.com/OffchainLabs/prysm/v7/beacon-chain/db" | ||
| "github.com/OffchainLabs/prysm/v7/beacon-chain/rpc/eth/shared" | ||
|
|
@@ -104,27 +106,51 @@ func (s *Server) PublishExecutionPayloadEnvelope(w http.ResponseWriter, r *http. | |
| return | ||
| } | ||
|
|
||
| // Contents wraps the signed envelope alongside blobs/kzg_proofs; the | ||
| // wrapper key distinguishes it from a bare envelope body. | ||
| var probe map[string]json.RawMessage | ||
| if err := json.Unmarshal(body, &probe); err != nil { | ||
| httputil.HandleError(w, "could not decode request body: "+err.Error(), http.StatusBadRequest) | ||
| return | ||
| } | ||
| if _, isContents := probe["signed_execution_payload_envelope"]; isContents { | ||
| s.publishExecutionPayloadEnvelopeContents(ctx, w, body) | ||
| return | ||
| } | ||
| var consensus *eth.SignedExecutionPayloadEnvelope | ||
| if httputil.IsRequestSsz(r) { | ||
| // Dispatch by SSZ lead offset: 12 = Contents, 100 = bare envelope. | ||
| contentsLeadOffset := []byte{12, 0, 0, 0} | ||
| if bytes.HasPrefix(body, contentsLeadOffset) { | ||
| contents := ð.SignedExecutionPayloadEnvelopeContents{} | ||
| if err := contents.UnmarshalSSZ(body); err != nil { | ||
| httputil.HandleError(w, "could not decode SSZ envelope contents: "+err.Error(), http.StatusBadRequest) | ||
| return | ||
| } | ||
| s.publishExecutionPayloadEnvelopeContentsSSZ(ctx, w, r, contents) | ||
| return | ||
| } | ||
| consensus = ð.SignedExecutionPayloadEnvelope{} | ||
| if err := consensus.UnmarshalSSZ(body); err != nil { | ||
| httputil.HandleError(w, "could not decode SSZ envelope: "+err.Error(), http.StatusBadRequest) | ||
| return | ||
| } | ||
| } else { | ||
| // Contents wraps the signed envelope alongside blobs/kzg_proofs; the | ||
| // wrapper key distinguishes it from a bare envelope body. | ||
| var probe map[string]json.RawMessage | ||
| if err := json.Unmarshal(body, &probe); err != nil { | ||
| httputil.HandleError(w, "could not decode request body: "+err.Error(), http.StatusBadRequest) | ||
| return | ||
| } | ||
| if _, isContents := probe["signed_execution_payload_envelope"]; isContents { | ||
| s.publishExecutionPayloadEnvelopeContents(ctx, w, r, body) | ||
| return | ||
| } | ||
|
|
||
| var jsonEnvelope structs.SignedExecutionPayloadEnvelope | ||
| if err := json.Unmarshal(body, &jsonEnvelope); err != nil { | ||
| httputil.HandleError(w, "could not decode request body: "+err.Error(), http.StatusBadRequest) | ||
| return | ||
| var jsonEnvelope structs.SignedExecutionPayloadEnvelope | ||
| if err := json.Unmarshal(body, &jsonEnvelope); err != nil { | ||
| httputil.HandleError(w, "could not decode request body: "+err.Error(), http.StatusBadRequest) | ||
| return | ||
| } | ||
| consensus, err = jsonEnvelope.ToConsensus() | ||
| if err != nil { | ||
| httputil.HandleError(w, "invalid signed execution payload envelope: "+err.Error(), http.StatusBadRequest) | ||
| return | ||
| } | ||
| } | ||
|
|
||
| consensus, err := jsonEnvelope.ToConsensus() | ||
| if err != nil { | ||
| httputil.HandleError(w, "invalid signed execution payload envelope: "+err.Error(), http.StatusBadRequest) | ||
| if err := s.validateEnvelopeBroadcast(ctx, r, consensus); err != nil { | ||
| httputil.HandleError(w, err.Error(), http.StatusBadRequest) | ||
| return | ||
| } | ||
|
|
||
|
|
@@ -145,10 +171,8 @@ func (s *Server) PublishExecutionPayloadEnvelope(w http.ResponseWriter, r *http. | |
| w.WriteHeader(http.StatusOK) | ||
| } | ||
|
|
||
| // publishExecutionPayloadEnvelopeContents handles the stateless variant: | ||
| // verifies caller-supplied blobs/proofs, broadcasts derived sidecars, then | ||
| // delegates the envelope to the bare publish path. | ||
| func (s *Server) publishExecutionPayloadEnvelopeContents(ctx context.Context, w http.ResponseWriter, body []byte) { | ||
| // publishExecutionPayloadEnvelopeContents handles the JSON stateless variant. | ||
| func (s *Server) publishExecutionPayloadEnvelopeContents(ctx context.Context, w http.ResponseWriter, r *http.Request, body []byte) { | ||
| var contents structs.SignedExecutionPayloadEnvelopeContents | ||
| if err := json.Unmarshal(body, &contents); err != nil { | ||
| httputil.HandleError(w, "could not decode envelope contents: "+err.Error(), http.StatusBadRequest) | ||
|
|
@@ -159,6 +183,25 @@ func (s *Server) publishExecutionPayloadEnvelopeContents(ctx context.Context, w | |
| httputil.HandleError(w, "invalid signed execution payload envelope contents: "+err.Error(), http.StatusBadRequest) | ||
| return | ||
| } | ||
| s.processEnvelopeContents(ctx, w, r, signed, kzgProofs, blobs) | ||
| } | ||
|
|
||
| // publishExecutionPayloadEnvelopeContentsSSZ handles the SSZ stateless variant. | ||
| func (s *Server) publishExecutionPayloadEnvelopeContentsSSZ(ctx context.Context, w http.ResponseWriter, r *http.Request, contents *eth.SignedExecutionPayloadEnvelopeContents) { | ||
| if contents == nil || contents.SignedExecutionPayloadEnvelope == nil { | ||
| httputil.HandleError(w, "nil signed execution payload envelope contents", http.StatusBadRequest) | ||
| return | ||
| } | ||
| s.processEnvelopeContents(ctx, w, r, contents.SignedExecutionPayloadEnvelope, contents.KzgProofs, contents.Blobs) | ||
| } | ||
|
|
||
| // processEnvelopeContents verifies caller-supplied blobs/proofs, broadcasts | ||
| // derived sidecars, then delegates the envelope to the bare publish path. | ||
| func (s *Server) processEnvelopeContents(ctx context.Context, w http.ResponseWriter, r *http.Request, signed *eth.SignedExecutionPayloadEnvelope, kzgProofs, blobs [][]byte) { | ||
| if err := s.validateEnvelopeBroadcast(ctx, r, signed); err != nil { | ||
| httputil.HandleError(w, err.Error(), http.StatusBadRequest) | ||
| return | ||
| } | ||
|
|
||
| if len(blobs) > 0 { | ||
| blockRoot := bytesutil.ToBytes32(signed.Message.BeaconBlockRoot) | ||
|
|
@@ -207,6 +250,50 @@ func (s *Server) publishExecutionPayloadEnvelopeContents(ctx context.Context, w | |
| w.WriteHeader(http.StatusOK) | ||
| } | ||
|
|
||
| // validateEnvelopeBroadcast applies broadcast_validation semantics to an | ||
| // envelope publish before it is broadcast to gossip. Spec: beacon-APIs #580. | ||
| // - gossip (default): no extra checks. | ||
| // - consensus: run full envelope consensus checks (signature + payload | ||
| // consistency against the pre-state at envelope.beacon_block_root). | ||
| // - consensus_and_equivocation: consensus + reject if a different beacon | ||
| // block at the envelope's slot has already been received. | ||
| func (s *Server) validateEnvelopeBroadcast(ctx context.Context, r *http.Request, signed *eth.SignedExecutionPayloadEnvelope) error { | ||
| level := r.URL.Query().Get(broadcastValidationQueryParam) | ||
| switch level { | ||
| case "", broadcastValidationGossip: | ||
| return nil | ||
| case broadcastValidationConsensus, broadcastValidationConsensusAndEquivocation: | ||
| default: | ||
| return errors.Errorf("invalid %s value: %q", broadcastValidationQueryParam, level) | ||
| } | ||
|
|
||
| envSlot := primitives.Slot(signed.Message.Payload.SlotNumber) | ||
| envRoot := bytesutil.ToBytes32(signed.Message.BeaconBlockRoot) | ||
|
|
||
| if level == broadcastValidationConsensusAndEquivocation { | ||
| if s.ForkchoiceFetcher.HighestReceivedBlockSlot() == envSlot && | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. what happens if you submit a payload late?
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. changed is this more appropriate? |
||
| s.ForkchoiceFetcher.HighestReceivedBlockRoot() != envRoot { | ||
| return errors.Wrapf(errEquivocatedBlock, "another block for slot %d already exists in fork choice", envSlot) | ||
| } | ||
| } | ||
|
|
||
| st, err := s.StateGenService.StateByRoot(ctx, envRoot) | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is going to be slow right
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. you're right, it's probably wrong too, we should have a hard requirement that it's head, is a race condition an issue? if we haven't processed block yet for state? |
||
| if err != nil { | ||
| return errors.Wrap(err, "could not get state for envelope beacon block root") | ||
| } | ||
| if st == nil || st.IsNil() { | ||
| return errors.Errorf("could not get state for envelope beacon block root %#x", envRoot) | ||
| } | ||
| roSigned, err := consensusblocks.WrappedROSignedExecutionPayloadEnvelope(signed) | ||
| if err != nil { | ||
| return errors.Wrap(err, "could not wrap signed envelope") | ||
| } | ||
| if err := gloas.VerifyExecutionPayloadEnvelope(ctx, st, roSigned); err != nil { | ||
| return errors.Wrap(err, "consensus validation failed") | ||
| } | ||
| return nil | ||
| } | ||
|
|
||
| // verifyCellProofs batch-verifies cell proofs against commitments derived | ||
| // from the supplied blobs. Does not tie data to a specific block — that needs | ||
| // the block's BlobKzgCommitments which a stateless receiver may not have. | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.