add engine API V3 of Cancun
This commit is contained in:
parent
ec17a5a348
commit
a7db7b9101
|
@ -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,
|
||||||
|
|
|
@ -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]]:
|
||||||
|
|
|
@ -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)
|
||||||
|
)
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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 =
|
||||||
|
|
|
@ -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
|
||||||
|
)
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
Subproject commit 943431de3fa16d7349b363c35ba5ea9f80b423d3
|
Subproject commit e68ff1e3f9f776b3ef77513f052c0aead51c96cb
|
Loading…
Reference in New Issue