eth/catalyst: check fork timestamps during engine_getPayload (#32754)

This adds checks into getPayload to ensure the correct version is called
for the fork which applies to the payload.

---------

Co-authored-by: jsvisa <delweng@gmail.com>
This commit is contained in:
lightclient 2025-11-28 10:02:24 -03:00 committed by GitHub
parent a122dbe459
commit 28376aea78
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -402,10 +402,12 @@ func (api *ConsensusAPI) ExchangeTransitionConfigurationV1(config engine.Transit
// GetPayloadV1 returns a cached payload by id. // GetPayloadV1 returns a cached payload by id.
func (api *ConsensusAPI) GetPayloadV1(payloadID engine.PayloadID) (*engine.ExecutableData, error) { func (api *ConsensusAPI) GetPayloadV1(payloadID engine.PayloadID) (*engine.ExecutableData, error) {
if !payloadID.Is(engine.PayloadV1) { data, err := api.getPayload(
return nil, engine.UnsupportedFork payloadID,
} false,
data, err := api.getPayload(payloadID, false) []engine.PayloadVersion{engine.PayloadV1},
nil,
)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -414,35 +416,34 @@ func (api *ConsensusAPI) GetPayloadV1(payloadID engine.PayloadID) (*engine.Execu
// GetPayloadV2 returns a cached payload by id. // GetPayloadV2 returns a cached payload by id.
func (api *ConsensusAPI) GetPayloadV2(payloadID engine.PayloadID) (*engine.ExecutionPayloadEnvelope, error) { func (api *ConsensusAPI) GetPayloadV2(payloadID engine.PayloadID) (*engine.ExecutionPayloadEnvelope, error) {
// executionPayload: ExecutionPayloadV1 | ExecutionPayloadV2 where: return api.getPayload(
// payloadID,
// - ExecutionPayloadV1 MUST be returned if the payload timestamp is lower false,
// than the Shanghai timestamp []engine.PayloadVersion{engine.PayloadV1, engine.PayloadV2},
// []forks.Fork{forks.Shanghai},
// - 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. This endpoint should only // GetPayloadV3 returns a cached payload by id. This endpoint should only
// be used for the Cancun fork. // be used for the Cancun fork.
func (api *ConsensusAPI) GetPayloadV3(payloadID engine.PayloadID) (*engine.ExecutionPayloadEnvelope, error) { func (api *ConsensusAPI) GetPayloadV3(payloadID engine.PayloadID) (*engine.ExecutionPayloadEnvelope, error) {
if !payloadID.Is(engine.PayloadV3) { return api.getPayload(
return nil, engine.UnsupportedFork payloadID,
} false,
return api.getPayload(payloadID, false) []engine.PayloadVersion{engine.PayloadV3},
[]forks.Fork{forks.Cancun},
)
} }
// GetPayloadV4 returns a cached payload by id. This endpoint should only // GetPayloadV4 returns a cached payload by id. This endpoint should only
// be used for the Prague fork. // be used for the Prague fork.
func (api *ConsensusAPI) GetPayloadV4(payloadID engine.PayloadID) (*engine.ExecutionPayloadEnvelope, error) { func (api *ConsensusAPI) GetPayloadV4(payloadID engine.PayloadID) (*engine.ExecutionPayloadEnvelope, error) {
if !payloadID.Is(engine.PayloadV3) { return api.getPayload(
return nil, engine.UnsupportedFork payloadID,
} false,
return api.getPayload(payloadID, false) []engine.PayloadVersion{engine.PayloadV3},
[]forks.Fork{forks.Prague},
)
} }
// GetPayloadV5 returns a cached payload by id. This endpoint should only // GetPayloadV5 returns a cached payload by id. This endpoint should only
@ -451,18 +452,35 @@ func (api *ConsensusAPI) GetPayloadV4(payloadID engine.PayloadID) (*engine.Execu
// This method follows the same specification as engine_getPayloadV4 with // This method follows the same specification as engine_getPayloadV4 with
// changes of returning BlobsBundleV2 with BlobSidecar version 1. // changes of returning BlobsBundleV2 with BlobSidecar version 1.
func (api *ConsensusAPI) GetPayloadV5(payloadID engine.PayloadID) (*engine.ExecutionPayloadEnvelope, error) { func (api *ConsensusAPI) GetPayloadV5(payloadID engine.PayloadID) (*engine.ExecutionPayloadEnvelope, error) {
if !payloadID.Is(engine.PayloadV3) { return api.getPayload(
return nil, engine.UnsupportedFork payloadID,
} false,
return api.getPayload(payloadID, false) []engine.PayloadVersion{engine.PayloadV3},
[]forks.Fork{
forks.Osaka,
forks.BPO1,
forks.BPO2,
forks.BPO3,
forks.BPO4,
forks.BPO5,
})
} }
func (api *ConsensusAPI) getPayload(payloadID engine.PayloadID, full bool) (*engine.ExecutionPayloadEnvelope, error) { // getPayload will retreive the specified payload and verify it conforms to the
// endpoint's allowed payload versions and forks.
func (api *ConsensusAPI) getPayload(payloadID engine.PayloadID, full bool, versions []engine.PayloadVersion, forks []forks.Fork) (*engine.ExecutionPayloadEnvelope, error) {
log.Trace("Engine API request received", "method", "GetPayload", "id", payloadID) log.Trace("Engine API request received", "method", "GetPayload", "id", payloadID)
if !payloadID.Is(versions...) {
return nil, engine.UnsupportedFork
}
data := api.localBlocks.get(payloadID, full) data := api.localBlocks.get(payloadID, full)
if data == nil { if data == nil {
return nil, engine.UnknownPayload return nil, engine.UnknownPayload
} }
if forks != nil && !api.checkFork(data.ExecutionPayload.Timestamp, forks...) {
return nil, engine.UnsupportedFork
}
return data, nil return data, nil
} }