From 77289c77957018e052ce5e8b8f2aec9387cdd664 Mon Sep 17 00:00:00 2001 From: andri lim Date: Mon, 23 Oct 2023 20:59:57 +0700 Subject: [PATCH] More cancun tests (#1843) * Engine API simulator: More Cancun tests * Fix Cancun validation in Engine API and TxPool --- .../nodocker/engine/cancun/blobs.nim | 6 + .../nodocker/engine/cancun/customizer.nim | 198 +- .../nodocker/engine/cancun/helpers.nim | 2 +- .../engine/cancun/step_devp2p_pooledtx.nim | 210 +- .../engine/cancun/step_launch_client.nim | 59 +- .../engine/cancun/step_newpayloads.nim | 179 +- .../engine/cancun/step_sendmodpayload.nim | 88 +- .../nodocker/engine/cancun_tests.nim | 2475 ++++++++--------- hive_integration/nodocker/engine/clmock.nim | 43 +- .../nodocker/engine/engine_callsigs.nim | 6 + .../nodocker/engine/engine_client.nim | 35 +- .../nodocker/engine/engine_env.nim | 26 +- hive_integration/nodocker/engine/test_env.nim | 9 +- hive_integration/nodocker/engine/types.nim | 30 + .../engine/withdrawals/wd_base_spec.nim | 13 +- nimbus/beacon/api_handler/api_forkchoice.nim | 2 +- nimbus/beacon/api_handler/api_getpayload.nim | 25 +- nimbus/beacon/api_handler/api_newpayload.nim | 6 +- nimbus/beacon/web3_eth_conv.nim | 16 + nimbus/core/tx_pool/tx_tasks/tx_classify.nim | 8 +- nimbus/core/validate.nim | 20 +- nimbus/rpc/engine_api.nim | 17 +- 22 files changed, 1754 insertions(+), 1719 deletions(-) diff --git a/hive_integration/nodocker/engine/cancun/blobs.nim b/hive_integration/nodocker/engine/cancun/blobs.nim index 9052a1b62..d1551bad0 100644 --- a/hive_integration/nodocker/engine/cancun/blobs.nim +++ b/hive_integration/nodocker/engine/cancun/blobs.nim @@ -26,6 +26,12 @@ func getBlobList*(startId: BlobID, count: int): BlobIDs = for i in 0.. startIndex: diff --git a/hive_integration/nodocker/engine/cancun/customizer.nim b/hive_integration/nodocker/engine/cancun/customizer.nim index b16b4002b..fa892513b 100644 --- a/hive_integration/nodocker/engine/cancun/customizer.nim +++ b/hive_integration/nodocker/engine/cancun/customizer.nim @@ -3,6 +3,7 @@ import nimcrypto/sysrand, stew/byteutils, ./blobs, + ../types, ../tx_sender, ../../../../nimbus/constants, ../../../../nimbus/utils/utils, @@ -19,7 +20,7 @@ method setEngineAPIVersionResolver*(cust: EngineAPIVersionResolver, v: CommonRef cust.com = v method forkchoiceUpdatedVersion*(cust: EngineAPIVersionResolver, - headTimestamp: uint64, payloadAttributesTimestamp: Option[uint64]): Version {.base.} = + headTimestamp: uint64, payloadAttributesTimestamp: Option[uint64] = none(uint64)): Version {.base.} = let ts = if payloadAttributesTimestamp.isNone: headTimestamp.EthTime else: payloadAttributesTimestamp.get().EthTime if cust.com.isCancunOrLater(ts): @@ -59,8 +60,8 @@ method getExpectedError*(cust: GetPayloadCustomizer): int {.base.} = type BaseGetPayloadCustomizer* = ref object of GetPayloadCustomizer - customPayloadID: Option[PayloadID] - expectedError : int + customPayloadID*: Option[PayloadID] + expectedError* : int method getPayloadID(cust: BaseGetPayloadCustomizer, basePayloadID: PayloadID): PayloadID = @@ -72,7 +73,7 @@ method getExpectedError(cust: BaseGetPayloadCustomizer): int = cust.expectedError type - UpgradegetPayloadVersion* = ref object of GetPayloadCustomizer + UpgradegetPayloadVersion* = ref object of BaseGetPayloadCustomizer method getPayloadVersion(cust: UpgradegetPayloadVersion, timestamp: uint64): Version = let version = procCall getPayloadVersion(cust.GetPayloadCustomizer, timestamp) @@ -80,7 +81,7 @@ method getPayloadVersion(cust: UpgradegetPayloadVersion, timestamp: uint64): Ver version.succ type - DowngradegetPayloadVersion* = ref object of GetPayloadCustomizer + DowngradegetPayloadVersion* = ref object of BaseGetPayloadCustomizer method getPayloadVersion(cust: DowngradegetPayloadVersion, timestamp: uint64): Version = let version = procCall getPayloadVersion(cust.GetPayloadCustomizer, timestamp) @@ -88,20 +89,20 @@ method getPayloadVersion(cust: DowngradegetPayloadVersion, timestamp: uint64): V version.pred type - PayloadAttributesCustomizer* = ref object of GetPayloadCustomizer + PayloadAttributesCustomizer* = ref object of BaseGetPayloadCustomizer method getPayloadAttributes*(cust: PayloadAttributesCustomizer, basePayloadAttributes: PayloadAttributes): PayloadAttributes {.base.} = doAssert(false, "getPayloadAttributes unimplemented") type BasePayloadAttributesCustomizer* = ref object of PayloadAttributesCustomizer - timestamp : Option[uint64] - prevRandao : Option[common.Hash256] - suggestedFeeRecipient : Option[common.EthAddress] - withdrawals : Option[seq[Withdrawal]] - removeWithdrawals : bool - beaconRoot : Option[common.Hash256] - removeBeaconRoot : bool + timestamp* : Option[uint64] + prevRandao* : Option[common.Hash256] + suggestedFeeRecipient* : Option[common.EthAddress] + withdrawals* : Option[seq[Withdrawal]] + removeWithdrawals* : bool + beaconRoot* : Option[common.Hash256] + removeBeaconRoot* : bool method getPayloadAttributes(cust: BasePayloadAttributesCustomizer, basePayloadAttributes: PayloadAttributes): PayloadAttributes = var customPayloadAttributes = PayloadAttributes( @@ -133,15 +134,6 @@ method getPayloadAttributes(cust: BasePayloadAttributesCustomizer, basePayloadAt return customPayloadAttributes -type - TimestampDeltaPayloadAttributesCustomizer* = ref object of BasePayloadAttributesCustomizer - timestampDelta: uint64 - -method getPayloadAttributes(cust: TimestampDeltaPayloadAttributesCustomizer, basePayloadAttributes: PayloadAttributes): PayloadAttributes = - var customPayloadAttributes = procCall getPayloadAttributes(cust.BasePayloadAttributesCustomizer, basePayloadAttributes) - customPayloadAttributes.timestamp = w3Qty(customPayloadAttributes.timestamp, cust.timestampDelta) - return customPayloadAttributes - type ForkchoiceUpdatedCustomizer* = ref object of BasePayloadAttributesCustomizer @@ -156,8 +148,7 @@ method getExpectInvalidStatus*(cust: ForkchoiceUpdatedCustomizer): bool {.base.} # Used as base to other customizers. type BaseForkchoiceUpdatedCustomizer* = ref object of ForkchoiceUpdatedCustomizer - expectedError : int - expectInvalidStatus: bool + expectInvalidStatus*: bool method getPayloadAttributes(cust: BaseForkchoiceUpdatedCustomizer, basePayloadAttributes: PayloadAttributes): PayloadAttributes = var customPayloadAttributes = procCall getPayloadAttributes(cust.BasePayloadAttributesCustomizer, basePayloadAttributes) @@ -166,9 +157,6 @@ method getPayloadAttributes(cust: BaseForkchoiceUpdatedCustomizer, basePayloadAt method getForkchoiceState(cust: BaseForkchoiceUpdatedCustomizer, baseForkchoiceUpdate: ForkchoiceStateV1): ForkchoiceStateV1 = return baseForkchoiceUpdate -method getExpectedError(cust: BaseForkchoiceUpdatedCustomizer): int = - return cust.expectedError - method getExpectInvalidStatus(cust: BaseForkchoiceUpdatedCustomizer): bool = return cust.expectInvalidStatus @@ -176,108 +164,120 @@ method getExpectInvalidStatus(cust: BaseForkchoiceUpdatedCustomizer): bool = type UpgradeforkchoiceUpdatedVersion* = ref object of BaseForkchoiceUpdatedCustomizer -method forkchoiceUpdatedVersion(cust: UpgradeforkchoiceUpdatedVersion, headTimestamp: uint64, payloadAttributesTimestamp: Option[uint64]): Version = +method forkchoiceUpdatedVersion(cust: UpgradeforkchoiceUpdatedVersion, headTimestamp: + uint64, payloadAttributesTimestamp: Option[uint64] = none(uint64)): Version = let version = procCall forkchoiceUpdatedVersion(EngineAPIVersionResolver(cust), headTimestamp, payloadAttributesTimestamp) doAssert(version != Version.high, "cannot upgrade version " & $Version.high) version.succ - + # Customizer that downgrades the version of the forkchoice directive call to the previous version. type DowngradeforkchoiceUpdatedVersion* = ref object of BaseForkchoiceUpdatedCustomizer -method forkchoiceUpdatedVersion(cust: DowngradeforkchoiceUpdatedVersion, headTimestamp: uint64, payloadAttributesTimestamp: Option[uint64]): Version = +method forkchoiceUpdatedVersion(cust: DowngradeforkchoiceUpdatedVersion, headTimestamp: uint64, + payloadAttributesTimestamp: Option[uint64] = none(uint64)): Version = let version = procCall forkchoiceUpdatedVersion(EngineAPIVersionResolver(cust), headTimestamp, payloadAttributesTimestamp) doAssert(version != Version.V1, "cannot downgrade version 1") version.pred type - VersionedHashRef* = ref object of RootRef - blobs*: seq[BlobID] - hashVersions*: seq[byte] - -proc getVersionedHashes*(v: VersionedHashRef): seq[common.Hash256] = - if v.blobs.len == 0: - return @[] - - result = newSeq[common.Hash256](v.blobs.len) - - var version: byte - for i, blobID in v.blobs: - if v.hashVersions.len > i: - version = v.hashVersions[i] - result[i] = blobID.getVersionedHash(version) - -proc description*(v: VersionedHashRef): string = - result = "VersionedHashes: " - for x in v.blobs: - result.add x.toHex - - if v.hashVersions.len > 0: - result.add " with versions " - result.add v.hashVersions.toHex + TimestampDeltaPayloadAttributesCustomizer* = ref object of BaseForkchoiceUpdatedCustomizer + timestampDelta*: int +method getPayloadAttributes(cust: TimestampDeltaPayloadAttributesCustomizer, basePayloadAttributes: PayloadAttributes): PayloadAttributes = + var customPayloadAttributes = procCall getPayloadAttributes(cust.BasePayloadAttributesCustomizer, basePayloadAttributes) + customPayloadAttributes.timestamp = w3Qty(customPayloadAttributes.timestamp, cust.timestampDelta) + return customPayloadAttributes + type VersionedHashesCustomizer* = ref object of RootRef + blobs*: Option[seq[BlobID]] + hashVersions*: seq[byte] + +method getVersionedHashes*(cust: VersionedHashesCustomizer, + baseVersionedHashes: openArray[common.Hash256]): Option[seq[common.Hash256]] {.base.} = + if cust.blobs.isNone: + return none(seq[common.Hash256]) + + let blobs = cust.blobs.get + var v = newSeq[common.Hash256](blobs.len) + + var version: byte + for i, blobID in blobs: + if cust.hashVersions.len > i: + version = cust.hashVersions[i] + v[i] = blobID.getVersionedHash(version) + some(v) + +method description*(cust: VersionedHashesCustomizer): string {.base.} = + result = "VersionedHashes: " + if cust.blobs.isSome: + for x in cust.blobs.get: + result.add x.toHex + + if cust.hashVersions.len > 0: + result.add " with versions " + result.add cust.hashVersions.toHex + +type IncreaseVersionVersionedHashes* = ref object of VersionedHashesCustomizer -method getVersionedHashes*(cust: VersionedHashesCustomizer, baseVersionedHashes: openArray[common.Hash256]): seq[common.Hash256] {.base.} = - doAssert(false, "getVersionedHashes unimplemented") - -method getVersionedHashes(cust: IncreaseVersionVersionedHashes, baseVersionedHashes: openArray[common.Hash256]): seq[common.Hash256] = +method getVersionedHashes(cust: IncreaseVersionVersionedHashes, + baseVersionedHashes: openArray[common.Hash256]): Option[seq[common.Hash256]] = doAssert(baseVersionedHashes.len > 0, "no versioned hashes available for modification") - result = newSeq[common.Hash256](baseVersionedHashes.len) + var v = newSeq[common.Hash256](baseVersionedHashes.len) for i, h in baseVersionedHashes: - result[i] = h - result[i].data[0] = result[i].data[0] + 1 + v[i] = h + v[i].data[0] = v[i].data[0] + 1 + some(v) type CorruptVersionedHashes* = ref object of VersionedHashesCustomizer -method getVersionedHashes(cust: CorruptVersionedHashes, baseVersionedHashes: openArray[common.Hash256]): seq[common.Hash256] = +method getVersionedHashes(cust: CorruptVersionedHashes, + baseVersionedHashes: openArray[common.Hash256]): Option[seq[common.Hash256]] = doAssert(baseVersionedHashes.len > 0, "no versioned hashes available for modification") - result = newSeq[common.Hash256](baseVersionedHashes.len) + var v = newSeq[common.Hash256](baseVersionedHashes.len) for i, h in baseVersionedHashes: - result[i] = h - result[i].data[h.data.len-1] = result[i].data[h.data.len-1] + 1 + v[i] = h + v[i].data[h.data.len-1] = v[i].data[h.data.len-1] + 1 + some(v) type RemoveVersionedHash* = ref object of VersionedHashesCustomizer -method getVersionedHashes(cust: RemoveVersionedHash, baseVersionedHashes: openArray[common.Hash256]): seq[common.Hash256] = +method getVersionedHashes(cust: RemoveVersionedHash, + baseVersionedHashes: openArray[common.Hash256]): Option[seq[common.Hash256]] = doAssert(baseVersionedHashes.len > 0, "no versioned hashes available for modification") - result = newSeq[common.Hash256](baseVersionedHashes.len - 1) + var v = newSeq[common.Hash256](baseVersionedHashes.len - 1) for i, h in baseVersionedHashes: if i < baseVersionedHashes.len-1: - result[i] = h - result[i].data[h.data.len-1] = result[i].data[h.data.len-1] + 1 + v[i] = h + v[i].data[h.data.len-1] = v[i].data[h.data.len-1] + 1 + some(v) type ExtraVersionedHash* = ref object of VersionedHashesCustomizer -method getVersionedHashes(cust: ExtraVersionedHash, baseVersionedHashes: openArray[common.Hash256]): seq[common.Hash256] = - result = newSeq[common.Hash256](baseVersionedHashes.len + 1) +method getVersionedHashes(cust: ExtraVersionedHash, + baseVersionedHashes: openArray[common.Hash256]): Option[seq[common.Hash256]] = + var v = newSeq[common.Hash256](baseVersionedHashes.len + 1) for i, h in baseVersionedHashes: - result[i] = h + v[i] = h var extraHash: common.Hash256 doAssert randomBytes(extraHash.data) == 32 extraHash.data[0] = VERSIONED_HASH_VERSION_KZG - result[^1] = extraHash - + v[^1] = extraHash + some(v) type PayloadCustomizer* = ref object of EngineAPIVersionResolver - ExecutableData* = object - basePayload*: ExecutionPayload - beaconRoot* : Option[common.Hash256] - attr* : PayloadAttributes - versionedHashes*: seq[common.Hash256] - -method customizePayload(cust: PayloadCustomizer, data: ExecutableData): ExecutableData {.base.} = +method customizePayload*(cust: PayloadCustomizer, data: ExecutableData): ExecutableData {.base.} = doAssert(false, "customizePayload unimplemented") method getTimestamp(cust: PayloadCustomizer, basePayload: ExecutionPayload): uint64 {.base.} = @@ -285,15 +285,17 @@ method getTimestamp(cust: PayloadCustomizer, basePayload: ExecutionPayload): uin type NewPayloadCustomizer* = ref object of PayloadCustomizer + expectedError* : int + expectInvalidStatus*: bool -method getExpectedError(cust: NewPayloadCustomizer): int {.base.} = - doAssert(false, "getExpectedError unimplemented") +method getExpectedError*(cust: NewPayloadCustomizer): int {.base.} = + cust.expectedError -method getExpectInvalidStatus(cust: NewPayloadCustomizer): bool {.base.} = - doAssert(false, "getExpectInvalidStatus unimplemented") +method getExpectInvalidStatus*(cust: NewPayloadCustomizer): bool {.base.}= + cust.expectInvalidStatus type - CustomPayloadData = object + CustomPayloadData* = object parentHash* : Option[common.Hash256] feeRecipient* : Option[common.EthAddress] stateRoot* : Option[common.Hash256] @@ -408,29 +410,21 @@ proc customizePayload*(cust: CustomPayloadData, data: ExecutableData): Executabl ) if cust.versionedHashesCustomizer.isNil.not: - result.versionedHashes = cust.versionedHashesCustomizer.getVersionedHashes(data.versionedHashes) - + doAssert(data.versionedHashes.isSome) + result.versionedHashes = cust.versionedHashesCustomizer.getVersionedHashes(data.versionedHashes.get) # Base new payload directive call cust. # Used as base to other customizers. type BaseNewPayloadVersionCustomizer* = ref object of NewPayloadCustomizer payloadCustomizer* : CustomPayloadData - expectedError* : int - expectInvalidStatus*: bool method customizePayload(cust: BaseNewPayloadVersionCustomizer, data: ExecutableData): ExecutableData = cust.payloadCustomizer.customizePayload(data) -method getExpectedError(cust: BaseNewPayloadVersionCustomizer): int = - cust.expectedError - -method getExpectInvalidStatus(cust: BaseNewPayloadVersionCustomizer): bool = - cust.expectInvalidStatus - # Customizer that upgrades the version of the payload to the next version. type - UpgradeNewPayloadVersion* = ref object of NewPayloadCustomizer + UpgradeNewPayloadVersion* = ref object of BaseNewPayloadVersionCustomizer method newPayloadVersion(cust: UpgradeNewPayloadVersion, timestamp: uint64): Version = let version = procCall newPayloadVersion(EngineAPIVersionResolver(cust), timestamp) @@ -439,7 +433,7 @@ method newPayloadVersion(cust: UpgradeNewPayloadVersion, timestamp: uint64): Ver # Customizer that downgrades the version of the payload to the previous version. type - DowngradeNewPayloadVersion* = ref object of NewPayloadCustomizer + DowngradeNewPayloadVersion* = ref object of BaseNewPayloadVersionCustomizer method newPayloadVersion(cust: DowngradeNewPayloadVersion, timestamp: uint64): Version = let version = procCall newPayloadVersion(EngineAPIVersionResolver(cust), timestamp) @@ -609,22 +603,22 @@ proc generateInvalidPayload*(sender: TxSender, data: ExecutableData, payloadFiel excessBlobGas: some(modExcessBlobGas), ) of InvalidVersionedHashesVersion: - doAssert(data.versionedHashes.len > 0, "no versioned hashes available for modification") + doAssert(data.versionedHashes.isNone, "no versioned hashes available for modification") customPayloadMod = CustomPayloadData( versionedHashesCustomizer: IncreaseVersionVersionedHashes(), ) of InvalidVersionedHashes: - doAssert(data.versionedHashes.len > 0, "no versioned hashes available for modification") + doAssert(data.versionedHashes.isNone, "no versioned hashes available for modification") customPayloadMod = CustomPayloadData( versionedHashesCustomizer: CorruptVersionedHashes(), ) of IncompleteVersionedHashes: - doAssert(data.versionedHashes.len > 0, "no versioned hashes available for modification") + doAssert(data.versionedHashes.isNone, "no versioned hashes available for modification") customPayloadMod = CustomPayloadData( versionedHashesCustomizer: RemoveVersionedHash(), ) of ExtraVersionedHashes: - doAssert(data.versionedHashes.len > 0, "no versioned hashes available for modification") + doAssert(data.versionedHashes.isNone, "no versioned hashes available for modification") customPayloadMod = CustomPayloadData( versionedHashesCustomizer: ExtraVersionedHash(), ) diff --git a/hive_integration/nodocker/engine/cancun/helpers.nim b/hive_integration/nodocker/engine/cancun/helpers.nim index 1105aa731..282e81305 100644 --- a/hive_integration/nodocker/engine/cancun/helpers.nim +++ b/hive_integration/nodocker/engine/cancun/helpers.nim @@ -213,4 +213,4 @@ proc verifyBeaconRootStorage*(client: RpcClient, payload: ExecutionPayload): boo get=beaconRoot(r.get).toHex return false - return true \ No newline at end of file + return true diff --git a/hive_integration/nodocker/engine/cancun/step_devp2p_pooledtx.nim b/hive_integration/nodocker/engine/cancun/step_devp2p_pooledtx.nim index c0bdbab78..7237ca969 100644 --- a/hive_integration/nodocker/engine/cancun/step_devp2p_pooledtx.nim +++ b/hive_integration/nodocker/engine/cancun/step_devp2p_pooledtx.nim @@ -1,134 +1,114 @@ import - ./step + std/strutils, + eth/common, + chronicles, + ./step_desc, + ./helpers, + ../types, + ../test_env, + ../../../../nimbus/utils/utils, + ../../../../nimbus/sync/protocol # A step that requests a Transaction hash via P2P and expects the correct full blob tx -type DevP2PRequestPooledTransactionHash struct { - # Client index to request the transaction hash from - ClientIndex uint64 - # Transaction Index to request - TransactionIndexes []uint64 - # Wait for a new pooled transaction message before actually requesting the transaction - WaitForNewPooledTransaction bool -} +type + DevP2PRequestPooledTransactionHash* = ref object of TestStep + # Client index to request the transaction hash from + clientIndex*: int + # Transaction Index to request + transactionIndexes*: seq[int] + # Wait for a new pooled transaction message before actually requesting the transaction + waitForNewPooledTransaction*: bool -func (step DevP2PRequestPooledTransactionHash) Execute(t *CancunTestContext) error { +method execute*(step: DevP2PRequestPooledTransactionHash, ctx: CancunTestContext): bool = # Get client index's enode - if step.ClientIndex >= uint64(len(t.TestEngines)) { - return error "invalid client index %d", step.ClientIndex) - } - engine = t.Engines[step.ClientIndex] - conn, err = devp2p.PeerEngineClient(engine, env.clMock) - if err != nil { - return error "error peering engine client: %v", err) - } - defer conn.Close() - info "Connected to client %d, remote public key: %s", step.ClientIndex, conn.RemoteKey()) + let env = ctx.env + doAssert(step.clientIndex < env.numEngines, "invalid client index" & $step.clientIndex) + let engine = env.engines(step.clientIndex) + let sec = env.addEngine(false, false) - var ( - txHashes = make([]Hash256, len(step.TransactionIndexes)) - txs = make([]typ.Transaction, len(step.TransactionIndexes)) - ok bool - ) - for i, txIndex = range step.TransactionIndexes { - txHashes[i], ok = t.TestBlobTxPool.HashesByIndex[txIndex] - if !ok { - return error "transaction index %d not found", step.TransactionIndexes[0]) - } - txs[i], ok = t.TestBlobTxPool.transactions[txHashes[i]] - if !ok { - return error "transaction %s not found", txHashes[i].String()) - } - } + engine.connect(sec.node) - # Timeout value for all requests - timeout = 20 * time.Second + var + txHashes = newSeq[common.Hash256](step.transactionIndexes.len) + txs = newSeq[Transaction](step.transactionIndexes.len) + + for i, txIndex in step.transactionIndexes: + if not ctx.txPool.hashesByIndex.hasKey(txIndex): + error "transaction not found", index=step.transactionIndexes[i] + return false + + txHashes[i] = ctx.txPool.hashesByIndex[txIndex] + + if not ctx.txPool.transactions.hasKey(txHashes[i]): + error "transaction not found", hash=txHashes[i].short + return false + + txs[i] = ctx.txPool.transactions[txHashes[i]] # Wait for a new pooled transaction message - if step.WaitForNewPooledTransaction { - msg, err = conn.WaitForResponse(timeout, 0) - if err != nil { - return errors.Wrap(err, "error waiting for response") - } - switch msg = msg.(type) { - case *devp2p.NewPooledTransactionHashes: - if len(msg.Hashes) != len(txHashes) { - return error "expected %d hashes, got %d", len(txHashes), len(msg.Hashes)) - } - if len(msg.Types) != len(txHashes) { - return error "expected %d types, got %d", len(txHashes), len(msg.Types)) - } - if len(msg.Sizes) != len(txHashes) { - return error "expected %d sizes, got %d", len(txHashes), len(msg.Sizes)) - } - for i = 0; i < len(txHashes); i++ { - hash, typ, size = msg.Hashes[i], msg.Types[i], msg.Sizes[i] - # Get the transaction - tx, ok = t.TestBlobTxPool.transactions[hash] - if !ok { - return error "transaction %s not found", hash.String()) - } + if step.waitForNewPooledTransaction: + let period = chronos.seconds(1) + var loop = 0 - if typ != tx.Type() { - return error "expected type %d, got %d", tx.Type(), typ) - } + while loop < 20: + if sec.numTxsInPool >= txs.len: + break + waitFor sleepAsync(period) + inc loop - b, err = tx.MarshalBinary() - if err != nil { - return errors.Wrap(err, "error marshaling transaction") - } - if size != uint32(len(b)) { - return error "expected size %d, got %d", len(b), size) - } - } - default: - return error "unexpected message type: %T", msg) - } - } + # those txs above should have been relayed to second client + # when it first connected + let secTxs = sec.getTxsInPool(txHashes) + if secTxs.len != txHashes.len: + error "expected txs from newPooledTxs num mismatch", + expect=txHashes.len, + get=secTxs.len + return false + + for i, secTx in secTxs: + let secTxBytes = rlp.encode(secTx) + let localTxBytes = rlp.encode(txs[i]) + + if secTxBytes.len != localTxBytes.len: + error "expected tx from newPooledTxs size mismatch", + expect=localTxBytes.len, + get=secTxBytes.len + return false + + if secTxBytes != localTxBytes: + error "expected tx from gnewPooledTxs bytes not equal" + return false # Send the request for the pooled transactions - getTxReq = &devp2p.GetPooledTransactions{ - RequestId: 1234, - GetPooledTransactionsPacket: txHashes, - } - if size, err = conn.Write(getTxReq); err != nil { - return errors.Wrap(err, "could not write to conn") - else: - info "Wrote %d bytes to conn", size) - } + let peer = sec.peer + let res = waitFor peer.getPooledTransactions(txHashes) + if res.isNone: + error "getPooledTransactions returns none" + return false - # Wait for the response - msg, err = conn.WaitForResponse(timeout, getTxReq.RequestId) - if err != nil { - return errors.Wrap(err, "error waiting for response") - } - switch msg = msg.(type) { - case *devp2p.PooledTransactions: - if len(msg.PooledTransactionsBytesPacket) != len(txHashes) { - return error "expected %d txs, got %d", len(txHashes), len(msg.PooledTransactionsBytesPacket)) - } - for i, txBytes = range msg.PooledTransactionsBytesPacket { - tx = txs[i] + let remoteTxs = res.get + if remoteTxs.transactions.len != txHashes.len: + error "expected txs from getPooledTransactions num mismatch", + expect=txHashes.len, + get=remoteTxs.transactions.len + return false - expBytes, err = tx.MarshalBinary() - if err != nil { - return errors.Wrap(err, "error marshaling transaction") - } + for i, remoteTx in remoteTxs.transactions: + let remoteTxBytes = rlp.encode(remoteTx) + let localTxBytes = rlp.encode(txs[i]) - if len(expBytes) != len(txBytes) { - return error "expected size %d, got %d", len(expBytes), len(txBytes)) - } + if remoteTxBytes.len != localTxBytes.len: + error "expected tx from getPooledTransactions size mismatch", + expect=localTxBytes.len, + get=remoteTxBytes.len + return false - if !bytes.Equal(expBytes, txBytes) { - return error "expected tx %#x, got %#x", expBytes, txBytes) - } + if remoteTxBytes != localTxBytes: + error "expected tx from getPooledTransactions bytes not equal" + return false - } - default: - return error "unexpected message type: %T", msg) - } - return nil -} + return true -func (step DevP2PRequestPooledTransactionHash) Description() string { - return fmt.Sprintf("DevP2PRequestPooledTransactionHash: client %d, transaction indexes %v", step.ClientIndex, step.TransactionIndexes) -} \ No newline at end of file +method description*(step: DevP2PRequestPooledTransactionHash): string = + "DevP2PRequestPooledTransactionHash: client $1, transaction indexes $1" % [ + $step.clientIndex, $step.transactionIndexes] diff --git a/hive_integration/nodocker/engine/cancun/step_launch_client.nim b/hive_integration/nodocker/engine/cancun/step_launch_client.nim index 46be4b385..bfe4778b7 100644 --- a/hive_integration/nodocker/engine/cancun/step_launch_client.nim +++ b/hive_integration/nodocker/engine/cancun/step_launch_client.nim @@ -1,47 +1,30 @@ import - ./step + std/strutils, + ./step_desc, + ../test_env # A step that launches a new client -type LaunchClients struct { - client.EngineStarter - ClientCount uint64 - SkipConnectingToBootnode bool - SkipAddingToCLMock bool -} +type + LaunchClients* = ref object of TestStep + clientCount* : int + skipConnectingToBootnode*: bool + skipAddingToCLMock* : bool -func (step LaunchClients) GetClientCount() uint64 { - clientCount = step.ClientCount - if clientCount == 0 { +func getClientCount(step: LaunchClients): int = + var clientCount = step.clientCount + if clientCount == 0: clientCount = 1 - } return clientCount -} -func (step LaunchClients) Execute(t *CancunTestContext) error { +method execute*(step: LaunchClients, ctx: CancunTestContext): bool = # Launch a new client - var ( - client client.EngineClient - err error - ) - clientCount = step.GetClientCount() - for i = uint64(0); i < clientCount; i++ { - if !step.SkipConnectingToBootnode { - client, err = step.StartClient(t.T, t.TestContext, t.Genesis, t.ClientParams, t.ClientFiles, t.Engines[0]) - else: - client, err = step.StartClient(t.T, t.TestContext, t.Genesis, t.ClientParams, t.ClientFiles) - } - if err != nil { - return err - } - t.Engines = append(t.Engines, client) - t.TestEngines = append(t.TestEngines, test.NewTestEngineClient(t.Env, client)) - if !step.SkipAddingToCLMock { - env.clMock.AddEngineClient(client) - } - } - return nil -} + let clientCount = step.getClientCount() + for i in 0..= uint64(len(t.TestEngines)) { - return error "invalid client index %d", step.ClientID) - } - testEngine = t.TestEngines[step.ClientID].WithEngineAPIVersionResolver(step.NewPayloadCustomizer) - r = env.client.NewPayload(payload) - if expectedError != nil { - r.ExpectErrorCode(*expectedError) + doAssert(step.clientID < env.numEngines(), "invalid client index " & $step.clientID) + + let eng = env.engines(step.clientID) + let r = eng.client.newPayload(version, payload) + if expectedError != 0: + r.expectErrorCode(expectedError) else: - r.ExpectStatus(expectedStatus) - } - return nil -} + r.expectNPStatus(expectedStatus) + + return true method description*(step: SendModifiedLatestPayload): string = - desc = fmt.Sprintf("SendModifiedLatestPayload: client %d, expected invalid=%T, ", step.ClientID, step.NewPayloadCustomizer.getExpectInvalidStatus()) - /* + let desc = "SendModifiedLatestPayload: client $1, expected invalid=$2" % [ + $step.clientID, $step.newPayloadCustomizer.getExpectInvalidStatus()] + #[ TODO: Figure out if we need this. if step.VersionedHashes != nil { desc += step.VersionedHashes.Description() } - */ - + ]# return desc -} \ No newline at end of file diff --git a/hive_integration/nodocker/engine/cancun_tests.nim b/hive_integration/nodocker/engine/cancun_tests.nim index a71f463d4..3e6f7608b 100644 --- a/hive_integration/nodocker/engine/cancun_tests.nim +++ b/hive_integration/nodocker/engine/cancun_tests.nim @@ -1,8 +1,9 @@ import - std/tables, + std/[tables, math, strutils], chronos, chronicles, stew/byteutils, + eth/common, ./types, ./base_spec, ./test_env, @@ -10,12 +11,16 @@ import ./cancun/step_desc, ./cancun/helpers, ./cancun/blobs, + ./cancun/customizer, ../../nimbus/constants, ../../nimbus/common/chain_config import ./cancun/step_newpayloads, - ./cancun/step_sendblobtx + ./cancun/step_sendblobtx, + ./cancun/step_launch_client, + ./cancun/step_sendmodpayload, + ./cancun/step_devp2p_pooledtx # Precalculate the first data gas cost increase const @@ -33,7 +38,6 @@ proc getGenesis(param: NetworkParams) = # Execution specification reference: # https:#github.com/ethereum/execution-apis/blob/main/src/engine/cancun.md proc specExecute(ws: BaseSpec): bool = - ws.mainFork = ForkCancun let cs = CancunSpec(ws) conf = envConfig(ws.getForkConfig()) @@ -85,8 +89,9 @@ let cancunTestList* = [ """, run: specExecute, spec: CancunSpec( + mainFork: ForkCancun, forkHeight: 1, - testSequence: @[ + testSequence: @[ # We are starting at Shanghai genesis so send a couple payloads to reach the fork NewPayloads().TestStep, @@ -102,7 +107,7 @@ let cancunTestList* = [ # We also verify that the blob transactions are included in the blobs bundle. NewPayloads( expectedIncludedBlobCount: TARGET_BLOBS_PER_BLOCK, - expectedBlobs: getBlobList(0, TARGET_BLOBS_PER_BLOCK), + expectedblobs: getBlobList(0, TARGET_BLOBS_PER_BLOCK), ), # Try to increase the data gas cost of the blob transactions @@ -132,72 +137,66 @@ let cancunTestList* = [ ] ) ), -] -#[ TestDesc( - spec: CancunSpec( - - - name: "Blob Transactions On Block 1, Cancun Genesis", - about: """ + name: "Blob Transactions On Block 1, Cancun Genesis", + about: """ Tests the Cancun fork since genesis. Verifications performed: * See Blob Transactions On Block 1, Shanghai Genesis """, - mainFork: Cancun, - ), + run: specExecute, + spec: CancunSpec( + mainFork: ForkCancun, + testSequence: @[ + NewPayloads(), # Create a single empty payload to push the client through the fork. + # First, we send a couple of blob transactions on genesis, + # with enough data gas cost to make sure they are included in the first block. + SendBlobTransactions( + transactionCount: TARGET_BLOBS_PER_BLOCK, + blobTransactionMaxBlobGasCost: u256(1), + ), - testSequence: @[ - NewPayloads(), # Create a single empty payload to push the client through the fork. - # First, we send a couple of blob transactions on genesis, - # with enough data gas cost to make sure they are included in the first block. - SendBlobTransactions( - transactionCount: TARGET_BLOBS_PER_BLOCK, - blobTransactionMaxBlobGasCost: u256(1), - ), + # We create the first payload, and verify that the blob transactions + # are included in the payload. + # We also verify that the blob transactions are included in the blobs bundle. + NewPayloads( + expectedIncludedBlobCount: TARGET_BLOBS_PER_BLOCK, + expectedblobs: getBlobList(0, TARGET_BLOBS_PER_BLOCK), + ), - # We create the first payload, and verify that the blob transactions - # are included in the payload. - # We also verify that the blob transactions are included in the blobs bundle. - NewPayloads( - expectedIncludedBlobCount: TARGET_BLOBS_PER_BLOCK, - expectedBlobs: getBlobList(0, TARGET_BLOBS_PER_BLOCK), - ), + # Try to increase the data gas cost of the blob transactions + # by maxing out the number of blobs for the next payloads. + SendBlobTransactions( + transactionCount: DATA_GAS_COST_INCREMENT_EXCEED_BLOBS div (MAX_BLOBS_PER_BLOCK-TARGET_BLOBS_PER_BLOCK) + 1, + blobsPerTransaction: MAX_BLOBS_PER_BLOCK, + blobTransactionMaxBlobGasCost: u256(1), + ), - # Try to increase the data gas cost of the blob transactions - # by maxing out the number of blobs for the next payloads. - SendBlobTransactions( - transactionCount: DATA_GAS_COST_INCREMENT_EXCEED_BLOBS/(MAX_BLOBS_PER_BLOCK-TARGET_BLOBS_PER_BLOCK) + 1, - blobsPerTransaction: MAX_BLOBS_PER_BLOCK, - blobTransactionMaxBlobGasCost: u256(1), - ), + # Next payloads will have max data blobs each + NewPayloads( + payloadCount: DATA_GAS_COST_INCREMENT_EXCEED_BLOBS div (MAX_BLOBS_PER_BLOCK - TARGET_BLOBS_PER_BLOCK), + expectedIncludedBlobCount: MAX_BLOBS_PER_BLOCK, + ), - # Next payloads will have max data blobs each - NewPayloads( - payloadCount: DATA_GAS_COST_INCREMENT_EXCEED_BLOBS / (MAX_BLOBS_PER_BLOCK - TARGET_BLOBS_PER_BLOCK), - expectedIncludedBlobCount: MAX_BLOBS_PER_BLOCK, - ), + # But there will be an empty payload, since the data gas cost increased + # and the last blob transaction was not included. + NewPayloads( + expectedIncludedBlobCount: 0, + ), - # But there will be an empty payload, since the data gas cost increased - # and the last blob transaction was not included. - NewPayloads( - expectedIncludedBlobCount: 0, - ), - - # But it will be included in the next payload - NewPayloads( - expectedIncludedBlobCount: MAX_BLOBS_PER_BLOCK, - ), + # But it will be included in the next payload + NewPayloads( + expectedIncludedBlobCount: MAX_BLOBS_PER_BLOCK, + ), + ] ), ), + TestDesc( - spec: CancunSpec( - - - name: "Blob Transaction Ordering, Single Account", - about: """ + name: "Blob Transaction Ordering, Single Account", + about: """ Send N blob transactions with MAX_BLOBS_PER_BLOCK-1 blobs each, using account A. Using same account, and an increased nonce from the previously sent @@ -208,42 +207,40 @@ let cancunTestList* = [ All transactions have sufficient data gas price to be included any of the payloads. """, - mainFork: Cancun, - ), + run: specExecute, + spec: CancunSpec( + mainFork: ForkCancun, + testSequence: @[ + # First send the MAX_BLOBS_PER_BLOCK-1 blob transactions. + SendBlobTransactions( + transactionCount: 5, + blobsPerTransaction: MAX_BLOBS_PER_BLOCK - 1, + blobTransactionMaxBlobGasCost: u256(100), + ), + # Then send the single-blob transactions + SendBlobTransactions( + transactionCount: MAX_BLOBS_PER_BLOCK + 1, + blobsPerTransaction: 1, + blobTransactionMaxBlobGasCost: u256(100), + ), - testSequence: @[ - # First send the MAX_BLOBS_PER_BLOCK-1 blob transactions. - SendBlobTransactions( - transactionCount: 5, - blobsPerTransaction: MAX_BLOBS_PER_BLOCK - 1, - blobTransactionMaxBlobGasCost: u256(100), - ), - # Then send the single-blob transactions - SendBlobTransactions( - transactionCount: MAX_BLOBS_PER_BLOCK + 1, - blobsPerTransaction: 1, - blobTransactionMaxBlobGasCost: u256(100), - ), + # First four payloads have MAX_BLOBS_PER_BLOCK-1 blobs each + NewPayloads( + payloadCount: 4, + expectedIncludedBlobCount: MAX_BLOBS_PER_BLOCK - 1, + ), - # First four payloads have MAX_BLOBS_PER_BLOCK-1 blobs each - NewPayloads( - payloadCount: 4, - expectedIncludedBlobCount: MAX_BLOBS_PER_BLOCK - 1, - ), - - # The rest of the payloads have full blobs - NewPayloads( - payloadCount: 2, - expectedIncludedBlobCount: MAX_BLOBS_PER_BLOCK, - ), + # The rest of the payloads have full blobs + NewPayloads( + payloadCount: 2, + expectedIncludedBlobCount: MAX_BLOBS_PER_BLOCK, + ), + ] ), ), TestDesc( - spec: CancunSpec( - - - name: "Blob Transaction Ordering, Single Account 2", - about: """ + name: "Blob Transaction Ordering, Single Account 2", + about: """ Send N blob transactions with MAX_BLOBS_PER_BLOCK-1 blobs each, using account A. Using same account, and an increased nonce from the previously sent @@ -255,51 +252,49 @@ let cancunTestList* = [ All transactions have sufficient data gas price to be included any of the payloads. """, - mainFork: Cancun, - ), + run: specExecute, + spec: CancunSpec( + mainFork: ForkCancun, + testSequence: @[ + # First send the MAX_BLOBS_PER_BLOCK-1 blob transactions. + SendBlobTransactions( + transactionCount: 5, + blobsPerTransaction: MAX_BLOBS_PER_BLOCK - 1, + blobTransactionMaxBlobGasCost: u256(100), + ), - testSequence: @[ - # First send the MAX_BLOBS_PER_BLOCK-1 blob transactions. - SendBlobTransactions( - transactionCount: 5, - blobsPerTransaction: MAX_BLOBS_PER_BLOCK - 1, - blobTransactionMaxBlobGasCost: u256(100), - ), + # Then send the dual-blob transaction + SendBlobTransactions( + transactionCount: 1, + blobsPerTransaction: 2, + blobTransactionMaxBlobGasCost: u256(100), + ), - # Then send the dual-blob transaction - SendBlobTransactions( - transactionCount: 1, - blobsPerTransaction: 2, - blobTransactionMaxBlobGasCost: u256(100), - ), + # Then send the single-blob transactions + SendBlobTransactions( + transactionCount: MAX_BLOBS_PER_BLOCK - 2, + blobsPerTransaction: 1, + blobTransactionMaxBlobGasCost: u256(100), + ), - # Then send the single-blob transactions - SendBlobTransactions( - transactionCount: MAX_BLOBS_PER_BLOCK - 2, - blobsPerTransaction: 1, - blobTransactionMaxBlobGasCost: u256(100), - ), + # First five payloads have MAX_BLOBS_PER_BLOCK-1 blobs each + NewPayloads( + payloadCount: 5, + expectedIncludedBlobCount: MAX_BLOBS_PER_BLOCK - 1, + ), - # First five payloads have MAX_BLOBS_PER_BLOCK-1 blobs each - NewPayloads( - payloadCount: 5, - expectedIncludedBlobCount: MAX_BLOBS_PER_BLOCK - 1, - ), - - # The rest of the payloads have full blobs - NewPayloads( - payloadCount: 1, - expectedIncludedBlobCount: MAX_BLOBS_PER_BLOCK, - ), + # The rest of the payloads have full blobs + NewPayloads( + payloadCount: 1, + expectedIncludedBlobCount: MAX_BLOBS_PER_BLOCK, + ), + ] ), ), TestDesc( - spec: CancunSpec( - - - name: "Blob Transaction Ordering, Multiple Accounts", - about: """ + name: "Blob Transaction Ordering, Multiple Accounts", + about: """ Send N blob transactions with MAX_BLOBS_PER_BLOCK-1 blobs each, using account A. Send N blob transactions with 1 blob each from account B. @@ -308,40 +303,37 @@ let cancunTestList* = [ All transactions have sufficient data gas price to be included any of the payloads. """, - mainFork: Cancun, - ), - - testSequence: @[ - # First send the MAX_BLOBS_PER_BLOCK-1 blob transactions from - # account A. - SendBlobTransactions( - transactionCount: 5, - blobsPerTransaction: MAX_BLOBS_PER_BLOCK - 1, - blobTransactionMaxBlobGasCost: u256(100), - AccountIndex: 0, - ), - # Then send the single-blob transactions from account B - SendBlobTransactions( - transactionCount: 5, - blobsPerTransaction: 1, - blobTransactionMaxBlobGasCost: u256(100), - AccountIndex: 1, - ), - - # All payloads have full blobs - NewPayloads( - payloadCount: 5, - expectedIncludedBlobCount: MAX_BLOBS_PER_BLOCK, - ), + run: specExecute, + spec: CancunSpec( + mainFork: ForkCancun, + testSequence: @[ + # First send the MAX_BLOBS_PER_BLOCK-1 blob transactions from + # account A. + SendBlobTransactions( + transactionCount: 5, + blobsPerTransaction: MAX_BLOBS_PER_BLOCK - 1, + blobTransactionMaxBlobGasCost: u256(100), + accountIndex: 0, + ), + # Then send the single-blob transactions from account B + SendBlobTransactions( + transactionCount: 5, + blobsPerTransaction: 1, + blobTransactionMaxBlobGasCost: u256(100), + accountIndex: 1, + ), + # All payloads have full blobs + NewPayloads( + payloadCount: 5, + expectedIncludedBlobCount: MAX_BLOBS_PER_BLOCK, + ), + ] ), ), TestDesc( - spec: CancunSpec( - - - name: "Blob Transaction Ordering, Multiple Clients", - about: """ + name: "Blob Transaction Ordering, Multiple Clients", + about: """ Send N blob transactions with MAX_BLOBS_PER_BLOCK-1 blobs each, using account A, to client A. Send N blob transactions with 1 blob each from account B, to client @@ -351,480 +343,441 @@ let cancunTestList* = [ All transactions have sufficient data gas price to be included any of the payloads. """, - mainFork: Cancun, - ), + run: specExecute, + spec: CancunSpec( + mainFork: ForkCancun, + testSequence: @[ + # Start a secondary client to also receive blob transactions + LaunchClients( + #engineStarter: hive_rpc.HiveRPCEngineStarter{), + # Skip adding the second client to the CL Mock to guarantee + # that all payloads are produced by client A. + # This is done to not have client B prioritizing single-blob + # transactions to fill one single payload. + skipAddingToCLMock: true, + ), - testSequence: @[ - # Start a secondary client to also receive blob transactions - LaunchClients{ - EngineStarter: hive_rpc.HiveRPCEngineStarter{), - # Skip adding the second client to the CL Mock to guarantee - # that all payloads are produced by client A. - # This is done to not have client B prioritizing single-blob - # transactions to fill one single payload. - SkipAddingToCLMock: true, - ), + # Create a block without any blobs to get past genesis + NewPayloads( + payloadCount: 1, + expectedIncludedBlobCount: 0, + ), - # Create a block without any blobs to get past genesis - NewPayloads( - payloadCount: 1, - expectedIncludedBlobCount: 0, - ), + # First send the MAX_BLOBS_PER_BLOCK-1 blob transactions from + # account A, to client A. + SendBlobTransactions( + transactionCount: 5, + blobsPerTransaction: MAX_BLOBS_PER_BLOCK - 1, + blobTransactionMaxBlobGasCost: u256(120), + accountIndex: 0, + clientIndex: 0, + ), + # Then send the single-blob transactions from account B, to client + # B. + SendBlobTransactions( + transactionCount: 5, + blobsPerTransaction: 1, + blobTransactionMaxBlobGasCost: u256(100), + accountIndex: 1, + clientIndex: 1, + ), - # First send the MAX_BLOBS_PER_BLOCK-1 blob transactions from - # account A, to client A. - SendBlobTransactions( - transactionCount: 5, - blobsPerTransaction: MAX_BLOBS_PER_BLOCK - 1, - blobTransactionMaxBlobGasCost: u256(120), - AccountIndex: 0, - ClientIndex: 0, - ), - # Then send the single-blob transactions from account B, to client - # B. - SendBlobTransactions( - transactionCount: 5, - blobsPerTransaction: 1, - blobTransactionMaxBlobGasCost: u256(100), - AccountIndex: 1, - ClientIndex: 1, - ), - - # All payloads have full blobs - NewPayloads( - payloadCount: 5, - expectedIncludedBlobCount: MAX_BLOBS_PER_BLOCK, - # Wait a bit more on before requesting the built payload from the client - GetPayloadDelay: 2, - ), + # All payloads have full blobs + NewPayloads( + payloadCount: 5, + expectedIncludedBlobCount: MAX_BLOBS_PER_BLOCK, + # Wait a bit more on before requesting the built payload from the client + getPayloadDelay: 2, + ), + ] ), ), TestDesc( - spec: CancunSpec( - - - name: "Replace Blob Transactions", - about: """ + name: "Replace Blob Transactions", + about: """ Test sending multiple blob transactions with the same nonce, but higher gas tip so the transaction is replaced. """, - mainFork: Cancun, - ), + run: specExecute, + spec: CancunSpec( + mainFork: ForkCancun, + testSequence: @[ + # Send multiple blob transactions with the same nonce. + SendBlobTransactions( # Blob ID 0 + transactionCount: 1, + blobTransactionMaxBlobGasCost: u256(1), + blobTransactionGasFeeCap: GasInt(1 ^ 9), + blobTransactionGasTipCap: GasInt(1 ^ 9), + ), + SendBlobTransactions( # Blob ID 1 + transactionCount: 1, + blobTransactionMaxBlobGasCost: u256(1 ^ 2), + blobTransactionGasFeeCap: GasInt(1 ^ 10), + blobTransactionGasTipCap: GasInt(1 ^ 10), + replaceTransactions: true, + ), + SendBlobTransactions( # Blob ID 2 + transactionCount: 1, + blobTransactionMaxBlobGasCost: u256(1 ^ 3), + blobTransactionGasFeeCap: GasInt(1 ^ 11), + blobTransactionGasTipCap: GasInt(1 ^ 11), + replaceTransactions: true, + ), + SendBlobTransactions( # Blob ID 3 + transactionCount: 1, + blobTransactionMaxBlobGasCost: u256(1 ^ 4), + blobTransactionGasFeeCap: GasInt(1 ^ 12), + blobTransactionGasTipCap: GasInt(1 ^ 12), + replaceTransactions: true, + ), - testSequence: @[ - # Send multiple blob transactions with the same nonce. - SendBlobTransactions( # Blob ID 0 - transactionCount: 1, - blobTransactionMaxBlobGasCost: u256(1), - BlobTransactionGasFeeCap: u256(1e9), - BlobTransactionGasTipCap: u256(1e9), - ), - SendBlobTransactions( # Blob ID 1 - transactionCount: 1, - blobTransactionMaxBlobGasCost: u256(1e2), - BlobTransactionGasFeeCap: u256(1e10), - BlobTransactionGasTipCap: u256(1e10), - ReplaceTransactions: true, - ), - SendBlobTransactions( # Blob ID 2 - transactionCount: 1, - blobTransactionMaxBlobGasCost: u256(1e3), - BlobTransactionGasFeeCap: u256(1e11), - BlobTransactionGasTipCap: u256(1e11), - ReplaceTransactions: true, - ), - SendBlobTransactions( # Blob ID 3 - transactionCount: 1, - blobTransactionMaxBlobGasCost: u256(1e4), - BlobTransactionGasFeeCap: u256(1e12), - BlobTransactionGasTipCap: u256(1e12), - ReplaceTransactions: true, - ), - - # We create the first payload, which must contain the blob tx - # with the higher tip. - NewPayloads( - expectedIncludedBlobCount: 1, - expectedBlobs: []helper.BlobID{3), - ), + # We create the first payload, which must contain the blob tx + # with the higher tip. + NewPayloads( + expectedIncludedBlobCount: 1, + expectedblobs: @[BlobID(3)], + ), + ] ), ), - TestDesc( - spec: CancunSpec( - - - name: "Parallel Blob Transactions", - about: """ + #[TestDesc( + name: "Parallel Blob Transactions", + about: """ Test sending multiple blob transactions in parallel from different accounts. Verify that a payload is created with the maximum number of blobs. """, - mainFork: Cancun, - ), - - testSequence: @[ - # Send multiple blob transactions with the same nonce. - ParallelSteps{ - Steps: []TestStep{ - SendBlobTransactions( - transactionCount: 5, - blobsPerTransaction: MAX_BLOBS_PER_BLOCK, - blobTransactionMaxBlobGasCost: u256(100), - AccountIndex: 0, - ), - SendBlobTransactions( - transactionCount: 5, - blobsPerTransaction: MAX_BLOBS_PER_BLOCK, - blobTransactionMaxBlobGasCost: u256(100), - AccountIndex: 1, - ), - SendBlobTransactions( - transactionCount: 5, - blobsPerTransaction: MAX_BLOBS_PER_BLOCK, - blobTransactionMaxBlobGasCost: u256(100), - AccountIndex: 2, - ), - SendBlobTransactions( - transactionCount: 5, - blobsPerTransaction: MAX_BLOBS_PER_BLOCK, - blobTransactionMaxBlobGasCost: u256(100), - AccountIndex: 3, - ), - SendBlobTransactions( - transactionCount: 5, - blobsPerTransaction: MAX_BLOBS_PER_BLOCK, - blobTransactionMaxBlobGasCost: u256(100), - AccountIndex: 4, - ), - SendBlobTransactions( - transactionCount: 5, - blobsPerTransaction: MAX_BLOBS_PER_BLOCK, - blobTransactionMaxBlobGasCost: u256(100), - AccountIndex: 5, - ), - SendBlobTransactions( - transactionCount: 5, - blobsPerTransaction: MAX_BLOBS_PER_BLOCK, - blobTransactionMaxBlobGasCost: u256(100), - AccountIndex: 6, - ), - SendBlobTransactions( - transactionCount: 5, - blobsPerTransaction: MAX_BLOBS_PER_BLOCK, - blobTransactionMaxBlobGasCost: u256(100), - AccountIndex: 7, - ), - SendBlobTransactions( - transactionCount: 5, - blobsPerTransaction: MAX_BLOBS_PER_BLOCK, - blobTransactionMaxBlobGasCost: u256(100), - AccountIndex: 8, - ), - SendBlobTransactions( - transactionCount: 5, - blobsPerTransaction: MAX_BLOBS_PER_BLOCK, - blobTransactionMaxBlobGasCost: u256(100), - AccountIndex: 9, + run: specExecute, + spec: CancunSpec( + mainFork: ForkCancun, + testSequence: @[ + # Send multiple blob transactions with the same nonce. + ParallelSteps{ + Steps: []TestStep{ + SendBlobTransactions( + transactionCount: 5, + blobsPerTransaction: MAX_BLOBS_PER_BLOCK, + blobTransactionMaxBlobGasCost: u256(100), + accountIndex: 0, + ), + SendBlobTransactions( + transactionCount: 5, + blobsPerTransaction: MAX_BLOBS_PER_BLOCK, + blobTransactionMaxBlobGasCost: u256(100), + accountIndex: 1, + ), + SendBlobTransactions( + transactionCount: 5, + blobsPerTransaction: MAX_BLOBS_PER_BLOCK, + blobTransactionMaxBlobGasCost: u256(100), + accountIndex: 2, + ), + SendBlobTransactions( + transactionCount: 5, + blobsPerTransaction: MAX_BLOBS_PER_BLOCK, + blobTransactionMaxBlobGasCost: u256(100), + accountIndex: 3, + ), + SendBlobTransactions( + transactionCount: 5, + blobsPerTransaction: MAX_BLOBS_PER_BLOCK, + blobTransactionMaxBlobGasCost: u256(100), + accountIndex: 4, + ), + SendBlobTransactions( + transactionCount: 5, + blobsPerTransaction: MAX_BLOBS_PER_BLOCK, + blobTransactionMaxBlobGasCost: u256(100), + accountIndex: 5, + ), + SendBlobTransactions( + transactionCount: 5, + blobsPerTransaction: MAX_BLOBS_PER_BLOCK, + blobTransactionMaxBlobGasCost: u256(100), + accountIndex: 6, + ), + SendBlobTransactions( + transactionCount: 5, + blobsPerTransaction: MAX_BLOBS_PER_BLOCK, + blobTransactionMaxBlobGasCost: u256(100), + accountIndex: 7, + ), + SendBlobTransactions( + transactionCount: 5, + blobsPerTransaction: MAX_BLOBS_PER_BLOCK, + blobTransactionMaxBlobGasCost: u256(100), + accountIndex: 8, + ), + SendBlobTransactions( + transactionCount: 5, + blobsPerTransaction: MAX_BLOBS_PER_BLOCK, + blobTransactionMaxBlobGasCost: u256(100), + accountIndex: 9, + ), ), ), - ), - # We create the first payload, which is guaranteed to have the first MAX_BLOBS_PER_BLOCK blobs. - NewPayloads( - expectedIncludedBlobCount: MAX_BLOBS_PER_BLOCK, - expectedBlobs: getBlobList(0, MAX_BLOBS_PER_BLOCK), - ), + # We create the first payload, which is guaranteed to have the first MAX_BLOBS_PER_BLOCK blobs. + NewPayloads( + expectedIncludedBlobCount: MAX_BLOBS_PER_BLOCK, + expectedblobs: getBlobList(0, MAX_BLOBS_PER_BLOCK), + ), + ] ), - ), + ),]# # ForkchoiceUpdatedV3 before cancun TestDesc( - spec: CancunSpec( - - name: "ForkchoiceUpdatedV3 Set Head to Shanghai Payload, Nil Payload Attributes", - about: """ + name: "ForkchoiceUpdatedV3 Set Head to Shanghai Payload, Nil Payload Attributes", + about: """ Test sending ForkchoiceUpdatedV3 to set the head of the chain to a Shanghai payload: - Send NewPayloadV2 with Shanghai payload on block 1 - Use ForkchoiceUpdatedV3 to set the head to the payload, with nil payload attributes Verify that client returns no error. """, - mainFork: Cancun, + run: specExecute, + spec: CancunSpec( + mainFork: ForkCancun, forkHeight: 2, - ), - - testSequence: @[ - NewPayloads( - FcUOnHeadSet: &helper.UpgradeForkchoiceUpdatedVersion{ - ForkchoiceUpdatedCustomizer: &helper.BaseForkchoiceUpdatedCustomizer{), - ), - ExpectationDescription: """ - ForkchoiceUpdatedV3 before Cancun returns no error without payload attributes - """, - ), + testSequence: @[ + NewPayloads( + fcUOnHeadSet: UpgradeForkchoiceUpdatedVersion(), + expectationDescription: """ + ForkchoiceUpdatedV3 before Cancun returns no error without payload attributes + """, + ).TestStep, + ] ), ), TestDesc( - spec: CancunSpec( - - name: "ForkchoiceUpdatedV3 To Request Shanghai Payload, Nil Beacon Root", - about: """ + name: "ForkchoiceUpdatedV3 To Request Shanghai Payload, Nil Beacon Root", + about: """ Test sending ForkchoiceUpdatedV3 to request a Shanghai payload: - Payload Attributes uses Shanghai timestamp - Payload Attributes' Beacon Root is nil Verify that client returns INVALID_PARAMS_ERROR. """, - mainFork: Cancun, + run: specExecute, + spec: CancunSpec( + mainFork: ForkCancun, forkHeight: 2, - ), - - testSequence: @[ - NewPayloads( - FcUOnPayloadRequest: &helper.UpgradeForkchoiceUpdatedVersion{ - ForkchoiceUpdatedCustomizer: &helper.BaseForkchoiceUpdatedCustomizer{ - ExpectedError: globals.INVALID_PARAMS_ERROR, + testSequence: @[ + NewPayloads( + fcUOnPayloadRequest: UpgradeForkchoiceUpdatedVersion( + expectedError: engineApiInvalidParams, ), - ), - ExpectationDescription: fmt.Sprintf(""" - ForkchoiceUpdatedV3 before Cancun with any nil field must return INVALID_PARAMS_ERROR (code %d) - """, *globals.INVALID_PARAMS_ERROR), - ), + expectationDescription: """ + ForkchoiceUpdatedV3 before Cancun with any nil field must return INVALID_PARAMS_ERROR (code $1) + """ % [$engineApiInvalidParams], + ).TestStep, + ] ), ), TestDesc( - spec: CancunSpec( - - name: "ForkchoiceUpdatedV3 To Request Shanghai Payload, Zero Beacon Root", - about: """ + name: "ForkchoiceUpdatedV3 To Request Shanghai Payload, Zero Beacon Root", + about: """ Test sending ForkchoiceUpdatedV3 to request a Shanghai payload: - Payload Attributes uses Shanghai timestamp - Payload Attributes' Beacon Root zero Verify that client returns UNSUPPORTED_FORK_ERROR. """, - mainFork: Cancun, + run: specExecute, + spec: CancunSpec( + mainFork: ForkCancun, forkHeight: 2, - ), - - testSequence: @[ - NewPayloads( - FcUOnPayloadRequest: &helper.UpgradeForkchoiceUpdatedVersion{ - ForkchoiceUpdatedCustomizer: &helper.BaseForkchoiceUpdatedCustomizer{ - PayloadAttributesCustomizer: &helper.BasePayloadAttributesCustomizer{ - BeaconRoot: &(common.Hash{}), - ), - ExpectedError: globals.UNSUPPORTED_FORK_ERROR, + testSequence: @[ + NewPayloads( + fcUOnPayloadRequest: UpgradeForkchoiceUpdatedVersion( + beaconRoot: some(common.Hash256()), + expectedError: engineApiUnsupportedFork, ), - ), - ExpectationDescription: fmt.Sprintf(""" - ForkchoiceUpdatedV3 before Cancun with beacon root must return UNSUPPORTED_FORK_ERROR (code %d) - """, *globals.UNSUPPORTED_FORK_ERROR), - ), + expectationDescription: """ + ForkchoiceUpdatedV3 before Cancun with beacon root must return UNSUPPORTED_FORK_ERROR (code $1) + """ % [$engineApiUnsupportedFork], + ).TestStep, + ] ), ), # ForkchoiceUpdatedV2 before cancun with beacon root TestDesc( - spec: CancunSpec( - - name: "ForkchoiceUpdatedV2 To Request Shanghai Payload, Zero Beacon Root", - about: """ + name: "ForkchoiceUpdatedV2 To Request Shanghai Payload, Zero Beacon Root", + about: """ Test sending ForkchoiceUpdatedV2 to request a Cancun payload: - Payload Attributes uses Shanghai timestamp - Payload Attributes' Beacon Root zero Verify that client returns INVALID_PARAMS_ERROR. """, - mainFork: Cancun, + run: specExecute, + spec: CancunSpec( + mainFork: ForkCancun, forkHeight: 1, - ), - - testSequence: @[ - NewPayloads( - FcUOnPayloadRequest: &helper.DowngradeForkchoiceUpdatedVersion{ - ForkchoiceUpdatedCustomizer: &helper.BaseForkchoiceUpdatedCustomizer{ - PayloadAttributesCustomizer: &helper.BasePayloadAttributesCustomizer{ - BeaconRoot: &(common.Hash{}), - ), - ExpectedError: globals.INVALID_PARAMS_ERROR, + testSequence: @[ + NewPayloads( + fcUOnPayloadRequest: DowngradeForkchoiceUpdatedVersion( + beaconRoot: some(common.Hash256()), + expectedError: engineApiInvalidParams, ), - ), - ExpectationDescription: fmt.Sprintf(""" - ForkchoiceUpdatedV2 before Cancun with beacon root field must return INVALID_PARAMS_ERROR (code %d) - """, *globals.INVALID_PARAMS_ERROR), - ), + expectationDescription: """ + ForkchoiceUpdatedV2 before Cancun with beacon root field must return INVALID_PARAMS_ERROR (code $1) + """ % [$engineApiInvalidParams], + ).TestStep, + ] ), ), # ForkchoiceUpdatedV2 after cancun TestDesc( - spec: CancunSpec( - - name: "ForkchoiceUpdatedV2 To Request Cancun Payload, Zero Beacon Root", - about: """ + name: "ForkchoiceUpdatedV2 To Request Cancun Payload, Zero Beacon Root", + about: """ Test sending ForkchoiceUpdatedV2 to request a Cancun payload: - Payload Attributes uses Cancun timestamp - Payload Attributes' Beacon Root zero Verify that client returns INVALID_PARAMS_ERROR. """, - mainFork: Cancun, + run: specExecute, + spec: CancunSpec( + mainFork: ForkCancun, forkHeight: 1, - ), - - testSequence: @[ - NewPayloads( - FcUOnPayloadRequest: &helper.DowngradeForkchoiceUpdatedVersion{ - ForkchoiceUpdatedCustomizer: &helper.BaseForkchoiceUpdatedCustomizer{ - ExpectedError: globals.INVALID_PARAMS_ERROR, + testSequence: @[ + NewPayloads( + fcUOnPayloadRequest: DowngradeForkchoiceUpdatedVersion( + expectedError: engineApiInvalidParams, ), - ), - ExpectationDescription: fmt.Sprintf(""" - ForkchoiceUpdatedV2 after Cancun with beacon root field must return INVALID_PARAMS_ERROR (code %d) - """, *globals.INVALID_PARAMS_ERROR), - ), + expectationDescription: """ + ForkchoiceUpdatedV2 after Cancun with beacon root field must return INVALID_PARAMS_ERROR (code $1) + """% [$engineApiInvalidParams], + ).TestStep, + ] ), ), - TestDesc( - spec: CancunSpec( - name: "ForkchoiceUpdatedV2 To Request Cancun Payload, Nil Beacon Root", - about: """ + TestDesc( + name: "ForkchoiceUpdatedV2 To Request Cancun Payload, Nil Beacon Root", + about: """ Test sending ForkchoiceUpdatedV2 to request a Cancun payload: - Payload Attributes uses Cancun timestamp - Payload Attributes' Beacon Root nil (not provided) Verify that client returns UNSUPPORTED_FORK_ERROR. """, - mainFork: Cancun, + run: specExecute, + spec: CancunSpec( + mainFork: ForkCancun, forkHeight: 1, - ), - - testSequence: @[ - NewPayloads( - FcUOnPayloadRequest: &helper.DowngradeForkchoiceUpdatedVersion{ - ForkchoiceUpdatedCustomizer: &helper.BaseForkchoiceUpdatedCustomizer{ - PayloadAttributesCustomizer: &helper.BasePayloadAttributesCustomizer{ - RemoveBeaconRoot: true, - ), - ExpectedError: globals.UNSUPPORTED_FORK_ERROR, + testSequence: @[ + NewPayloads( + fcUOnPayloadRequest: DowngradeForkchoiceUpdatedVersion( + removeBeaconRoot: true, + expectedError: engineApiUnsupportedFork, ), - ), - ExpectationDescription: fmt.Sprintf(""" - ForkchoiceUpdatedV2 after Cancun must return UNSUPPORTED_FORK_ERROR (code %d) - """, *globals.UNSUPPORTED_FORK_ERROR), - ), + expectationDescription: """ + ForkchoiceUpdatedV2 after Cancun must return UNSUPPORTED_FORK_ERROR (code $1) + """ % [$engineApiUnsupportedFork], + ).TestStep, + ] ), ), # ForkchoiceUpdatedV3 with modified BeaconRoot Attribute TestDesc( - spec: CancunSpec( - - name: "ForkchoiceUpdatedV3 Modifies Payload ID on Different Beacon Root", - about: """ + name: "ForkchoiceUpdatedV3 Modifies Payload ID on Different Beacon Root", + about: """ Test requesting a Cancun Payload using ForkchoiceUpdatedV3 twice with the beacon root payload attribute as the only change between requests and verify that the payload ID is different. """, - mainFork: Cancun, - ), - - testSequence: @[ - SendBlobTransactions( - transactionCount: 1, - blobsPerTransaction: MAX_BLOBS_PER_BLOCK, - blobTransactionMaxBlobGasCost: u256(100), - ), - NewPayloads( - expectedIncludedBlobCount: MAX_BLOBS_PER_BLOCK, - FcUOnPayloadRequest: &helper.BaseForkchoiceUpdatedCustomizer{ - PayloadAttributesCustomizer: &helper.BasePayloadAttributesCustomizer{ - BeaconRoot: &(common.Hash{}), + run: specExecute, + spec: CancunSpec( + mainFork: ForkCancun, + testSequence: @[ + SendBlobTransactions( + transactionCount: 1, + blobsPerTransaction: MAX_BLOBS_PER_BLOCK, + blobTransactionMaxBlobGasCost: u256(100), + ), + NewPayloads( + expectedIncludedBlobCount: MAX_BLOBS_PER_BLOCK, + fcUOnPayloadRequest: BaseForkchoiceUpdatedCustomizer( + beaconRoot: some(common.Hash256()), ), ), - ), - SendBlobTransactions( - transactionCount: 1, - blobsPerTransaction: MAX_BLOBS_PER_BLOCK, - blobTransactionMaxBlobGasCost: u256(100), - ), - NewPayloads( - expectedIncludedBlobCount: MAX_BLOBS_PER_BLOCK, - FcUOnPayloadRequest: &helper.BaseForkchoiceUpdatedCustomizer{ - PayloadAttributesCustomizer: &helper.BasePayloadAttributesCustomizer{ - BeaconRoot: &(common.Hash{1}), + SendBlobTransactions( + transactionCount: 1, + blobsPerTransaction: MAX_BLOBS_PER_BLOCK, + blobTransactionMaxBlobGasCost: u256(100), + ), + NewPayloads( + expectedIncludedBlobCount: MAX_BLOBS_PER_BLOCK, + fcUOnPayloadRequest: BaseForkchoiceUpdatedCustomizer( + beaconRoot: some(toHash(1.u256)), ), ), - ), + ] ), ), # GetPayloadV3 Before Cancun, Negative Tests TestDesc( - spec: CancunSpec( - - name: "GetPayloadV3 To Request Shanghai Payload", - about: """ + name: "GetPayloadV3 To Request Shanghai Payload", + about: """ Test requesting a Shanghai PayloadID using GetPayloadV3. Verify that client returns UNSUPPORTED_FORK_ERROR. """, - mainFork: Cancun, + run: specExecute, + spec: CancunSpec( + mainFork: ForkCancun, forkHeight: 2, - ), - - testSequence: @[ - NewPayloads( - GetPayloadCustomizer: &helper.UpgradeGetPayloadVersion{ - GetPayloadCustomizer: &helper.BaseGetPayloadCustomizer{ - ExpectedError: globals.UNSUPPORTED_FORK_ERROR, + testSequence: @[ + NewPayloads( + getPayloadCustomizer: UpgradeGetPayloadVersion( + expectedError: engineApiUnsupportedFork, ), - ), - ExpectationDescription: fmt.Sprintf(""" - GetPayloadV3 To Request Shanghai Payload must return UNSUPPORTED_FORK_ERROR (code %d) - """, *globals.UNSUPPORTED_FORK_ERROR), - ), + expectationDescription: """ + GetPayloadV3 To Request Shanghai Payload must return UNSUPPORTED_FORK_ERROR (code $1) + """ % [$engineApiUnsupportedFork], + ).TestStep, + ] ), ), # GetPayloadV2 After Cancun, Negative Tests TestDesc( - spec: CancunSpec( - - name: "GetPayloadV2 To Request Cancun Payload", - about: """ + name: "GetPayloadV2 To Request Cancun Payload", + about: """ Test requesting a Cancun PayloadID using GetPayloadV2. Verify that client returns UNSUPPORTED_FORK_ERROR. """, - mainFork: Cancun, + run: specExecute, + spec: CancunSpec( + mainFork: ForkCancun, forkHeight: 1, - ), - - testSequence: @[ - NewPayloads( - GetPayloadCustomizer: &helper.DowngradeGetPayloadVersion{ - GetPayloadCustomizer: &helper.BaseGetPayloadCustomizer{ - ExpectedError: globals.UNSUPPORTED_FORK_ERROR, + testSequence: @[ + NewPayloads( + getPayloadCustomizer: DowngradeGetPayloadVersion( + expectedError: engineApiUnsupportedFork, ), - ), - ExpectationDescription: fmt.Sprintf(""" - GetPayloadV2 To Request Cancun Payload must return UNSUPPORTED_FORK_ERROR (code %d) - """, *globals.UNSUPPORTED_FORK_ERROR), - ), + expectationDescription: """ + GetPayloadV2 To Request Cancun Payload must return UNSUPPORTED_FORK_ERROR (code $1) + """ % [$engineApiUnsupportedFork], + ).TestStep, + ] ), ), # NewPayloadV3 Before Cancun, Negative Tests TestDesc( - spec: CancunSpec( - - name: "NewPayloadV3 Before Cancun, Nil Data Fields, Nil Versioned Hashes, Nil Beacon Root", - about: """ + name: "NewPayloadV3 Before Cancun, Nil Data Fields, Nil Versioned Hashes, Nil Beacon Root", + about: """ Test sending NewPayloadV3 Before Cancun with: - nil ExcessBlobGas - nil BlobGasUsed @@ -833,972 +786,953 @@ let cancunTestList* = [ Verify that client returns INVALID_PARAMS_ERROR """, - mainFork: Cancun, + run: specExecute, + spec: CancunSpec( + mainFork: ForkCancun, forkHeight: 2, - ), - - testSequence: @[ - NewPayloads( - NewPayloadCustomizer: &helper.UpgradeNewPayloadVersion{ - NewPayloadCustomizer: &helper.BaseNewPayloadVersionCustomizer{ + testSequence: @[ + NewPayloads( + newPayloadCustomizer: UpgradeNewPayloadVersion( payloadCustomizer: CustomPayloadData( - VersionedHashesCustomizer: &VersionedHashes{ - Blobs: nil, - ), + versionedHashesCustomizer: VersionedHashesCustomizer() ), - ExpectedError: globals.INVALID_PARAMS_ERROR, + expectedError: engineApiInvalidParams, ), - ), - ExpectationDescription: fmt.Sprintf(""" - NewPayloadV3 before Cancun with any nil field must return INVALID_PARAMS_ERROR (code %d) - """, *globals.INVALID_PARAMS_ERROR), - ), + expectationDescription: """ + NewPayloadV3 before Cancun with any nil field must return INVALID_PARAMS_ERROR (code $1) + """ % [$engineApiInvalidParams], + ).TestStep, + ] ), ), - TestDesc( - spec: CancunSpec( - name: "NewPayloadV3 Before Cancun, Nil ExcessBlobGas, 0x00 BlobGasUsed, Nil Versioned Hashes, Nil Beacon Root", - about: """ + TestDesc( + name: "NewPayloadV3 Before Cancun, Nil ExcessBlobGas, 0x00 BlobGasUsed, Nil Versioned Hashes, Nil Beacon Root", + about: """ Test sending NewPayloadV3 Before Cancun with: - nil ExcessBlobGas - 0x00 BlobGasUsed - nil Versioned Hashes Array - nil Beacon Root """, - mainFork: Cancun, + run: specExecute, + spec: CancunSpec( + mainFork: ForkCancun, forkHeight: 2, - ), - - testSequence: @[ - NewPayloads( - NewPayloadCustomizer: &helper.UpgradeNewPayloadVersion{ - NewPayloadCustomizer: &helper.BaseNewPayloadVersionCustomizer{ + testSequence: @[ + NewPayloads( + newPayloadCustomizer: UpgradeNewPayloadVersion( payloadCustomizer: CustomPayloadData( - BlobGasUsed: pUint64(0), + blobGasUsed: some(0'u64), ), - ExpectedError: globals.INVALID_PARAMS_ERROR, + expectedError: engineApiInvalidParams, ), - ), - ExpectationDescription: fmt.Sprintf(""" - NewPayloadV3 before Cancun with any nil field must return INVALID_PARAMS_ERROR (code %d) - """, *globals.INVALID_PARAMS_ERROR), - ), + expectationDescription: """ + NewPayloadV3 before Cancun with any nil field must return INVALID_PARAMS_ERROR (code $1) + """ % [$engineApiInvalidParams], + ).TestStep, + ] ), ), - TestDesc( - spec: CancunSpec( - name: "NewPayloadV3 Before Cancun, 0x00 ExcessBlobGas, Nil BlobGasUsed, Nil Versioned Hashes, Nil Beacon Root", - about: """ + #[TestDescXXX( + name: "NewPayloadV3 Before Cancun, 0x00 ExcessBlobGas, Nil BlobGasUsed, Nil Versioned Hashes, Nil Beacon Root", + about: """ Test sending NewPayloadV3 Before Cancun with: - 0x00 ExcessBlobGas - nil BlobGasUsed - nil Versioned Hashes Array - nil Beacon Root """, - mainFork: Cancun, - forkHeight: 2, - ), - - testSequence: @[ - NewPayloads( - NewPayloadCustomizer: &helper.UpgradeNewPayloadVersion{ - NewPayloadCustomizer: &helper.BaseNewPayloadVersionCustomizer{ - payloadCustomizer: CustomPayloadData( - ExcessBlobGas: pUint64(0), - ), - ExpectedError: globals.INVALID_PARAMS_ERROR, - ), - ), - ExpectationDescription: fmt.Sprintf(""" - NewPayloadV3 before Cancun with any nil field must return INVALID_PARAMS_ERROR (code %d) - """, *globals.INVALID_PARAMS_ERROR), - ), - ), - ), - TestDesc( + run: specExecute, spec: CancunSpec( + mainFork: ForkCancun, + forkHeight: 2, + testSequence: @[ + NewPayloads( + newPayloadCustomizer: UpgradeNewPayloadVersion( + payloadCustomizer: CustomPayloadData( + excessBlobGas: some(0'u64), + ), + expectedError: engineApiInvalidParams, + ), + expectationDescription: """ + NewPayloadV3 before Cancun with any nil field must return INVALID_PARAMS_ERROR (code $1) + """ % [$engineApiInvalidParams], + ).TestStep, + ] + ), + ),]# - name: "NewPayloadV3 Before Cancun, Nil Data Fields, Empty Array Versioned Hashes, Nil Beacon Root", - about: """ + TestDesc( + name: "NewPayloadV3 Before Cancun, Nil Data Fields, Empty Array Versioned Hashes, Nil Beacon Root", + about: """ Test sending NewPayloadV3 Before Cancun with: - nil ExcessBlobGas - nil BlobGasUsed - Empty Versioned Hashes Array - nil Beacon Root """, - mainFork: Cancun, + run: specExecute, + spec: CancunSpec( + mainFork: ForkCancun, forkHeight: 2, - ), - - testSequence: @[ - NewPayloads( - NewPayloadCustomizer: &helper.UpgradeNewPayloadVersion{ - NewPayloadCustomizer: &helper.BaseNewPayloadVersionCustomizer{ + testSequence: @[ + NewPayloads( + newPayloadCustomizer: UpgradeNewPayloadVersion( payloadCustomizer: CustomPayloadData( - VersionedHashesCustomizer: &VersionedHashes{ - Blobs: []helper.BlobID{), + versionedHashesCustomizer: VersionedHashesCustomizer( + blobs: some(newSeq[BlobID]()), ), ), - ExpectedError: globals.INVALID_PARAMS_ERROR, + expectedError: engineApiInvalidParams, ), - ), - ExpectationDescription: fmt.Sprintf(""" - NewPayloadV3 before Cancun with any nil field must return INVALID_PARAMS_ERROR (code %d) - """, *globals.INVALID_PARAMS_ERROR), - ), + expectationDescription: """ + NewPayloadV3 before Cancun with any nil field must return INVALID_PARAMS_ERROR (code $1) + """ % [$engineApiInvalidParams], + ).TestStep, + ] ), ), - TestDesc( - spec: CancunSpec( - name: "NewPayloadV3 Before Cancun, Nil Data Fields, Nil Versioned Hashes, Zero Beacon Root", - about: """ + #[TestDescXXX( + name: "NewPayloadV3 Before Cancun, Nil Data Fields, Nil Versioned Hashes, Zero Beacon Root", + about: """ Test sending NewPayloadV3 Before Cancun with: - nil ExcessBlobGas - nil BlobGasUsed - nil Versioned Hashes Array - Zero Beacon Root """, - mainFork: Cancun, - forkHeight: 2, - ), - - testSequence: @[ - NewPayloads( - NewPayloadCustomizer: &helper.UpgradeNewPayloadVersion{ - NewPayloadCustomizer: &helper.BaseNewPayloadVersionCustomizer{ - payloadCustomizer: CustomPayloadData( - ParentBeaconRoot: &(common.Hash{}), - ), - ExpectedError: globals.INVALID_PARAMS_ERROR, - ), - ), - ExpectationDescription: fmt.Sprintf(""" - NewPayloadV3 before Cancun with any nil field must return INVALID_PARAMS_ERROR (code %d) - """, *globals.INVALID_PARAMS_ERROR), - ), - ), - ), - TestDesc( + run: specExecute, spec: CancunSpec( + mainFork: ForkCancun, + forkHeight: 2, + testSequence: @[ + NewPayloads( + newPayloadCustomizer: UpgradeNewPayloadVersion( + payloadCustomizer: CustomPayloadData( + parentBeaconRoot: some(common.Hash256()), + ), + expectedError: engineApiInvalidParams, + ), + expectationDescription: """ + NewPayloadV3 before Cancun with any nil field must return INVALID_PARAMS_ERROR (code $1) + """ % [$engineApiInvalidParams], + ).TestStep, + ] + ), + ),]# - name: "NewPayloadV3 Before Cancun, 0x00 Data Fields, Empty Array Versioned Hashes, Zero Beacon Root", - about: """ + TestDesc( + name: "NewPayloadV3 Before Cancun, 0x00 Data Fields, Empty Array Versioned Hashes, Zero Beacon Root", + about: """ Test sending NewPayloadV3 Before Cancun with: - 0x00 ExcessBlobGas - 0x00 BlobGasUsed - Empty Versioned Hashes Array - Zero Beacon Root """, - mainFork: Cancun, + run: specExecute, + spec: CancunSpec( + mainFork: ForkCancun, forkHeight: 2, - ), - - testSequence: @[ - NewPayloads( - NewPayloadCustomizer: &helper.UpgradeNewPayloadVersion{ - NewPayloadCustomizer: &helper.BaseNewPayloadVersionCustomizer{ + testSequence: @[ + NewPayloads( + newPayloadCustomizer: UpgradeNewPayloadVersion( payloadCustomizer: CustomPayloadData( - ExcessBlobGas: pUint64(0), - BlobGasUsed: pUint64(0), - ParentBeaconRoot: &(common.Hash{}), - VersionedHashesCustomizer: &VersionedHashes{ - Blobs: []helper.BlobID{), + excessBlobGas: some(0'u64), + blobGasUsed: some(0'u64), + parentBeaconRoot: some(common.Hash256()), + versionedHashesCustomizer: VersionedHashesCustomizer( + blobs: some(newSeq[BlobID]()), ), ), - ExpectedError: globals.UNSUPPORTED_FORK_ERROR, + expectedError: engineApiUnsupportedFork, ), - ), - ExpectationDescription: fmt.Sprintf(""" - NewPayloadV3 before Cancun with no nil fields must return UNSUPPORTED_FORK_ERROR (code %d) - """, *globals.UNSUPPORTED_FORK_ERROR), - ), + expectationDescription: """ + NewPayloadV3 before Cancun with no nil fields must return UNSUPPORTED_FORK_ERROR (code $1) + """ % [$engineApiUnsupportedFork], + ).TestStep, + ] ), ), # NewPayloadV3 After Cancun, Negative Tests - TestDesc( - spec: CancunSpec( - - name: "NewPayloadV3 After Cancun, Nil ExcessBlobGas, 0x00 BlobGasUsed, Empty Array Versioned Hashes, Zero Beacon Root", - about: """ + #[TestDescXXX( + name: "NewPayloadV3 After Cancun, Nil ExcessBlobGas, 0x00 BlobGasUsed, Empty Array Versioned Hashes, Zero Beacon Root", + about: """ Test sending NewPayloadV3 After Cancun with: - nil ExcessBlobGas - 0x00 BlobGasUsed - Empty Versioned Hashes Array - Zero Beacon Root """, - mainFork: Cancun, + run: specExecute, + spec: CancunSpec( + mainFork: ForkCancun, forkHeight: 1, - ), - - testSequence: @[ - NewPayloads( - NewPayloadCustomizer: &helper.BaseNewPayloadVersionCustomizer{ - payloadCustomizer: CustomPayloadData( - RemoveExcessBlobGas: true, + testSequence: @[ + NewPayloads( + newPayloadCustomizer: BaseNewPayloadVersionCustomizer( + payloadCustomizer: CustomPayloadData( + removeExcessBlobGas: true, + ), + expectedError: engineApiInvalidParams, ), - ExpectedError: globals.INVALID_PARAMS_ERROR, - ), - ExpectationDescription: fmt.Sprintf(""" - NewPayloadV3 after Cancun with nil ExcessBlobGas must return INVALID_PARAMS_ERROR (code %d) - """, *globals.INVALID_PARAMS_ERROR), - ), + expectationDescription: """ + NewPayloadV3 after Cancun with nil ExcessBlobGas must return INVALID_PARAMS_ERROR (code $1) + """ % [$engineApiInvalidParams], + ).TestStep, + ] ), ), - TestDesc( - spec: CancunSpec( - name: "NewPayloadV3 After Cancun, 0x00 ExcessBlobGas, Nil BlobGasUsed, Empty Array Versioned Hashes", - about: """ + TestDescXXX( + name: "NewPayloadV3 After Cancun, 0x00 ExcessBlobGas, Nil BlobGasUsed, Empty Array Versioned Hashes", + about: """ Test sending NewPayloadV3 After Cancun with: - 0x00 ExcessBlobGas - nil BlobGasUsed - Empty Versioned Hashes Array """, - mainFork: Cancun, - forkHeight: 1, - ), - - testSequence: @[ - NewPayloads( - NewPayloadCustomizer: &helper.BaseNewPayloadVersionCustomizer{ - payloadCustomizer: CustomPayloadData( - RemoveBlobGasUsed: true, - ), - ExpectedError: globals.INVALID_PARAMS_ERROR, - ), - ExpectationDescription: fmt.Sprintf(""" - NewPayloadV3 after Cancun with nil BlobGasUsed must return INVALID_PARAMS_ERROR (code %d) - """, *globals.INVALID_PARAMS_ERROR), - ), - ), - ), - TestDesc( + run: specExecute, spec: CancunSpec( + mainFork: ForkCancun, + forkHeight: 1, + testSequence: @[ + NewPayloads( + newPayloadCustomizer: BaseNewPayloadVersionCustomizer( + payloadCustomizer: CustomPayloadData( + removeblobGasUsed: true, + ), + expectedError: engineApiInvalidParams, + ), + expectationDescription: """ + NewPayloadV3 after Cancun with nil BlobGasUsed must return INVALID_PARAMS_ERROR (code $1) + """ % [$engineApiInvalidParams], + ).TestStep, + ] + ), + ),]# - name: "NewPayloadV3 After Cancun, 0x00 Blob Fields, Empty Array Versioned Hashes, Nil Beacon Root", - about: """ + TestDesc( + name: "NewPayloadV3 After Cancun, 0x00 Blob Fields, Empty Array Versioned Hashes, Nil Beacon Root", + about: """ Test sending NewPayloadV3 After Cancun with: - 0x00 ExcessBlobGas - nil BlobGasUsed - Empty Versioned Hashes Array """, - mainFork: Cancun, + run: specExecute, + spec: CancunSpec( + mainFork: ForkCancun, forkHeight: 1, - ), - - testSequence: @[ - NewPayloads( - NewPayloadCustomizer: &helper.BaseNewPayloadVersionCustomizer{ - payloadCustomizer: CustomPayloadData( - RemoveParentBeaconRoot: true, + testSequence: @[ + NewPayloads( + newPayloadCustomizer: BaseNewPayloadVersionCustomizer( + payloadCustomizer: CustomPayloadData( + removeParentBeaconRoot: true, + ), + expectedError: engineApiInvalidParams, ), - ExpectedError: globals.INVALID_PARAMS_ERROR, - ), - ExpectationDescription: fmt.Sprintf(""" - NewPayloadV3 after Cancun with nil parentBeaconBlockRoot must return INVALID_PARAMS_ERROR (code %d) - """, *globals.INVALID_PARAMS_ERROR), - ), + expectationDescription: """ + NewPayloadV3 after Cancun with nil parentBeaconBlockRoot must return INVALID_PARAMS_ERROR (code $1) + """ % [$engineApiInvalidParams], + ).TestStep, + ] ), ), # Fork time tests TestDesc( - spec: CancunSpec( - - name: "ForkchoiceUpdatedV2 then ForkchoiceUpdatedV3 Valid Payload Building Requests", - about: """ + name: "ForkchoiceUpdatedV2 then ForkchoiceUpdatedV3 Valid Payload Building Requests", + about: """ Test requesting a Shanghai ForkchoiceUpdatedV2 payload followed by a Cancun ForkchoiceUpdatedV3 request. Verify that client correctly returns the Cancun payload. """, - mainFork: Cancun, + run: specExecute, + spec: CancunSpec( + mainFork: ForkCancun, # We request two blocks from the client, first on shanghai and then on cancun, both with # the same parent. # Client must respond correctly to later request. forkHeight: 1, - BlockTimestampIncrement: 2, - ), - - testSequence: @[ - # First, we send a couple of blob transactions on genesis, - # with enough data gas cost to make sure they are included in the first block. - SendBlobTransactions( - transactionCount: TARGET_BLOBS_PER_BLOCK, - blobTransactionMaxBlobGasCost: u256(1), - ), - NewPayloads( - expectedIncludedBlobCount: TARGET_BLOBS_PER_BLOCK, - # This customizer only simulates requesting a Shanghai payload 1 second before cancun. - # CL Mock will still request the Cancun payload afterwards - FcUOnPayloadRequest: &helper.BaseForkchoiceUpdatedCustomizer{ - PayloadAttributesCustomizer: &helper.TimestampDeltaPayloadAttributesCustomizer{ - PayloadAttributesCustomizer: &helper.BasePayloadAttributesCustomizer{ - RemoveBeaconRoot: true, - ), - TimestampDelta: -1, - ), + blockTimestampIncrement: 2, + testSequence: @[ + # First, we send a couple of blob transactions on genesis, + # with enough data gas cost to make sure they are included in the first block. + SendBlobTransactions( + transactionCount: TARGET_BLOBS_PER_BLOCK, + blobTransactionMaxBlobGasCost: u256(1), ), - ExpectationDescription: """ - ForkchoiceUpdatedV3 must construct transaction with blob payloads even if a ForkchoiceUpdatedV2 was previously requested - """, - ), + NewPayloads( + expectedIncludedBlobCount: TARGET_BLOBS_PER_BLOCK, + # This customizer only simulates requesting a Shanghai payload 1 second before cancun. + # CL Mock will still request the Cancun payload afterwards + fcUOnPayloadRequest: TimestampDeltaPayloadAttributesCustomizer( + removeBeaconRoot: true, + timestampDelta: -1, + ), + expectationDescription: """ + ForkchoiceUpdatedV3 must construct transaction with blob payloads even if a ForkchoiceUpdatedV2 was previously requested + """, + ), + ] ), ), # Test versioned hashes in Engine API NewPayloadV3 TestDesc( - spec: CancunSpec( - - - name: "NewPayloadV3 Versioned Hashes, Missing Hash", - about: """ + name: "NewPayloadV3 Versioned Hashes, Missing Hash", + about: """ Tests VersionedHashes in Engine API NewPayloadV3 where the array is missing one of the hashes. """, - mainFork: Cancun, - ), - testSequence: @[ - SendBlobTransactions( - transactionCount: TARGET_BLOBS_PER_BLOCK, - blobTransactionMaxBlobGasCost: u256(1), - ), - NewPayloads( - expectedIncludedBlobCount: TARGET_BLOBS_PER_BLOCK, - expectedBlobs: getBlobList(0, TARGET_BLOBS_PER_BLOCK), - NewPayloadCustomizer: &helper.BaseNewPayloadVersionCustomizer{ - payloadCustomizer: CustomPayloadData( - VersionedHashesCustomizer: &VersionedHashes{ - Blobs: getBlobList(0, TARGET_BLOBS_PER_BLOCK-1), - ), - ), - ExpectInvalidStatus: true, + run: specExecute, + spec: CancunSpec( + mainFork: ForkCancun, + testSequence: @[ + SendBlobTransactions( + transactionCount: TARGET_BLOBS_PER_BLOCK, + blobTransactionMaxBlobGasCost: u256(1), ), - ExpectationDescription: """ - NewPayloadV3 with incorrect list of versioned hashes must return INVALID status - """, - ), + NewPayloads( + expectedIncludedBlobCount: TARGET_BLOBS_PER_BLOCK, + expectedblobs: getBlobList(0, TARGET_BLOBS_PER_BLOCK), + newPayloadCustomizer: BaseNewPayloadVersionCustomizer( + payloadCustomizer: CustomPayloadData( + versionedHashesCustomizer: VersionedHashesCustomizer( + blobs: some(getBlobList(0, TARGET_BLOBS_PER_BLOCK-1)), + ), + ), + expectInvalidStatus: true, + ), + expectationDescription: """ + NewPayloadV3 with incorrect list of versioned hashes must return INVALID status + """, + ), + ] ), ), + TestDesc( - spec: CancunSpec( - - - name: "NewPayloadV3 Versioned Hashes, Extra Hash", - about: """ + name: "NewPayloadV3 Versioned Hashes, Extra Hash", + about: """ Tests VersionedHashes in Engine API NewPayloadV3 where the array is has an extra hash for a blob that is not in the payload. """, - mainFork: Cancun, - ), - # TODO: It could be worth it to also test this with a blob that is in the - # mempool but was not included in the payload. - testSequence: @[ - SendBlobTransactions( - transactionCount: TARGET_BLOBS_PER_BLOCK, - blobTransactionMaxBlobGasCost: u256(1), - ), - NewPayloads( - expectedIncludedBlobCount: TARGET_BLOBS_PER_BLOCK, - expectedBlobs: getBlobList(0, TARGET_BLOBS_PER_BLOCK), - NewPayloadCustomizer: &helper.BaseNewPayloadVersionCustomizer{ - payloadCustomizer: CustomPayloadData( - VersionedHashesCustomizer: &VersionedHashes{ - Blobs: getBlobList(0, TARGET_BLOBS_PER_BLOCK+1), - ), - ), - ExpectInvalidStatus: true, + run: specExecute, + spec: CancunSpec( + mainFork: ForkCancun, + # TODO: It could be worth it to also test this with a blob that is in the + # mempool but was not included in the payload. + testSequence: @[ + SendBlobTransactions( + transactionCount: TARGET_BLOBS_PER_BLOCK, + blobTransactionMaxBlobGasCost: u256(1), ), - ExpectationDescription: """ - NewPayloadV3 with incorrect list of versioned hashes must return INVALID status - """, - ), + NewPayloads( + expectedIncludedBlobCount: TARGET_BLOBS_PER_BLOCK, + expectedblobs: getBlobList(0, TARGET_BLOBS_PER_BLOCK), + newPayloadCustomizer: BaseNewPayloadVersionCustomizer( + payloadCustomizer: CustomPayloadData( + versionedHashesCustomizer: VersionedHashesCustomizer( + blobs: some(getBlobList(0, TARGET_BLOBS_PER_BLOCK+1)), + ), + ), + expectInvalidStatus: true, + ), + expectationDescription: """ + NewPayloadV3 with incorrect list of versioned hashes must return INVALID status + """, + ), + ] ), ), TestDesc( - spec: CancunSpec( - - name: "NewPayloadV3 Versioned Hashes, Out of Order", - about: """ + name: "NewPayloadV3 Versioned Hashes, Out of Order", + about: """ Tests VersionedHashes in Engine API NewPayloadV3 where the array is out of order. """, - mainFork: Cancun, - ), - testSequence: @[ - SendBlobTransactions( - transactionCount: TARGET_BLOBS_PER_BLOCK, - blobTransactionMaxBlobGasCost: u256(1), - ), - NewPayloads( - expectedIncludedBlobCount: TARGET_BLOBS_PER_BLOCK, - expectedBlobs: getBlobList(0, TARGET_BLOBS_PER_BLOCK), - NewPayloadCustomizer: &helper.BaseNewPayloadVersionCustomizer{ - payloadCustomizer: CustomPayloadData( - VersionedHashesCustomizer: &VersionedHashes{ - Blobs: getBlobListByIndex(helper.BlobID(TARGET_BLOBS_PER_BLOCK-1), 0), - ), - ), - ExpectInvalidStatus: true, + run: specExecute, + spec: CancunSpec( + mainFork: ForkCancun, + testSequence: @[ + SendBlobTransactions( + transactionCount: TARGET_BLOBS_PER_BLOCK, + blobTransactionMaxBlobGasCost: u256(1), ), - ExpectationDescription: """ - NewPayloadV3 with incorrect list of versioned hashes must return INVALID status - """, - ), + NewPayloads( + expectedIncludedBlobCount: TARGET_BLOBS_PER_BLOCK, + expectedblobs: getBlobList(0, TARGET_BLOBS_PER_BLOCK), + newPayloadCustomizer: BaseNewPayloadVersionCustomizer( + payloadCustomizer: CustomPayloadData( + versionedHashesCustomizer: VersionedHashesCustomizer( + blobs: some(getBlobListByIndex(BlobID(TARGET_BLOBS_PER_BLOCK-1), 0)), + ), + ), + expectInvalidStatus: true, + ), + expectationDescription: """ + NewPayloadV3 with incorrect list of versioned hashes must return INVALID status + """, + ), + ] ), ), TestDesc( - spec: CancunSpec( - - name: "NewPayloadV3 Versioned Hashes, Repeated Hash", - about: """ + name: "NewPayloadV3 Versioned Hashes, Repeated Hash", + about: """ Tests VersionedHashes in Engine API NewPayloadV3 where the array has a blob that is repeated in the array. """, - mainFork: Cancun, - ), - testSequence: @[ - SendBlobTransactions( - transactionCount: TARGET_BLOBS_PER_BLOCK, - blobTransactionMaxBlobGasCost: u256(1), - ), - NewPayloads( - expectedIncludedBlobCount: TARGET_BLOBS_PER_BLOCK, - expectedBlobs: getBlobList(0, TARGET_BLOBS_PER_BLOCK), - NewPayloadCustomizer: &helper.BaseNewPayloadVersionCustomizer{ - payloadCustomizer: CustomPayloadData( - VersionedHashesCustomizer: &VersionedHashes{ - Blobs: append(getBlobList(0, TARGET_BLOBS_PER_BLOCK), helper.BlobID(TARGET_BLOBS_PER_BLOCK-1)), - ), - ), - ExpectInvalidStatus: true, + run: specExecute, + spec: CancunSpec( + mainFork: ForkCancun, + testSequence: @[ + SendBlobTransactions( + transactionCount: TARGET_BLOBS_PER_BLOCK, + blobTransactionMaxBlobGasCost: u256(1), ), - ExpectationDescription: """ - NewPayloadV3 with incorrect list of versioned hashes must return INVALID status - """, - ), + NewPayloads( + expectedIncludedBlobCount: TARGET_BLOBS_PER_BLOCK, + expectedblobs: getBlobList(0, TARGET_BLOBS_PER_BLOCK), + newPayloadCustomizer: BaseNewPayloadVersionCustomizer( + payloadCustomizer: CustomPayloadData( + versionedHashesCustomizer: VersionedHashesCustomizer( + blobs: some(getBlobList(0, TARGET_BLOBS_PER_BLOCK, BlobID(TARGET_BLOBS_PER_BLOCK-1))), + ), + ), + expectInvalidStatus: true, + ), + expectationDescription: """ + NewPayloadV3 with incorrect list of versioned hashes must return INVALID status + """, + ), + ] ), ), TestDesc( - spec: CancunSpec( - - name: "NewPayloadV3 Versioned Hashes, Incorrect Hash", - about: """ + name: "NewPayloadV3 Versioned Hashes, Incorrect Hash", + about: """ Tests VersionedHashes in Engine API NewPayloadV3 where the array has a blob hash that does not belong to any blob contained in the payload. """, - mainFork: Cancun, - ), - testSequence: @[ - SendBlobTransactions( - transactionCount: TARGET_BLOBS_PER_BLOCK, - blobTransactionMaxBlobGasCost: u256(1), - ), - NewPayloads( - expectedIncludedBlobCount: TARGET_BLOBS_PER_BLOCK, - expectedBlobs: getBlobList(0, TARGET_BLOBS_PER_BLOCK), - NewPayloadCustomizer: &helper.BaseNewPayloadVersionCustomizer{ - payloadCustomizer: CustomPayloadData( - VersionedHashesCustomizer: &VersionedHashes{ - Blobs: append(getBlobList(0, TARGET_BLOBS_PER_BLOCK-1), helper.BlobID(TARGET_BLOBS_PER_BLOCK)), - ), - ), - ExpectInvalidStatus: true, + run: specExecute, + spec: CancunSpec( + mainFork: ForkCancun, + testSequence: @[ + SendBlobTransactions( + transactionCount: TARGET_BLOBS_PER_BLOCK, + blobTransactionMaxBlobGasCost: u256(1), ), - ExpectationDescription: """ - NewPayloadV3 with incorrect hash in list of versioned hashes must return INVALID status - """, - ), + NewPayloads( + expectedIncludedBlobCount: TARGET_BLOBS_PER_BLOCK, + expectedblobs: getBlobList(0, TARGET_BLOBS_PER_BLOCK), + newPayloadCustomizer: BaseNewPayloadVersionCustomizer( + payloadCustomizer: CustomPayloadData( + versionedHashesCustomizer: VersionedHashesCustomizer( + blobs: some(getBlobList(0, TARGET_BLOBS_PER_BLOCK-1, BlobID(TARGET_BLOBS_PER_BLOCK))), + ), + ), + expectInvalidStatus: true, + ), + expectationDescription: """ + NewPayloadV3 with incorrect hash in list of versioned hashes must return INVALID status + """, + ), + ] ), ), - TestDesc( - spec: CancunSpec( - name: "NewPayloadV3 Versioned Hashes, Incorrect Version", - about: """ + TestDesc( + name: "NewPayloadV3 Versioned Hashes, Incorrect Version", + about: """ Tests VersionedHashes in Engine API NewPayloadV3 where the array has a single blob that has an incorrect version. """, - mainFork: Cancun, - ), - testSequence: @[ - SendBlobTransactions( - transactionCount: TARGET_BLOBS_PER_BLOCK, - blobTransactionMaxBlobGasCost: u256(1), - ), - NewPayloads( - expectedIncludedBlobCount: TARGET_BLOBS_PER_BLOCK, - expectedBlobs: getBlobList(0, TARGET_BLOBS_PER_BLOCK), - NewPayloadCustomizer: &helper.BaseNewPayloadVersionCustomizer{ - payloadCustomizer: CustomPayloadData( - VersionedHashesCustomizer: &VersionedHashes{ - Blobs: getBlobList(0, TARGET_BLOBS_PER_BLOCK), - HashVersions: []byte{VERSIONED_HASH_VERSION_KZG, VERSIONED_HASH_VERSION_KZG + 1), - ), - ), - ExpectInvalidStatus: true, + run: specExecute, + spec: CancunSpec( + mainFork: ForkCancun, + testSequence: @[ + SendBlobTransactions( + transactionCount: TARGET_BLOBS_PER_BLOCK, + blobTransactionMaxBlobGasCost: u256(1), ), - ExpectationDescription: """ - NewPayloadV3 with incorrect version in list of versioned hashes must return INVALID status - """, - ), + NewPayloads( + expectedIncludedBlobCount: TARGET_BLOBS_PER_BLOCK, + expectedblobs: getBlobList(0, TARGET_BLOBS_PER_BLOCK), + newPayloadCustomizer: BaseNewPayloadVersionCustomizer( + payloadCustomizer: CustomPayloadData( + versionedHashesCustomizer: VersionedHashesCustomizer( + blobs: some(getBlobList(0, TARGET_BLOBS_PER_BLOCK)), + hashVersions: @[VERSIONED_HASH_VERSION_KZG.byte, (VERSIONED_HASH_VERSION_KZG + 1).byte], + ), + ), + expectInvalidStatus: true, + ), + expectationDescription: """ + NewPayloadV3 with incorrect version in list of versioned hashes must return INVALID status + """, + ), + ] ), ), TestDesc( - spec: CancunSpec( - - name: "NewPayloadV3 Versioned Hashes, Nil Hashes", - about: """ + name: "NewPayloadV3 Versioned Hashes, Nil Hashes", + about: """ Tests VersionedHashes in Engine API NewPayloadV3 where the array is nil, even though the fork has already happened. """, - mainFork: Cancun, - ), - testSequence: @[ - SendBlobTransactions( - transactionCount: TARGET_BLOBS_PER_BLOCK, - blobTransactionMaxBlobGasCost: u256(1), - ), - NewPayloads( - expectedIncludedBlobCount: TARGET_BLOBS_PER_BLOCK, - expectedBlobs: getBlobList(0, TARGET_BLOBS_PER_BLOCK), - NewPayloadCustomizer: &helper.BaseNewPayloadVersionCustomizer{ - payloadCustomizer: CustomPayloadData( - VersionedHashesCustomizer: &VersionedHashes{ - Blobs: nil, - ), - ), - ExpectedError: globals.INVALID_PARAMS_ERROR, + run: specExecute, + spec: CancunSpec( + mainFork: ForkCancun, + testSequence: @[ + SendBlobTransactions( + transactionCount: TARGET_BLOBS_PER_BLOCK, + blobTransactionMaxBlobGasCost: u256(1), ), - ExpectationDescription: """ - NewPayloadV3 after Cancun with nil VersionedHashes must return INVALID_PARAMS_ERROR (code -32602) - """, - ), + NewPayloads( + expectedIncludedBlobCount: TARGET_BLOBS_PER_BLOCK, + expectedblobs: getBlobList(0, TARGET_BLOBS_PER_BLOCK), + newPayloadCustomizer: BaseNewPayloadVersionCustomizer( + payloadCustomizer: CustomPayloadData( + versionedHashesCustomizer: VersionedHashesCustomizer( + blobs: none(seq[BlobID]), + ), + ), + expectedError: engineApiInvalidParams, + ), + expectationDescription: """ + NewPayloadV3 after Cancun with nil VersionedHashes must return INVALID_PARAMS_ERROR (code -32602) + """, + ), + ] ), ), TestDesc( - spec: CancunSpec( - - name: "NewPayloadV3 Versioned Hashes, Empty Hashes", - about: """ + name: "NewPayloadV3 Versioned Hashes, Empty Hashes", + about: """ Tests VersionedHashes in Engine API NewPayloadV3 where the array is empty, even though there are blobs in the payload. """, - mainFork: Cancun, - ), - testSequence: @[ - SendBlobTransactions( - transactionCount: TARGET_BLOBS_PER_BLOCK, - blobTransactionMaxBlobGasCost: u256(1), - ), - NewPayloads( - expectedIncludedBlobCount: TARGET_BLOBS_PER_BLOCK, - expectedBlobs: getBlobList(0, TARGET_BLOBS_PER_BLOCK), - NewPayloadCustomizer: &helper.BaseNewPayloadVersionCustomizer{ - payloadCustomizer: CustomPayloadData( - VersionedHashesCustomizer: &VersionedHashes{ - Blobs: []helper.BlobID{), - ), - ), - ExpectInvalidStatus: true, + run: specExecute, + spec: CancunSpec( + mainFork: ForkCancun, + testSequence: @[ + SendBlobTransactions( + transactionCount: TARGET_BLOBS_PER_BLOCK, + blobTransactionMaxBlobGasCost: u256(1), ), - ExpectationDescription: """ - NewPayloadV3 with incorrect list of versioned hashes must return INVALID status - """, - ), + NewPayloads( + expectedIncludedBlobCount: TARGET_BLOBS_PER_BLOCK, + expectedblobs: getBlobList(0, TARGET_BLOBS_PER_BLOCK), + newPayloadCustomizer: BaseNewPayloadVersionCustomizer( + payloadCustomizer: CustomPayloadData( + versionedHashesCustomizer: VersionedHashesCustomizer( + blobs: some(newSeq[BlobID]()), + ), + ), + expectInvalidStatus: true, + ), + expectationDescription: """ + NewPayloadV3 with incorrect list of versioned hashes must return INVALID status + """, + ), + ] ), ), TestDesc( - spec: CancunSpec( - - name: "NewPayloadV3 Versioned Hashes, Non-Empty Hashes", - about: """ + name: "NewPayloadV3 Versioned Hashes, Non-Empty Hashes", + about: """ Tests VersionedHashes in Engine API NewPayloadV3 where the array is contains hashes, even though there are no blobs in the payload. """, - mainFork: Cancun, - ), - testSequence: @[ - NewPayloads( - expectedBlobs: []helper.BlobID{), - NewPayloadCustomizer: &helper.BaseNewPayloadVersionCustomizer{ - payloadCustomizer: CustomPayloadData( - VersionedHashesCustomizer: &VersionedHashes{ - Blobs: []helper.BlobID{0), + run: specExecute, + spec: CancunSpec( + mainFork: ForkCancun, + testSequence: @[ + NewPayloads( + expectedblobs: @[], + newPayloadCustomizer: BaseNewPayloadVersionCustomizer( + payloadCustomizer: CustomPayloadData( + versionedHashesCustomizer: VersionedHashesCustomizer( + blobs: some(@[BlobID(0)]), + ), ), + expectInvalidStatus: true, ), - ExpectInvalidStatus: true, - ), - ExpectationDescription: """ - NewPayloadV3 with incorrect list of versioned hashes must return INVALID status - """, - ), + expectationDescription: """ + NewPayloadV3 with incorrect list of versioned hashes must return INVALID status + """, + ).TestStep, + ] ), ), # Test versioned hashes in Engine API NewPayloadV3 on syncing clients TestDesc( - spec: CancunSpec( - - - name: "NewPayloadV3 Versioned Hashes, Missing Hash (Syncing)", - about: """ + name: "NewPayloadV3 Versioned Hashes, Missing Hash (Syncing)", + about: """ Tests VersionedHashes in Engine API NewPayloadV3 where the array is missing one of the hashes. """, - mainFork: Cancun, - ), - testSequence: @[ - NewPayloads(), # Send new payload so the parent is unknown to the secondary client - SendBlobTransactions( - transactionCount: TARGET_BLOBS_PER_BLOCK, - blobTransactionMaxBlobGasCost: u256(1), - ), - NewPayloads( - expectedIncludedBlobCount: TARGET_BLOBS_PER_BLOCK, - expectedBlobs: getBlobList(0, TARGET_BLOBS_PER_BLOCK), - ), - - LaunchClients{ - EngineStarter: hive_rpc.HiveRPCEngineStarter{), - SkipAddingToCLMock: true, - SkipConnectingToBootnode: true, # So the client is in a perpetual syncing state - ), - SendModifiedLatestPayload{ - ClientID: 1, - NewPayloadCustomizer: &helper.BaseNewPayloadVersionCustomizer{ - payloadCustomizer: CustomPayloadData( - VersionedHashesCustomizer: &VersionedHashes{ - Blobs: getBlobList(0, TARGET_BLOBS_PER_BLOCK-1), - ), - ), - ExpectInvalidStatus: true, + run: specExecute, + spec: CancunSpec( + mainFork: ForkCancun, + testSequence: @[ + NewPayloads(), # Send new payload so the parent is unknown to the secondary client + SendBlobTransactions( + transactionCount: TARGET_BLOBS_PER_BLOCK, + blobTransactionMaxBlobGasCost: u256(1), ), - ), + NewPayloads( + expectedIncludedBlobCount: TARGET_BLOBS_PER_BLOCK, + expectedblobs: getBlobList(0, TARGET_BLOBS_PER_BLOCK), + ), + + LaunchClients( + #engineStarter: hive_rpc.HiveRPCEngineStarter{), + skipAddingToCLMock: true, + skipConnectingToBootnode: true, # So the client is in a perpetual syncing state + ), + SendModifiedLatestPayload( + clientID: 1, + newPayloadCustomizer: BaseNewPayloadVersionCustomizer( + payloadCustomizer: CustomPayloadData( + versionedHashesCustomizer: VersionedHashesCustomizer( + blobs: some(getBlobList(0, TARGET_BLOBS_PER_BLOCK-1)), + ), + ), + expectInvalidStatus: true, + ), + ), + ] ), ), + TestDesc( - spec: CancunSpec( - - - name: "NewPayloadV3 Versioned Hashes, Extra Hash (Syncing)", - about: """ + name: "NewPayloadV3 Versioned Hashes, Extra Hash (Syncing)", + about: """ Tests VersionedHashes in Engine API NewPayloadV3 where the array is has an extra hash for a blob that is not in the payload. """, - mainFork: Cancun, - ), - # TODO: It could be worth it to also test this with a blob that is in the - # mempool but was not included in the payload. - testSequence: @[ - NewPayloads(), # Send new payload so the parent is unknown to the secondary client - SendBlobTransactions( - transactionCount: TARGET_BLOBS_PER_BLOCK, - blobTransactionMaxBlobGasCost: u256(1), - ), - NewPayloads( - expectedIncludedBlobCount: TARGET_BLOBS_PER_BLOCK, - expectedBlobs: getBlobList(0, TARGET_BLOBS_PER_BLOCK), - ), - - LaunchClients{ - EngineStarter: hive_rpc.HiveRPCEngineStarter{), - SkipAddingToCLMock: true, - SkipConnectingToBootnode: true, # So the client is in a perpetual syncing state - ), - SendModifiedLatestPayload{ - ClientID: 1, - NewPayloadCustomizer: &helper.BaseNewPayloadVersionCustomizer{ - payloadCustomizer: CustomPayloadData( - VersionedHashesCustomizer: &VersionedHashes{ - Blobs: getBlobList(0, TARGET_BLOBS_PER_BLOCK+1), - ), - ), - ExpectInvalidStatus: true, + run: specExecute, + spec: CancunSpec( + mainFork: ForkCancun, + # TODO: It could be worth it to also test this with a blob that is in the + # mempool but was not included in the payload. + testSequence: @[ + NewPayloads(), # Send new payload so the parent is unknown to the secondary client + SendBlobTransactions( + transactionCount: TARGET_BLOBS_PER_BLOCK, + blobTransactionMaxBlobGasCost: u256(1), ), - ), + NewPayloads( + expectedIncludedBlobCount: TARGET_BLOBS_PER_BLOCK, + expectedblobs: getBlobList(0, TARGET_BLOBS_PER_BLOCK), + ), + + LaunchClients( + #engineStarter: hive_rpc.HiveRPCEngineStarter{), + skipAddingToCLMock: true, + skipConnectingToBootnode: true, # So the client is in a perpetual syncing state + ), + SendModifiedLatestPayload( + clientID: 1, + newPayloadCustomizer: BaseNewPayloadVersionCustomizer( + payloadCustomizer: CustomPayloadData( + versionedHashesCustomizer: VersionedHashesCustomizer( + blobs: some(getBlobList(0, TARGET_BLOBS_PER_BLOCK+1)), + ), + ), + expectInvalidStatus: true, + ), + ), + ] ), ), TestDesc( - spec: CancunSpec( - - name: "NewPayloadV3 Versioned Hashes, Out of Order (Syncing)", - about: """ + name: "NewPayloadV3 Versioned Hashes, Out of Order (Syncing)", + about: """ Tests VersionedHashes in Engine API NewPayloadV3 where the array is out of order. """, - mainFork: Cancun, - ), - testSequence: @[ - NewPayloads(), # Send new payload so the parent is unknown to the secondary client - SendBlobTransactions( - transactionCount: TARGET_BLOBS_PER_BLOCK, - blobTransactionMaxBlobGasCost: u256(1), - ), - NewPayloads( - expectedIncludedBlobCount: TARGET_BLOBS_PER_BLOCK, - expectedBlobs: getBlobList(0, TARGET_BLOBS_PER_BLOCK), - ), - LaunchClients{ - EngineStarter: hive_rpc.HiveRPCEngineStarter{), - SkipAddingToCLMock: true, - SkipConnectingToBootnode: true, # So the client is in a perpetual syncing state - ), - SendModifiedLatestPayload{ - ClientID: 1, - NewPayloadCustomizer: &helper.BaseNewPayloadVersionCustomizer{ - payloadCustomizer: CustomPayloadData( - VersionedHashesCustomizer: &VersionedHashes{ - Blobs: getBlobListByIndex(helper.BlobID(TARGET_BLOBS_PER_BLOCK-1), 0), - ), - ), - ExpectInvalidStatus: true, + run: specExecute, + spec: CancunSpec( + mainFork: ForkCancun, + testSequence: @[ + NewPayloads(), # Send new payload so the parent is unknown to the secondary client + SendBlobTransactions( + transactionCount: TARGET_BLOBS_PER_BLOCK, + blobTransactionMaxBlobGasCost: u256(1), ), - ), + NewPayloads( + expectedIncludedBlobCount: TARGET_BLOBS_PER_BLOCK, + expectedblobs: getBlobList(0, TARGET_BLOBS_PER_BLOCK), + ), + + LaunchClients( + #engineStarter: hive_rpc.HiveRPCEngineStarter{), + skipAddingToCLMock: true, + skipConnectingToBootnode: true, # So the client is in a perpetual syncing state + ), + SendModifiedLatestPayload( + clientID: 1, + newPayloadCustomizer: BaseNewPayloadVersionCustomizer( + payloadCustomizer: CustomPayloadData( + versionedHashesCustomizer: VersionedHashesCustomizer( + blobs: some(getBlobListByIndex(BlobID(TARGET_BLOBS_PER_BLOCK-1), 0)), + ), + ), + expectInvalidStatus: true, + ), + ), + ] ), ), TestDesc( - spec: CancunSpec( - - name: "NewPayloadV3 Versioned Hashes, Repeated Hash (Syncing)", - about: """ + name: "NewPayloadV3 Versioned Hashes, Repeated Hash (Syncing)", + about: """ Tests VersionedHashes in Engine API NewPayloadV3 where the array has a blob that is repeated in the array. """, - mainFork: Cancun, - ), - testSequence: @[ - NewPayloads(), # Send new payload so the parent is unknown to the secondary client - SendBlobTransactions( - transactionCount: TARGET_BLOBS_PER_BLOCK, - blobTransactionMaxBlobGasCost: u256(1), - ), - NewPayloads( - expectedIncludedBlobCount: TARGET_BLOBS_PER_BLOCK, - expectedBlobs: getBlobList(0, TARGET_BLOBS_PER_BLOCK), - ), - - LaunchClients{ - EngineStarter: hive_rpc.HiveRPCEngineStarter{), - SkipAddingToCLMock: true, - SkipConnectingToBootnode: true, # So the client is in a perpetual syncing state - ), - SendModifiedLatestPayload{ - ClientID: 1, - NewPayloadCustomizer: &helper.BaseNewPayloadVersionCustomizer{ - payloadCustomizer: CustomPayloadData( - VersionedHashesCustomizer: &VersionedHashes{ - Blobs: append(getBlobList(0, TARGET_BLOBS_PER_BLOCK), helper.BlobID(TARGET_BLOBS_PER_BLOCK-1)), - ), - ), - ExpectInvalidStatus: true, + run: specExecute, + spec: CancunSpec( + mainFork: ForkCancun, + testSequence: @[ + NewPayloads(), # Send new payload so the parent is unknown to the secondary client + SendBlobTransactions( + transactionCount: TARGET_BLOBS_PER_BLOCK, + blobTransactionMaxBlobGasCost: u256(1), ), - ), + NewPayloads( + expectedIncludedBlobCount: TARGET_BLOBS_PER_BLOCK, + expectedblobs: getBlobList(0, TARGET_BLOBS_PER_BLOCK), + ), + + LaunchClients( + #engineStarter: hive_rpc.HiveRPCEngineStarter{), + skipAddingToCLMock: true, + skipConnectingToBootnode: true, # So the client is in a perpetual syncing state + ), + SendModifiedLatestPayload( + clientID: 1, + newPayloadCustomizer: BaseNewPayloadVersionCustomizer( + payloadCustomizer: CustomPayloadData( + versionedHashesCustomizer: VersionedHashesCustomizer( + blobs: some(getBlobList(0, TARGET_BLOBS_PER_BLOCK, BlobID(TARGET_BLOBS_PER_BLOCK-1))), + ), + ), + expectInvalidStatus: true, + ), + ), + ] ), ), TestDesc( - spec: CancunSpec( - - name: "NewPayloadV3 Versioned Hashes, Incorrect Hash (Syncing)", - about: """ + name: "NewPayloadV3 Versioned Hashes, Incorrect Hash (Syncing)", + about: """ Tests VersionedHashes in Engine API NewPayloadV3 where the array has a blob that is repeated in the array. """, - mainFork: Cancun, - ), - testSequence: @[ - NewPayloads(), # Send new payload so the parent is unknown to the secondary client - SendBlobTransactions( - transactionCount: TARGET_BLOBS_PER_BLOCK, - blobTransactionMaxBlobGasCost: u256(1), - ), - NewPayloads( - expectedIncludedBlobCount: TARGET_BLOBS_PER_BLOCK, - expectedBlobs: getBlobList(0, TARGET_BLOBS_PER_BLOCK), - ), - - LaunchClients{ - EngineStarter: hive_rpc.HiveRPCEngineStarter{), - SkipAddingToCLMock: true, - SkipConnectingToBootnode: true, # So the client is in a perpetual syncing state - ), - SendModifiedLatestPayload{ - ClientID: 1, - NewPayloadCustomizer: &helper.BaseNewPayloadVersionCustomizer{ - payloadCustomizer: CustomPayloadData( - VersionedHashesCustomizer: &VersionedHashes{ - Blobs: append(getBlobList(0, TARGET_BLOBS_PER_BLOCK-1), helper.BlobID(TARGET_BLOBS_PER_BLOCK)), - ), - ), - ExpectInvalidStatus: true, + run: specExecute, + spec: CancunSpec( + mainFork: ForkCancun, + testSequence: @[ + NewPayloads(), # Send new payload so the parent is unknown to the secondary client + SendBlobTransactions( + transactionCount: TARGET_BLOBS_PER_BLOCK, + blobTransactionMaxBlobGasCost: u256(1), ), - ), + NewPayloads( + expectedIncludedBlobCount: TARGET_BLOBS_PER_BLOCK, + expectedblobs: getBlobList(0, TARGET_BLOBS_PER_BLOCK), + ), + + LaunchClients( + #engineStarter: hive_rpc.HiveRPCEngineStarter{), + skipAddingToCLMock: true, + skipConnectingToBootnode: true, # So the client is in a perpetual syncing state + ), + SendModifiedLatestPayload( + clientID: 1, + newPayloadCustomizer: BaseNewPayloadVersionCustomizer( + payloadCustomizer: CustomPayloadData( + versionedHashesCustomizer: VersionedHashesCustomizer( + blobs: some(getBlobList(0, TARGET_BLOBS_PER_BLOCK-1, BlobID(TARGET_BLOBS_PER_BLOCK))), + ), + ), + expectInvalidStatus: true, + ), + ), + ] ), ), - TestDesc( - spec: CancunSpec( - name: "NewPayloadV3 Versioned Hashes, Incorrect Version (Syncing)", - about: """ + TestDesc( + name: "NewPayloadV3 Versioned Hashes, Incorrect Version (Syncing)", + about: """ Tests VersionedHashes in Engine API NewPayloadV3 where the array has a single blob that has an incorrect version. """, - mainFork: Cancun, - ), - testSequence: @[ - NewPayloads(), # Send new payload so the parent is unknown to the secondary client - SendBlobTransactions( - transactionCount: TARGET_BLOBS_PER_BLOCK, - blobTransactionMaxBlobGasCost: u256(1), - ), - NewPayloads( - expectedIncludedBlobCount: TARGET_BLOBS_PER_BLOCK, - expectedBlobs: getBlobList(0, TARGET_BLOBS_PER_BLOCK), - ), - - LaunchClients{ - EngineStarter: hive_rpc.HiveRPCEngineStarter{), - SkipAddingToCLMock: true, - SkipConnectingToBootnode: true, # So the client is in a perpetual syncing state - ), - SendModifiedLatestPayload{ - ClientID: 1, - NewPayloadCustomizer: &helper.BaseNewPayloadVersionCustomizer{ - payloadCustomizer: CustomPayloadData( - VersionedHashesCustomizer: &VersionedHashes{ - Blobs: getBlobList(0, TARGET_BLOBS_PER_BLOCK), - HashVersions: []byte{VERSIONED_HASH_VERSION_KZG, VERSIONED_HASH_VERSION_KZG + 1), - ), - ), - ExpectInvalidStatus: true, + run: specExecute, + spec: CancunSpec( + mainFork: ForkCancun, + testSequence: @[ + NewPayloads(), # Send new payload so the parent is unknown to the secondary client + SendBlobTransactions( + transactionCount: TARGET_BLOBS_PER_BLOCK, + blobTransactionMaxBlobGasCost: u256(1), ), - ), + NewPayloads( + expectedIncludedBlobCount: TARGET_BLOBS_PER_BLOCK, + expectedblobs: getBlobList(0, TARGET_BLOBS_PER_BLOCK), + ), + + LaunchClients( + #engineStarter: hive_rpc.HiveRPCEngineStarter{), + skipAddingToCLMock: true, + skipConnectingToBootnode: true, # So the client is in a perpetual syncing state + ), + SendModifiedLatestPayload( + clientID: 1, + newPayloadCustomizer: BaseNewPayloadVersionCustomizer( + payloadCustomizer: CustomPayloadData( + versionedHashesCustomizer: VersionedHashesCustomizer( + blobs: some(getBlobList(0, TARGET_BLOBS_PER_BLOCK)), + hashVersions: @[VERSIONED_HASH_VERSION_KZG.byte, (VERSIONED_HASH_VERSION_KZG + 1).byte], + ), + ), + expectInvalidStatus: true, + ), + ), + ] ), ), TestDesc( - spec: CancunSpec( - - name: "NewPayloadV3 Versioned Hashes, Nil Hashes (Syncing)", - about: """ + name: "NewPayloadV3 Versioned Hashes, Nil Hashes (Syncing)", + about: """ Tests VersionedHashes in Engine API NewPayloadV3 where the array is nil, even though the fork has already happened. """, - mainFork: Cancun, - ), - testSequence: @[ - NewPayloads(), # Send new payload so the parent is unknown to the secondary client - SendBlobTransactions( - transactionCount: TARGET_BLOBS_PER_BLOCK, - blobTransactionMaxBlobGasCost: u256(1), - ), - NewPayloads( - expectedIncludedBlobCount: TARGET_BLOBS_PER_BLOCK, - expectedBlobs: getBlobList(0, TARGET_BLOBS_PER_BLOCK), - ), - - LaunchClients{ - EngineStarter: hive_rpc.HiveRPCEngineStarter{), - SkipAddingToCLMock: true, - SkipConnectingToBootnode: true, # So the client is in a perpetual syncing state - ), - SendModifiedLatestPayload{ - ClientID: 1, - NewPayloadCustomizer: &helper.BaseNewPayloadVersionCustomizer{ - payloadCustomizer: CustomPayloadData( - VersionedHashesCustomizer: &VersionedHashes{ - Blobs: nil, - ), - ), - ExpectedError: globals.INVALID_PARAMS_ERROR, + run: specExecute, + spec: CancunSpec( + mainFork: ForkCancun, + testSequence: @[ + NewPayloads(), # Send new payload so the parent is unknown to the secondary client + SendBlobTransactions( + transactionCount: TARGET_BLOBS_PER_BLOCK, + blobTransactionMaxBlobGasCost: u256(1), ), - ), + NewPayloads( + expectedIncludedBlobCount: TARGET_BLOBS_PER_BLOCK, + expectedblobs: getBlobList(0, TARGET_BLOBS_PER_BLOCK), + ), + + LaunchClients( + #engineStarter: hive_rpc.HiveRPCEngineStarter{), + skipAddingToCLMock: true, + skipConnectingToBootnode: true, # So the client is in a perpetual syncing state + ), + SendModifiedLatestPayload( + clientID: 1, + newPayloadCustomizer: BaseNewPayloadVersionCustomizer( + payloadCustomizer: CustomPayloadData( + versionedHashesCustomizer: VersionedHashesCustomizer( + blobs: none(seq[BlobID]), + ), + ), + expectedError: engineApiInvalidParams, + ), + ), + ] ), ), TestDesc( - spec: CancunSpec( - - name: "NewPayloadV3 Versioned Hashes, Empty Hashes (Syncing)", - about: """ + name: "NewPayloadV3 Versioned Hashes, Empty Hashes (Syncing)", + about: """ Tests VersionedHashes in Engine API NewPayloadV3 where the array is empty, even though there are blobs in the payload. """, - mainFork: Cancun, - ), - testSequence: @[ - NewPayloads(), # Send new payload so the parent is unknown to the secondary client - SendBlobTransactions( - transactionCount: TARGET_BLOBS_PER_BLOCK, - blobTransactionMaxBlobGasCost: u256(1), - ), - NewPayloads( - expectedIncludedBlobCount: TARGET_BLOBS_PER_BLOCK, - expectedBlobs: getBlobList(0, TARGET_BLOBS_PER_BLOCK), - ), - - LaunchClients{ - EngineStarter: hive_rpc.HiveRPCEngineStarter{), - SkipAddingToCLMock: true, - SkipConnectingToBootnode: true, # So the client is in a perpetual syncing state - ), - SendModifiedLatestPayload{ - ClientID: 1, - NewPayloadCustomizer: &helper.BaseNewPayloadVersionCustomizer{ - payloadCustomizer: CustomPayloadData( - VersionedHashesCustomizer: &VersionedHashes{ - Blobs: []helper.BlobID{), - ), - ), - ExpectInvalidStatus: true, + run: specExecute, + spec: CancunSpec( + mainFork: ForkCancun, + testSequence: @[ + NewPayloads(), # Send new payload so the parent is unknown to the secondary client + SendBlobTransactions( + transactionCount: TARGET_BLOBS_PER_BLOCK, + blobTransactionMaxBlobGasCost: u256(1), ), - ), + NewPayloads( + expectedIncludedBlobCount: TARGET_BLOBS_PER_BLOCK, + expectedblobs: getBlobList(0, TARGET_BLOBS_PER_BLOCK), + ), + + LaunchClients( + #engineStarter: hive_rpc.HiveRPCEngineStarter{), + skipAddingToCLMock: true, + skipConnectingToBootnode: true, # So the client is in a perpetual syncing state + ), + SendModifiedLatestPayload( + clientID: 1, + newPayloadCustomizer: BaseNewPayloadVersionCustomizer( + payloadCustomizer: CustomPayloadData( + versionedHashesCustomizer: VersionedHashesCustomizer( + blobs: some(newSeq[BlobID]()), + ), + ), + expectInvalidStatus: true, + ), + ), + ] ), ), TestDesc( - spec: CancunSpec( - - name: "NewPayloadV3 Versioned Hashes, Non-Empty Hashes (Syncing)", - about: """ + name: "NewPayloadV3 Versioned Hashes, Non-Empty Hashes (Syncing)", + about: """ Tests VersionedHashes in Engine API NewPayloadV3 where the array is contains hashes, even though there are no blobs in the payload. """, - mainFork: Cancun, - ), - testSequence: @[ - NewPayloads(), # Send new payload so the parent is unknown to the secondary client - NewPayloads( - expectedBlobs: []helper.BlobID{), - ), - - LaunchClients{ - EngineStarter: hive_rpc.HiveRPCEngineStarter{), - SkipAddingToCLMock: true, - SkipConnectingToBootnode: true, # So the client is in a perpetual syncing state - ), - SendModifiedLatestPayload{ - ClientID: 1, - NewPayloadCustomizer: &helper.BaseNewPayloadVersionCustomizer{ - payloadCustomizer: CustomPayloadData( - VersionedHashesCustomizer: &VersionedHashes{ - Blobs: []helper.BlobID{0), - ), - ), - ExpectInvalidStatus: true, + run: specExecute, + spec: CancunSpec( + mainFork: ForkCancun, + testSequence: @[ + NewPayloads(), # Send new payload so the parent is unknown to the secondary client + NewPayloads( + expectedblobs: @[], ), - ), + LaunchClients( + #engineStarter: hive_rpc.HiveRPCEngineStarter{), + skipAddingToCLMock: true, + skipConnectingToBootnode: true, # So the client is in a perpetual syncing state + ), + SendModifiedLatestPayload( + clientID: 1, + newPayloadCustomizer: BaseNewPayloadVersionCustomizer( + payloadCustomizer: CustomPayloadData( + versionedHashesCustomizer: VersionedHashesCustomizer( + blobs: some(@[BlobID(0)]), + ), + ), + expectInvalidStatus: true, + ), + ), + ] ), ), @@ -1806,76 +1740,77 @@ let cancunTestList* = [ # Most cases are contained in https:#github.com/ethereum/execution-spec-tests/tree/main/tests/cancun/eip4844_blobs # and can be executed using """pyspec""" simulator. TestDesc( - spec: CancunSpec( - - name: "Incorrect BlobGasUsed: Non-Zero on Zero Blobs", - about: """ + name: "Incorrect blobGasUsed: Non-Zero on Zero Blobs", + about: """ Send a payload with zero blobs, but non-zero BlobGasUsed. """, - mainFork: Cancun, - ), - testSequence: @[ - NewPayloads( - NewPayloadCustomizer: &helper.BaseNewPayloadVersionCustomizer{ - payloadCustomizer: CustomPayloadData( - BlobGasUsed: pUint64(1), + run: specExecute, + spec: CancunSpec( + mainFork: ForkCancun, + testSequence: @[ + NewPayloads( + newPayloadCustomizer: BaseNewPayloadVersionCustomizer( + payloadCustomizer: CustomPayloadData( + blobGasUsed: some(1'u64), + ), + expectInvalidStatus: true, ), - ExpectInvalidStatus: true, - ), - ), + ).TestStep, + ] ), ), + TestDesc( - spec: CancunSpec( - - - name: "Incorrect BlobGasUsed: GAS_PER_BLOB on Zero Blobs", - about: """ + name: "Incorrect blobGasUsed: GAS_PER_BLOB on Zero Blobs", + about: """ Send a payload with zero blobs, but non-zero BlobGasUsed. """, - mainFork: Cancun, - ), - testSequence: @[ - NewPayloads( - NewPayloadCustomizer: &helper.BaseNewPayloadVersionCustomizer{ - payloadCustomizer: CustomPayloadData( - BlobGasUsed: pUint64(cancun.GAS_PER_BLOB), + run: specExecute, + spec: CancunSpec( + mainFork: ForkCancun, + testSequence: @[ + NewPayloads( + newPayloadCustomizer: BaseNewPayloadVersionCustomizer( + payloadCustomizer: CustomPayloadData( + blobGasUsed: some(GAS_PER_BLOB.uint64), + ), + expectInvalidStatus: true, ), - ExpectInvalidStatus: true, - ), - ), + ).TestStep, + ] ), ), # DevP2P tests TestDesc( - spec: CancunSpec( - - name: "Request Blob Pooled Transactions", - about: """ + name: "Request Blob Pooled Transactions", + about: """ Requests blob pooled transactions and verify correct encoding. """, - mainFork: Cancun, - ), - testSequence: @[ + run: specExecute, + spec: CancunSpec( + mainFork: ForkCancun, + testSequence: @[ # Get past the genesis - NewPayloads( - payloadCount: 1, - ), - # Send multiple transactions with multiple blobs each - SendBlobTransactions( - transactionCount: 1, - blobTransactionMaxBlobGasCost: u256(1), - ), - DevP2PRequestPooledTransactionHash{ - ClientIndex: 0, - TransactionIndexes: []uint64{0), - WaitForNewPooledTransaction: true, - ), + NewPayloads( + payloadCount: 1, + ), + # Send multiple transactions with multiple blobs each + SendBlobTransactions( + transactionCount: 1, + blobTransactionMaxBlobGasCost: u256(1), + ), + DevP2PRequestPooledTransactionHash( + clientIndex: 0, + transactionIndexes: @[0], + waitForNewPooledTransaction: true, + ), + ] ), ), -} +] +#[ var EngineAPITests []test.Spec func init() { @@ -1886,7 +1821,7 @@ func init() { # Cancun specific variants for pre-existing tests baseSpec := test.BaseSpec{ - mainFork: Cancun, + mainFork: ForkCancun, } onlyBlobTxsSpec := test.BaseSpec{ mainFork: Cancun, @@ -1898,8 +1833,8 @@ func init() { { BaseSpec: baseSpec, Description: "Missing BeaconRoot", - Customizer: &helper.BasePayloadAttributesCustomizer{ - RemoveBeaconRoot: true, + Customizer: BasePayloadAttributesCustomizer{ + removeBeaconRoot: true, ), # Error is expected on syncing because V3 checks all fields to be present ErrorOnSync: true, diff --git a/hive_integration/nodocker/engine/clmock.nim b/hive_integration/nodocker/engine/clmock.nim index d6b88d950..c21e3a6b9 100644 --- a/hive_integration/nodocker/engine/clmock.nim +++ b/hive_integration/nodocker/engine/clmock.nim @@ -43,6 +43,9 @@ type # Chain History headerHistory : Table[uint64, common.BlockHeader] + # Payload ID History + payloadIDHistory : Table[string, PayloadID] + # PoS Chain History Information prevRandaoHistory* : Table[uint64, common.Hash256] executedPayloadHistory* : Table[uint64, ExecutionPayload] @@ -78,6 +81,21 @@ type onSafeBlockChange * : proc(): bool {.gcsafe.} onFinalizedBlockChange* : proc(): bool {.gcsafe.} + +proc collectBlobHashes(list: openArray[Web3Tx]): seq[common.Hash256] = + for w3tx in list: + let tx = ethTx(w3Tx) + for h in tx.versionedHashes: + result.add h + +func latestExecutableData*(cl: CLMocker): ExecutableData = + ExecutableData( + basePayload: cl.latestPayloadBuilt, + beaconRoot : ethHash cl.latestPayloadAttributes.parentBeaconBlockRoot, + attr : cl.latestPayloadAttributes, + versionedHashes: some(collectBlobHashes(cl.latestPayloadBuilt.transactions)), + ) + func latestPayloadNumber*(h: Table[uint64, ExecutionPayload]): uint64 = result = 0'u64 for n, _ in h: @@ -167,6 +185,19 @@ proc isBlockPoS*(cl: CLMocker, bn: common.BlockNumber): bool = return true +proc addPayloadID*(cl: CLMocker, eng: EngineEnv, newPayloadID: PayloadID): bool = + # Check if payload ID has been used before + var zeroPayloadID: PayloadID + if cl.payloadIDHistory.getOrDefault(eng.ID(), zeroPayloadID) == newPayloadID: + error "reused payload ID", ID = newPayloadID.toHex + return false + + # Add payload ID to history + cl.payloadIDHistory[eng.ID()] = newPayloadID + info "CLMocker: Added payload for client", + ID=newPayloadID.toHex, ID=eng.ID() + return true + # Return the per-block timestamp value increment func getTimestampIncrement(cl: CLMocker): EthTime = EthTime cl.blockTimestampIncrement.get(1) @@ -472,12 +503,14 @@ proc produceSingleBlock*(cl: CLMocker, cb: BlockProcessCallbacks): bool {.gcsafe if cb.onPayloadProducerSelected != nil: if not cb.onPayloadProducerSelected(): + debugEcho "***PAYLOAD PRODUCER SELECTED ERROR***" return false cl.generatePayloadAttributes() if cb.onPayloadAttributesGenerated != nil: if not cb.onPayloadAttributesGenerated(): + debugEcho "***ON PAYLOAD ATTRIBUTES ERROR***" return false if not cl.requestNextPayload(): @@ -487,6 +520,7 @@ proc produceSingleBlock*(cl: CLMocker, cb: BlockProcessCallbacks): bool {.gcsafe if cb.onRequestNextPayload != nil: if not cb.onRequestNextPayload(): + debugEcho "***ON REQUEST NEXT PAYLOAD ERROR***" return false # Give the client a delay between getting the payload ID and actually retrieving the payload @@ -494,18 +528,21 @@ proc produceSingleBlock*(cl: CLMocker, cb: BlockProcessCallbacks): bool {.gcsafe let period = chronos.seconds(cl.payloadProductionClientDelay) waitFor sleepAsync(period) - if not cl.getNextPayload(): + if not cl.getNextPayload(): return false if cb.onGetPayload != nil: if not cb.onGetPayload(): + debugEcho "***ON GET PAYLOAD ERROR***" return false if not cl.broadcastNextNewPayload(): + debugEcho "***ON BROADCAST NEXT NEW PAYLOAD ERROR***" return false if cb.onNewPayloadBroadcast != nil: if not cb.onNewPayloadBroadcast(): + debugEcho "***ON NEW PAYLOAD BROADCAST ERROR***" return false # Broadcast forkchoice updated with new HeadBlock to all clients @@ -523,20 +560,24 @@ proc produceSingleBlock*(cl: CLMocker, cb: BlockProcessCallbacks): bool {.gcsafe cl.latestForkchoice.finalizedBlockHash = cl.headHashHistory[hhLen - cl.slotsToFinalized - 1] if not cl.broadcastLatestForkchoice(): + debugEcho "***ON BROADCAST LATEST FORK CHOICE ERROR***" return false if cb.onForkchoiceBroadcast != nil: if not cb.onForkchoiceBroadcast(): + debugEcho "***ON FORK CHOICE BROADCAST ERROR***" return false # Broadcast forkchoice updated with new SafeBlock to all clients if cb.onSafeBlockChange != nil and cl.latestForkchoice.safeBlockHash != previousForkchoice.safeBlockHash: if not cb.onSafeBlockChange(): + debugEcho "***ON SAFE BLOCK CHANGE ERROR***" return false # Broadcast forkchoice updated with new FinalizedBlock to all clients if cb.onFinalizedBlockChange != nil and cl.latestForkchoice.finalizedBlockHash != previousForkchoice.finalizedBlockHash: if not cb.onFinalizedBlockChange(): + debugEcho "***ON FINALIZED BLOCK CHANGE ERROR***" return false # Broadcast forkchoice updated with new FinalizedBlock to all clients diff --git a/hive_integration/nodocker/engine/engine_callsigs.nim b/hive_integration/nodocker/engine/engine_callsigs.nim index be9b0cb21..8059f80f1 100644 --- a/hive_integration/nodocker/engine/engine_callsigs.nim +++ b/hive_integration/nodocker/engine/engine_callsigs.nim @@ -3,6 +3,12 @@ import web3/engine_api_types, ../../../nimbus/rpc/execution_types +proc engine_newPayloadV1(payload: ExecutionPayload): PayloadStatusV1 +proc engine_newPayloadV2(payload: ExecutionPayload): PayloadStatusV1 +proc engine_newPayloadV3(payload: ExecutionPayload, + expectedBlobVersionedHashes: Option[seq[VersionedHash]], + parentBeaconBlockRoot: Option[FixedBytes[32]]): PayloadStatusV1 + proc engine_newPayloadV2(payload: ExecutionPayloadV1OrV2): PayloadStatusV1 proc engine_forkchoiceUpdatedV2(forkchoiceState: ForkchoiceStateV1, payloadAttributes: Option[PayloadAttributes]): ForkchoiceUpdatedResponse proc engine_forkchoiceUpdatedV3(forkchoiceState: ForkchoiceStateV1, payloadAttributes: Option[PayloadAttributes]): ForkchoiceUpdatedResponse diff --git a/hive_integration/nodocker/engine/engine_client.nim b/hive_integration/nodocker/engine/engine_client.nim index 02bb6e7be..dcf0c2136 100644 --- a/hive_integration/nodocker/engine/engine_client.nim +++ b/hive_integration/nodocker/engine/engine_client.nim @@ -8,7 +8,8 @@ import ../../../premix/parser, ../../../nimbus/rpc/hexstrings, ../../../nimbus/beacon/execution_types, - ../../../nimbus/beacon/web3_eth_conv + ../../../nimbus/beacon/web3_eth_conv, + ./types import web3/engine_api as web3_engine_api @@ -144,6 +145,27 @@ proc newPayloadV3*(client: RpcClient, wrapTrySimpleRes: client.engine_newPayloadV3(payload, versionedHashes, parentBeaconBlockRoot) +proc newPayloadV1*(client: RpcClient, + payload: ExecutionPayload): + Result[PayloadStatusV1, string] = + wrapTrySimpleRes: + client.engine_newPayloadV1(payload) + +proc newPayloadV2*(client: RpcClient, + payload: ExecutionPayload): + Result[PayloadStatusV1, string] = + wrapTrySimpleRes: + client.engine_newPayloadV2(payload) + +proc newPayloadV3*(client: RpcClient, + payload: ExecutionPayload, + versionedHashes: Option[seq[VersionedHash]], + parentBeaconBlockRoot: Option[FixedBytes[32]] + ): + Result[PayloadStatusV1, string] = + wrapTrySimpleRes: + client.engine_newPayloadV3(payload, versionedHashes, parentBeaconBlockRoot) + proc collectBlobHashes(list: openArray[Web3Tx]): seq[Web3Hash] = for w3tx in list: let tx = ethTx(w3Tx) @@ -165,6 +187,17 @@ proc newPayload*(client: RpcClient, versionedHashes, w3Hash beaconRoot.get) +proc newPayload*(client: RpcClient, + version: Version, + payload: ExecutableData): Result[PayloadStatusV1, string] = + case version + of Version.V1: return client.newPayloadV1(payload.basePayload) + of Version.V2: return client.newPayloadV2(payload.basePayload) + of Version.V3: + return client.newPayloadV3(payload.basePayload, + w3Hashes payload.versionedHashes, + w3Hash payload.beaconRoot) + proc exchangeCapabilities*(client: RpcClient, methods: seq[string]): Result[seq[string], string] = diff --git a/hive_integration/nodocker/engine/engine_env.nim b/hive_integration/nodocker/engine/engine_env.nim index 80b3156af..2bd0ec148 100644 --- a/hive_integration/nodocker/engine/engine_env.nim +++ b/hive_integration/nodocker/engine/engine_env.nim @@ -11,6 +11,7 @@ import core/sealer, core/chain, core/tx_pool, + core/tx_pool/tx_item, core/block_import, rpc, sync/protocol, @@ -34,6 +35,7 @@ type ttd : DifficultyInt client : RpcHttpClient sync : BeaconSyncRef + txPool : TxPoolRef const baseFolder = "hive_integration/nodocker/engine" @@ -135,7 +137,8 @@ proc newEngineEnv*(conf: var NimbusConf, chainFile: string, enableAuth: bool): E server : server, sealer : sealer, client : client, - sync : sync + sync : sync, + txPool : txPool ) proc close*(env: EngineEnv) = @@ -169,3 +172,24 @@ func node*(env: EngineEnv): ENode = proc connect*(env: EngineEnv, node: ENode) = waitFor env.node.connectToNode(node) + +func ID*(env: EngineEnv): string = + $env.node.listeningAddress + +proc peer*(env: EngineEnv): Peer = + doAssert(env.node.numPeers > 0) + for peer in env.node.peers: + return peer + +proc getTxsInPool*(env: EngineEnv, txHashes: openArray[Hash256]): seq[Transaction] = + result = newSeqOfCap[Transaction](txHashes.len) + for txHash in txHashes: + let res = env.txPool.getItem(txHash) + if res.isErr: continue + let item = res.get + if item.reject == txInfoOk: + result.add item.tx + +proc numTxsInPool*(env: EngineEnv): int = + env.txPool.numTxs + diff --git a/hive_integration/nodocker/engine/test_env.nim b/hive_integration/nodocker/engine/test_env.nim index e5d1f3310..b4abd4466 100644 --- a/hive_integration/nodocker/engine/test_env.nim +++ b/hive_integration/nodocker/engine/test_env.nim @@ -82,11 +82,12 @@ func engine*(env: TestEnv): EngineEnv = proc setupCLMock*(env: TestEnv) = env.clmock = newCLMocker(env.engine, env.engine.com) -proc addEngine*(env: TestEnv, addToCL: bool = true): EngineEnv = +proc addEngine*(env: TestEnv, addToCL: bool = true, connectBootNode: bool = true): EngineEnv = doAssert(env.clMock.isNil.not) var conf = env.conf # clone the conf let eng = env.addEngine(conf) - eng.connect(env.engine.node) + if connectBootNode: + eng.connect(env.engine.node) if addToCL: env.clMock.addEngine(eng) eng @@ -144,10 +145,10 @@ proc sendTx*(env: TestEnv, tx: Transaction): bool = proc sendTx*(env: TestEnv, sender: TestAccount, eng: EngineEnv, tc: BlobTx): Result[Transaction, void] = env.sender.sendTx(sender, eng.client, tc) - + proc replaceTx*(env: TestEnv, sender: TestAccount, eng: EngineEnv, tc: BlobTx): Result[Transaction, void] = env.sender.replaceTx(sender, eng.client, tc) - + proc verifyPoWProgress*(env: TestEnv, lastBlockHash: common.Hash256): bool = let res = waitFor env.client.verifyPoWProgress(lastBlockHash) if res.isErr: diff --git a/hive_integration/nodocker/engine/types.nim b/hive_integration/nodocker/engine/types.nim index 329561fbb..79aded5b2 100644 --- a/hive_integration/nodocker/engine/types.nim +++ b/hive_integration/nodocker/engine/types.nim @@ -29,6 +29,12 @@ type run* : proc(spec: BaseSpec): bool spec* : BaseSpec + ExecutableData* = object + basePayload*: ExecutionPayload + beaconRoot* : Option[common.Hash256] + attr* : PayloadAttributes + versionedHashes*: Option[seq[common.Hash256]] + const DefaultTimeout* = 60 # seconds DefaultSleep* = 1 @@ -152,3 +158,27 @@ template expectLatestValidHash*(res: untyped, expectedHash: Web3Hash) = error "Expect latest valid hash isSome" testCond s.latestValidHash.get == expectedHash: error "latest valid hash mismatch", expect=expectedHash, get=s.latestValidHash.get + +template expectErrorCode*(res: untyped, errCode: int, expectedDesc: string) = + testCond res.isErr: + error "unexpected result, want error, get ok" + testCond res.error.find($errCode) != -1: + fatal "DEBUG", msg=expectedDesc + +template expectNoError*(res: untyped, expectedDesc: string) = + testCond res.isOk: + fatal "DEBUG", msg=expectedDesc, err=res.error + +template expectPayloadStatus*(res: untyped, cond: PayloadExecutionStatus) = + testCond res.isOk: + error "Unexpected FCU Error", msg=res.error + let s = res.get() + testCond s.payloadStatus.status == cond: + error "Unexpected FCU status", expect=cond, get=s.payloadStatus.status + +template expectNPStatus*(res: untyped, cond: PayloadExecutionStatus) = + testCond res.isOk: + error "Unexpected newPayload error", msg=res.error + let s = res.get() + testCond s.status == cond: + error "Unexpected newPayload status", expect=cond, get=s.status diff --git a/hive_integration/nodocker/engine/withdrawals/wd_base_spec.nim b/hive_integration/nodocker/engine/withdrawals/wd_base_spec.nim index f0a680258..67b851b62 100644 --- a/hive_integration/nodocker/engine/withdrawals/wd_base_spec.nim +++ b/hive_integration/nodocker/engine/withdrawals/wd_base_spec.nim @@ -231,7 +231,6 @@ proc execute*(ws: WDBaseSpec, env: TestEnv): bool = # Produce any blocks necessary to reach withdrawals fork var pbRes = env.clMock.produceBlocks(ws.getPreWithdrawalsBlockCount, BlockProcessCallbacks( onPayloadProducerSelected: proc(): bool = - # Send some transactions let numTx = ws.getTransactionCountPerPayload() for i in 0.. expectedVersion: + raise unsupportedFork("getPayload" & $expectedVersion & + " expect ExecutionPayload" & $expectedVersion & + " but get ExecutionPayload" & $version) + GetPayloadV2Response( - executionPayload: payload, + executionPayload: payloadGeneric.V1V2, blockValue: blockValue ) @@ -36,11 +44,16 @@ proc getPayloadV3*(ben: BeaconEngineRef, id: PayloadID): GetPayloadV3Response = trace "Engine API request received", meth = "GetPayload", id - var payload: ExecutionPayloadV3 + var payloadGeneric: ExecutionPayload var blockValue: UInt256 - if not ben.get(id, blockValue, payload): + if not ben.get(id, blockValue, payloadGeneric): raise unknownPayload("Unknown payload") + let version = payloadGeneric.version + if version != Version.V3: + raise unsupportedFork("getPayloadV3 expect ExecutionPayloadV3 but get ExecutionPayload" & $version) + + let payload = payloadGeneric.V3 let com = ben.com if not com.isCancunOrLater(ethTime payload.timestamp): raise unsupportedFork("payload timestamp is less than Cancun activation") diff --git a/nimbus/beacon/api_handler/api_newpayload.nim b/nimbus/beacon/api_handler/api_newpayload.nim index f679aac51..7527f98fc 100644 --- a/nimbus/beacon/api_handler/api_newpayload.nim +++ b/nimbus/beacon/api_handler/api_newpayload.nim @@ -38,7 +38,7 @@ template validateVersion(com, timestamp, version, expectedVersion) = raise invalidParams("if timestamp is earlier than Shanghai, " & "payload must be ExecutionPayloadV1") - if version != expectedVersion: + if expectedVersion == Version.V3 and version != expectedVersion: raise invalidParams("newPayload" & $expectedVersion & " expect ExecutionPayload" & $expectedVersion & " but got ExecutionPayload" & $version) @@ -54,6 +54,10 @@ proc newPayload*(ben: BeaconEngineRef, number = payload.blockNumber, hash = payload.blockHash + if expectedVersion == Version.V3: + if beaconRoot.isNone: + raise invalidParams("newPayloadV3 expect beaconRoot but got none") + let com = ben.com db = com.db diff --git a/nimbus/beacon/web3_eth_conv.nim b/nimbus/beacon/web3_eth_conv.nim index 8c02bbc30..05b59102c 100644 --- a/nimbus/beacon/web3_eth_conv.nim +++ b/nimbus/beacon/web3_eth_conv.nim @@ -71,6 +71,9 @@ func w3PrevRandao*(): Web3PrevRandao = func w3Address*(): Web3Address = discard +func w3Hash*(): Web3Hash = + discard + # ------------------------------------------------------------------------------ # Web3 types to Eth types # ------------------------------------------------------------------------------ @@ -144,6 +147,19 @@ func ethTxs*(list: openArray[Web3Tx], removeBlobs = false): func w3Hash*(x: common.Hash256): Web3Hash = Web3Hash x.data +func w3Hashes*(list: openArray[common.Hash256]): seq[Web3Hash] = + for x in list: + result.add Web3Hash x.data + +func w3Hashes*(z: Option[seq[common.Hash256]]): Option[seq[Web3Hash]] = + if z.isNone: none(seq[Web3Hash]) + else: + let list = z.get + var v = newSeq[Web3Hash](list.len) + for x in list: + v.add Web3Hash x.data + some(v) + func w3Hash*(x: Option[common.Hash256]): Option[BlockHash] = if x.isNone: none(BlockHash) else: some(BlockHash x.get.data) diff --git a/nimbus/core/tx_pool/tx_tasks/tx_classify.nim b/nimbus/core/tx_pool/tx_tasks/tx_classify.nim index 7460af04b..6a5bb6872 100644 --- a/nimbus/core/tx_pool/tx_tasks/tx_classify.nim +++ b/nimbus/core/tx_pool/tx_tasks/tx_classify.nim @@ -37,7 +37,13 @@ logScope: # ------------------------------------------------------------------------------ proc checkTxBasic(xp: TxPoolRef; item: TxItemRef): bool = - let res = validateTxBasic(item.tx.removeNetworkPayload, xp.chain.nextFork) + let res = validateTxBasic( + item.tx.removeNetworkPayload, + xp.chain.nextFork, + # A new transaction of the next fork may be + # coming before the fork activated + validateFork = false + ) if res.isOk: return true item.info = res.error diff --git a/nimbus/core/validate.nim b/nimbus/core/validate.nim index bd4257566..192236640 100644 --- a/nimbus/core/validate.nim +++ b/nimbus/core/validate.nim @@ -226,16 +226,18 @@ func gasCost*(tx: Transaction): UInt256 = proc validateTxBasic*( tx: Transaction; ## tx to validate - fork: EVMFork): Result[void, string] = + fork: EVMFork, + validateFork: bool = true): Result[void, string] = - if tx.txType == TxEip2930 and fork < FkBerlin: - return err("invalid tx: Eip2930 Tx type detected before Berlin") - - if tx.txType == TxEip1559 and fork < FkLondon: - return err("invalid tx: Eip1559 Tx type detected before London") - - if tx.txType == TxEip4844 and fork < FkCancun: - return err("invalid tx: Eip4844 Tx type detected before Cancun") + if validateFork: + if tx.txType == TxEip2930 and fork < FkBerlin: + return err("invalid tx: Eip2930 Tx type detected before Berlin") + + if tx.txType == TxEip1559 and fork < FkLondon: + return err("invalid tx: Eip1559 Tx type detected before London") + + if tx.txType == TxEip4844 and fork < FkCancun: + return err("invalid tx: Eip4844 Tx type detected before Cancun") if fork >= FkShanghai and tx.contractCreation and tx.payload.len > EIP3860_MAX_INITCODE_SIZE: return err("invalid tx: initcode size exceeds maximum") diff --git a/nimbus/rpc/engine_api.nim b/nimbus/rpc/engine_api.nim index b284d4866..5d0a0300f 100644 --- a/nimbus/rpc/engine_api.nim +++ b/nimbus/rpc/engine_api.nim @@ -15,7 +15,8 @@ import ../beacon/api_handler, ../beacon/beacon_engine, ../beacon/web3_eth_conv, - ../beacon/execution_types + ../beacon/execution_types, + ../beacon/api_handler/api_utils {.push raises: [].} @@ -50,17 +51,19 @@ proc setupEngineAPI*(engine: BeaconEngineRef, server: RpcServer) = return engine.newPayload(Version.V2, payload) server.rpc("engine_newPayloadV3") do(payload: ExecutionPayload, - expectedBlobVersionedHashes: seq[Web3Hash], - parentBeaconBlockRoot: Web3Hash) -> PayloadStatusV1: - if not validateVersionedHashed(payload, expectedBlobVersionedHashes): + expectedBlobVersionedHashes: Option[seq[Web3Hash]], + parentBeaconBlockRoot: Option[Web3Hash]) -> PayloadStatusV1: + if expectedBlobVersionedHashes.isNone: + raise invalidParams("newPayloadV3 expect blobVersionedHashes but got none") + if not validateVersionedHashed(payload, expectedBlobVersionedHashes.get): return invalidStatus() - return engine.newPayload(Version.V3, payload, some(parentBeaconBlockRoot)) + return engine.newPayload(Version.V3, payload, parentBeaconBlockRoot) server.rpc("engine_getPayloadV1") do(payloadId: PayloadID) -> ExecutionPayloadV1: - return engine.getPayload(payloadId).executionPayload.V1 + return engine.getPayload(Version.V1, payloadId).executionPayload.V1 server.rpc("engine_getPayloadV2") do(payloadId: PayloadID) -> GetPayloadV2Response: - return engine.getPayload(payloadId) + return engine.getPayload(Version.V2, payloadId) server.rpc("engine_getPayloadV3") do(payloadId: PayloadID) -> GetPayloadV3Response: return engine.getPayloadV3(payloadId)