Skip to content
Merged
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
14 changes: 14 additions & 0 deletions api/server/structs/block.go
Original file line number Diff line number Diff line change
Expand Up @@ -577,3 +577,17 @@ func (s *SignedBeaconBlockGloas) MessageRawJson() ([]byte, error) {
func (s *SignedBeaconBlockGloas) SigString() string {
return s.Signature
}

type ExecutionPayloadEnvelope struct {
Payload *ExecutionPayloadDeneb `json:"payload"`
ExecutionRequests *ExecutionRequests `json:"execution_requests"`
BuilderIndex string `json:"builder_index"`
BeaconBlockRoot string `json:"beacon_block_root"`
Slot string `json:"slot"`
StateRoot string `json:"state_root"`
}

type SignedExecutionPayloadEnvelope struct {
Message *ExecutionPayloadEnvelope `json:"message"`
Signature string `json:"signature"`
}
23 changes: 23 additions & 0 deletions api/server/structs/conversions_block.go
Original file line number Diff line number Diff line change
Expand Up @@ -3275,3 +3275,26 @@ func (d *PayloadAttestationData) ToConsensus() (*eth.PayloadAttestationData, err
BlobDataAvailable: d.BlobDataAvailable,
}, nil
}

// SignedExecutionPayloadEnvelopeFromConsensus converts a proto envelope to the API struct.
func SignedExecutionPayloadEnvelopeFromConsensus(e *eth.SignedExecutionPayloadEnvelope) (*SignedExecutionPayloadEnvelope, error) {
payload, err := ExecutionPayloadDenebFromConsensus(e.Message.Payload)
if err != nil {
return nil, err
}
var requests *ExecutionRequests
if e.Message.ExecutionRequests != nil {
requests = ExecutionRequestsFromConsensus(e.Message.ExecutionRequests)
}
return &SignedExecutionPayloadEnvelope{
Message: &ExecutionPayloadEnvelope{
Payload: payload,
ExecutionRequests: requests,
BuilderIndex: fmt.Sprintf("%d", e.Message.BuilderIndex),
BeaconBlockRoot: hexutil.Encode(e.Message.BeaconBlockRoot),
Slot: fmt.Sprintf("%d", e.Message.Slot),
StateRoot: hexutil.Encode(e.Message.StateRoot),
},
Signature: hexutil.Encode(e.Signature),
}, nil
}
7 changes: 7 additions & 0 deletions api/server/structs/endpoints_beacon.go
Original file line number Diff line number Diff line change
Expand Up @@ -285,6 +285,13 @@ type GetBlobsResponse struct {
Data []string `json:"data"` //blobs
}

type GetExecutionPayloadEnvelopeResponse struct {
Version string `json:"version"`
ExecutionOptimistic bool `json:"execution_optimistic"`
Finalized bool `json:"finalized"`
Data *SignedExecutionPayloadEnvelope `json:"data"`
}

