Skip to content
1 change: 1 addition & 0 deletions execution_chain/beacon/api_handler.nim
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ export
getPayloadV3,
getPayloadV4,
getPayloadV5,
getPayloadV6,
getPayloadBodiesByHash,
getPayloadBodiesByRange,
newPayload,
Expand Down
36 changes: 33 additions & 3 deletions execution_chain/beacon/api_handler/api_getpayload.nim
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down Expand Up @@ -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:
Expand All @@ -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,
)
)

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,
)
47 changes: 33 additions & 14 deletions execution_chain/beacon/api_handler/api_newpayload.nim
Original file line number Diff line number Diff line change
Expand Up @@ -41,20 +41,41 @@ func validateVersionedHashed(payload: ExecutionPayload,
true

template validateVersion(com, timestamp, payloadVersion, apiVersion) =
if apiVersion == Version.V4:
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)

elif apiVersion == Version.V4:
if not com.isPragueOrLater(timestamp):
raise unsupportedFork("newPayloadV4 expect payload timestamp fall within Prague")

if com.isPragueOrLater(timestamp):
if payloadVersion != Version.V3:
raise invalidParams("if timestamp is Prague or later, " &
"payload must be ExecutionPayloadV3, got ExecutionPayload" & $payloadVersion)
raise invalidParams("newPayload" & $apiVersion &
" expect ExecutionPayloadV3" &
" but got ExecutionPayload" & $payloadVersion)

if apiVersion == Version.V3:
elif apiVersion == Version.V3:
if not com.isCancunOrLater(timestamp):
raise unsupportedFork("newPayloadV3 expect payload timestamp fall within Cancun")
if payloadVersion != Version.V3:
raise invalidParams("newPayload" & $apiVersion &
" expect ExecutionPayloadV3" &
" but got ExecutionPayload" & $payloadVersion)

if com.isCancunOrLater(timestamp):
if com.isAmsterdamOrLater(timestamp):
if payloadVersion != Version.V4:
raise invalidParams("if timestamp is Amsterdam or later, " &
"payload must be ExecutionPayloadV4, got ExecutionPayload" & $payloadVersion)

elif com.isPragueOrLater(timestamp):
if payloadVersion != Version.V3:
raise invalidParams("if timestamp is Prague or later, " &
"payload must be ExecutionPayloadV3, got ExecutionPayload" & $payloadVersion)

elif com.isCancunOrLater(timestamp):
if payloadVersion != Version.V3:
raise invalidParams("if timestamp is Cancun or later, " &
"payload must be ExecutionPayloadV3, got ExecutionPayload" & $payloadVersion)
Expand All @@ -68,13 +89,6 @@ template validateVersion(com, timestamp, payloadVersion, apiVersion) =
raise invalidParams("if timestamp is earlier than Shanghai, " &
"payload must be ExecutionPayloadV1, got ExecutionPayload" & $payloadVersion)

if apiVersion == Version.V3 or apiVersion == Version.V4:
# both newPayloadV3 and newPayloadV4 expect ExecutionPayloadV3
if payloadVersion != Version.V3:
raise invalidParams("newPayload" & $apiVersion &
" expect ExecutionPayload3" &
" but got ExecutionPayload" & $payloadVersion)

template validatePayload(apiVersion, payloadVersion, payload) =
if payloadVersion >= Version.V2:
if payload.withdrawals.isNone:
Expand All @@ -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):
Expand Down
14 changes: 12 additions & 2 deletions execution_chain/beacon/payload_conv.nim
Original file line number Diff line number Diff line change
Expand Up @@ -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
# ------------------------------------------------------------------------------
Expand All @@ -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 =
Expand Down Expand Up @@ -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,
)
24 changes: 22 additions & 2 deletions execution_chain/beacon/web3_eth_conv.nim
Original file line number Diff line number Diff line change
Expand Up @@ -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
# ------------------------------------------------------------------------------
Expand Down Expand Up @@ -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)
12 changes: 7 additions & 5 deletions execution_chain/block_access_list/block_access_list_builder.nim
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,8 @@ type
accounts*: Table[Address, AccountData]
## Maps address -> account data

BlockAccessListRef* = ref BlockAccessList

template init*(T: type AccountData): T =
AccountData()

Expand Down Expand Up @@ -119,11 +121,11 @@ func slotCmp(x, y: StorageKey | StorageValue): int =
func slotChangesCmp(x, y: SlotChanges): int =
cmp(x.slot.data.toHex(), y.slot.data.toHex())

func addressCmp(x, y: AccountChanges): int =
func accChangesCmp(x, y: AccountChanges): int =
cmp(x.address.data.toHex(), y.address.data.toHex())

func buildBlockAccessList*(builder: BlockAccessListBuilderRef): BlockAccessList =
var blockAccessList: BlockAccessList
func buildBlockAccessList*(builder: BlockAccessListBuilderRef): BlockAccessListRef =
let blockAccessList: BlockAccessListRef = new BlockAccessList

for address, accData in builder.accounts.mpairs():
# Collect and sort storageChanges
Expand Down Expand Up @@ -163,7 +165,7 @@ func buildBlockAccessList*(builder: BlockAccessListBuilderRef): BlockAccessList
codeChanges.add((BlockAccessIndex(balIndex), Bytecode(code)))
codeChanges.sort(balIndexCmp)

blockAccessList.add(AccountChanges(
blockAccessList[].add(AccountChanges(
address: address,
storageChanges: storageChanges,
storageReads: storageReads,
Expand All @@ -172,6 +174,6 @@ func buildBlockAccessList*(builder: BlockAccessListBuilderRef): BlockAccessList
codeChanges: codeChanges
))

blockAccessList.sort(addressCmp)
blockAccessList[].sort(accChangesCmp)

blockAccessList
Loading
Loading