diff --git a/execution_chain/beacon/api_handler.nim b/execution_chain/beacon/api_handler.nim index 5a45378b40..0c4f64bc7b 100644 --- a/execution_chain/beacon/api_handler.nim +++ b/execution_chain/beacon/api_handler.nim @@ -25,6 +25,7 @@ export getPayloadV3, getPayloadV4, getPayloadV5, + getPayloadV6, getPayloadBodiesByHash, getPayloadBodiesByRange, newPayload, diff --git a/execution_chain/beacon/api_handler/api_getpayload.nim b/execution_chain/beacon/api_handler/api_getpayload.nim index 976d52fb2f..3eecbf3449 100644 --- a/execution_chain/beacon/api_handler/api_getpayload.nim +++ b/execution_chain/beacon/api_handler/api_getpayload.nim @@ -26,7 +26,7 @@ proc getPayload*(ben: BeaconEngineRef, let bundle = ben.getPayloadBundle(id).valueOr: raise unknownPayload("Unknown bundle") - let + let version = bundle.payload.version com = ben.com @@ -112,7 +112,7 @@ proc getPayloadV5*(ben: BeaconEngineRef, id: Bytes8): GetPayloadV5Response = let version = bundle.payload.version if version != Version.V3: - raise unsupportedFork("getPayloadV5 expect payloadV3 but get payload" & $version) + raise unsupportedFork("getPayloadV5 expect ExecutionPayloadV3 but got ExecutionPayload" & $version) if bundle.blobsBundle.isNil: raise unsupportedFork("getPayloadV5 is missing BlobsBundleV2") if bundle.executionRequests.isNone: @@ -122,10 +122,40 @@ proc getPayloadV5*(ben: BeaconEngineRef, id: Bytes8): GetPayloadV5Response = if not com.isOsakaOrLater(ethTime bundle.payload.timestamp): raise unsupportedFork("bundle timestamp is less than Osaka activation") + if com.isAmsterdamOrLater(ethTime bundle.payload.timestamp): + raise unsupportedFork("bundle timestamp greater than Amsterdam must use getPayloadV6") + GetPayloadV5Response( executionPayload: bundle.payload.V3, blockValue: bundle.blockValue, blobsBundle: bundle.blobsBundle.V2, shouldOverrideBuilder: false, executionRequests: bundle.executionRequests.get, - ) \ No newline at end of file + ) + +proc getPayloadV6*(ben: BeaconEngineRef, id: Bytes8): GetPayloadV6Response = + trace "Engine API request received", + meth = "GetPayload", id + + let bundle = ben.getPayloadBundle(id).valueOr: + raise unknownPayload("Unknown bundle") + + let version = bundle.payload.version + if version != Version.V4: + raise unsupportedFork("getPayloadV6 expect ExecutionPayloadV4 but got ExecutionPayload" & $version) + if bundle.blobsBundle.isNil: + raise unsupportedFork("getPayloadV6 is missing BlobsBundleV2") + if bundle.executionRequests.isNone: + raise unsupportedFork("getPayloadV6 is missing executionRequests") + + let com = ben.com + if not com.isAmsterdamOrLater(ethTime bundle.payload.timestamp): + raise unsupportedFork("bundle timestamp is less than Amsterdam activation") + + GetPayloadV6Response( + executionPayload: bundle.payload.V4, + blockValue: bundle.blockValue, + blobsBundle: bundle.blobsBundle.V2, + shouldOverrideBuilder: false, + executionRequests: bundle.executionRequests.get, + ) diff --git a/execution_chain/beacon/api_handler/api_newpayload.nim b/execution_chain/beacon/api_handler/api_newpayload.nim index 6668ca6d49..4ed727dade 100644 --- a/execution_chain/beacon/api_handler/api_newpayload.nim +++ b/execution_chain/beacon/api_handler/api_newpayload.nim @@ -41,6 +41,20 @@ func validateVersionedHashed(payload: ExecutionPayload, true template validateVersion(com, timestamp, payloadVersion, apiVersion) = + if apiVersion == Version.V5: + if not com.isAmsterdamOrLater(timestamp): + raise unsupportedFork("newPayloadV5 expect payload timestamp fall within Amsterdam") + + if payloadVersion != Version.V4: + raise invalidParams("newPayload" & $apiVersion & + " expect ExecutionPayloadV4" & + " but got ExecutionPayload" & $payloadVersion) + + if com.isAmsterdamOrLater(timestamp): + if payloadVersion != Version.V4: + raise invalidParams("if timestamp is Amsterdam or later, " & + "payload must be ExecutionPayloadV4, got ExecutionPayload" & $payloadVersion) + if apiVersion == Version.V4: if not com.isPragueOrLater(timestamp): raise unsupportedFork("newPayloadV4 expect payload timestamp fall within Prague") @@ -72,7 +86,7 @@ template validateVersion(com, timestamp, payloadVersion, apiVersion) = # both newPayloadV3 and newPayloadV4 expect ExecutionPayloadV3 if payloadVersion != Version.V3: raise invalidParams("newPayload" & $apiVersion & - " expect ExecutionPayload3" & + " expect ExecutionPayloadV3" & " but got ExecutionPayload" & $payloadVersion) template validatePayload(apiVersion, payloadVersion, payload) = @@ -89,6 +103,11 @@ template validatePayload(apiVersion, payloadVersion, payload) = raise invalidParams("newPayload" & $apiVersion & "excessBlobGas is expected from execution payload") + if apiVersion >= Version.V5 or payloadVersion >= Version.V4: + if payload.blockAccessList.isNone: + raise invalidParams("newPayload" & $apiVersion & + "blockAccessList is expected from execution payload") + # https://github.com/ethereum/execution-apis/blob/40088597b8b4f48c45184da002e27ffc3c37641f/src/engine/prague.md#request func validateExecutionRequest(blockHash: Hash32, requests: openArray[seq[byte]], apiVersion: Version): diff --git a/execution_chain/beacon/payload_conv.nim b/execution_chain/beacon/payload_conv.nim index 69fd47365d..38ad2f87ea 100644 --- a/execution_chain/beacon/payload_conv.nim +++ b/execution_chain/beacon/payload_conv.nim @@ -40,6 +40,12 @@ func wdRoot(x: Opt[seq[WithdrawalV1]]): Opt[Hash32] = func txRoot(list: openArray[Web3Tx]): Hash32 = orderedTrieRoot(list) +func balHash(bal: Opt[seq[byte]]): Opt[Hash32] = + if bal.isNone(): + Opt.none(Hash32) + else: + Opt.some(keccak256(bal.get)) + # ------------------------------------------------------------------------------ # Public functions # ------------------------------------------------------------------------------ @@ -63,6 +69,7 @@ func executionPayload*(blk: Block): ExecutionPayload = withdrawals : w3Withdrawals blk.withdrawals, blobGasUsed : w3Qty blk.header.blobGasUsed, excessBlobGas: w3Qty blk.header.excessBlobGas, + blockAccessList: w3BlockAccessList blk.blockAccessList ) func executionPayloadV1V2*(blk: Block): ExecutionPayloadV1OrV2 = @@ -110,23 +117,26 @@ func blockHeader*(p: ExecutionPayload, excessBlobGas : u64(p.excessBlobGas), parentBeaconBlockRoot: parentBeaconBlockRoot, requestsHash : requestsHash, + blockAccessListHash: balHash p.blockAccessList, ) func blockBody*(p: ExecutionPayload): - BlockBody {.gcsafe, raises:[RlpError].} = + BlockBody {.gcsafe, raises: [RlpError].} = BlockBody( uncles : @[], transactions: ethTxs p.transactions, withdrawals : ethWithdrawals p.withdrawals, + blockAccessList: ethBlockAccessList p.blockAccessList, ) func ethBlock*(p: ExecutionPayload, parentBeaconBlockRoot: Opt[Hash32], requestsHash: Opt[Hash32]): - Block {.gcsafe, raises:[RlpError].} = + Block {.gcsafe, raises: [RlpError].} = Block( header : blockHeader(p, parentBeaconBlockRoot, requestsHash), uncles : @[], transactions: ethTxs p.transactions, withdrawals : ethWithdrawals p.withdrawals, + blockAccessList: ethBlockAccessList p.blockAccessList, ) diff --git a/execution_chain/beacon/web3_eth_conv.nim b/execution_chain/beacon/web3_eth_conv.nim index f2bbd4576d..6c12dede61 100644 --- a/execution_chain/beacon/web3_eth_conv.nim +++ b/execution_chain/beacon/web3_eth_conv.nim @@ -84,15 +84,26 @@ func ethWithdrawals*(x: Opt[seq[WithdrawalV1]]): if x.isNone: Opt.none(seq[Withdrawal]) else: Opt.some(ethWithdrawals x.get) -func ethTx*(x: Web3Tx): common.Transaction {.gcsafe, raises:[RlpError].} = +func ethTx*(x: Web3Tx): common.Transaction {.gcsafe, raises: [RlpError].} = result = rlp.decode(distinctBase x, common.Transaction) func ethTxs*(list: openArray[Web3Tx]): - seq[common.Transaction] {.gcsafe, raises:[RlpError].} = + seq[common.Transaction] {.gcsafe, raises: [RlpError].} = result = newSeqOfCap[common.Transaction](list.len) for x in list: result.add ethTx(x) +func ethBlockAccessList*( + bal: openArray[byte]): BlockAccessList {.gcsafe, raises: [RlpError].} = + rlp.decode(bal, BlockAccessList) + +func ethBlockAccessList*( + bal: Opt[seq[byte]]): Opt[BlockAccessList] {.gcsafe, raises: [RlpError].} = + if bal.isNone(): + Opt.none(BlockAccessList) + else: + Opt.some(ethBlockAccessList(bal.get)) + # ------------------------------------------------------------------------------ # Eth types to Web3 types # ------------------------------------------------------------------------------ @@ -154,4 +165,13 @@ func w3Txs*(list: openArray[common.Transaction]): seq[Web3Tx] = for tx in list: result.add w3Tx(tx) +func w3BlockAccessList*(bal: BlockAccessList): seq[byte] = + bal.encode() + +func w3BlockAccessList*(bal: Opt[BlockAccessList]): Opt[seq[byte]] = + if bal.isNone(): + Opt.none(seq[byte]) + else: + Opt.some(w3BlockAccessList(bal.get)) + chronicles.formatIt(Quantity): $(distinctBase it) diff --git a/execution_chain/rpc/engine_api.nim b/execution_chain/rpc/engine_api.nim index c2ed3fbec4..f6d856c625 100644 --- a/execution_chain/rpc/engine_api.nim +++ b/execution_chain/rpc/engine_api.nim @@ -25,11 +25,13 @@ const supportedMethods: HashSet[string] = "engine_newPayloadV2", "engine_newPayloadV3", "engine_newPayloadV4", + "engine_newPayloadV5", "engine_getPayloadV1", "engine_getPayloadV2", "engine_getPayloadV3", "engine_getPayloadV4", "engine_getPayloadV5", + "engine_getPayloadV6", "engine_forkchoiceUpdatedV1", "engine_forkchoiceUpdatedV2", "engine_forkchoiceUpdatedV3", @@ -66,6 +68,13 @@ proc setupEngineAPI*(engine: BeaconEngineRef, server: RpcServer) = await engine.newPayload(Version.V4, payload, expectedBlobVersionedHashes, parentBeaconBlockRoot, executionRequests) + server.rpc("engine_newPayloadV5") do(payload: ExecutionPayload, + expectedBlobVersionedHashes: Opt[seq[Hash32]], + parentBeaconBlockRoot: Opt[Hash32], + executionRequests: Opt[seq[seq[byte]]]) -> PayloadStatusV1: + await engine.newPayload(Version.V5, payload, + expectedBlobVersionedHashes, parentBeaconBlockRoot, executionRequests) + server.rpc("engine_getPayloadV1") do(payloadId: Bytes8) -> ExecutionPayloadV1: return engine.getPayload(Version.V1, payloadId).executionPayload.V1 @@ -81,6 +90,9 @@ proc setupEngineAPI*(engine: BeaconEngineRef, server: RpcServer) = server.rpc("engine_getPayloadV5") do(payloadId: Bytes8) -> GetPayloadV5Response: return engine.getPayloadV5(payloadId) + server.rpc("engine_getPayloadV6") do(payloadId: Bytes8) -> GetPayloadV6Response: + return engine.getPayloadV6(payloadId) + server.rpc("engine_forkchoiceUpdatedV1") do(update: ForkchoiceStateV1, attrs: Opt[PayloadAttributesV1]) -> ForkchoiceUpdatedResponse: await engine.forkchoiceUpdated(Version.V1, update, attrs.payloadAttributes) diff --git a/hive_integration/engine_client.nim b/hive_integration/engine_client.nim index 8f9d0fab8b..f4b17def59 100644 --- a/hive_integration/engine_client.nim +++ b/hive_integration/engine_client.nim @@ -217,7 +217,8 @@ proc newPayload*(client: RpcClient, payload.versionedHashes, payload.beaconRoot, payload.executionRequests) - of Version.V6: discard + of Version.V6: + discard # TODO: Hive testing for Amsterdam proc exchangeCapabilities*(client: RpcClient, methods: seq[string]):