mirror of
https://github.com/status-im/nimbus-eth1.git
synced 2025-02-15 05:26:36 +00:00
Fixes related to executionRequests of Pectra (#2787)
This commit is contained in:
parent
6b2d341ebb
commit
738cb277cf
@ -92,6 +92,7 @@ proc getPayload*(client: RpcClient,
|
||||
blockValue: Opt.some(x.blockValue),
|
||||
blobsBundle: Opt.some(x.blobsBundle),
|
||||
shouldOverrideBuilder: Opt.some(x.shouldOverrideBuilder),
|
||||
executionRequests: Opt.some(x.executionRequests),
|
||||
))
|
||||
elif version == Version.V3:
|
||||
let x = client.getPayloadV3(payloadId).valueOr:
|
||||
|
@ -190,7 +190,11 @@ proc forkchoiceUpdated*(ben: BeaconEngineRef,
|
||||
raise invalidAttr(error)
|
||||
|
||||
let id = computePayloadId(blockHash, attrs)
|
||||
ben.put(id, bundle.blockValue, bundle.executionPayload, bundle.blobsBundle)
|
||||
ben.put(id,
|
||||
bundle.blockValue,
|
||||
bundle.executionPayload,
|
||||
bundle.blobsBundle,
|
||||
bundle.executionRequests)
|
||||
|
||||
info "Created payload for sealing",
|
||||
id = id.toHex,
|
||||
|
@ -34,47 +34,48 @@ func validateVersionedHashed(payload: ExecutionPayload,
|
||||
return false
|
||||
true
|
||||
|
||||
template validateVersion(com, timestamp, version, apiVersion) =
|
||||
template validateVersion(com, timestamp, payloadVersion, apiVersion) =
|
||||
if apiVersion == Version.V4:
|
||||
if not com.isPragueOrLater(timestamp):
|
||||
raise unsupportedFork("newPayloadV4 expect payload timestamp fall within Prague")
|
||||
|
||||
if com.isPragueOrLater(timestamp):
|
||||
if version != Version.V3:
|
||||
if payloadVersion != Version.V3:
|
||||
raise invalidParams("if timestamp is Prague or later, " &
|
||||
"payload must be ExecutionPayloadV3, got ExecutionPayload" & $version)
|
||||
"payload must be ExecutionPayloadV3, got ExecutionPayload" & $payloadVersion)
|
||||
|
||||
if apiVersion == Version.V3:
|
||||
if not com.isCancunOrLater(timestamp):
|
||||
raise unsupportedFork("newPayloadV3 expect payload timestamp fall within Cancun")
|
||||
|
||||
if com.isCancunOrLater(timestamp):
|
||||
if version != Version.V3:
|
||||
if payloadVersion != Version.V3:
|
||||
raise invalidParams("if timestamp is Cancun or later, " &
|
||||
"payload must be ExecutionPayloadV3, got ExecutionPayload" & $version)
|
||||
"payload must be ExecutionPayloadV3, got ExecutionPayload" & $payloadVersion)
|
||||
|
||||
elif com.isShanghaiOrLater(timestamp):
|
||||
if version != Version.V2:
|
||||
if payloadVersion != Version.V2:
|
||||
raise invalidParams("if timestamp is Shanghai or later, " &
|
||||
"payload must be ExecutionPayloadV2, got ExecutionPayload" & $version)
|
||||
"payload must be ExecutionPayloadV2, got ExecutionPayload" & $payloadVersion)
|
||||
|
||||
elif version != Version.V1:
|
||||
elif payloadVersion != Version.V1:
|
||||
raise invalidParams("if timestamp is earlier than Shanghai, " &
|
||||
"payload must be ExecutionPayloadV1, got ExecutionPayload" & $version)
|
||||
"payload must be ExecutionPayloadV1, got ExecutionPayload" & $payloadVersion)
|
||||
|
||||
if apiVersion >= Version.V3:
|
||||
if version != apiVersion:
|
||||
if apiVersion == Version.V3 or apiVersion == Version.V4:
|
||||
# both newPayloadV3 and newPayloadV4 expect ExecutionPayloadV3
|
||||
if payloadVersion != Version.V3:
|
||||
raise invalidParams("newPayload" & $apiVersion &
|
||||
" expect ExecutionPayload" & $apiVersion &
|
||||
" but got ExecutionPayload" & $version)
|
||||
" expect ExecutionPayload3" &
|
||||
" but got ExecutionPayload" & $payloadVersion)
|
||||
|
||||
template validatePayload(apiVersion, version, payload, executionRequests) =
|
||||
if version >= Version.V2:
|
||||
template validatePayload(apiVersion, payloadVersion, payload) =
|
||||
if payloadVersion >= Version.V2:
|
||||
if payload.withdrawals.isNone:
|
||||
raise invalidParams("newPayload" & $apiVersion &
|
||||
"withdrawals is expected from execution payload")
|
||||
|
||||
if apiVersion >= Version.V3 or version >= Version.V3:
|
||||
if apiVersion >= Version.V3 or payloadVersion >= Version.V3:
|
||||
if payload.blobGasUsed.isNone:
|
||||
raise invalidParams("newPayload" & $apiVersion &
|
||||
"blobGasUsed is expected from execution payload")
|
||||
@ -82,11 +83,6 @@ template validatePayload(apiVersion, version, payload, executionRequests) =
|
||||
raise invalidParams("newPayload" & $apiVersion &
|
||||
"excessBlobGas is expected from execution payload")
|
||||
|
||||
if apiVersion >= Version.V4 or version >= Version.V4:
|
||||
if executionRequests.isNone:
|
||||
raise invalidParams("newPayload" & $apiVersion &
|
||||
"executionRequests is expected from execution payload")
|
||||
|
||||
proc newPayload*(ben: BeaconEngineRef,
|
||||
apiVersion: Version,
|
||||
payload: ExecutionPayload,
|
||||
@ -103,6 +99,11 @@ proc newPayload*(ben: BeaconEngineRef,
|
||||
if beaconRoot.isNone:
|
||||
raise invalidParams("newPayloadV3 expect beaconRoot but got none")
|
||||
|
||||
if apiVersion >= Version.V4:
|
||||
if executionRequests.isNone:
|
||||
raise invalidParams("newPayload" & $apiVersion &
|
||||
": executionRequests is expected from execution payload")
|
||||
|
||||
let
|
||||
com = ben.com
|
||||
db = com.db
|
||||
@ -110,7 +111,7 @@ proc newPayload*(ben: BeaconEngineRef,
|
||||
version = payload.version
|
||||
requestsHash = calcRequestsHash(executionRequests)
|
||||
|
||||
validatePayload(apiVersion, version, payload, executionRequests)
|
||||
validatePayload(apiVersion, version, payload)
|
||||
validateVersion(com, timestamp, version, apiVersion)
|
||||
|
||||
var blk = ethBlock(payload, beaconRoot, requestsHash)
|
||||
|
@ -121,6 +121,12 @@ func put*(ben: BeaconEngineRef, id: Bytes8,
|
||||
blobsBundle: Opt[BlobsBundleV1]) =
|
||||
ben.queue.put(id, blockValue, payload, blobsBundle)
|
||||
|
||||
func put*(ben: BeaconEngineRef, id: Bytes8,
|
||||
blockValue: UInt256, payload: ExecutionPayload,
|
||||
blobsBundle: Opt[BlobsBundleV1],
|
||||
executionRequests: Opt[array[3, seq[byte]]]) =
|
||||
ben.queue.put(id, blockValue, payload, blobsBundle, executionRequests)
|
||||
|
||||
func put*(ben: BeaconEngineRef, id: Bytes8,
|
||||
blockValue: UInt256, payload: SomeExecutionPayload,
|
||||
blobsBundle: Opt[BlobsBundleV1]) =
|
||||
@ -185,14 +191,15 @@ func get*(ben: BeaconEngineRef, id: Bytes8,
|
||||
# Public functions
|
||||
# ------------------------------------------------------------------------------
|
||||
|
||||
type ExecutionPayloadAndBlobsBundle* = object
|
||||
type AssembledExecutionPayload* = object
|
||||
executionPayload*: ExecutionPayload
|
||||
blobsBundle*: Opt[BlobsBundleV1]
|
||||
blockValue*: UInt256
|
||||
executionRequests*: Opt[array[3, seq[byte]]]
|
||||
|
||||
proc generatePayload*(ben: BeaconEngineRef,
|
||||
attrs: PayloadAttributes):
|
||||
Result[ExecutionPayloadAndBlobsBundle, string] =
|
||||
Result[AssembledExecutionPayload, string] =
|
||||
wrapException:
|
||||
let
|
||||
xp = ben.txPool
|
||||
@ -231,10 +238,11 @@ proc generatePayload*(ben: BeaconEngineRef,
|
||||
proofs: blobData.proofs.mapIt it.Web3KZGProof,
|
||||
blobs: blobData.blobs.mapIt it.Web3Blob)
|
||||
|
||||
ok ExecutionPayloadAndBlobsBundle(
|
||||
ok AssembledExecutionPayload(
|
||||
executionPayload: executionPayload(bundle.blk),
|
||||
blobsBundle: blobsBundle,
|
||||
blockValue: bundle.blockValue)
|
||||
blockValue: bundle.blockValue,
|
||||
executionRequests: bundle.executionRequests)
|
||||
|
||||
func setInvalidAncestor*(ben: BeaconEngineRef, header: Header, blockHash: Hash32) =
|
||||
ben.invalidBlocksHits[blockHash] = 1
|
||||
|
@ -152,6 +152,16 @@ proc procBlkEpilogue(
|
||||
clearEmptyAccount = vmState.com.isSpuriousOrLater(header.number),
|
||||
clearCache = true)
|
||||
|
||||
var
|
||||
withdrawalReqs: seq[byte]
|
||||
consolidationReqs: seq[byte]
|
||||
|
||||
if header.requestsHash.isSome:
|
||||
# Execute EIP-7002 and EIP-7251 before calculating stateRoot
|
||||
# because they will alter the state
|
||||
withdrawalReqs = processDequeueWithdrawalRequests(vmState)
|
||||
consolidationReqs = processDequeueConsolidationRequests(vmState)
|
||||
|
||||
if not skipValidation:
|
||||
let stateDB = vmState.stateDB
|
||||
if header.stateRoot != stateDB.rootHash:
|
||||
@ -181,8 +191,6 @@ proc procBlkEpilogue(
|
||||
if header.requestsHash.isSome:
|
||||
let
|
||||
depositReqs = ?parseDepositLogs(vmState.allLogs)
|
||||
withdrawalReqs = processDequeueWithdrawalRequests(vmState)
|
||||
consolidationReqs = processDequeueConsolidationRequests(vmState)
|
||||
requestsHash = calcRequestsHashInsertType(depositReqs, withdrawalReqs, consolidationReqs)
|
||||
|
||||
if header.requestsHash.get != requestsHash:
|
||||
|
@ -460,15 +460,16 @@ func com*(xp: TxPoolRef): CommonRef =
|
||||
## Getter
|
||||
xp.vmState.com
|
||||
|
||||
type EthBlockAndBlobsBundle* = object
|
||||
type AssembledBlock* = object
|
||||
blk*: EthBlock
|
||||
blobsBundle*: Opt[BlobsBundle]
|
||||
blockValue*: UInt256
|
||||
executionRequests*: Opt[array[3, seq[byte]]]
|
||||
|
||||
proc assembleBlock*(
|
||||
xp: TxPoolRef,
|
||||
someBaseFee: bool = false
|
||||
): Result[EthBlockAndBlobsBundle, string] {.gcsafe,raises: [CatchableError].} =
|
||||
): Result[AssembledBlock, string] {.gcsafe,raises: [CatchableError].} =
|
||||
## Getter, retrieves a packed block ready for mining and signing depending
|
||||
## on the internally cached block chain head, the txs in the pool and some
|
||||
## tuning parameters. The following block header fields are left
|
||||
@ -520,10 +521,17 @@ proc assembleBlock*(
|
||||
# make sure baseFee always has something
|
||||
blk.header.baseFeePerGas = Opt.some(blk.header.baseFeePerGas.get(0.u256))
|
||||
|
||||
ok EthBlockAndBlobsBundle(
|
||||
let executionRequestsOpt =
|
||||
if com.isPragueOrLater(blk.header.timestamp):
|
||||
Opt.some(pst.executionRequests)
|
||||
else:
|
||||
Opt.none(array[3, seq[byte]])
|
||||
|
||||
ok AssembledBlock(
|
||||
blk: blk,
|
||||
blobsBundle: blobsBundleOpt,
|
||||
blockValue: pst.blockValue)
|
||||
blockValue: pst.blockValue,
|
||||
executionRequests: executionRequestsOpt)
|
||||
|
||||
# core/tx_pool.go(474): func (pool SetGasPrice,*TxPool) Stats() (int, int) {
|
||||
# core/tx_pool.go(1728): func (t *txLookup) Count() int {
|
||||
|
@ -122,6 +122,7 @@ proc setupVMState(com: CommonRef; parent: Header): BaseVMState =
|
||||
difficulty : UInt256.zero(),
|
||||
coinbase : pos.feeRecipient,
|
||||
excessBlobGas: calcExcessBlobGas(parent),
|
||||
parentHash : parent.blockHash,
|
||||
)
|
||||
|
||||
BaseVMState.new(
|
||||
|
@ -26,6 +26,7 @@ import
|
||||
../../evm/state,
|
||||
../../evm/types,
|
||||
../eip4844,
|
||||
../eip6110,
|
||||
"."/[tx_desc, tx_item, tx_tabs, tx_tabs/tx_status, tx_info],
|
||||
tx_tasks/[tx_bucket]
|
||||
|
||||
@ -42,6 +43,9 @@ type
|
||||
stateRoot: Hash32
|
||||
receiptsRoot: Hash32
|
||||
logsBloom: Bloom
|
||||
withdrawalReqs: seq[byte]
|
||||
consolidationReqs: seq[byte]
|
||||
depositReqs: seq[byte]
|
||||
|
||||
GrabResult = enum
|
||||
FetchNextItem
|
||||
@ -187,6 +191,11 @@ proc vmExecInit(xp: TxPoolRef): Result[TxPacker, string]
|
||||
xp.vmState.processBeaconBlockRoot(beaconRoot).isOkOr:
|
||||
return err(error)
|
||||
|
||||
# EIP-2935
|
||||
if xp.nextFork >= FkPrague:
|
||||
xp.vmState.processParentBlockHash(xp.vmState.blockCtx.parentHash).isOkOr:
|
||||
return err(error)
|
||||
|
||||
ok(packer)
|
||||
|
||||
proc vmExecGrabItem(pst: var TxPacker; item: TxItemRef): GrabResult
|
||||
@ -203,7 +212,7 @@ proc vmExecGrabItem(pst: var TxPacker; item: TxItemRef): GrabResult
|
||||
if pst.numBlobPerBlock + item.tx.versionedHashes.len > MAX_BLOBS_PER_BLOCK:
|
||||
return ContinueWithNextAccount
|
||||
pst.numBlobPerBlock += item.tx.versionedHashes.len
|
||||
|
||||
|
||||
let blobGasUsed = item.tx.getTotalBlobGas
|
||||
if vmState.blobGasUsed + blobGasUsed > MAX_BLOB_GAS_PER_BLOCK:
|
||||
return ContinueWithNextAccount
|
||||
@ -245,7 +254,7 @@ proc vmExecGrabItem(pst: var TxPacker; item: TxItemRef): GrabResult
|
||||
|
||||
FetchNextItem
|
||||
|
||||
proc vmExecCommit(pst: var TxPacker) =
|
||||
proc vmExecCommit(pst: var TxPacker): Result[void, string] =
|
||||
let
|
||||
vmState = pst.vmState
|
||||
stateDB = vmState.stateDB
|
||||
@ -255,6 +264,12 @@ proc vmExecCommit(pst: var TxPacker) =
|
||||
for withdrawal in vmState.com.pos.withdrawals:
|
||||
stateDB.addBalance(withdrawal.address, withdrawal.weiAmount)
|
||||
|
||||
# EIP-6110, EIP-7002, EIP-7251
|
||||
if vmState.fork >= FkPrague:
|
||||
pst.withdrawalReqs = processDequeueWithdrawalRequests(vmState)
|
||||
pst.consolidationReqs = processDequeueConsolidationRequests(vmState)
|
||||
pst.depositReqs = ?parseDepositLogs(vmState.allLogs)
|
||||
|
||||
# Finish up, then vmState.stateDB.rootHash may be accessed
|
||||
stateDB.persist(clearEmptyAccount = vmState.fork >= FkSpurious)
|
||||
|
||||
@ -265,7 +280,7 @@ proc vmExecCommit(pst: var TxPacker) =
|
||||
pst.receiptsRoot = vmState.receipts.calcReceiptsRoot
|
||||
pst.logsBloom = vmState.receipts.createBloom
|
||||
pst.stateRoot = vmState.stateDB.rootHash
|
||||
|
||||
ok()
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# Public functions
|
||||
@ -293,7 +308,7 @@ proc packerVmExec*(xp: TxPoolRef): Result[TxPacker, string]
|
||||
if rc == ContinueWithNextAccount:
|
||||
break account # continue with next account
|
||||
|
||||
pst.vmExecCommit()
|
||||
?pst.vmExecCommit()
|
||||
ok(pst)
|
||||
# Block chain will roll back automatically
|
||||
|
||||
@ -305,7 +320,7 @@ proc assembleHeader*(pst: TxPacker): Header =
|
||||
pos = com.pos
|
||||
|
||||
result = Header(
|
||||
parentHash: vmState.parent.blockHash,
|
||||
parentHash: vmState.blockCtx.parentHash,
|
||||
ommersHash: EMPTY_UNCLE_HASH,
|
||||
coinbase: pos.feeRecipient,
|
||||
stateRoot: pst.stateRoot,
|
||||
@ -330,9 +345,25 @@ proc assembleHeader*(pst: TxPacker): Header =
|
||||
result.blobGasUsed = Opt.some vmState.blobGasUsed
|
||||
result.excessBlobGas = Opt.some vmState.blockCtx.excessBlobGas
|
||||
|
||||
if com.isPragueOrLater(pos.timestamp):
|
||||
let requestsHash = calcRequestsHashInsertType(pst.depositReqs,
|
||||
pst.withdrawalReqs, pst.consolidationReqs)
|
||||
result.requestsHash = Opt.some(requestsHash)
|
||||
|
||||
func blockValue*(pst: TxPacker): UInt256 =
|
||||
pst.blockValue
|
||||
|
||||
func executionRequests*(pst: TxPacker): array[3, seq[byte]] =
|
||||
result[0] = newSeqOfCap[byte](pst.depositReqs.len+1)
|
||||
result[0].add 0x00.byte
|
||||
result[0].add pst.depositReqs
|
||||
result[1] = newSeqOfCap[byte](pst.withdrawalReqs.len+1)
|
||||
result[1].add 0x01.byte
|
||||
result[1].add pst.withdrawalReqs
|
||||
result[2] = newSeqOfCap[byte](pst.consolidationReqs.len+1)
|
||||
result[2].add 0x02.byte
|
||||
result[2].add pst.consolidationReqs
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# End
|
||||
# ------------------------------------------------------------------------------
|
||||
|
@ -56,6 +56,8 @@ proc debug*(h: Header): string =
|
||||
result.add "excessBlobGas : " & $h.excessBlobGas.get() & "\n"
|
||||
if h.parentBeaconBlockRoot.isSome:
|
||||
result.add "beaconRoot : " & $h.parentBeaconBlockRoot.get() & "\n"
|
||||
if h.requestsHash.isSome:
|
||||
result.add "requestsHash : " & $h.requestsHash.get() & "\n"
|
||||
result.add "blockHash : " & $blockHash(h) & "\n"
|
||||
|
||||
proc dumpAccounts*(vmState: BaseVMState): JsonNode =
|
||||
|
@ -53,9 +53,22 @@ proc setupClient(port: Port): RpcHttpClient =
|
||||
waitFor client.connect("127.0.0.1", port, false)
|
||||
return client
|
||||
|
||||
proc setupEnv(): TestEnv =
|
||||
proc setupEnv(envFork: HardFork = MergeFork): TestEnv =
|
||||
doAssert(envFork >= MergeFork)
|
||||
|
||||
let
|
||||
conf = setupConfig()
|
||||
|
||||
if envFork >= Shanghai:
|
||||
conf.networkParams.config.shanghaiTime = Opt.some(0.EthTime)
|
||||
|
||||
if envFork >= Cancun:
|
||||
conf.networkParams.config.cancunTime = Opt.some(0.EthTime)
|
||||
|
||||
if envFork >= Prague:
|
||||
conf.networkParams.config.pragueTime = Opt.some(0.EthTime)
|
||||
|
||||
let
|
||||
com = setupCom(conf)
|
||||
head = com.db.getCanonicalHead()
|
||||
chain = newForkedChain(com, head)
|
||||
@ -91,7 +104,7 @@ proc close(env: TestEnv) =
|
||||
waitFor env.client.close()
|
||||
waitFor env.server.closeWait()
|
||||
|
||||
proc runTest(env: TestEnv): Result[void, string] =
|
||||
proc runBasicCycleTest(env: TestEnv): Result[void, string] =
|
||||
let
|
||||
client = env.client
|
||||
header = ? client.latestHeader()
|
||||
@ -116,14 +129,56 @@ proc runTest(env: TestEnv): Result[void, string] =
|
||||
|
||||
if bn != 1:
|
||||
return err("Expect returned block number: 1, got: " & $bn)
|
||||
|
||||
|
||||
ok()
|
||||
|
||||
proc runNewPayloadV4Test(env: TestEnv): Result[void, string] =
|
||||
let
|
||||
client = env.client
|
||||
header = ? client.latestHeader()
|
||||
update = ForkchoiceStateV1(
|
||||
headBlockHash: header.blockHash
|
||||
)
|
||||
time = getTime().toUnix
|
||||
attr = PayloadAttributes(
|
||||
timestamp: w3Qty(time + 1),
|
||||
prevRandao: default(Bytes32),
|
||||
suggestedFeeRecipient: default(Address),
|
||||
withdrawals: Opt.some(newSeq[WithdrawalV1]()),
|
||||
parentBeaconBlockRoot: Opt.some(default(Hash32))
|
||||
)
|
||||
fcuRes = ? client.forkchoiceUpdated(Version.V3, update, Opt.some(attr))
|
||||
payload = ? client.getPayload(fcuRes.payloadId.get, Version.V4)
|
||||
res = ? client.newPayload(Version.V4,
|
||||
payload.executionPayload,
|
||||
Opt.some(default(Hash32)),
|
||||
payload.executionRequests)
|
||||
|
||||
if res.status != PayloadExecutionStatus.valid:
|
||||
return err("res.status should equals to PayloadExecutionStatus.valid")
|
||||
|
||||
if res.latestValidHash.isNone or
|
||||
res.latestValidHash.get != payload.executionPayload.blockHash:
|
||||
return err("lastestValidHash mismatch")
|
||||
|
||||
if res.validationError.isSome:
|
||||
return err("validationError should empty")
|
||||
|
||||
ok()
|
||||
|
||||
proc engineApiMain*() =
|
||||
suite "Engine API":
|
||||
test "Basic cycle":
|
||||
let env = setupEnv()
|
||||
let res = env.runTest()
|
||||
let res = env.runBasicCycleTest()
|
||||
if res.isErr:
|
||||
debugEcho "FAILED TO EXECUTE TEST: ", res.error
|
||||
check res.isOk
|
||||
env.close()
|
||||
|
||||
test "newPayloadV4":
|
||||
let env = setupEnv(Prague)
|
||||
let res = env.runNewPayloadV4Test()
|
||||
if res.isErr:
|
||||
debugEcho "FAILED TO EXECUTE TEST: ", res.error
|
||||
check res.isOk
|
||||
|
Loading…
x
Reference in New Issue
Block a user