Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions execution_chain/beacon/api_handler.nim
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@ import
./api_handler/api_getbodies,
./api_handler/api_newpayload,
./api_handler/api_forkchoice,
./api_handler/api_getblobs
./api_handler/api_getblobs,
./api_handler/api_getinclusionlist

# ------------------------------------------------------------------------------
# Public functions
Expand All @@ -34,4 +35,5 @@ export
forkchoiceUpdated,
getBlobsV1,
getBlobsV2,
getBlobsV3
getBlobsV3,
getInclusionList
11 changes: 9 additions & 2 deletions execution_chain/beacon/api_handler/api_forkchoice.nim
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,14 @@ template validateVersion(attr, com, apiVersion) =
version = attr.version
timestamp = ethTime(attr.timestamp)

if apiVersion == Version.V4:
if apiVersion == Version.V5:
if version != apiVersion:
raise invalidAttr("forkChoiceUpdatedV5 expect PayloadAttributesV5" &
" but got PayloadAttributes" & $version)
if not com.isBogotaOrLater(timestamp):
raise unsupportedFork(
"forkchoiceUpdatedV5 get invalid payloadAttributes timestamp")
elif apiVersion == Version.V4:
if version != apiVersion:
raise invalidAttr("forkChoiceUpdatedV4 expect PayloadAttributesV4" &
" but got PayloadAttributes" & $version)
Expand Down Expand Up @@ -80,7 +87,7 @@ template validateHeaderTimestamp(header, com, apiVersion) =

proc forkchoiceUpdated*(ben: BeaconEngineRef,
apiVersion: Version,
update: ForkchoiceStateV1,
update: ForkchoiceState,
attrsOpt: Opt[PayloadAttributes]):
Future[ForkchoiceUpdatedResponse]
{.async: (raises: [CancelledError, ApplicationError]).} =
Expand Down
20 changes: 20 additions & 0 deletions execution_chain/beacon/api_handler/api_getinclusionlist.nim
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# Nimbus
# Copyright (c) 2026 Status Research & Development GmbH
# Licensed under either of
# * Apache License, version 2.0, ([LICENSE-APACHE](LICENSE-APACHE))
# * MIT license ([LICENSE-MIT](LICENSE-MIT))
# at your option.
# This file may not be copied, modified, or distributed except according to
# those terms.

import
eth/common/hashes,
web3/execution_types,
../beacon_engine

{.push gcsafe, raises:[].}

proc getInclusionList*(ben: BeaconEngineRef,
apiVersion: Version,
parentHash: Hash32): InclusionList =
discard
13 changes: 10 additions & 3 deletions execution_chain/beacon/api_handler/api_newpayload.nim
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ template validatePayload(apiVersion, payloadVersion, payload) =
# https://github.com/ethereum/execution-apis/blob/40088597b8b4f48c45184da002e27ffc3c37641f/src/engine/prague.md#request
func validateExecutionRequest(blockHash: Hash32,
requests: openArray[seq[byte]], apiVersion: Version):
Opt[PayloadStatusV1] {.raises: [ApplicationError].} =
Opt[PayloadStatus] {.raises: [ApplicationError].} =
var previousRequestType = -1
for request in requests:
if request.len == 0:
Expand Down Expand Up @@ -141,8 +141,9 @@ proc newPayload*(ben: BeaconEngineRef,
payload: ExecutionPayload,
versionedHashes = Opt.none(seq[Hash32]),
beaconRoot = Opt.none(Hash32),
executionRequests = Opt.none(seq[seq[byte]])):
Future[PayloadStatusV1] {.async: (raises: [CancelledError, ApplicationError, RlpError]).} =
executionRequests = Opt.none(seq[seq[byte]]),
inclusionList = Opt.none(InclusionList)):
Future[PayloadStatus] {.async: (raises: [CancelledError, ApplicationError, RlpError]).} =

