add engine API V3 of Cancun

This commit is contained in:
jangko 2023-08-08 14:29:23 +07:00
parent ec17a5a348
commit a7db7b9101
No known key found for this signature in database
GPG Key ID: 31702AE10541E6B9
7 changed files with 422 additions and 45 deletions

View File

@ -27,7 +27,8 @@ import
clique_cfg, clique_cfg,
clique_sealer], clique_sealer],
../utils/utils, ../utils/utils,
../common/[common, context] ../common/[common, context],
../rpc/execution_types
from web3/ethtypes as web3types import nil, TypedTransaction, WithdrawalV1, ExecutionPayloadV1OrV2, toExecutionPayloadV1OrV2, toExecutionPayloadV1 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) result.add toWithdrawal(x)
proc generateExecutionPayload*(engine: SealingEngineRef, proc generateExecutionPayload*(engine: SealingEngineRef,
payloadAttrs: PayloadAttributesV1 | PayloadAttributesV2): Result[ExecutionPayloadV1OrV2, string] = payloadAttrs: SomePayloadAttributes): Result[ExecutionPayload, string] =
let let
headBlock = try: engine.chain.db.getCanonicalHead() headBlock = try: engine.chain.db.getCanonicalHead()
except CatchableError: return err "No head block in database" except CatchableError: return err "No head block in database"
@ -170,6 +171,8 @@ proc generateExecutionPayload*(engine: SealingEngineRef,
when payloadAttrs is PayloadAttributesV2: when payloadAttrs is PayloadAttributesV2:
engine.txPool.withdrawals = payloadAttrs.withdrawals.toWithdrawals engine.txPool.withdrawals = payloadAttrs.withdrawals.toWithdrawals
elif payloadAttrs is PayloadAttributesV3:
engine.txPool.withdrawals = payloadAttrs.withdrawals.toWithdrawals
else: else:
engine.txPool.withdrawals = @[] engine.txPool.withdrawals = @[]
@ -199,7 +202,17 @@ proc generateExecutionPayload*(engine: SealingEngineRef,
else: else:
none[seq[WithdrawalV1]]() 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, parentHash: Web3BlockHash blk.header.parentHash.data,
feeRecipient: Web3Address blk.header.coinbase, feeRecipient: Web3Address blk.header.coinbase,
stateRoot: Web3BlockHash blk.header.stateRoot.data, stateRoot: Web3BlockHash blk.header.stateRoot.data,
@ -214,13 +227,11 @@ proc generateExecutionPayload*(engine: SealingEngineRef,
baseFeePerGas: blk.header.fee.get(UInt256.zero), baseFeePerGas: blk.header.fee.get(UInt256.zero),
blockHash: Web3BlockHash blockHash.data, blockHash: Web3BlockHash blockHash.data,
transactions: transactions, 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, proc new*(_: type SealingEngineRef,
chain: ChainRef, chain: ChainRef,
ctx: EthContext, ctx: EthContext,

View File

@ -11,7 +11,8 @@ import
std/[typetraits, times, strutils, sequtils, sets], std/[typetraits, times, strutils, sequtils, sets],
stew/[results, byteutils], stew/[results, byteutils],
json_rpc/rpcserver, json_rpc/rpcserver,
web3/[conversions, engine_api_types], web3/[conversions],
web3/engine_api_types as web3types,
eth/rlp, eth/rlp,
eth/common/eth_types, eth/common/eth_types,
eth/common/eth_types_rlp, eth/common/eth_types_rlp,
@ -22,6 +23,7 @@ import
../core/[tx_pool, sealer], ../core/[tx_pool, sealer],
../evm/async/data_sources, ../evm/async/data_sources,
./merge/[mergetypes, mergeutils], ./merge/[mergetypes, mergeutils],
./execution_types,
# put chronicles import last because Nim # put chronicles import last because Nim
# compiler resolve `$` for logging # compiler resolve `$` for logging
# arguments differently on Windows vs posix # arguments differently on Windows vs posix
@ -30,7 +32,11 @@ import
{.push raises: [].} {.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] = func toPayloadAttributesV1OrPayloadAttributesV2*(a: PayloadAttributesV1OrV2): Result[PayloadAttributesV1, PayloadAttributesV2] =
@ -92,7 +98,10 @@ template unsafeQuantityToInt64(q: Quantity): int64 =
# null.) --Adam # null.) --Adam
# https://github.com/ethereum/execution-apis/blob/main/src/engine/specification.md#engine_newpayloadv1 # 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", trace "Engine API request received",
meth = "newPayload", number = $(distinctBase payload.blockNumber), hash = payload.blockHash meth = "newPayload", number = $(distinctBase payload.blockNumber), hash = payload.blockHash
@ -221,6 +230,41 @@ proc handle_getPayload(api: EngineApiRef, payloadId: PayloadID): GetPayloadV2Res
blockValue: blockValue 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 # 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].} = proc handle_exchangeTransitionConfiguration(sealingEngine: SealingEngineRef, com: CommonRef, conf: TransitionConfigurationV1): TransitionConfigurationV1 {.raises: [CatchableError].} =
trace "Engine API request received", trace "Engine API request received",
@ -281,10 +325,16 @@ proc handle_exchangeTransitionConfiguration(sealingEngine: SealingEngineRef, com
# If there are payloadAttributes: # If there are payloadAttributes:
# we try to assemble a block with the payloadAttributes and return its payloadID # 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 # 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 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]): when not(payloadAttributes is Option[PayloadAttributesV2]):
raise invalidParams("if timestamp is Shanghai or later, payloadAttributes must be PayloadAttributesV2") raise invalidParams("if timestamp is Shanghai or later, payloadAttributes must be PayloadAttributesV2")
else: else:
@ -475,6 +525,7 @@ const supportedMethods: HashSet[string] =
"engine_exchangeTransitionConfigurationV1", "engine_exchangeTransitionConfigurationV1",
"engine_forkchoiceUpdatedV1", "engine_forkchoiceUpdatedV1",
"engine_forkchoiceUpdatedV2", "engine_forkchoiceUpdatedV2",
"engine_forkchoiceUpdatedV3",
"engine_getPayloadBodiesByHashV1" "engine_getPayloadBodiesByHashV1"
]) ])
@ -498,12 +549,31 @@ proc setupEngineAPI*(
server.rpc("engine_newPayloadV1") do(payload: ExecutionPayloadV1) -> PayloadStatusV1: server.rpc("engine_newPayloadV1") do(payload: ExecutionPayloadV1) -> PayloadStatusV1:
return handle_newPayload(sealingEngine, api, com, maybeAsyncDataSource, payload) return handle_newPayload(sealingEngine, api, com, maybeAsyncDataSource, payload)
server.rpc("engine_newPayloadV2") do(payload: ExecutionPayloadV1OrV2) -> PayloadStatusV1: server.rpc("engine_newPayloadV2") do(payload: ExecutionPayload) -> PayloadStatusV1:
let p = payload.toExecutionPayloadV1OrExecutionPayloadV2 if payload.version == Version.V1:
if p.isOk: return handle_newPayload(sealingEngine, api, com, maybeAsyncDataSource, payload.V1)
return handle_newPayload(sealingEngine, api, com, maybeAsyncDataSource, p.get)
else: 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: server.rpc("engine_getPayloadV1") do(payloadId: PayloadID) -> ExecutionPayloadV1:
let r = handle_getPayload(api, payloadId) let r = handle_getPayload(api, payloadId)
@ -512,6 +582,9 @@ proc setupEngineAPI*(
server.rpc("engine_getPayloadV2") do(payloadId: PayloadID) -> GetPayloadV2Response: server.rpc("engine_getPayloadV2") do(payloadId: PayloadID) -> GetPayloadV2Response:
return handle_getPayload(api, payloadId) 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: server.rpc("engine_exchangeTransitionConfigurationV1") do(conf: TransitionConfigurationV1) -> TransitionConfigurationV1:
return handle_exchangeTransitionConfiguration(sealingEngine, com, conf) return handle_exchangeTransitionConfiguration(sealingEngine, com, conf)
@ -522,15 +595,30 @@ proc setupEngineAPI*(
server.rpc("engine_forkchoiceUpdatedV2") do( server.rpc("engine_forkchoiceUpdatedV2") do(
update: ForkchoiceStateV1, update: ForkchoiceStateV1,
payloadAttributes: Option[PayloadAttributesV1OrV2]) -> ForkchoiceUpdatedResponse: payloadAttributes: Option[PayloadAttributes]) -> ForkchoiceUpdatedResponse:
if payloadAttributes.isNone: if payloadAttributes.isNone:
return handle_forkchoiceUpdated(sealingEngine, com, api, update, none[PayloadAttributesV2]()) return handle_forkchoiceUpdated(sealingEngine, com, api, update, none[PayloadAttributesV2]())
else: else:
let a = payloadAttributes.get.toPayloadAttributesV1OrPayloadAttributesV2 let attr = payloadAttributes.get
if a.isOk: if attr.version == Version.V1:
return handle_forkchoiceUpdated(sealingEngine, com, api, update, some(a.get)) return handle_forkchoiceUpdated(sealingEngine, com, api, update, some(attr.V1))
else: 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( server.rpc("engine_getPayloadBodiesByHashV1") do(
hashes: seq[BlockHash]) -> seq[Option[ExecutionPayloadBodyV1]]: hashes: seq[BlockHash]) -> seq[Option[ExecutionPayloadBodyV1]]:

View File

@ -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)
)

View File

@ -28,10 +28,10 @@ type
db : CoreDbRef db : CoreDbRef
status: TransitionStatus 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)) 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()) var bytes = db.kvt.get(transitionStatusKey().toOpenArray())
if bytes.len > 0: if bytes.len > 0:
try: try:
@ -39,7 +39,7 @@ proc readStatus(db: CoreDbRef): TransitionStatus {.gcsafe, raises: [RlpError].}
except CatchableError: except CatchableError:
error "Failed to decode POS transition status" 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( MergerRef(
db: db, db: db,
status: db.readStatus() 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 # ReachTTD is called whenever the first NewHead message received
# from the consensus-layer. # from the consensus-layer.
proc reachTTD*(m: MergerRef) {.gcsafe, raises: [RlpError].} = proc reachTTD*(m: MergerRef) {.gcsafe, raises: [].} =
if m.status.leftPoW: if m.status.leftPoW:
return return
@ -58,7 +58,7 @@ proc reachTTD*(m: MergerRef) {.gcsafe, raises: [RlpError].} =
# FinalizePoS is called whenever the first FinalisedBlock message received # FinalizePoS is called whenever the first FinalisedBlock message received
# from the consensus-layer. # from the consensus-layer.
proc finalizePoS*(m: MergerRef) {.gcsafe, raises: [RlpError].} = proc finalizePoS*(m: MergerRef) {.gcsafe, raises: [].} =
if m.status.enteredPoS: if m.status.enteredPoS:
return return

View File

@ -9,7 +9,9 @@
import import
web3/engine_api_types, web3/engine_api_types,
./merger ./merger,
../execution_types
import eth/common/eth_types except BlockHeader import eth/common/eth_types except BlockHeader
@ -40,7 +42,7 @@ type
PayloadItem = object PayloadItem = object
id: PayloadID id: PayloadID
payload: ExecutionPayloadV1OrV2 payload: ExecutionPayload
HeaderItem = object HeaderItem = object
hash: Hash256 hash: Hash256
@ -81,16 +83,13 @@ proc get*(api: EngineApiRef, hash: Hash256, header: var EthBlockHeader): bool =
return true return true
false 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)) api.payloadQueue.put(PayloadItem(id: id, payload: payload))
proc put*(api: EngineApiRef, id: PayloadID, payload: ExecutionPayloadV1) = proc put*(api: EngineApiRef, id: PayloadID, payload: SomeExecutionPayload) =
api.put(id, payload.toExecutionPayloadV1OrV2) api.put(id, payload.executionPayload)
proc put*(api: EngineApiRef, id: PayloadID, payload: ExecutionPayloadV2) = proc get*(api: EngineApiRef, id: PayloadID, payload: var ExecutionPayload): bool =
api.put(id, payload.toExecutionPayloadV1OrV2)
proc get*(api: EngineApiRef, id: PayloadID, payload: var ExecutionPayloadV1OrV2): bool =
for x in api.payloadQueue: for x in api.payloadQueue:
if x.id == id: if x.id == id:
payload = x.payload payload = x.payload
@ -98,9 +97,31 @@ proc get*(api: EngineApiRef, id: PayloadID, payload: var ExecutionPayloadV1OrV2)
false false
proc get*(api: EngineApiRef, id: PayloadID, payload: var ExecutionPayloadV1): bool = proc get*(api: EngineApiRef, id: PayloadID, payload: var ExecutionPayloadV1): bool =
var p: ExecutionPayloadV1OrV2 var p: ExecutionPayload
let found = api.get(id, p) 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 return found
proc merger*(api: EngineApiRef): MergerRef = proc merger*(api: EngineApiRef): MergerRef =

