From a7db7b9101dd3316290b342fec3a4acb0431763e Mon Sep 17 00:00:00 2001 From: jangko Date: Tue, 8 Aug 2023 14:29:23 +0700 Subject: [PATCH] add engine API V3 of Cancun --- nimbus/core/sealer.nim | 27 ++-- nimbus/rpc/engine_api.nim | 118 ++++++++++++++-- nimbus/rpc/execution_types.nim | 234 ++++++++++++++++++++++++++++++++ nimbus/rpc/merge/merger.nim | 10 +- nimbus/rpc/merge/mergetypes.nim | 43 ++++-- nimbus/rpc/merge/mergeutils.nim | 33 ++++- vendor/nim-web3 | 2 +- 7 files changed, 422 insertions(+), 45 deletions(-) create mode 100644 nimbus/rpc/execution_types.nim diff --git a/nimbus/core/sealer.nim b/nimbus/core/sealer.nim index cc06c3a0b..43ba543e4 100644 --- a/nimbus/core/sealer.nim +++ b/nimbus/core/sealer.nim @@ -27,7 +27,8 @@ import clique_cfg, clique_sealer], ../utils/utils, - ../common/[common, context] + ../common/[common, context], + ../rpc/execution_types from web3/ethtypes as web3types import nil, TypedTransaction, WithdrawalV1, ExecutionPayloadV1OrV2, toExecutionPayloadV1OrV2, toExecutionPayloadV1 @@ -158,7 +159,7 @@ func toWithdrawals(list: openArray[WithdrawalV1]): seq[Withdrawal] = result.add toWithdrawal(x) proc generateExecutionPayload*(engine: SealingEngineRef, - payloadAttrs: PayloadAttributesV1 | PayloadAttributesV2): Result[ExecutionPayloadV1OrV2, string] = + payloadAttrs: SomePayloadAttributes): Result[ExecutionPayload, string] = let headBlock = try: engine.chain.db.getCanonicalHead() except CatchableError: return err "No head block in database" @@ -170,6 +171,8 @@ proc generateExecutionPayload*(engine: SealingEngineRef, when payloadAttrs is PayloadAttributesV2: engine.txPool.withdrawals = payloadAttrs.withdrawals.toWithdrawals + elif payloadAttrs is PayloadAttributesV3: + engine.txPool.withdrawals = payloadAttrs.withdrawals.toWithdrawals else: engine.txPool.withdrawals = @[] @@ -199,7 +202,17 @@ proc generateExecutionPayload*(engine: SealingEngineRef, else: none[seq[WithdrawalV1]]() - return ok(ExecutionPayloadV1OrV2( + let blobGasUsed = if blk.header.blobGasUsed.isSome: + some(blk.header.blobGasUsed.get.Quantity) + else: + none(Quantity) + + let excessBlobGas = if blk.header.excessBlobGas.isSome: + some(blk.header.excessBlobGas.get.Quantity) + else: + none(Quantity) + + return ok(ExecutionPayload( parentHash: Web3BlockHash blk.header.parentHash.data, feeRecipient: Web3Address blk.header.coinbase, stateRoot: Web3BlockHash blk.header.stateRoot.data, @@ -214,13 +227,11 @@ proc generateExecutionPayload*(engine: SealingEngineRef, baseFeePerGas: blk.header.fee.get(UInt256.zero), blockHash: Web3BlockHash blockHash.data, transactions: transactions, - withdrawals: withdrawals + withdrawals: withdrawals, + blobGasUsed: blobGasUsed, + excessBlobGas: excessBlobGas )) -proc generateExecutionPayloadV1*(engine: SealingEngineRef, - payloadAttrs: PayloadAttributesV1): Result[ExecutionPayloadV1, string] = - return generateExecutionPayload(engine, payloadAttrs).map(toExecutionPayloadV1) - proc new*(_: type SealingEngineRef, chain: ChainRef, ctx: EthContext, diff --git a/nimbus/rpc/engine_api.nim b/nimbus/rpc/engine_api.nim index 4f096be7a..56b1f380c 100644 --- a/nimbus/rpc/engine_api.nim +++ b/nimbus/rpc/engine_api.nim @@ -11,7 +11,8 @@ import std/[typetraits, times, strutils, sequtils, sets], stew/[results, byteutils], json_rpc/rpcserver, - web3/[conversions, engine_api_types], + web3/[conversions], + web3/engine_api_types as web3types, eth/rlp, eth/common/eth_types, eth/common/eth_types_rlp, @@ -22,6 +23,7 @@ import ../core/[tx_pool, sealer], ../evm/async/data_sources, ./merge/[mergetypes, mergeutils], + ./execution_types, # put chronicles import last because Nim # compiler resolve `$` for logging # arguments differently on Windows vs posix @@ -30,7 +32,11 @@ import {.push raises: [].} -type Hash256 = eth_types.Hash256 +type + Hash256 = eth_types.Hash256 + Web3Blob = web3types.Blob + Web3KZGProof = web3types.KZGProof + Web3KZGCommitment = web3types.KZGCommitment func toPayloadAttributesV1OrPayloadAttributesV2*(a: PayloadAttributesV1OrV2): Result[PayloadAttributesV1, PayloadAttributesV2] = @@ -92,7 +98,10 @@ template unsafeQuantityToInt64(q: Quantity): int64 = # null.) --Adam # https://github.com/ethereum/execution-apis/blob/main/src/engine/specification.md#engine_newpayloadv1 -proc handle_newPayload(sealingEngine: SealingEngineRef, api: EngineApiRef, com: CommonRef, maybeAsyncDataSource: Option[AsyncDataSource], payload: ExecutionPayloadV1 | ExecutionPayloadV2): PayloadStatusV1 {.raises: [CatchableError].} = +proc handle_newPayload(sealingEngine: SealingEngineRef, + api: EngineApiRef, + com: CommonRef, maybeAsyncDataSource: Option[AsyncDataSource], + payload: SomeExecutionPayload): PayloadStatusV1 {.raises: [CatchableError].} = trace "Engine API request received", meth = "newPayload", number = $(distinctBase payload.blockNumber), hash = payload.blockHash @@ -221,6 +230,41 @@ proc handle_getPayload(api: EngineApiRef, payloadId: PayloadID): GetPayloadV2Res blockValue: blockValue ) +proc handle_getPayloadV3(api: EngineApiRef, com: CommonRef, payloadId: PayloadID): GetPayloadV3Response {.raises: [CatchableError].} = + trace "Engine API request received", + meth = "GetPayload", id = payloadId.toHex + + var payload: ExecutionPayloadV3 + if not api.get(payloadId, payload): + raise unknownPayload("Unknown payload") + + if not com.isCancunOrLater(fromUnix(payload.timestamp.unsafeQuantityToInt64)): + raise unsupportedFork("payload timestamp is less than Cancun activation") + + var + blockValue: UInt256 + blobsBundle: BlobsBundleV1 + + try: + for ttx in payload.transactions: + let tx = rlp.decode(distinctBase(ttx), Transaction) + blockValue += u256(tx.gasPrice * tx.maxPriorityFee) + 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") + + return GetPayloadV3Response( + executionPayload: payload, + blockValue: blockValue, + blobsBundle: blobsBundle + ) + # https://github.com/ethereum/execution-apis/blob/main/src/engine/specification.md#engine_exchangetransitionconfigurationv1 proc handle_exchangeTransitionConfiguration(sealingEngine: SealingEngineRef, com: CommonRef, conf: TransitionConfigurationV1): TransitionConfigurationV1 {.raises: [CatchableError].} = trace "Engine API request received", @@ -281,10 +325,16 @@ proc handle_exchangeTransitionConfiguration(sealingEngine: SealingEngineRef, com # If there are payloadAttributes: # we try to assemble a block with the payloadAttributes and return its payloadID # https://github.com/ethereum/execution-apis/blob/main/src/engine/shanghai.md#engine_forkchoiceupdatedv2 -proc handle_forkchoiceUpdated(sealingEngine: SealingEngineRef, com: CommonRef, api: EngineApiRef, update: ForkchoiceStateV1, payloadAttributes: Option[PayloadAttributesV1] | Option[PayloadAttributesV2]): ForkchoiceUpdatedResponse {.raises: [CatchableError].} = +proc handle_forkchoiceUpdated(sealingEngine: SealingEngineRef, + com: CommonRef, api: EngineApiRef, + update: ForkchoiceStateV1, + payloadAttributes: SomeOptionalPayloadAttributes): ForkchoiceUpdatedResponse {.raises: [CatchableError].} = if payloadAttributes.isSome: - if com.isShanghaiOrLater(fromUnix(payloadAttributes.get.timestamp.unsafeQuantityToInt64)): + if com.isCancunOrLater(fromUnix(payloadAttributes.get.timestamp.unsafeQuantityToInt64)): + when not(payloadAttributes is Option[PayloadAttributesV3]): + raise invalidParams("if timestamp is Cancun or later, payloadAttributes must be PayloadAttributesV3") + elif com.isShanghaiOrLater(fromUnix(payloadAttributes.get.timestamp.unsafeQuantityToInt64)): when not(payloadAttributes is Option[PayloadAttributesV2]): raise invalidParams("if timestamp is Shanghai or later, payloadAttributes must be PayloadAttributesV2") else: @@ -475,6 +525,7 @@ const supportedMethods: HashSet[string] = "engine_exchangeTransitionConfigurationV1", "engine_forkchoiceUpdatedV1", "engine_forkchoiceUpdatedV2", + "engine_forkchoiceUpdatedV3", "engine_getPayloadBodiesByHashV1" ]) @@ -498,12 +549,31 @@ proc setupEngineAPI*( server.rpc("engine_newPayloadV1") do(payload: ExecutionPayloadV1) -> PayloadStatusV1: return handle_newPayload(sealingEngine, api, com, maybeAsyncDataSource, payload) - server.rpc("engine_newPayloadV2") do(payload: ExecutionPayloadV1OrV2) -> PayloadStatusV1: - let p = payload.toExecutionPayloadV1OrExecutionPayloadV2 - if p.isOk: - return handle_newPayload(sealingEngine, api, com, maybeAsyncDataSource, p.get) + server.rpc("engine_newPayloadV2") do(payload: ExecutionPayload) -> PayloadStatusV1: + if payload.version == Version.V1: + return handle_newPayload(sealingEngine, api, com, maybeAsyncDataSource, payload.V1) else: - return handle_newPayload(sealingEngine, api, com, maybeAsyncDataSource, p.error) + return handle_newPayload(sealingEngine, api, com, maybeAsyncDataSource, payload.V2) + + server.rpc("engine_newPayloadV3") do(payload: ExecutionPayload, + expectedBlobVersionedHashes: seq[FixedBytes[32]], + parentBeaconBlockRoot: FixedBytes[32]) -> PayloadStatusV1: + case payload.version: + of Version.V1: + return handle_newPayload(sealingEngine, api, com, maybeAsyncDataSource, payload.V1) + of Version.V2: + return handle_newPayload(sealingEngine, api, com, maybeAsyncDataSource, payload.V2) + of Version.V3: + if not com.isCancunOrLater(fromUnix(payload.timestamp.unsafeQuantityToInt64)): + raise unsupportedFork("payload timestamp is less than Cancun activation") + var versionedHashes: seq[Hash256] + for x in payload.transactions: + let tx = rlp.decode(distinctBase(x), Transaction) + versionedHashes.add tx.versionedHashes + for i, x in expectedBlobVersionedHashes: + if distinctBase(x) != versionedHashes[i].data: + return invalidStatus() + return handle_newPayload(sealingEngine, api, com, maybeAsyncDataSource, payload.V3) server.rpc("engine_getPayloadV1") do(payloadId: PayloadID) -> ExecutionPayloadV1: let r = handle_getPayload(api, payloadId) @@ -512,6 +582,9 @@ proc setupEngineAPI*( server.rpc("engine_getPayloadV2") do(payloadId: PayloadID) -> GetPayloadV2Response: return handle_getPayload(api, payloadId) + server.rpc("engine_getPayloadV3") do(payloadId: PayloadID) -> GetPayloadV3Response: + return handle_getPayloadV3(api, com, payloadId) + server.rpc("engine_exchangeTransitionConfigurationV1") do(conf: TransitionConfigurationV1) -> TransitionConfigurationV1: return handle_exchangeTransitionConfiguration(sealingEngine, com, conf) @@ -522,15 +595,30 @@ proc setupEngineAPI*( server.rpc("engine_forkchoiceUpdatedV2") do( update: ForkchoiceStateV1, - payloadAttributes: Option[PayloadAttributesV1OrV2]) -> ForkchoiceUpdatedResponse: + payloadAttributes: Option[PayloadAttributes]) -> ForkchoiceUpdatedResponse: if payloadAttributes.isNone: return handle_forkchoiceUpdated(sealingEngine, com, api, update, none[PayloadAttributesV2]()) else: - let a = payloadAttributes.get.toPayloadAttributesV1OrPayloadAttributesV2 - if a.isOk: - return handle_forkchoiceUpdated(sealingEngine, com, api, update, some(a.get)) + let attr = payloadAttributes.get + if attr.version == Version.V1: + return handle_forkchoiceUpdated(sealingEngine, com, api, update, some(attr.V1)) else: - return handle_forkchoiceUpdated(sealingEngine, com, api, update, some(a.error)) + return handle_forkchoiceUpdated(sealingEngine, com, api, update, some(attr.V2)) + + server.rpc("engine_forkchoiceUpdatedV3") do( + update: ForkchoiceStateV1, + payloadAttributes: Option[PayloadAttributes]) -> ForkchoiceUpdatedResponse: + if payloadAttributes.isNone: + return handle_forkchoiceUpdated(sealingEngine, com, api, update, none[PayloadAttributesV3]()) + else: + let attr = payloadAttributes.get + case attr.version + of Version.V1: + return handle_forkchoiceUpdated(sealingEngine, com, api, update, some(attr.V1)) + of Version.V2: + return handle_forkchoiceUpdated(sealingEngine, com, api, update, some(attr.V2)) + of Version.V3: + return handle_forkchoiceUpdated(sealingEngine, com, api, update, some(attr.V3)) server.rpc("engine_getPayloadBodiesByHashV1") do( hashes: seq[BlockHash]) -> seq[Option[ExecutionPayloadBodyV1]]: diff --git a/nimbus/rpc/execution_types.nim b/nimbus/rpc/execution_types.nim new file mode 100644 index 000000000..8382f4c9c --- /dev/null +++ b/nimbus/rpc/execution_types.nim @@ -0,0 +1,234 @@ +import + stint, + web3/ethtypes, + web3/engine_api_types + +export + engine_api_types + +type + ExecutionPayload* = object + parentHash*: Hash256 + feeRecipient*: Address + stateRoot*: Hash256 + receiptsRoot*: Hash256 + logsBloom*: FixedBytes[256] + prevRandao*: FixedBytes[32] + blockNumber*: Quantity + gasLimit*: Quantity + gasUsed*: Quantity + timestamp*: Quantity + extraData*: DynamicBytes[0, 32] + baseFeePerGas*: UInt256 + blockHash*: Hash256 + transactions*: seq[TypedTransaction] + withdrawals*: Option[seq[WithdrawalV1]] + blobGasUsed*: Option[Quantity] + excessBlobGas*: Option[Quantity] + + PayloadAttributes* = object + timestamp*: Quantity + prevRandao*: FixedBytes[32] + suggestedFeeRecipient*: Address + withdrawals*: Option[seq[WithdrawalV1]] + parentBeaconBlockRoot*: Option[FixedBytes[32]] + + SomePayloadAttributes* = + PayloadAttributesV1 | + PayloadAttributesV2 | + PayloadAttributesV3 + + SomeOptionalPayloadAttributes* = + Option[PayloadAttributesV1] | + Option[PayloadAttributesV2] | + Option[PayloadAttributesV3] + + Version* {.pure.} = enum + V1 + V2 + V3 + +func version*(payload: ExecutionPayload): Version = + if payload.blobGasUsed.isSome and payload.excessBlobGas.isSome: + return Version.V3 + + if payload.withdrawals.isSome: + return Version.V2 + + Version.V1 + +func version*(attr: PayloadAttributes): Version = + if attr.parentBeaconBlockRoot.isSome: + return Version.V3 + + if attr.withdrawals.isSome: + return Version.V2 + + Version.V1 + +func V1V2*(attr: PayloadAttributes): PayloadAttributesV1OrV2 = + PayloadAttributesV1OrV2( + timestamp: attr.timestamp, + prevRandao: attr.prevRandao, + suggestedFeeRecipient: attr.suggestedFeeRecipient, + withdrawals: attr.withdrawals + ) + +func V1*(attr: PayloadAttributes): PayloadAttributesV1 = + PayloadAttributesV1( + timestamp: attr.timestamp, + prevRandao: attr.prevRandao, + suggestedFeeRecipient: attr.suggestedFeeRecipient + ) + +func V2*(attr: PayloadAttributes): PayloadAttributesV2 = + PayloadAttributesV2( + timestamp: attr.timestamp, + prevRandao: attr.prevRandao, + suggestedFeeRecipient: attr.suggestedFeeRecipient, + withdrawals: attr.withdrawals.get + ) + +func V3*(attr: PayloadAttributes): PayloadAttributesV3 = + PayloadAttributesV3( + timestamp: attr.timestamp, + prevRandao: attr.prevRandao, + suggestedFeeRecipient: attr.suggestedFeeRecipient, + withdrawals: attr.withdrawals.get, + parentBeaconBlockRoot: attr.parentBeaconBlockRoot.get + ) + +func V1V2*(p: ExecutionPayload): ExecutionPayloadV1OrV2 = + ExecutionPayloadV1OrV2( + parentHash: p.parentHash, + feeRecipient: p.feeRecipient, + stateRoot: p.stateRoot, + receiptsRoot: p.receiptsRoot, + logsBloom: p.logsBloom, + prevRandao: p.prevRandao, + blockNumber: p.blockNumber, + gasLimit: p.gasLimit, + gasUsed: p.gasUsed, + timestamp: p.timestamp, + extraData: p.extraData, + baseFeePerGas: p.baseFeePerGas, + blockHash: p.blockHash, + transactions: p.transactions, + withdrawals: p.withdrawals + ) + +func V1*(p: ExecutionPayload): ExecutionPayloadV1 = + ExecutionPayloadV1( + parentHash: p.parentHash, + feeRecipient: p.feeRecipient, + stateRoot: p.stateRoot, + receiptsRoot: p.receiptsRoot, + logsBloom: p.logsBloom, + prevRandao: p.prevRandao, + blockNumber: p.blockNumber, + gasLimit: p.gasLimit, + gasUsed: p.gasUsed, + timestamp: p.timestamp, + extraData: p.extraData, + baseFeePerGas: p.baseFeePerGas, + blockHash: p.blockHash, + transactions: p.transactions + ) + +func V2*(p: ExecutionPayload): ExecutionPayloadV2 = + ExecutionPayloadV2( + parentHash: p.parentHash, + feeRecipient: p.feeRecipient, + stateRoot: p.stateRoot, + receiptsRoot: p.receiptsRoot, + logsBloom: p.logsBloom, + prevRandao: p.prevRandao, + blockNumber: p.blockNumber, + gasLimit: p.gasLimit, + gasUsed: p.gasUsed, + timestamp: p.timestamp, + extraData: p.extraData, + baseFeePerGas: p.baseFeePerGas, + blockHash: p.blockHash, + transactions: p.transactions, + withdrawals: p.withdrawals.get + ) + +func V3*(p: ExecutionPayload): ExecutionPayloadV3 = + ExecutionPayloadV3( + parentHash: p.parentHash, + feeRecipient: p.feeRecipient, + stateRoot: p.stateRoot, + receiptsRoot: p.receiptsRoot, + logsBloom: p.logsBloom, + prevRandao: p.prevRandao, + blockNumber: p.blockNumber, + gasLimit: p.gasLimit, + gasUsed: p.gasUsed, + timestamp: p.timestamp, + extraData: p.extraData, + baseFeePerGas: p.baseFeePerGas, + blockHash: p.blockHash, + transactions: p.transactions, + withdrawals: p.withdrawals.get, + blobGasUsed: p.blobGasUsed.get, + excessBlobGas: p.excessBlobGas.get + ) + +func executionPayload*(p: ExecutionPayloadV1): ExecutionPayload = + ExecutionPayload( + parentHash: p.parentHash, + feeRecipient: p.feeRecipient, + stateRoot: p.stateRoot, + receiptsRoot: p.receiptsRoot, + logsBloom: p.logsBloom, + prevRandao: p.prevRandao, + blockNumber: p.blockNumber, + gasLimit: p.gasLimit, + gasUsed: p.gasUsed, + timestamp: p.timestamp, + extraData: p.extraData, + baseFeePerGas: p.baseFeePerGas, + blockHash: p.blockHash, + transactions: p.transactions + ) + +func executionPayload*(p: ExecutionPayloadV2): ExecutionPayload = + ExecutionPayload( + parentHash: p.parentHash, + feeRecipient: p.feeRecipient, + stateRoot: p.stateRoot, + receiptsRoot: p.receiptsRoot, + logsBloom: p.logsBloom, + prevRandao: p.prevRandao, + blockNumber: p.blockNumber, + gasLimit: p.gasLimit, + gasUsed: p.gasUsed, + timestamp: p.timestamp, + extraData: p.extraData, + baseFeePerGas: p.baseFeePerGas, + blockHash: p.blockHash, + transactions: p.transactions, + withdrawals: some(p.withdrawals) + ) + +func executionPayload*(p: ExecutionPayloadV3): ExecutionPayload = + ExecutionPayload( + parentHash: p.parentHash, + feeRecipient: p.feeRecipient, + stateRoot: p.stateRoot, + receiptsRoot: p.receiptsRoot, + logsBloom: p.logsBloom, + prevRandao: p.prevRandao, + blockNumber: p.blockNumber, + gasLimit: p.gasLimit, + gasUsed: p.gasUsed, + timestamp: p.timestamp, + extraData: p.extraData, + baseFeePerGas: p.baseFeePerGas, + blockHash: p.blockHash, + transactions: p.transactions, + withdrawals: some(p.withdrawals), + blobGasUsed: some(p.blobGasUsed), + excessBlobGas: some(p.excessBlobGas) + ) diff --git a/nimbus/rpc/merge/merger.nim b/nimbus/rpc/merge/merger.nim index e22440480..09559b7df 100644 --- a/nimbus/rpc/merge/merger.nim +++ b/nimbus/rpc/merge/merger.nim @@ -28,10 +28,10 @@ type db : CoreDbRef status: TransitionStatus -proc writeStatus(db: CoreDbRef, status: TransitionStatus) {.gcsafe, raises: [RlpError].} = +proc writeStatus(db: CoreDbRef, status: TransitionStatus) {.gcsafe, raises: [].} = db.kvt.put(transitionStatusKey().toOpenArray(), rlp.encode(status)) -proc readStatus(db: CoreDbRef): TransitionStatus {.gcsafe, raises: [RlpError].} = +proc readStatus(db: CoreDbRef): TransitionStatus {.gcsafe, raises: [].} = var bytes = db.kvt.get(transitionStatusKey().toOpenArray()) if bytes.len > 0: try: @@ -39,7 +39,7 @@ proc readStatus(db: CoreDbRef): TransitionStatus {.gcsafe, raises: [RlpError].} except CatchableError: error "Failed to decode POS transition status" -proc new*(_: type MergerRef, db: CoreDbRef): MergerRef {.gcsafe, raises: [RlpError].} = +proc new*(_: type MergerRef, db: CoreDbRef): MergerRef {.gcsafe, raises: [].} = MergerRef( db: db, status: db.readStatus() @@ -47,7 +47,7 @@ proc new*(_: type MergerRef, db: CoreDbRef): MergerRef {.gcsafe, raises: [RlpErr # ReachTTD is called whenever the first NewHead message received # from the consensus-layer. -proc reachTTD*(m: MergerRef) {.gcsafe, raises: [RlpError].} = +proc reachTTD*(m: MergerRef) {.gcsafe, raises: [].} = if m.status.leftPoW: return @@ -58,7 +58,7 @@ proc reachTTD*(m: MergerRef) {.gcsafe, raises: [RlpError].} = # FinalizePoS is called whenever the first FinalisedBlock message received # from the consensus-layer. -proc finalizePoS*(m: MergerRef) {.gcsafe, raises: [RlpError].} = +proc finalizePoS*(m: MergerRef) {.gcsafe, raises: [].} = if m.status.enteredPoS: return diff --git a/nimbus/rpc/merge/mergetypes.nim b/nimbus/rpc/merge/mergetypes.nim index 51600eb29..e0b007d9b 100644 --- a/nimbus/rpc/merge/mergetypes.nim +++ b/nimbus/rpc/merge/mergetypes.nim @@ -9,7 +9,9 @@ import web3/engine_api_types, - ./merger + ./merger, + ../execution_types + import eth/common/eth_types except BlockHeader @@ -40,7 +42,7 @@ type PayloadItem = object id: PayloadID - payload: ExecutionPayloadV1OrV2 + payload: ExecutionPayload HeaderItem = object hash: Hash256 @@ -81,16 +83,13 @@ proc get*(api: EngineApiRef, hash: Hash256, header: var EthBlockHeader): bool = return true false -proc put*(api: EngineApiRef, id: PayloadID, payload: ExecutionPayloadV1OrV2) = +proc put*(api: EngineApiRef, id: PayloadID, payload: ExecutionPayload) = api.payloadQueue.put(PayloadItem(id: id, payload: payload)) -proc put*(api: EngineApiRef, id: PayloadID, payload: ExecutionPayloadV1) = - api.put(id, payload.toExecutionPayloadV1OrV2) +proc put*(api: EngineApiRef, id: PayloadID, payload: SomeExecutionPayload) = + api.put(id, payload.executionPayload) -proc put*(api: EngineApiRef, id: PayloadID, payload: ExecutionPayloadV2) = - api.put(id, payload.toExecutionPayloadV1OrV2) - -proc get*(api: EngineApiRef, id: PayloadID, payload: var ExecutionPayloadV1OrV2): bool = +proc get*(api: EngineApiRef, id: PayloadID, payload: var ExecutionPayload): bool = for x in api.payloadQueue: if x.id == id: payload = x.payload @@ -98,9 +97,31 @@ proc get*(api: EngineApiRef, id: PayloadID, payload: var ExecutionPayloadV1OrV2) false proc get*(api: EngineApiRef, id: PayloadID, payload: var ExecutionPayloadV1): bool = - var p: ExecutionPayloadV1OrV2 + var p: ExecutionPayload let found = api.get(id, p) - payload = p.toExecutionPayloadV1 + doAssert(p.version == Version.V1) + payload = p.V1 + return found + +proc get*(api: EngineApiRef, id: PayloadID, payload: var ExecutionPayloadV2): bool = + var p: ExecutionPayload + let found = api.get(id, p) + doAssert(p.version == Version.V2) + payload = p.V2 + return found + +proc get*(api: EngineApiRef, id: PayloadID, payload: var ExecutionPayloadV3): bool = + var p: ExecutionPayload + let found = api.get(id, p) + doAssert(p.version == Version.V3) + payload = p.V3 + return found + +proc get*(api: EngineApiRef, id: PayloadID, payload: var ExecutionPayloadV1OrV2): bool = + var p: ExecutionPayload + let found = api.get(id, p) + doAssert(p.version in {Version.V1, Version.V2}) + payload = p.V1V2 return found proc merger*(api: EngineApiRef): MergerRef = diff --git a/nimbus/rpc/merge/mergeutils.nim b/nimbus/rpc/merge/mergeutils.nim index 8593a5515..1d7215cb4 100644 --- a/nimbus/rpc/merge/mergeutils.nim +++ b/nimbus/rpc/merge/mergeutils.nim @@ -17,11 +17,12 @@ import ../../constants, ../../db/core_db, ../../utils/utils, + ../../rpc/execution_types, ./mergetypes type Hash256 = eth_types.Hash256 -proc computePayloadId*(headBlockHash: Hash256, params: PayloadAttributesV1 | PayloadAttributesV2): PayloadID = +proc computePayloadId*(headBlockHash: Hash256, params: SomePayloadAttributes): PayloadID = var dest: Hash256 var ctx: sha256 ctx.init() @@ -73,7 +74,7 @@ proc toWithdrawalV1*(w: Withdrawal): WithdrawalV1 = amount: Quantity(w.amount) # AARDVARK: is this wei or gwei or what? ) -proc maybeWithdrawalsRoot(payload: ExecutionPayloadV1 | ExecutionPayloadV2): Option[Hash256] = +proc maybeWithdrawalsRoot(payload: SomeExecutionPayload): Option[Hash256] = when payload is ExecutionPayloadV1: none(Hash256) else: @@ -87,7 +88,19 @@ proc toWithdrawals(withdrawals: openArray[WithdrawalV1]): seq[WithDrawal] = for wd in withdrawals: result.add toWithdrawal(wd) -proc toBlockHeader*(payload: ExecutionPayloadV1 | ExecutionPayloadV2): EthBlockHeader = +proc maybeBlobGasUsed(payload: SomeExecutionPayload): Option[uint64] = + when payload is ExecutionPayloadV3: + some(payload.blobGasUsed.uint64) + else: + none(uint64) + +proc maybeExcessBlobGas(payload: SomeExecutionPayload): Option[uint64] = + when payload is ExecutionPayloadV3: + some(payload.excessBlobGas.uint64) + else: + none(uint64) + +proc toBlockHeader*(payload: SomeExecutionPayload): EthBlockHeader = let transactions = seq[seq[byte]](payload.transactions) let txRoot = calcRootHashRlp(transactions) @@ -108,18 +121,22 @@ proc toBlockHeader*(payload: ExecutionPayloadV1 | ExecutionPayloadV2): EthBlockH mixDigest : payload.prevRandao.asEthHash, # EIP-4399 redefine `mixDigest` -> `prevRandao` nonce : default(BlockNonce), fee : some payload.baseFeePerGas, - withdrawalsRoot: payload.maybeWithdrawalsRoot # EIP-4895 + withdrawalsRoot: payload.maybeWithdrawalsRoot, # EIP-4895 + blobGasUsed : payload.maybeBlobGasUsed, # EIP-4844 + excessBlobGas : payload.maybeExcessBlobGas, # EIP-4844 ) proc toTypedTransaction*(tx: Transaction): TypedTransaction = TypedTransaction(rlp.encode(tx)) -proc toBlockBody*(payload: ExecutionPayloadV1 | ExecutionPayloadV2): BlockBody = +proc toBlockBody*(payload: SomeExecutionPayload): BlockBody = result.transactions.setLen(payload.transactions.len) for i, tx in payload.transactions: result.transactions[i] = rlp.decode(distinctBase tx, Transaction) when payload is ExecutionPayloadV2: result.withdrawals = some(payload.withdrawals.toWithdrawals) + when payload is ExecutionPayloadV3: + result.withdrawals = some(payload.withdrawals.toWithdrawals) proc `$`*(x: BlockHash): string = toHex(x) @@ -216,3 +233,9 @@ proc invalidAttr*(msg: string): ref InvalidRequest = code: engineApiInvalidPayloadAttributes, msg: msg ) + +proc unsupportedFork*(msg: string): ref InvalidRequest = + (ref InvalidRequest)( + code: engineApiUnsupportedFork, + msg: msg + ) diff --git a/vendor/nim-web3 b/vendor/nim-web3 index 943431de3..e68ff1e3f 160000 --- a/vendor/nim-web3 +++ b/vendor/nim-web3 @@ -1 +1 @@ -Subproject commit 943431de3fa16d7349b363c35ba5ea9f80b423d3 +Subproject commit e68ff1e3f9f776b3ef77513f052c0aead51c96cb