From ea8378511af641878a1634f16d056692823c0b53 Mon Sep 17 00:00:00 2001 From: Gary Rong Date: Wed, 17 Sep 2025 10:14:53 +0800 Subject: [PATCH] beacon, eth: add more comments about engine API --- beacon/engine/gen_epe.go | 4 ++-- beacon/engine/types.go | 40 ++++++++++++++++++++++++++++++++++------ eth/catalyst/api.go | 19 ++++++++++++++++--- 3 files changed, 52 insertions(+), 11 deletions(-) diff --git a/beacon/engine/gen_epe.go b/beacon/engine/gen_epe.go index deada06166..cf7bd9ee3f 100644 --- a/beacon/engine/gen_epe.go +++ b/beacon/engine/gen_epe.go @@ -17,7 +17,7 @@ func (e ExecutionPayloadEnvelope) MarshalJSON() ([]byte, error) { type ExecutionPayloadEnvelope struct { ExecutionPayload *ExecutableData `json:"executionPayload" gencodec:"required"` BlockValue *hexutil.Big `json:"blockValue" gencodec:"required"` - BlobsBundle *BlobsBundleV1 `json:"blobsBundle"` + BlobsBundle *BlobsBundle `json:"blobsBundle"` Requests []hexutil.Bytes `json:"executionRequests"` Override bool `json:"shouldOverrideBuilder"` Witness *hexutil.Bytes `json:"witness,omitempty"` @@ -42,7 +42,7 @@ func (e *ExecutionPayloadEnvelope) UnmarshalJSON(input []byte) error { type ExecutionPayloadEnvelope struct { ExecutionPayload *ExecutableData `json:"executionPayload" gencodec:"required"` BlockValue *hexutil.Big `json:"blockValue" gencodec:"required"` - BlobsBundle *BlobsBundleV1 `json:"blobsBundle"` + BlobsBundle *BlobsBundle `json:"blobsBundle"` Requests []hexutil.Bytes `json:"executionRequests"` Override *bool `json:"shouldOverrideBuilder"` Witness *hexutil.Bytes `json:"witness,omitempty"` diff --git a/beacon/engine/types.go b/beacon/engine/types.go index 76bfd22a23..56784c4266 100644 --- a/beacon/engine/types.go +++ b/beacon/engine/types.go @@ -33,8 +33,22 @@ import ( type PayloadVersion byte var ( + // PayloadV1 is the identifier of ExecutionPayloadV1 introduced in paris fork. + // https://github.com/ethereum/execution-apis/blob/main/src/engine/paris.md#executionpayloadv1 PayloadV1 PayloadVersion = 0x1 + + // PayloadV2 is the identifier of ExecutionPayloadV2 introduced in shanghai fork. + // + // https://github.com/ethereum/execution-apis/blob/main/src/engine/shanghai.md#executionpayloadv2 + // ExecutionPayloadV2 has the syntax of ExecutionPayloadV1 and appends a + // single field: withdrawals. PayloadV2 PayloadVersion = 0x2 + + // PayloadV3 is the identifier of ExecutionPayloadV3 introduced in cancun fork. + // + // https://github.com/ethereum/execution-apis/blob/main/src/engine/cancun.md#executionpayloadv3 + // ExecutionPayloadV3 has the syntax of ExecutionPayloadV2 and appends the new + // fields: blobGasUsed and excessBlobGas. PayloadV3 PayloadVersion = 0x3 ) @@ -106,13 +120,18 @@ type StatelessPayloadStatusV1 struct { type ExecutionPayloadEnvelope struct { ExecutionPayload *ExecutableData `json:"executionPayload" gencodec:"required"` BlockValue *big.Int `json:"blockValue" gencodec:"required"` - BlobsBundle *BlobsBundleV1 `json:"blobsBundle"` + BlobsBundle *BlobsBundle `json:"blobsBundle"` Requests [][]byte `json:"executionRequests"` Override bool `json:"shouldOverrideBuilder"` Witness *hexutil.Bytes `json:"witness,omitempty"` } -type BlobsBundleV1 struct { +// BlobsBundle includes the marshalled sidecar data. Note this structure is +// shared by BlobsBundleV1 and BlobsBundleV2 for the sake of simplicity. +// +// - BlobsBundleV1: proofs contain exactly len(blobs) kzg proofs. +// - BlobsBundleV2: proofs contain exactly CELLS_PER_EXT_BLOB * len(blobs) cell proofs. +type BlobsBundle struct { Commitments []hexutil.Bytes `json:"commitments"` Proofs []hexutil.Bytes `json:"proofs"` Blobs []hexutil.Bytes `json:"blobs"` @@ -327,18 +346,27 @@ func BlockToExecutableData(block *types.Block, fees *big.Int, sidecars []*types. } // Add blobs. - bundle := BlobsBundleV1{ + bundle := BlobsBundle{ Commitments: make([]hexutil.Bytes, 0), Blobs: make([]hexutil.Bytes, 0), Proofs: make([]hexutil.Bytes, 0), } for _, sidecar := range sidecars { for j := range sidecar.Blobs { - bundle.Blobs = append(bundle.Blobs, hexutil.Bytes(sidecar.Blobs[j][:])) - bundle.Commitments = append(bundle.Commitments, hexutil.Bytes(sidecar.Commitments[j][:])) + bundle.Blobs = append(bundle.Blobs, sidecar.Blobs[j][:]) + bundle.Commitments = append(bundle.Commitments, sidecar.Commitments[j][:]) } + // - Before the Osaka fork, only version-0 blob transactions should be packed, + // with the proof length equal to len(blobs). + // + // - After the Osaka fork, only version-1 blob transactions should be packed, + // with the proof length equal to CELLS_PER_EXT_BLOB * len(blobs). + // + // Ideally, length validation should be performed based on the bundle version. + // In practice, this is unnecessary because blob transaction filtering is + // already done during payload construction. for _, proof := range sidecar.Proofs { - bundle.Proofs = append(bundle.Proofs, hexutil.Bytes(proof[:])) + bundle.Proofs = append(bundle.Proofs, proof[:]) } } diff --git a/eth/catalyst/api.go b/eth/catalyst/api.go index b222470228..b5feee060e 100644 --- a/eth/catalyst/api.go +++ b/eth/catalyst/api.go @@ -418,13 +418,21 @@ func (api *ConsensusAPI) GetPayloadV1(payloadID engine.PayloadID) (*engine.Execu // GetPayloadV2 returns a cached payload by id. func (api *ConsensusAPI) GetPayloadV2(payloadID engine.PayloadID) (*engine.ExecutionPayloadEnvelope, error) { + // executionPayload: ExecutionPayloadV1 | ExecutionPayloadV2 where: + // + // - ExecutionPayloadV1 MUST be returned if the payload timestamp is lower + // than the Shanghai timestamp + // + // - ExecutionPayloadV2 MUST be returned if the payload timestamp is greater + // or equal to the Shanghai timestamp if !payloadID.Is(engine.PayloadV1, engine.PayloadV2) { return nil, engine.UnsupportedFork } return api.getPayload(payloadID, false) } -// GetPayloadV3 returns a cached payload by id. +// GetPayloadV3 returns a cached payload by id. This endpoint should only +// be used after the Cancun fork. func (api *ConsensusAPI) GetPayloadV3(payloadID engine.PayloadID) (*engine.ExecutionPayloadEnvelope, error) { if !payloadID.Is(engine.PayloadV3) { return nil, engine.UnsupportedFork @@ -432,7 +440,8 @@ func (api *ConsensusAPI) GetPayloadV3(payloadID engine.PayloadID) (*engine.Execu return api.getPayload(payloadID, false) } -// GetPayloadV4 returns a cached payload by id. +// GetPayloadV4 returns a cached payload by id. This endpoint should only +// be used after the Prague fork. func (api *ConsensusAPI) GetPayloadV4(payloadID engine.PayloadID) (*engine.ExecutionPayloadEnvelope, error) { if !payloadID.Is(engine.PayloadV3) { return nil, engine.UnsupportedFork @@ -440,7 +449,11 @@ func (api *ConsensusAPI) GetPayloadV4(payloadID engine.PayloadID) (*engine.Execu return api.getPayload(payloadID, false) } -// GetPayloadV5 returns a cached payload by id. +// GetPayloadV5 returns a cached payload by id. This endpoint should only +// be used after the Osaka fork. +// +// This method follows the same specification as engine_getPayloadV4 with +// changes of returning BlobsBundleV2 with BlobSidecar version 1. func (api *ConsensusAPI) GetPayloadV5(payloadID engine.PayloadID) (*engine.ExecutionPayloadEnvelope, error) { if !payloadID.Is(engine.PayloadV3) { return nil, engine.UnsupportedFork