View File

@ -17,11 +17,12 @@ import
../../constants, ../../constants,
../../db/core_db, ../../db/core_db,
../../utils/utils, ../../utils/utils,
../../rpc/execution_types,
./mergetypes ./mergetypes
type Hash256 = eth_types.Hash256 type Hash256 = eth_types.Hash256
proc computePayloadId*(headBlockHash: Hash256, params: PayloadAttributesV1 | PayloadAttributesV2): PayloadID = proc computePayloadId*(headBlockHash: Hash256, params: SomePayloadAttributes): PayloadID =
var dest: Hash256 var dest: Hash256
var ctx: sha256 var ctx: sha256
ctx.init() ctx.init()
@ -73,7 +74,7 @@ proc toWithdrawalV1*(w: Withdrawal): WithdrawalV1 =
amount: Quantity(w.amount) # AARDVARK: is this wei or gwei or what? 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: when payload is ExecutionPayloadV1:
none(Hash256) none(Hash256)
else: else:
@ -87,7 +88,19 @@ proc toWithdrawals(withdrawals: openArray[WithdrawalV1]): seq[WithDrawal] =
for wd in withdrawals: for wd in withdrawals:
result.add toWithdrawal(wd) 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 transactions = seq[seq[byte]](payload.transactions)
let txRoot = calcRootHashRlp(transactions) let txRoot = calcRootHashRlp(transactions)
@ -108,18 +121,22 @@ proc toBlockHeader*(payload: ExecutionPayloadV1 | ExecutionPayloadV2): EthBlockH
mixDigest : payload.prevRandao.asEthHash, # EIP-4399 redefine `mixDigest` -> `prevRandao` mixDigest : payload.prevRandao.asEthHash, # EIP-4399 redefine `mixDigest` -> `prevRandao`
nonce : default(BlockNonce), nonce : default(BlockNonce),
fee : some payload.baseFeePerGas, 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 = proc toTypedTransaction*(tx: Transaction): TypedTransaction =
TypedTransaction(rlp.encode(tx)) TypedTransaction(rlp.encode(tx))
proc toBlockBody*(payload: ExecutionPayloadV1 | ExecutionPayloadV2): BlockBody = proc toBlockBody*(payload: SomeExecutionPayload): BlockBody =
result.transactions.setLen(payload.transactions.len) result.transactions.setLen(payload.transactions.len)
for i, tx in payload.transactions: for i, tx in payload.transactions:
result.transactions[i] = rlp.decode(distinctBase tx, Transaction) result.transactions[i] = rlp.decode(distinctBase tx, Transaction)
when payload is ExecutionPayloadV2: when payload is ExecutionPayloadV2:
result.withdrawals = some(payload.withdrawals.toWithdrawals) result.withdrawals = some(payload.withdrawals.toWithdrawals)
when payload is ExecutionPayloadV3:
result.withdrawals = some(payload.withdrawals.toWithdrawals)
proc `$`*(x: BlockHash): string = proc `$`*(x: BlockHash): string =
toHex(x) toHex(x)
@ -216,3 +233,9 @@ proc invalidAttr*(msg: string): ref InvalidRequest =
code: engineApiInvalidPayloadAttributes, code: engineApiInvalidPayloadAttributes,
msg: msg msg: msg
) )
proc unsupportedFork*(msg: string): ref InvalidRequest =
(ref InvalidRequest)(
code: engineApiUnsupportedFork,
msg: msg
)

2
vendor/nim-web3 vendored

@ -1 +1 @@
Subproject commit 943431de3fa16d7349b363c35ba5ea9f80b423d3 Subproject commit e68ff1e3f9f776b3ef77513f052c0aead51c96cb