type SSZQueryRequest struct {
Query string `json:"query"`
IncludeProof bool `json:"include_proof,omitempty"`
Expand Down
5 changes: 5 additions & 0 deletions api/server/structs/endpoints_events.go
Original file line number Diff line number Diff line change
Expand Up @@ -112,3 +112,8 @@ type LightClientOptimisticUpdateEvent struct {
Version string `json:"version"`
Data *LightClientOptimisticUpdate `json:"data"`
}

type PayloadEvent struct {
Slot string `json:"slot"`
BlockRoot string `json:"block_root"`
}
10 changes: 10 additions & 0 deletions beacon-chain/blockchain/receive_execution_payload_envelope.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ import (
"context"
"fmt"

"github.com/OffchainLabs/prysm/v7/beacon-chain/core/feed"
statefeed "github.com/OffchainLabs/prysm/v7/beacon-chain/core/feed/state"
"github.com/OffchainLabs/prysm/v7/beacon-chain/core/gloas"
"github.com/OffchainLabs/prysm/v7/beacon-chain/core/transition"
"github.com/OffchainLabs/prysm/v7/beacon-chain/execution"
Expand Down Expand Up @@ -102,6 +104,14 @@ func (s *Service) ReceiveExecutionPayloadEnvelope(ctx context.Context, signed in
return err
}

s.cfg.StateNotifier.StateFeed().Send(&feed.Event{
Type: statefeed.PayloadProcessed,
Data: &statefeed.PayloadProcessedData{
Slot: envelope.Slot(),
BlockRoot: root,
},
})

execution, err := envelope.Execution()
if err != nil {
log.WithError(err).Error("Could not get execution payload from envelope for logging")
Expand Down
8 changes: 8 additions & 0 deletions beacon-chain/core/feed/state/events.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@ const (
LightClientOptimisticUpdate
// PayloadAttributes events are fired upon a missed slot or new head.
PayloadAttributes
// PayloadProcessed is sent after a payload envelope has been processed.
PayloadProcessed
)

// BlockProcessedData is the data sent with BlockProcessed events.
Expand Down Expand Up @@ -72,3 +74,9 @@ type InitializedData struct {
// GenesisValidatorsRoot represents state.validators.HashTreeRoot().
GenesisValidatorsRoot []byte
}

// PayloadProcessedData is the data sent with PayloadProcessed events.
type PayloadProcessedData struct {
Slot primitives.Slot
BlockRoot [32]byte
}
28 changes: 28 additions & 0 deletions beacon-chain/execution/engine_client.go
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,7 @@ type Reconstructor interface {
) (map[[32]byte]*pb.ExecutionPayloadDeneb, error)
ReconstructBlobSidecars(ctx context.Context, block interfaces.ReadOnlySignedBeaconBlock, blockRoot [fieldparams.RootLength]byte, hi func(uint64) bool) ([]blocks.VerifiedROBlob, error)
ConstructDataColumnSidecars(ctx context.Context, populator peerdas.ConstructionPopulator) ([]blocks.VerifiedRODataColumn, error)
ReconstructExecutionPayloadEnvelope(ctx context.Context, envelope *ethpb.SignedBlindedExecutionPayloadEnvelope) (*ethpb.SignedExecutionPayloadEnvelope, error)
}

// EngineCaller defines a client that can interact with an Ethereum
Expand Down Expand Up @@ -652,6 +653,33 @@ func (s *Service) ReconstructFullBellatrixBlockBatch(
return unb, nil
}

// ReconstructExecutionPayloadEnvelope takes a blinded execution payload envelope and
// reconstructs the full envelope by fetching the execution payload from the EL via
// eth_getBlockByHash.
func (s *Service) ReconstructExecutionPayloadEnvelope(
ctx context.Context, envelope *ethpb.SignedBlindedExecutionPayloadEnvelope,
) (*ethpb.SignedExecutionPayloadEnvelope, error) {
if envelope == nil || envelope.Message == nil {
return nil, errors.New("nil blinded execution payload envelope")
}
blockHash := bytesutil.ToBytes32(envelope.Message.BlockHash)
payload, err := s.ReconstructFullExecutionPayloadByHash(ctx, blockHash)
if err != nil {
return nil, errors.Wrap(err, "could not reconstruct execution payload")
}
return &ethpb.SignedExecutionPayloadEnvelope{
Message: &ethpb.ExecutionPayloadEnvelope{
Payload: payload,
ExecutionRequests: envelope.Message.ExecutionRequests,
BuilderIndex: envelope.Message.BuilderIndex,
BeaconBlockRoot: envelope.Message.BeaconBlockRoot,
Slot: envelope.Message.Slot,
StateRoot: envelope.Message.StateRoot,
},
Signature: envelope.Signature,
}, nil
}

// ReconstructFullExecutionPayloadByHash reconstructs a full deneb payload from EL data by block hash.
func (s *Service) ReconstructFullExecutionPayloadByHash(
ctx context.Context, blockHash [32]byte,
Expand Down
44 changes: 44 additions & 0 deletions beacon-chain/execution/testing/mock_engine_client.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import (
"github.com/OffchainLabs/prysm/v7/consensus-types/primitives"
"github.com/OffchainLabs/prysm/v7/encoding/bytesutil"
pb "github.com/OffchainLabs/prysm/v7/proto/engine/v1"
ethpb "github.com/OffchainLabs/prysm/v7/proto/prysm/v1alpha1"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/holiman/uint256"
Expand Down Expand Up @@ -171,6 +172,49 @@ func (e *EngineClient) ConstructDataColumnSidecars(context.Context, peerdas.Cons
return e.DataColumnSidecars, e.ErrorDataColumnSidecars
}

// ReconstructExecutionPayloadEnvelope --
func (e *EngineClient) ReconstructExecutionPayloadEnvelope(
_ context.Context, envelope *ethpb.SignedBlindedExecutionPayloadEnvelope,
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

do we need context if it's not used?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

This is in the mock, the original function uses it.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

thanks just noticed that didn't realize in initial review

) (*ethpb.SignedExecutionPayloadEnvelope, error) {
if e.Err != nil {
return nil, e.Err
}
payload, ok := e.ExecutionPayloadByBlockHash[bytesutil.ToBytes32(envelope.Message.BlockHash)]
if !ok {
return nil, errors.New("execution payload not found for block hash")
}
return &ethpb.SignedExecutionPayloadEnvelope{
Message: &ethpb.ExecutionPayloadEnvelope{
Payload: payloadToPayloadDeneb(payload),
ExecutionRequests: envelope.Message.ExecutionRequests,
BuilderIndex: envelope.Message.BuilderIndex,
BeaconBlockRoot: envelope.Message.BeaconBlockRoot,
Slot: envelope.Message.Slot,
StateRoot: envelope.Message.StateRoot,
},
Signature: envelope.Signature,
}, nil
}

func payloadToPayloadDeneb(p *pb.ExecutionPayload) *pb.ExecutionPayloadDeneb {
return &pb.ExecutionPayloadDeneb{
ParentHash: p.ParentHash,
FeeRecipient: p.FeeRecipient,
StateRoot: p.StateRoot,
ReceiptsRoot: p.ReceiptsRoot,
LogsBloom: p.LogsBloom,
PrevRandao: p.PrevRandao,
BlockNumber: p.BlockNumber,
GasLimit: p.GasLimit,
GasUsed: p.GasUsed,
Timestamp: p.Timestamp,
ExtraData: p.ExtraData,
BaseFeePerGas: p.BaseFeePerGas,
BlockHash: p.BlockHash,
Transactions: p.Transactions,
}
}

// GetTerminalBlockHash --
func (e *EngineClient) GetTerminalBlockHash(ctx context.Context, transitionTime uint64) ([]byte, bool, error) {
ttd := new(big.Int)
Expand Down
9 changes: 9 additions & 0 deletions beacon-chain/rpc/endpoints.go
Original file line number Diff line number Diff line change
Expand Up @@ -891,6 +891,15 @@ func (s *Service) beaconEndpoints(
handler: server.GetProposerLookahead,
methods: []string{http.MethodGet},
},
{
template: "/eth/v1/beacon/execution_payload_envelope/{block_root}",
name: namespace + ".GetExecutionPayloadEnvelope",
middleware: []middleware.Middleware{
middleware.AcceptHeaderHandler([]string{api.JsonMediaType, api.OctetStreamMediaType}),
},
handler: server.GetExecutionPayloadEnvelope,
methods: []string{http.MethodGet},
},
}
}

Expand Down
1 change: 1 addition & 0 deletions beacon-chain/rpc/endpoints_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ func Test_endpoints(t *testing.T) {
"/eth/v1/beacon/states/{state_id}/pending_partial_withdrawals": {http.MethodGet},
"/eth/v1/beacon/states/{state_id}/pending_consolidations": {http.MethodGet},
"/eth/v1/beacon/states/{state_id}/proposer_lookahead": {http.MethodGet},
"/eth/v1/beacon/execution_payload_envelope/{block_root}": {http.MethodGet},
"/eth/v1/beacon/headers": {http.MethodGet},
"/eth/v1/beacon/headers/{block_id}": {http.MethodGet},
"/eth/v2/beacon/blinded_blocks": {http.MethodPost},
Expand Down
1 change: 1 addition & 0 deletions beacon-chain/rpc/eth/beacon/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ go_library(
name = "go_default_library",
srcs = [
"handlers.go",
"handlers_gloas.go",
"handlers_pool.go",
"handlers_state.go",
"handlers_validator.go",
Expand Down
74 changes: 74 additions & 0 deletions beacon-chain/rpc/eth/beacon/handlers_gloas.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
package beacon

import (
"net/http"

"github.com/OffchainLabs/prysm/v7/api"
"github.com/OffchainLabs/prysm/v7/api/server/structs"
"github.com/OffchainLabs/prysm/v7/beacon-chain/db"
"github.com/OffchainLabs/prysm/v7/encoding/bytesutil"
"github.com/OffchainLabs/prysm/v7/monitoring/tracing/trace"
"github.com/OffchainLabs/prysm/v7/network/httputil"
"github.com/OffchainLabs/prysm/v7/runtime/version"
"github.com/pkg/errors"
)

// GetExecutionPayloadEnvelope retrieves a full execution payload envelope by beacon block root.
// The blinded envelope is fetched from the DB and the full execution payload is reconstructed
// from the EL via eth_getBlockByHash.
func (s *Server) GetExecutionPayloadEnvelope(w http.ResponseWriter, r *http.Request) {
ctx, span := trace.StartSpan(r.Context(), "beacon.GetExecutionPayloadEnvelope")
defer span.End()

rootBytes, err := bytesutil.DecodeHexWithLength(r.PathValue("block_root"), 32)
if err != nil {
httputil.HandleError(w, "Could not decode block root: "+err.Error(), http.StatusBadRequest)
return
}
root := [32]byte(rootBytes)
blinded, err := s.BeaconDB.ExecutionPayloadEnvelope(ctx, root)
if err != nil {
if errors.Is(err, db.ErrNotFound) {
httputil.HandleError(w, "execution payload envelope not found", http.StatusNotFound)
return
}
httputil.HandleError(w, "could not retrieve execution payload envelope: "+err.Error(), http.StatusInternalServerError)
return
}
full, err := s.ExecutionReconstructor.ReconstructExecutionPayloadEnvelope(ctx, blinded)
if err != nil {
httputil.HandleError(w, "could not reconstruct execution payload envelope: "+err.Error(), http.StatusInternalServerError)
return
}

w.Header().Set(api.VersionHeader, version.String(version.Gloas))

if httputil.RespondWithSsz(r) {
sszBytes, err := full.MarshalSSZ()
if err != nil {
httputil.HandleError(w, "could not marshal envelope to SSZ: "+err.Error(), http.StatusInternalServerError)
return
}
httputil.WriteSsz(w, sszBytes)
return
}

isOptimistic, err := s.OptimisticModeFetcher.IsOptimisticForRoot(ctx, root)
if err != nil {
httputil.HandleError(w, "could not check optimistic status: "+err.Error(), http.StatusInternalServerError)
return
}
finalized := s.FinalizationFetcher.IsFinalized(ctx, root)

jsonEnvelope, err := structs.SignedExecutionPayloadEnvelopeFromConsensus(full)
if err != nil {
httputil.HandleError(w, "could not convert envelope to JSON: "+err.Error(), http.StatusInternalServerError)
return
}
httputil.WriteJson(w, &structs.GetExecutionPayloadEnvelopeResponse{
Version: version.String(version.Gloas),
ExecutionOptimistic: isOptimistic,
Finalized: finalized,
Data: jsonEnvelope,
})
}
21 changes: 20 additions & 1 deletion beacon-chain/rpc/eth/events/events.go
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,11 @@ const (
LightClientOptimisticUpdateTopic = "light_client_optimistic_update"
// DataColumnTopic represents a data column sidecar event topic
DataColumnTopic = "data_column_sidecar"
// ExecutionPayloadTopic represents a new execution payload envelope event topic
ExecutionPayloadTopic = "execution_payload_available"
// ExecutionPayloadBidTopic represents a new execution payload bid event topic.
// This topic is currently not triggered but is recognized to avoid client subscription errors.
ExecutionPayloadBidTopic = "execution_payload_bid"
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

we need some tests for this events.go file

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

you can take it from this pr #16323

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

we don'tneed payload_attestation_message for dora to be happy?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

not for now, payloads and the payload event are enough to show the green/yellow status of payloads.

)

var (
Expand Down Expand Up @@ -118,9 +123,14 @@ var stateFeedEventTopics = map[feed.EventType]string{
statefeed.Reorg: ChainReorgTopic,
statefeed.BlockProcessed: BlockTopic,
statefeed.PayloadAttributes: PayloadAttributesTopic,
statefeed.PayloadProcessed: ExecutionPayloadTopic,
}

var topicsForStateFeed = topicsForFeed(stateFeedEventTopics)
var topicsForStateFeed = func() map[string]bool {
m := topicsForFeed(stateFeedEventTopics)
m[ExecutionPayloadBidTopic] = true
return m
}()
var topicsForOpsFeed = topicsForFeed(opsFeedEventTopics)

func topicsForFeed(em map[feed.EventType]string) map[string]bool {
Expand Down Expand Up @@ -466,6 +476,8 @@ func topicForEvent(event *feed.Event) string {
return PayloadAttributesTopic
case *operation.DataColumnReceivedData:
return DataColumnTopic
case *statefeed.PayloadProcessedData:
return ExecutionPayloadTopic
default:
return InvalidTopic
}
Expand Down Expand Up @@ -638,6 +650,13 @@ func (s *Server) lazyReaderForEvent(ctx context.Context, event *feed.Event, topi
}
return jsonMarshalReader(eventName, blk)
}, nil
case *statefeed.PayloadProcessedData:
return func() io.Reader {
return jsonMarshalReader(eventName, &structs.PayloadEvent{
Slot: fmt.Sprintf("%d", v.Slot),
BlockRoot: hexutil.Encode(v.BlockRoot[:]),
})
}, nil
default:
return nil, errors.Wrapf(errUnhandledEventData, "event data type %T unsupported", v)
}
Expand Down
8 changes: 8 additions & 0 deletions beacon-chain/rpc/eth/events/events_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -393,6 +393,7 @@ func TestStreamEvents_OperationsEvents(t *testing.T) {
FinalizedCheckpointTopic,
ChainReorgTopic,
BlockTopic,
ExecutionPayloadTopic,
})
require.NoError(t, err)
request := topics.testHttpRequest(testSync.ctx, t)
Expand Down Expand Up @@ -445,6 +446,13 @@ func TestStreamEvents_OperationsEvents(t *testing.T) {
ExecutionOptimistic: false,
},
},
{
Type: statefeed.PayloadProcessed,
Data: &statefeed.PayloadProcessedData{
Slot: 10,
BlockRoot: [32]byte{0x9a},
},
},
}

go func() {
Expand Down
2 changes: 2 additions & 0 deletions changelog/potuz_envelope_endpoints.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
### Added
- Add Gloas payload_envelope endpoint and some event streams.
Loading
Loading