mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-02-26 15:47:21 +00:00
eth/catalyst, beacon/engine: enable BPO and Osaka on stateless APIs (#32636)
Addresses https://github.com/ethereum/go-ethereum/issues/32630 This pull request enables the stateless engine APIs for Osaka and the following BPOs. Apart from that, a few more descriptions have been added in the engine APIs, making it easier to follow the spec change.
This commit is contained in:
parent
ab95477a65
commit
2a82964727
4 changed files with 60 additions and 19 deletions
|
|
@ -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"`
|
||||
|
|
|
|||
|
|
@ -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"`
|
||||
|
|
@ -125,7 +144,7 @@ type BlobAndProofV1 struct {
|
|||
|
||||
type BlobAndProofV2 struct {
|
||||
Blob hexutil.Bytes `json:"blob"`
|
||||
CellProofs []hexutil.Bytes `json:"proofs"`
|
||||
CellProofs []hexutil.Bytes `json:"proofs"` // proofs MUST contain exactly CELLS_PER_EXT_BLOB cell proofs.
|
||||
}
|
||||
|
||||
// JSON type overrides for ExecutionPayloadEnvelope.
|
||||
|
|
@ -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[:])
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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 for 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 for 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
|
||||
|
|
@ -637,7 +650,7 @@ func (api *ConsensusAPI) NewPayloadV4(params engine.ExecutableData, versionedHas
|
|||
case executionRequests == nil:
|
||||
return invalidStatus, paramsErr("nil executionRequests post-prague")
|
||||
case !api.checkFork(params.Timestamp, forks.Prague, forks.Osaka, forks.BPO1, forks.BPO2, forks.BPO3, forks.BPO4, forks.BPO5):
|
||||
return invalidStatus, unsupportedForkErr("newPayloadV4 must only be called for Prague payloads")
|
||||
return invalidStatus, unsupportedForkErr("newPayloadV4 must only be called for prague/osaka payloads")
|
||||
}
|
||||
requests := convertRequests(executionRequests)
|
||||
if err := validateRequests(requests); err != nil {
|
||||
|
|
|
|||
|
|
@ -73,8 +73,8 @@ func (api *ConsensusAPI) ForkchoiceUpdatedWithWitnessV3(update engine.Forkchoice
|
|||
return engine.STATUS_INVALID, attributesErr("missing withdrawals")
|
||||
case params.BeaconRoot == nil:
|
||||
return engine.STATUS_INVALID, attributesErr("missing beacon root")
|
||||
case !api.checkFork(params.Timestamp, forks.Cancun, forks.Prague):
|
||||
return engine.STATUS_INVALID, unsupportedForkErr("fcuV3 must only be called for cancun or prague payloads")
|
||||
case !api.checkFork(params.Timestamp, forks.Cancun, forks.Prague, forks.Osaka, forks.BPO1, forks.BPO2, forks.BPO3, forks.BPO4, forks.BPO5):
|
||||
return engine.STATUS_INVALID, unsupportedForkErr("fcuV3 must only be called for cancun/prague/osaka payloads")
|
||||
}
|
||||
}
|
||||
// TODO(matt): the spec requires that fcu is applied when called on a valid
|
||||
|
|
@ -151,8 +151,8 @@ func (api *ConsensusAPI) NewPayloadWithWitnessV4(params engine.ExecutableData, v
|
|||
return invalidStatus, paramsErr("nil beaconRoot post-cancun")
|
||||
case executionRequests == nil:
|
||||
return invalidStatus, paramsErr("nil executionRequests post-prague")
|
||||
case !api.checkFork(params.Timestamp, forks.Prague):
|
||||
return invalidStatus, unsupportedForkErr("newPayloadV4 must only be called for prague payloads")
|
||||
case !api.checkFork(params.Timestamp, forks.Prague, forks.Osaka, forks.BPO1, forks.BPO2, forks.BPO3, forks.BPO4, forks.BPO5):
|
||||
return invalidStatus, unsupportedForkErr("newPayloadV4 must only be called for prague/osaka payloads")
|
||||
}
|
||||
requests := convertRequests(executionRequests)
|
||||
if err := validateRequests(requests); err != nil {
|
||||
|
|
@ -228,8 +228,8 @@ func (api *ConsensusAPI) ExecuteStatelessPayloadV4(params engine.ExecutableData,
|
|||
return engine.StatelessPayloadStatusV1{Status: engine.INVALID}, paramsErr("nil beaconRoot post-cancun")
|
||||
case executionRequests == nil:
|
||||
return engine.StatelessPayloadStatusV1{Status: engine.INVALID}, paramsErr("nil executionRequests post-prague")
|
||||
case !api.checkFork(params.Timestamp, forks.Prague, forks.Osaka):
|
||||
return engine.StatelessPayloadStatusV1{Status: engine.INVALID}, unsupportedForkErr("newPayloadV4 must only be called for prague payloads")
|
||||
case !api.checkFork(params.Timestamp, forks.Prague, forks.Osaka, forks.BPO1, forks.BPO2, forks.BPO3, forks.BPO4, forks.BPO5):
|
||||
return engine.StatelessPayloadStatusV1{Status: engine.INVALID}, unsupportedForkErr("newPayloadV4 must only be called for prague/osaka payloads")
|
||||
}
|
||||
requests := convertRequests(executionRequests)
|
||||
if err := validateRequests(requests); err != nil {
|
||||
|
|
|
|||
Loading…
Reference in a new issue