trace "Engine API request received",
meth = "newPayload",
Expand All @@ -162,6 +163,12 @@ proc newPayload*(ben: BeaconEngineRef,
if res.isSome:
return res.value

if apiVersion >= Version.V5:
if inclusionList.isNone:
raise invalidParams("newPayload" & $apiVersion &
": inclusionList is expected from execution payload")
{.warning: "Please implement newPayload inclusionList validation".}

let
com = ben.com
chain = ben.chain
Expand Down
34 changes: 17 additions & 17 deletions execution_chain/beacon/api_handler/api_utils.nim
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ proc computePayloadId*(blockHash: common.Hash32,

proc validateBlockHash*(header: common.Header,
wantHash: common.Hash32,
version: Version): Result[void, PayloadStatusV1]
version: Version): Result[void, PayloadStatus]
{.gcsafe.} =
let gotHash = header.computeBlockHash
if wantHash != gotHash:
Expand All @@ -60,7 +60,7 @@ proc validateBlockHash*(header: common.Header,
else:
PayloadExecutionStatus.invalid

let res = PayloadStatusV1(
let res = PayloadStatus(
status: status,
validationError: Opt.some("blockhash mismatch, want " &
$wantHash & ", got " & $gotHash)
Expand All @@ -72,16 +72,16 @@ proc validateBlockHash*(header: common.Header,
template toValidHash*(x: common.Hash32): Opt[Hash32] =
Opt.some(x)

proc simpleFCU*(status: PayloadStatusV1): ForkchoiceUpdatedResponse =
proc simpleFCU*(status: PayloadStatus): ForkchoiceUpdatedResponse =
ForkchoiceUpdatedResponse(payloadStatus: status)

proc simpleFCU*(status: PayloadExecutionStatus): ForkchoiceUpdatedResponse =
ForkchoiceUpdatedResponse(payloadStatus: PayloadStatusV1(status: status))
ForkchoiceUpdatedResponse(payloadStatus: PayloadStatus(status: status))

proc simpleFCU*(status: PayloadExecutionStatus,
msg: string): ForkchoiceUpdatedResponse =
ForkchoiceUpdatedResponse(
payloadStatus: PayloadStatusV1(
payloadStatus: PayloadStatus(
status: status,
validationError: Opt.some(msg)
)
Expand All @@ -91,7 +91,7 @@ proc invalidFCU*(
validationError: string,
hash = default(common.Hash32)): ForkchoiceUpdatedResponse =
ForkchoiceUpdatedResponse(payloadStatus:
PayloadStatusV1(
PayloadStatus(
status: PayloadExecutionStatus.invalid,
latestValidHash: toValidHash(hash),
validationError: Opt.some validationError
Expand All @@ -101,39 +101,39 @@ proc invalidFCU*(
proc validFCU*(id: Opt[Bytes8],
validHash: common.Hash32): ForkchoiceUpdatedResponse =
ForkchoiceUpdatedResponse(
payloadStatus: PayloadStatusV1(
payloadStatus: PayloadStatus(
status: PayloadExecutionStatus.valid,
latestValidHash: toValidHash(validHash)
),
payloadId: id
)

proc invalidStatus*(validHash: common.Hash32, msg: string): PayloadStatusV1 =
PayloadStatusV1(
proc invalidStatus*(validHash: common.Hash32, msg: string): PayloadStatus =
PayloadStatus(
status: PayloadExecutionStatus.invalid,
latestValidHash: toValidHash(validHash),
validationError: Opt.some(msg)
)

proc invalidStatus*(validHash = default(common.Hash32)): PayloadStatusV1 =
PayloadStatusV1(
proc invalidStatus*(validHash = default(common.Hash32)): PayloadStatus =
PayloadStatus(
status: PayloadExecutionStatus.invalid,
latestValidHash: toValidHash(validHash)
)

proc acceptedStatus*(validHash: common.Hash32): PayloadStatusV1 =
PayloadStatusV1(
proc acceptedStatus*(validHash: common.Hash32): PayloadStatus =
PayloadStatus(
status: PayloadExecutionStatus.accepted,
latestValidHash: toValidHash(validHash)
)

proc acceptedStatus*(): PayloadStatusV1 =
PayloadStatusV1(
proc acceptedStatus*(): PayloadStatus =
PayloadStatus(
status: PayloadExecutionStatus.accepted
)

proc validStatus*(validHash: common.Hash32): PayloadStatusV1 =
PayloadStatusV1(
proc validStatus*(validHash: common.Hash32): PayloadStatus =
PayloadStatus(
status: PayloadExecutionStatus.valid,
latestValidHash: toValidHash(validHash)
)
Expand Down
10 changes: 5 additions & 5 deletions execution_chain/beacon/beacon_engine.nim
Original file line number Diff line number Diff line change
Expand Up @@ -192,7 +192,7 @@ func setInvalidAncestor*(ben: BeaconEngineRef, header: Header, blockHash: Hash32
# checkInvalidAncestor checks whether the specified chain end links to a known
# bad ancestor. If yes, it constructs the payload failure response to return.
proc checkInvalidAncestor*(ben: BeaconEngineRef,
check, head: Hash32): Opt[PayloadStatusV1] =
check, head: Hash32): Opt[PayloadStatus] =
proc latestValidHash(chain: ForkedChainRef, invalid: auto): Hash32 =
let parent = chain.headerByHash(invalid.parentHash).valueOr:
return invalid.parentHash
Expand Down Expand Up @@ -221,7 +221,7 @@ proc checkInvalidAncestor*(ben: BeaconEngineRef,
for x in deleted:
ben.invalidTipsets.del(x)

return Opt.none(PayloadStatusV1)
return Opt.none(PayloadStatus)

# Not too many failures yet, mark the head of the invalid chain as invalid
if check != head:
Expand All @@ -244,7 +244,7 @@ proc checkInvalidAncestor*(ben: BeaconEngineRef,
let lastValid = latestValidHash(ben.chain, invalid)
return Opt.some invalidStatus(lastValid, "links to previously rejected block")
do:
return Opt.none(PayloadStatusV1)
return Opt.none(PayloadStatus)

# delayPayloadImport stashes the given block away for import at a later time,
# either via a forkchoice update or a sync extension. This method is meant to
Expand All @@ -255,14 +255,14 @@ proc delayPayloadImport*(
blockHash: Hash32,
blk: Block,
blockAccessList: Opt[BlockAccessListRef]
): PayloadStatusV1 =
): PayloadStatus =
# Sanity check that this block's parent is not on a previously invalidated
# chain. If it is, mark the block as invalid too.
ben.checkInvalidAncestor(blk.header.parentHash, blockHash).valueOr:
# Stash the block away for a potential forced forkchoice update to it
# at a later time.
ben.chain.quarantine.addOrphan(blockHash, blk, blockAccessList)
return PayloadStatusV1(status: PayloadExecutionStatus.syncing)
return PayloadStatus(status: PayloadExecutionStatus.syncing)

func latestFork*(ben: BeaconEngineRef): HardFork =
let timestamp = max(ben.txPool.timestamp, ben.chain.latestHeader.timestamp)
Expand Down
40 changes: 29 additions & 11 deletions execution_chain/rpc/engine_api.nim
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ const supportedMethods: HashSet[string] =
"engine_newPayloadV3",
"engine_newPayloadV4",
"engine_newPayloadV5",
"engine_newPayloadV6",
"engine_getPayloadV1",
"engine_getPayloadV2",
"engine_getPayloadV3",
Expand All @@ -36,14 +37,16 @@ const supportedMethods: HashSet[string] =
"engine_forkchoiceUpdatedV2",
"engine_forkchoiceUpdatedV3",
"engine_forkchoiceUpdatedV4",
"engine_forkchoiceUpdatedV5",
"engine_getPayloadBodiesByHashV1",
"engine_getPayloadBodiesByHashV2",
"engine_getPayloadBodiesByRangeV1",
"engine_getPayloadBodiesByRangeV1",
"engine_getPayloadBodiesByRangeV2",
"engine_getClientVersionV1",
"engine_getBlobsV1",
"engine_getBlobsV2",
"engine_getBlobsV3"
"engine_getBlobsV3",
"engine_getInclusionListV1",
])

# I'm trying to keep the handlers below very thin, and move the
Expand All @@ -54,31 +57,39 @@ proc setupEngineAPI*(engine: BeaconEngineRef, server: RpcServer) =
proc engine_exchangeCapabilities(methods: seq[string]): seq[string] =
return methods.filterIt(supportedMethods.contains(it))

proc engine_newPayloadV1(payload: ExecutionPayloadV1): PayloadStatusV1 {.async: (raises: [CancelledError, ApplicationError, RlpError]).} =
proc engine_newPayloadV1(payload: ExecutionPayloadV1): PayloadStatus {.async: (raises: [CancelledError, ApplicationError, RlpError]).} =
await engine.newPayload(Version.V1, payload.executionPayload)

proc engine_newPayloadV2(payload: ExecutionPayload): PayloadStatusV1 {.async: (raises: [CancelledError, ApplicationError, RlpError]).} =
proc engine_newPayloadV2(payload: ExecutionPayload): PayloadStatus {.async: (raises: [CancelledError, ApplicationError, RlpError]).} =
await engine.newPayload(Version.V2, payload)

proc engine_newPayloadV3(payload: ExecutionPayload,
expectedBlobVersionedHashes: Opt[seq[Hash32]],
parentBeaconBlockRoot: Opt[Hash32]): PayloadStatusV1 {.async: (raises: [CancelledError, ApplicationError, RlpError]).} =
parentBeaconBlockRoot: Opt[Hash32]): PayloadStatus {.async: (raises: [CancelledError, ApplicationError, RlpError]).} =
await engine.newPayload(Version.V3, payload, expectedBlobVersionedHashes, parentBeaconBlockRoot)

proc engine_newPayloadV4(payload: ExecutionPayload,
expectedBlobVersionedHashes: Opt[seq[Hash32]],
parentBeaconBlockRoot: Opt[Hash32],
executionRequests: Opt[seq[seq[byte]]]): PayloadStatusV1 {.async: (raises: [CancelledError, ApplicationError, RlpError]).} =
executionRequests: Opt[seq[seq[byte]]]): PayloadStatus {.async: (raises: [CancelledError, ApplicationError, RlpError]).} =
await engine.newPayload(Version.V4, payload,
expectedBlobVersionedHashes, parentBeaconBlockRoot, executionRequests)

proc engine_newPayloadV5(payload: ExecutionPayload,
expectedBlobVersionedHashes: Opt[seq[Hash32]],
parentBeaconBlockRoot: Opt[Hash32],
executionRequests: Opt[seq[seq[byte]]]): PayloadStatusV1 {.async: (raises: [CancelledError, ApplicationError, RlpError]).} =
executionRequests: Opt[seq[seq[byte]]]): PayloadStatus {.async: (raises: [CancelledError, ApplicationError, RlpError]).} =
await engine.newPayload(Version.V5, payload,
expectedBlobVersionedHashes, parentBeaconBlockRoot, executionRequests)

proc engine_newPayloadV6(payload: ExecutionPayload,
expectedBlobVersionedHashes: Opt[seq[Hash32]],
parentBeaconBlockRoot: Opt[Hash32],
executionRequests: Opt[seq[seq[byte]]],
inclusionList: Opt[InclusionList]): PayloadStatus {.async: (raises: [CancelledError, ApplicationError, RlpError]).} =
await engine.newPayload(Version.V6, payload,
expectedBlobVersionedHashes, parentBeaconBlockRoot, executionRequests, inclusionList)

proc engine_getPayloadV1(payloadId: Bytes8): ExecutionPayloadV1 {.raises: [CatchableError].} =
return engine.getPayload(Version.V1, payloadId).executionPayload.V1

Expand All @@ -97,22 +108,26 @@ proc setupEngineAPI*(engine: BeaconEngineRef, server: RpcServer) =
proc engine_getPayloadV6(payloadId: Bytes8): GetPayloadV6Response {.raises: [CatchableError].} =
return engine.getPayloadV6(payloadId)

proc engine_forkchoiceUpdatedV1(update: ForkchoiceStateV1,
proc engine_forkchoiceUpdatedV1(update: ForkchoiceState,
attrs: Opt[PayloadAttributesV1]): ForkchoiceUpdatedResponse {.async: (raises: [CancelledError, ApplicationError]).} =
await engine.forkchoiceUpdated(Version.V1, update, attrs.payloadAttributes)

proc engine_forkchoiceUpdatedV2(update: ForkchoiceStateV1,
proc engine_forkchoiceUpdatedV2(update: ForkchoiceState,
attrs: Opt[PayloadAttributes]): ForkchoiceUpdatedResponse {.async: (raises: [CancelledError, ApplicationError]).} =
await engine.forkchoiceUpdated(Version.V2, update, attrs)

proc engine_forkchoiceUpdatedV3(update: ForkchoiceStateV1,
proc engine_forkchoiceUpdatedV3(update: ForkchoiceState,
attrs: Opt[PayloadAttributes]): ForkchoiceUpdatedResponse {.async: (raises: [CancelledError, ApplicationError]).} =
await engine.forkchoiceUpdated(Version.V3, update, attrs)

proc engine_forkchoiceUpdatedV4(update: ForkchoiceStateV1,
proc engine_forkchoiceUpdatedV4(update: ForkchoiceState,
attrs: Opt[PayloadAttributes]): ForkchoiceUpdatedResponse {.async: (raises: [CancelledError, ApplicationError]).} =
await engine.forkchoiceUpdated(Version.V4, update, attrs)

proc engine_forkchoiceUpdatedV5(update: ForkchoiceState,
attrs: Opt[PayloadAttributes]): ForkchoiceUpdatedResponse {.async: (raises: [CancelledError, ApplicationError]).} =
await engine.forkchoiceUpdated(Version.V5, update, attrs)

proc engine_getPayloadBodiesByHashV1(hashes: seq[Hash32]):
seq[Opt[ExecutionPayloadBodyV1]] {.raises: [CatchableError].} =
return engine.getPayloadBodiesByHashV1(hashes)
Expand Down Expand Up @@ -150,3 +165,6 @@ proc setupEngineAPI*(engine: BeaconEngineRef, server: RpcServer) =
proc engine_getBlobsV3(versionedHashes: seq[VersionedHash]):
seq[Opt[BlobAndProofV2]] {.raises: [ApplicationError].} =
return engine.getBlobsV3(versionedHashes)

proc engine_getInclusionListV1(parentHash: Hash32): InclusionList {.raises: [ApplicationError].} =
return engine.getInclusionList(Version.V5, parentHash)
Loading
Loading