mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-06-06 15:08:39 +00:00
eth/catalyst: add Engine API stubs for Amsterdam fork
Add Engine API method stubs for the Amsterdam fork (Gloas on CL side): - engine_newPayloadV5 for Amsterdam payloads - engine_getPayloadV6 for Amsterdam payloads - engine_newPayloadWithWitnessV5 for witness generation - engine_executeStatelessPayloadV5 for stateless execution - Update engine_forkchoiceUpdatedV3 to accept Amsterdam payloads - Add PayloadV4 constant for ExecutionPayloadV4 This is a minimal implementation with method stubs only - no blockAccessList (EIP-7928) integration yet. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
parent
c12959dc8c
commit
1f3041824f
3 changed files with 106 additions and 4 deletions
|
|
@ -50,6 +50,13 @@ var (
|
||||||
// ExecutionPayloadV3 has the syntax of ExecutionPayloadV2 and appends the new
|
// ExecutionPayloadV3 has the syntax of ExecutionPayloadV2 and appends the new
|
||||||
// fields: blobGasUsed and excessBlobGas.
|
// fields: blobGasUsed and excessBlobGas.
|
||||||
PayloadV3 PayloadVersion = 0x3
|
PayloadV3 PayloadVersion = 0x3
|
||||||
|
|
||||||
|
// PayloadV4 is the identifier of ExecutionPayloadV4 introduced in amsterdam fork.
|
||||||
|
//
|
||||||
|
// https://github.com/ethereum/execution-apis/blob/main/src/engine/amsterdam.md#executionpayloadv4
|
||||||
|
// ExecutionPayloadV4 has the syntax of ExecutionPayloadV3 and appends the new
|
||||||
|
// field: blockAccessList (EIP-7928).
|
||||||
|
PayloadV4 PayloadVersion = 0x4
|
||||||
)
|
)
|
||||||
|
|
||||||
//go:generate go run github.com/fjl/gencodec -type PayloadAttributes -field-override payloadAttributesMarshaling -out gen_blockparams.go
|
//go:generate go run github.com/fjl/gencodec -type PayloadAttributes -field-override payloadAttributesMarshaling -out gen_blockparams.go
|
||||||
|
|
|
||||||
|
|
@ -198,8 +198,8 @@ func (api *ConsensusAPI) ForkchoiceUpdatedV3(update engine.ForkchoiceStateV1, pa
|
||||||
return engine.STATUS_INVALID, attributesErr("missing withdrawals")
|
return engine.STATUS_INVALID, attributesErr("missing withdrawals")
|
||||||
case params.BeaconRoot == nil:
|
case params.BeaconRoot == nil:
|
||||||
return engine.STATUS_INVALID, attributesErr("missing beacon root")
|
return engine.STATUS_INVALID, attributesErr("missing beacon root")
|
||||||
case !api.checkFork(params.Timestamp, forks.Cancun, forks.Prague, forks.Osaka, forks.BPO1, forks.BPO2, forks.BPO3, forks.BPO4, forks.BPO5):
|
case !api.checkFork(params.Timestamp, forks.Cancun, forks.Prague, forks.Osaka, forks.BPO1, forks.Amsterdam, forks.BPO2, forks.BPO3, forks.BPO4, forks.BPO5):
|
||||||
return engine.STATUS_INVALID, unsupportedForkErr("fcuV3 must only be called for cancun/prague/osaka payloads")
|
return engine.STATUS_INVALID, unsupportedForkErr("fcuV3 must only be called for cancun/prague/osaka/amsterdam payloads")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// TODO(matt): the spec requires that fcu is applied when called on a valid
|
// TODO(matt): the spec requires that fcu is applied when called on a valid
|
||||||
|
|
@ -452,9 +452,24 @@ func (api *ConsensusAPI) GetPayloadV5(payloadID engine.PayloadID) (*engine.Execu
|
||||||
forks.BPO3,
|
forks.BPO3,
|
||||||
forks.BPO4,
|
forks.BPO4,
|
||||||
forks.BPO5,
|
forks.BPO5,
|
||||||
|
// Amsterdam uses GetPayloadV6
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetPayloadV6 returns a cached payload by id. This endpoint should only
|
||||||
|
// be used after the Amsterdam fork.
|
||||||
|
//
|
||||||
|
// This method follows the same specification as engine_getPayloadV5 with
|
||||||
|
// changes of returning ExecutionPayloadV4 with blockAccessList.
|
||||||
|
func (api *ConsensusAPI) GetPayloadV6(payloadID engine.PayloadID) (*engine.ExecutionPayloadEnvelope, error) {
|
||||||
|
return api.getPayload(
|
||||||
|
payloadID,
|
||||||
|
false,
|
||||||
|
[]engine.PayloadVersion{engine.PayloadV4},
|
||||||
|
[]forks.Fork{forks.Amsterdam},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
// getPayload will retrieve the specified payload and verify it conforms to the
|
// getPayload will retrieve the specified payload and verify it conforms to the
|
||||||
// endpoint's allowed payload versions and forks.
|
// endpoint's allowed payload versions and forks.
|
||||||
//
|
//
|
||||||
|
|
@ -687,6 +702,8 @@ func (api *ConsensusAPI) NewPayloadV4(params engine.ExecutableData, versionedHas
|
||||||
return invalidStatus, paramsErr("nil beaconRoot post-cancun")
|
return invalidStatus, paramsErr("nil beaconRoot post-cancun")
|
||||||
case executionRequests == nil:
|
case executionRequests == nil:
|
||||||
return invalidStatus, paramsErr("nil executionRequests post-prague")
|
return invalidStatus, paramsErr("nil executionRequests post-prague")
|
||||||
|
case api.checkFork(params.Timestamp, forks.Amsterdam):
|
||||||
|
return invalidStatus, unsupportedForkErr("newPayloadV4 must not be called for amsterdam payloads, use newPayloadV5")
|
||||||
case !api.checkFork(params.Timestamp, forks.Prague, forks.Osaka, forks.BPO1, forks.BPO2, forks.BPO3, forks.BPO4, forks.BPO5):
|
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")
|
return invalidStatus, unsupportedForkErr("newPayloadV4 must only be called for prague/osaka payloads")
|
||||||
}
|
}
|
||||||
|
|
@ -697,6 +714,32 @@ func (api *ConsensusAPI) NewPayloadV4(params engine.ExecutableData, versionedHas
|
||||||
return api.newPayload(params, versionedHashes, beaconRoot, requests, false)
|
return api.newPayload(params, versionedHashes, beaconRoot, requests, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NewPayloadV5 creates an Eth1 block, inserts it in the chain, and returns the status of the chain.
|
||||||
|
// This endpoint should be used for the Amsterdam fork.
|
||||||
|
func (api *ConsensusAPI) NewPayloadV5(params engine.ExecutableData, versionedHashes []common.Hash, beaconRoot *common.Hash, executionRequests []hexutil.Bytes) (engine.PayloadStatusV1, error) {
|
||||||
|
switch {
|
||||||
|
case params.Withdrawals == nil:
|
||||||
|
return invalidStatus, paramsErr("nil withdrawals post-shanghai")
|
||||||
|
case params.ExcessBlobGas == nil:
|
||||||
|
return invalidStatus, paramsErr("nil excessBlobGas post-cancun")
|
||||||
|
case params.BlobGasUsed == nil:
|
||||||
|
return invalidStatus, paramsErr("nil blobGasUsed post-cancun")
|
||||||
|
case versionedHashes == nil:
|
||||||
|
return invalidStatus, paramsErr("nil versionedHashes post-cancun")
|
||||||
|
case beaconRoot == nil:
|
||||||
|
return invalidStatus, paramsErr("nil beaconRoot post-cancun")
|
||||||
|
case executionRequests == nil:
|
||||||
|
return invalidStatus, paramsErr("nil executionRequests post-prague")
|
||||||
|
case !api.checkFork(params.Timestamp, forks.Amsterdam):
|
||||||
|
return invalidStatus, unsupportedForkErr("newPayloadV5 must only be called for amsterdam payloads")
|
||||||
|
}
|
||||||
|
requests := convertRequests(executionRequests)
|
||||||
|
if err := validateRequests(requests); err != nil {
|
||||||
|
return engine.PayloadStatusV1{Status: engine.INVALID}, engine.InvalidParams.With(err)
|
||||||
|
}
|
||||||
|
return api.newPayload(params, versionedHashes, beaconRoot, requests, false)
|
||||||
|
}
|
||||||
|
|
||||||
func (api *ConsensusAPI) newPayload(params engine.ExecutableData, versionedHashes []common.Hash, beaconRoot *common.Hash, requests [][]byte, witness bool) (engine.PayloadStatusV1, error) {
|
func (api *ConsensusAPI) newPayload(params engine.ExecutableData, versionedHashes []common.Hash, beaconRoot *common.Hash, requests [][]byte, witness bool) (engine.PayloadStatusV1, error) {
|
||||||
// The locking here is, strictly, not required. Without these locks, this can happen:
|
// The locking here is, strictly, not required. Without these locks, this can happen:
|
||||||
//
|
//
|
||||||
|
|
|
||||||
|
|
@ -73,8 +73,8 @@ func (api *ConsensusAPI) ForkchoiceUpdatedWithWitnessV3(update engine.Forkchoice
|
||||||
return engine.STATUS_INVALID, attributesErr("missing withdrawals")
|
return engine.STATUS_INVALID, attributesErr("missing withdrawals")
|
||||||
case params.BeaconRoot == nil:
|
case params.BeaconRoot == nil:
|
||||||
return engine.STATUS_INVALID, attributesErr("missing beacon root")
|
return engine.STATUS_INVALID, attributesErr("missing beacon root")
|
||||||
case !api.checkFork(params.Timestamp, forks.Cancun, forks.Prague, forks.Osaka, forks.BPO1, forks.BPO2, forks.BPO3, forks.BPO4, forks.BPO5):
|
case !api.checkFork(params.Timestamp, forks.Cancun, forks.Prague, forks.Osaka, forks.BPO1, forks.Amsterdam, forks.BPO2, forks.BPO3, forks.BPO4, forks.BPO5):
|
||||||
return engine.STATUS_INVALID, unsupportedForkErr("fcuV3 must only be called for cancun/prague/osaka payloads")
|
return engine.STATUS_INVALID, unsupportedForkErr("fcuV3 must only be called for cancun/prague/osaka/amsterdam payloads")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// TODO(matt): the spec requires that fcu is applied when called on a valid
|
// TODO(matt): the spec requires that fcu is applied when called on a valid
|
||||||
|
|
@ -161,6 +161,32 @@ func (api *ConsensusAPI) NewPayloadWithWitnessV4(params engine.ExecutableData, v
|
||||||
return api.newPayload(params, versionedHashes, beaconRoot, requests, true)
|
return api.newPayload(params, versionedHashes, beaconRoot, requests, true)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NewPayloadWithWitnessV5 is analogous to NewPayloadV5, only it also generates
|
||||||
|
// and returns a stateless witness after running the payload.
|
||||||
|
func (api *ConsensusAPI) NewPayloadWithWitnessV5(params engine.ExecutableData, versionedHashes []common.Hash, beaconRoot *common.Hash, executionRequests []hexutil.Bytes) (engine.PayloadStatusV1, error) {
|
||||||
|
switch {
|
||||||
|
case params.Withdrawals == nil:
|
||||||
|
return invalidStatus, paramsErr("nil withdrawals post-shanghai")
|
||||||
|
case params.ExcessBlobGas == nil:
|
||||||
|
return invalidStatus, paramsErr("nil excessBlobGas post-cancun")
|
||||||
|
case params.BlobGasUsed == nil:
|
||||||
|
return invalidStatus, paramsErr("nil blobGasUsed post-cancun")
|
||||||
|
case versionedHashes == nil:
|
||||||
|
return invalidStatus, paramsErr("nil versionedHashes post-cancun")
|
||||||
|
case beaconRoot == nil:
|
||||||
|
return invalidStatus, paramsErr("nil beaconRoot post-cancun")
|
||||||
|
case executionRequests == nil:
|
||||||
|
return invalidStatus, paramsErr("nil executionRequests post-prague")
|
||||||
|
case !api.checkFork(params.Timestamp, forks.Amsterdam):
|
||||||
|
return invalidStatus, unsupportedForkErr("newPayloadWithWitnessV5 must only be called for amsterdam payloads")
|
||||||
|
}
|
||||||
|
requests := convertRequests(executionRequests)
|
||||||
|
if err := validateRequests(requests); err != nil {
|
||||||
|
return engine.PayloadStatusV1{Status: engine.INVALID}, engine.InvalidParams.With(err)
|
||||||
|
}
|
||||||
|
return api.newPayload(params, versionedHashes, beaconRoot, requests, true)
|
||||||
|
}
|
||||||
|
|
||||||
// ExecuteStatelessPayloadV1 is analogous to NewPayloadV1, only it operates in
|
// ExecuteStatelessPayloadV1 is analogous to NewPayloadV1, only it operates in
|
||||||
// a stateless mode on top of a provided witness instead of the local database.
|
// a stateless mode on top of a provided witness instead of the local database.
|
||||||
func (api *ConsensusAPI) ExecuteStatelessPayloadV1(params engine.ExecutableData, opaqueWitness hexutil.Bytes) (engine.StatelessPayloadStatusV1, error) {
|
func (api *ConsensusAPI) ExecuteStatelessPayloadV1(params engine.ExecutableData, opaqueWitness hexutil.Bytes) (engine.StatelessPayloadStatusV1, error) {
|
||||||
|
|
@ -238,6 +264,32 @@ func (api *ConsensusAPI) ExecuteStatelessPayloadV4(params engine.ExecutableData,
|
||||||
return api.executeStatelessPayload(params, versionedHashes, beaconRoot, requests, opaqueWitness)
|
return api.executeStatelessPayload(params, versionedHashes, beaconRoot, requests, opaqueWitness)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ExecuteStatelessPayloadV5 is analogous to NewPayloadV5, only it operates in
|
||||||
|
// a stateless mode on top of a provided witness instead of the local database.
|
||||||
|
func (api *ConsensusAPI) ExecuteStatelessPayloadV5(params engine.ExecutableData, versionedHashes []common.Hash, beaconRoot *common.Hash, executionRequests []hexutil.Bytes, opaqueWitness hexutil.Bytes) (engine.StatelessPayloadStatusV1, error) {
|
||||||
|
switch {
|
||||||
|
case params.Withdrawals == nil:
|
||||||
|
return engine.StatelessPayloadStatusV1{Status: engine.INVALID}, paramsErr("nil withdrawals post-shanghai")
|
||||||
|
case params.ExcessBlobGas == nil:
|
||||||
|
return engine.StatelessPayloadStatusV1{Status: engine.INVALID}, paramsErr("nil excessBlobGas post-cancun")
|
||||||
|
case params.BlobGasUsed == nil:
|
||||||
|
return engine.StatelessPayloadStatusV1{Status: engine.INVALID}, paramsErr("nil blobGasUsed post-cancun")
|
||||||
|
case versionedHashes == nil:
|
||||||
|
return engine.StatelessPayloadStatusV1{Status: engine.INVALID}, paramsErr("nil versionedHashes post-cancun")
|
||||||
|
case beaconRoot == nil:
|
||||||
|
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.Amsterdam):
|
||||||
|
return engine.StatelessPayloadStatusV1{Status: engine.INVALID}, unsupportedForkErr("executeStatelessPayloadV5 must only be called for amsterdam payloads")
|
||||||
|
}
|
||||||
|
requests := convertRequests(executionRequests)
|
||||||
|
if err := validateRequests(requests); err != nil {
|
||||||
|
return engine.StatelessPayloadStatusV1{Status: engine.INVALID}, engine.InvalidParams.With(err)
|
||||||
|
}
|
||||||
|
return api.executeStatelessPayload(params, versionedHashes, beaconRoot, requests, opaqueWitness)
|
||||||
|
}
|
||||||
|
|
||||||
func (api *ConsensusAPI) executeStatelessPayload(params engine.ExecutableData, versionedHashes []common.Hash, beaconRoot *common.Hash, requests [][]byte, opaqueWitness hexutil.Bytes) (engine.StatelessPayloadStatusV1, error) {
|
func (api *ConsensusAPI) executeStatelessPayload(params engine.ExecutableData, versionedHashes []common.Hash, beaconRoot *common.Hash, requests [][]byte, opaqueWitness hexutil.Bytes) (engine.StatelessPayloadStatusV1, error) {
|
||||||
log.Trace("Engine API request received", "method", "ExecuteStatelessPayload", "number", params.Number, "hash", params.BlockHash)
|
log.Trace("Engine API request received", "method", "ExecuteStatelessPayload", "number", params.Number, "hash", params.BlockHash)
|
||||||
block, err := engine.ExecutableDataToBlockNoHash(params, versionedHashes, beaconRoot, requests)
|
block, err := engine.ExecutableDataToBlockNoHash(params, versionedHashes, beaconRoot, requests)
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue