diff --git a/nimbus/beacon/api_handler.nim b/nimbus/beacon/api_handler.nim index 56ca18f0d..7875cfd90 100644 --- a/nimbus/beacon/api_handler.nim +++ b/nimbus/beacon/api_handler.nim @@ -1,5 +1,5 @@ # Nimbus -# Copyright (c) 2023 Status Research & Development GmbH +# Copyright (c) 2023-2024 Status Research & Development GmbH # Licensed under either of # * Apache License, version 2.0, ([LICENSE-APACHE](LICENSE-APACHE)) # * MIT license ([LICENSE-MIT](LICENSE-MIT)) @@ -47,6 +47,7 @@ export invalidStatus, getPayload, getPayloadV3, + getPayloadV4, getPayloadBodiesByHash, getPayloadBodiesByRange, exchangeConf, diff --git a/nimbus/beacon/api_handler/api_getpayload.nim b/nimbus/beacon/api_handler/api_getpayload.nim index 6b494adfc..087a7d592 100644 --- a/nimbus/beacon/api_handler/api_getpayload.nim +++ b/nimbus/beacon/api_handler/api_getpayload.nim @@ -1,5 +1,5 @@ # Nimbus -# Copyright (c) 2023 Status Research & Development GmbH +# Copyright (c) 2023-2024 Status Research & Development GmbH # Licensed under either of # * Apache License, version 2.0, ([LICENSE-APACHE](LICENSE-APACHE)) # * MIT license ([LICENSE-MIT](LICENSE-MIT)) @@ -80,3 +80,44 @@ proc getPayloadV3*(ben: BeaconEngineRef, id: PayloadID): GetPayloadV3Response = blobsBundle: blobsBundle, shouldOverrideBuilder: false ) + +proc getPayloadV4*(ben: BeaconEngineRef, id: PayloadID): GetPayloadV4Response = + trace "Engine API request received", + meth = "GetPayload", id + + var payloadGeneric: ExecutionPayload + var blockValue: UInt256 + if not ben.get(id, blockValue, payloadGeneric): + raise unknownPayload("Unknown payload") + + let version = payloadGeneric.version + if version != Version.V4: + raise unsupportedFork("getPayloadV4 expect ExecutionPayloadV4 but get ExecutionPayload" & $version) + + let payload = payloadGeneric.V4 + let com = ben.com + if not com.isPragueOrLater(ethTime payload.timestamp): + raise unsupportedFork("payload timestamp is less than Prague activation") + + var + blobsBundle: BlobsBundleV1 + + try: + for ttx in payload.transactions: + let tx = rlp.decode(distinctBase(ttx), Transaction) + if tx.networkPayload.isNil.not: + for blob in tx.networkPayload.blobs: + blobsBundle.blobs.add Web3Blob(blob) + for p in tx.networkPayload.proofs: + blobsBundle.proofs.add Web3KZGProof(p) + for k in tx.networkPayload.commitments: + blobsBundle.commitments.add Web3KZGCommitment(k) + except RlpError: + doAssert(false, "found TypedTransaction that RLP failed to decode") + + GetPayloadV4Response( + executionPayload: payload, + blockValue: blockValue, + blobsBundle: blobsBundle, + shouldOverrideBuilder: false + ) diff --git a/nimbus/beacon/api_handler/api_newpayload.nim b/nimbus/beacon/api_handler/api_newpayload.nim index 025b9764b..e261ce8ba 100644 --- a/nimbus/beacon/api_handler/api_newpayload.nim +++ b/nimbus/beacon/api_handler/api_newpayload.nim @@ -20,6 +20,15 @@ import {.push gcsafe, raises:[CatchableError].} template validateVersion(com, timestamp, version, apiVersion) = + if apiVersion == Version.V4: + if not com.isPragueOrLater(timestamp): + raise unsupportedFork("newPayloadV4 expect payload timestamp fall within Prague") + + if com.isPragueOrLater(timestamp): + if version != Version.V4: + raise invalidParams("if timestamp is Prague or later, " & + "payload must be ExecutionPayloadV4") + if apiVersion == Version.V3: if not com.isCancunOrLater(timestamp): raise unsupportedFork("newPayloadV3 expect payload timestamp fall within Cancun") @@ -42,14 +51,19 @@ template validateVersion(com, timestamp, version, apiVersion) = raise invalidParams("if timestamp is earlier than Shanghai, " & "payload must be ExecutionPayloadV1") - if apiVersion == Version.V3: + if apiVersion >= Version.V3: if version != apiVersion: raise invalidParams("newPayload" & $apiVersion & " expect ExecutionPayload" & $apiVersion & " but got ExecutionPayload" & $version) template validatePayload(apiVersion, version, payload) = - if version == Version.V3: + if version >= Version.V2: + if payload.withdrawals.isNone: + raise invalidParams("newPayload" & $apiVersion & + "withdrawals is expected from execution payload") + + if version >= Version.V3: if payload.blobGasUsed.isNone: raise invalidParams("newPayload" & $apiVersion & "blobGasUsed is expected from execution payload") @@ -57,6 +71,15 @@ template validatePayload(apiVersion, version, payload) = raise invalidParams("newPayload" & $apiVersion & "excessBlobGas is expected from execution payload") + if version >= Version.V4: + if payload.depositReceipts.isNone: + raise invalidParams("newPayload" & $apiVersion & + "depositReceipts is expected from execution payload") + if payload.exits.isNone: + raise invalidParams("newPayload" & $apiVersion & + "exits is expected from execution payload") + + proc newPayload*(ben: BeaconEngineRef, apiVersion: Version, payload: ExecutionPayload, diff --git a/nimbus/rpc/engine_api.nim b/nimbus/rpc/engine_api.nim index fe7fea9a5..ecee40a50 100644 --- a/nimbus/rpc/engine_api.nim +++ b/nimbus/rpc/engine_api.nim @@ -23,9 +23,11 @@ const supportedMethods: HashSet[string] = "engine_newPayloadV1", "engine_newPayloadV2", "engine_newPayloadV3", + "engine_newPayloadV4", "engine_getPayloadV1", "engine_getPayloadV2", "engine_getPayloadV3", + "engine_getPayloadV4", "engine_exchangeTransitionConfigurationV1", "engine_forkchoiceUpdatedV1", "engine_forkchoiceUpdatedV2", @@ -57,6 +59,15 @@ proc setupEngineAPI*(engine: BeaconEngineRef, server: RpcServer) = return invalidStatus() return engine.newPayload(Version.V3, payload, parentBeaconBlockRoot) + server.rpc("engine_newPayloadV4") do(payload: ExecutionPayload, + expectedBlobVersionedHashes: Option[seq[Web3Hash]], + parentBeaconBlockRoot: Option[Web3Hash]) -> PayloadStatusV1: + if expectedBlobVersionedHashes.isNone: + raise invalidParams("newPayloadV4 expect blobVersionedHashes but got none") + if not validateVersionedHashed(payload, expectedBlobVersionedHashes.get): + return invalidStatus() + return engine.newPayload(Version.V4, payload, parentBeaconBlockRoot) + server.rpc("engine_getPayloadV1") do(payloadId: PayloadID) -> ExecutionPayloadV1: return engine.getPayload(Version.V1, payloadId).executionPayload.V1 @@ -66,6 +77,9 @@ proc setupEngineAPI*(engine: BeaconEngineRef, server: RpcServer) = server.rpc("engine_getPayloadV3") do(payloadId: PayloadID) -> GetPayloadV3Response: return engine.getPayloadV3(payloadId) + server.rpc("engine_getPayloadV4") do(payloadId: PayloadID) -> GetPayloadV4Response: + return engine.getPayloadV4(payloadId) + server.rpc("engine_exchangeTransitionConfigurationV1") do( conf: TransitionConfigurationV1) -> TransitionConfigurationV1: return engine.exchangeConf(conf)