Skip to content

Commit 2a82964

Browse files
authored
eth/catalyst, beacon/engine: enable BPO and Osaka on stateless APIs (#32636)
Addresses #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.
1 parent ab95477 commit 2a82964

File tree

4 files changed

+60
-19
lines changed

4 files changed

+60
-19
lines changed

beacon/engine/gen_epe.go

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

beacon/engine/types.go

Lines changed: 35 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -33,8 +33,22 @@ import (
3333
type PayloadVersion byte
3434

3535
var (
36+
// PayloadV1 is the identifier of ExecutionPayloadV1 introduced in paris fork.
37+
// https://github.com/ethereum/execution-apis/blob/main/src/engine/paris.md#executionpayloadv1
3638
PayloadV1 PayloadVersion = 0x1
39+
40+
// PayloadV2 is the identifier of ExecutionPayloadV2 introduced in shanghai fork.
41+
//
42+
// https://github.com/ethereum/execution-apis/blob/main/src/engine/shanghai.md#executionpayloadv2
43+
// ExecutionPayloadV2 has the syntax of ExecutionPayloadV1 and appends a
44+
// single field: withdrawals.
3745
PayloadV2 PayloadVersion = 0x2
46+
47+
// PayloadV3 is the identifier of ExecutionPayloadV3 introduced in cancun fork.
48+
//
49+
// https://github.com/ethereum/execution-apis/blob/main/src/engine/cancun.md#executionpayloadv3
50+
// ExecutionPayloadV3 has the syntax of ExecutionPayloadV2 and appends the new
51+
// fields: blobGasUsed and excessBlobGas.
3852
PayloadV3 PayloadVersion = 0x3
3953
)
4054

@@ -106,13 +120,18 @@ type StatelessPayloadStatusV1 struct {
106120
type ExecutionPayloadEnvelope struct {
107121
ExecutionPayload *ExecutableData `json:"executionPayload" gencodec:"required"`
108122
BlockValue *big.Int `json:"blockValue" gencodec:"required"`
109-
BlobsBundle *BlobsBundleV1 `json:"blobsBundle"`
123+
BlobsBundle *BlobsBundle `json:"blobsBundle"`
110124
Requests [][]byte `json:"executionRequests"`
111125
Override bool `json:"shouldOverrideBuilder"`
112126
Witness *hexutil.Bytes `json:"witness,omitempty"`
113127
}
114128

115-
type BlobsBundleV1 struct {
129+
// BlobsBundle includes the marshalled sidecar data. Note this structure is
130+
// shared by BlobsBundleV1 and BlobsBundleV2 for the sake of simplicity.
131+
//
132+
// - BlobsBundleV1: proofs contain exactly len(blobs) kzg proofs.
133+
// - BlobsBundleV2: proofs contain exactly CELLS_PER_EXT_BLOB * len(blobs) cell proofs.
134+
type BlobsBundle struct {
116135
Commitments []hexutil.Bytes `json:"commitments"`
117136
Proofs []hexutil.Bytes `json:"proofs"`
118137
Blobs []hexutil.Bytes `json:"blobs"`
@@ -125,7 +144,7 @@ type BlobAndProofV1 struct {
125144

126145
type BlobAndProofV2 struct {
127146
Blob hexutil.Bytes `json:"blob"`
128-
CellProofs []hexutil.Bytes `json:"proofs"`
147+
CellProofs []hexutil.Bytes `json:"proofs"` // proofs MUST contain exactly CELLS_PER_EXT_BLOB cell proofs.
129148
}
130149

131150
// JSON type overrides for ExecutionPayloadEnvelope.
@@ -327,18 +346,27 @@ func BlockToExecutableData(block *types.Block, fees *big.Int, sidecars []*types.
327346
}
328347

329348
// Add blobs.
330-
bundle := BlobsBundleV1{
349+
bundle := BlobsBundle{
331350
Commitments: make([]hexutil.Bytes, 0),
332351
Blobs: make([]hexutil.Bytes, 0),
333352
Proofs: make([]hexutil.Bytes, 0),
334353
}
335354
for _, sidecar := range sidecars {
336355
for j := range sidecar.Blobs {
337-
bundle.Blobs = append(bundle.Blobs, hexutil.Bytes(sidecar.Blobs[j][:]))
338-
bundle.Commitments = append(bundle.Commitments, hexutil.Bytes(sidecar.Commitments[j][:]))
356+
bundle.Blobs = append(bundle.Blobs, sidecar.Blobs[j][:])
357+
bundle.Commitments = append(bundle.Commitments, sidecar.Commitments[j][:])
339358
}
359+
// - Before the Osaka fork, only version-0 blob transactions should be packed,
360+
// with the proof length equal to len(blobs).
361+
//
362+
// - After the Osaka fork, only version-1 blob transactions should be packed,
363+
// with the proof length equal to CELLS_PER_EXT_BLOB * len(blobs).
364+
//
365+
// Ideally, length validation should be performed based on the bundle version.
366+
// In practice, this is unnecessary because blob transaction filtering is
367+
// already done during payload construction.
340368
for _, proof := range sidecar.Proofs {
341-
bundle.Proofs = append(bundle.Proofs, hexutil.Bytes(proof[:]))
369+
bundle.Proofs = append(bundle.Proofs, proof[:])
342370
}
343371
}
344372

eth/catalyst/api.go

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -418,29 +418,42 @@ func (api *ConsensusAPI) GetPayloadV1(payloadID engine.PayloadID) (*engine.Execu
418418

419419
// GetPayloadV2 returns a cached payload by id.
420420
func (api *ConsensusAPI) GetPayloadV2(payloadID engine.PayloadID) (*engine.ExecutionPayloadEnvelope, error) {
421+
// executionPayload: ExecutionPayloadV1 | ExecutionPayloadV2 where:
422+
//
423+
// - ExecutionPayloadV1 MUST be returned if the payload timestamp is lower
424+
// than the Shanghai timestamp
425+
//
426+
// - ExecutionPayloadV2 MUST be returned if the payload timestamp is greater
427+
// or equal to the Shanghai timestamp
421428
if !payloadID.Is(engine.PayloadV1, engine.PayloadV2) {
422429
return nil, engine.UnsupportedFork
423430
}
424431
return api.getPayload(payloadID, false)
425432
}
426433

427-
// GetPayloadV3 returns a cached payload by id.
434+
// GetPayloadV3 returns a cached payload by id. This endpoint should only
435+
// be used for the Cancun fork.
428436
func (api *ConsensusAPI) GetPayloadV3(payloadID engine.PayloadID) (*engine.ExecutionPayloadEnvelope, error) {
429437
if !payloadID.Is(engine.PayloadV3) {
430438
return nil, engine.UnsupportedFork
431439
}
432440
return api.getPayload(payloadID, false)
433441
}
434442

435-
// GetPayloadV4 returns a cached payload by id.
443+
// GetPayloadV4 returns a cached payload by id. This endpoint should only
444+
// be used for the Prague fork.
436445
func (api *ConsensusAPI) GetPayloadV4(payloadID engine.PayloadID) (*engine.ExecutionPayloadEnvelope, error) {
437446
if !payloadID.Is(engine.PayloadV3) {
438447
return nil, engine.UnsupportedFork
439448
}
440449
return api.getPayload(payloadID, false)
441450
}
442451

443-
// GetPayloadV5 returns a cached payload by id.
452+
// GetPayloadV5 returns a cached payload by id. This endpoint should only
453+
// be used after the Osaka fork.
454+
//
455+
// This method follows the same specification as engine_getPayloadV4 with
456+
// changes of returning BlobsBundleV2 with BlobSidecar version 1.
444457
func (api *ConsensusAPI) GetPayloadV5(payloadID engine.PayloadID) (*engine.ExecutionPayloadEnvelope, error) {
445458
if !payloadID.Is(engine.PayloadV3) {
446459
return nil, engine.UnsupportedFork
@@ -637,7 +650,7 @@ func (api *ConsensusAPI) NewPayloadV4(params engine.ExecutableData, versionedHas
637650
case executionRequests == nil:
638651
return invalidStatus, paramsErr("nil executionRequests post-prague")
639652
case !api.checkFork(params.Timestamp, forks.Prague, forks.Osaka, forks.BPO1, forks.BPO2, forks.BPO3, forks.BPO4, forks.BPO5):
640-
return invalidStatus, unsupportedForkErr("newPayloadV4 must only be called for Prague payloads")
653+
return invalidStatus, unsupportedForkErr("newPayloadV4 must only be called for prague/osaka payloads")
641654
}
642655
requests := convertRequests(executionRequests)
643656
if err := validateRequests(requests); err != nil {

eth/catalyst/witness.go

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -73,8 +73,8 @@ func (api *ConsensusAPI) ForkchoiceUpdatedWithWitnessV3(update engine.Forkchoice
7373
return engine.STATUS_INVALID, attributesErr("missing withdrawals")
7474
case params.BeaconRoot == nil:
7575
return engine.STATUS_INVALID, attributesErr("missing beacon root")
76-
case !api.checkFork(params.Timestamp, forks.Cancun, forks.Prague):
77-
return engine.STATUS_INVALID, unsupportedForkErr("fcuV3 must only be called for cancun or prague payloads")
76+
case !api.checkFork(params.Timestamp, forks.Cancun, forks.Prague, forks.Osaka, forks.BPO1, forks.BPO2, forks.BPO3, forks.BPO4, forks.BPO5):
77+
return engine.STATUS_INVALID, unsupportedForkErr("fcuV3 must only be called for cancun/prague/osaka payloads")
7878
}
7979
}
8080
// 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
151151
return invalidStatus, paramsErr("nil beaconRoot post-cancun")
152152
case executionRequests == nil:
153153
return invalidStatus, paramsErr("nil executionRequests post-prague")
154-
case !api.checkFork(params.Timestamp, forks.Prague):
155-
return invalidStatus, unsupportedForkErr("newPayloadV4 must only be called for prague payloads")
154+
case !api.checkFork(params.Timestamp, forks.Prague, forks.Osaka, forks.BPO1, forks.BPO2, forks.BPO3, forks.BPO4, forks.BPO5):
155+
return invalidStatus, unsupportedForkErr("newPayloadV4 must only be called for prague/osaka payloads")
156156
}
157157
requests := convertRequests(executionRequests)
158158
if err := validateRequests(requests); err != nil {
@@ -228,8 +228,8 @@ func (api *ConsensusAPI) ExecuteStatelessPayloadV4(params engine.ExecutableData,
228228
return engine.StatelessPayloadStatusV1{Status: engine.INVALID}, paramsErr("nil beaconRoot post-cancun")
229229
case executionRequests == nil:
230230
return engine.StatelessPayloadStatusV1{Status: engine.INVALID}, paramsErr("nil executionRequests post-prague")
231-
case !api.checkFork(params.Timestamp, forks.Prague, forks.Osaka):
232-
return engine.StatelessPayloadStatusV1{Status: engine.INVALID}, unsupportedForkErr("newPayloadV4 must only be called for prague payloads")
231+
case !api.checkFork(params.Timestamp, forks.Prague, forks.Osaka, forks.BPO1, forks.BPO2, forks.BPO3, forks.BPO4, forks.BPO5):
232+
return engine.StatelessPayloadStatusV1{Status: engine.INVALID}, unsupportedForkErr("newPayloadV4 must only be called for prague/osaka payloads")
233233
}
234234
requests := convertRequests(executionRequests)
235235
if err := validateRequests(requests); err != nil {

0 commit comments

Comments
 (0)