More Engine API tests

This commit is contained in:
jangko 2023-11-01 18:09:49 +07:00
parent 682b160777
commit 69254e614f
No known key found for this signature in database
GPG Key ID: 31702AE10541E6B9
11 changed files with 306 additions and 288 deletions

View File

@ -10,17 +10,23 @@
import
std/strutils,
./engine_spec
chronicles,
./engine_spec,
../cancun/customizer
type
ForkchoiceStateField = enum
ForkchoiceStateField* = enum
HeadblockHash = "Head"
SafeblockHash = "Safe"
FinalizedblockHash = "Finalized"
type
InconsistentForkchoiceTest* = ref object of EngineSpec
field*: ForkchoiceStateField
field*: ForkchoiceStateField
Shadow = ref object
canon: seq[ExecutableData]
alt: seq[ExecutableData]
method withMainFork(cs: InconsistentForkchoiceTest, fork: EngineFork): BaseSpec =
var res = cs.clone()
@ -28,64 +34,67 @@ method withMainFork(cs: InconsistentForkchoiceTest, fork: EngineFork): BaseSpec
return res
method getName(cs: InconsistentForkchoiceTest): string =
return "Inconsistent %s in ForkchoiceState", cs.Field)
)
return "Inconsistent $1 in ForkchoiceState" % [$cs.field]
# Send an inconsistent ForkchoiceState with a known payload that belongs to a side chain as head, safe or finalized.
method execute(cs: InconsistentForkchoiceTest, env: TestEnv): bool =
# Wait until TTD is reached by this client
let ok = waitFor env.clMock.waitForTTD()
# Wait until TTD is reached by this client
let ok = waitFor env.clMock.waitForTTD()
testCond ok
shadow.canon = make([]*ExecutableData, 0)
shadow.alt = make([]*ExecutableData, 0)
# Produce blocks before starting the test
env.clMock.produceBlocks(3, BlockProcessCallbacks(
onGetPayload: proc(): bool =
# Generate and send an alternative side chain
customData = CustomPayloadData()
customData.ExtraData = &([]byte(0x01))
if len(shadow.alt) > 0 (
customData.parentHash = &shadow.alt[len(shadow.alt)-1].blockHash
)
alternativePayload, err = customData.CustomizePayload(env.clMock.latestPayloadBuilt)
if err != nil (
fatal "Unable to construct alternative payload: %v", t.TestName, err)
)
shadow.alt = append(shadow.alt, alternativePayload)
latestCanonicalPayload = env.clMock.latestPayloadBuilt
shadow.canon = append(shadow.canon, &latestCanonicalPayload)
var shadow = Shadow()
# Send the alternative payload
r = env.engine.client.newPayload(alternativePayload)
r.expectStatusEither(PayloadExecutionStatus.valid, test.Accepted)
),
))
# Send the invalid ForkchoiceStates
inconsistentFcU = ForkchoiceStateV1(
headblockHash: shadow.canon[len(shadow.alt)-1].blockHash,
safeblockHash: shadow.canon[len(shadow.alt)-2].blockHash,
finalizedblockHash: shadow.canon[len(shadow.alt)-3].blockHash,
)
switch cs.Field (
case HeadblockHash:
inconsistentFcU.headblockHash = shadow.alt[len(shadow.alt)-1].blockHash
case SafeblockHash:
inconsistentFcU.safeblockHash = shadow.alt[len(shadow.canon)-2].blockHash
case FinalizedblockHash:
inconsistentFcU.finalizedblockHash = shadow.alt[len(shadow.canon)-3].blockHash
)
r = env.engine.client.forkchoiceUpdated(inconsistentFcU, nil, env.clMock.latestPayloadBuilt.timestamp)
r.expectError()
# Produce blocks before starting the test
let pbRes = env.clMock.produceBlocks(3, BlockProcessCallbacks(
onGetPayload: proc(): bool =
# Generate and send an alternative side chain
var customData = CustomPayloadData(
extraData: some(@[0x01.byte])
)
# Return to the canonical chain
r = env.engine.client.forkchoiceUpdated(env.clMock.latestForkchoice, nil, env.clMock.latestPayloadBuilt.timestamp)
r.expectPayloadStatus(PayloadExecutionStatus.valid)
)
if shadow.alt.len > 0:
customData.parentHash = some(ethHash shadow.alt[^1].blockHash)
let altPayload = customData.customizePayload(env.clMock.latestExecutableData)
shadow.alt.add altPayload
shadow.canon.add env.clMock.latestExecutableData
# Send the alternative payload
let version = env.engine.version(altPayload.timestamp)
let r = env.engine.client.newPayload(version, altPayload)
r.expectStatusEither([PayloadExecutionStatus.valid, PayloadExecutionStatus.accepted])
return true
))
testCond pbRes
# Send the invalid ForkchoiceStates
var inconsistentFcU = ForkchoiceStateV1(
headblockHash: shadow.canon[len(shadow.alt)-1].blockHash,
safeblockHash: shadow.canon[len(shadow.alt)-2].blockHash,
finalizedblockHash: shadow.canon[len(shadow.alt)-3].blockHash,
)
case cs.field
of HeadblockHash:
inconsistentFcU.headblockHash = shadow.alt[len(shadow.alt)-1].blockHash
of SafeblockHash:
inconsistentFcU.safeblockHash = shadow.alt[len(shadow.canon)-2].blockHash
of FinalizedblockHash:
inconsistentFcU.finalizedblockHash = shadow.alt[len(shadow.canon)-3].blockHash
let version = env.engine.version(env.clMock.latestPayloadBuilt.timestamp)
var r = env.engine.client.forkchoiceUpdated(version, inconsistentFcU)
r.expectError()
# Return to the canonical chain
r = env.engine.client.forkchoiceUpdated(version, env.clMock.latestForkchoice)
r.expectPayloadStatus(PayloadExecutionStatus.valid)
return true
type
ForkchoiceUpdatedUnknownblockHashTest* = ref object of EngineSpec
field: ForkchoiceStateField
field*: ForkchoiceStateField
method withMainFork(cs: ForkchoiceUpdatedUnknownblockHashTest, fork: EngineFork): BaseSpec =
var res = cs.clone()
@ -93,77 +102,75 @@ method withMainFork(cs: ForkchoiceUpdatedUnknownblockHashTest, fork: EngineFork)
return res
method getName(cs: ForkchoiceUpdatedUnknownblockHashTest): string =
return "Unknown %sblockHash", cs.Field)
)
return "Unknown $1blockHash" % [$cs.field]
# Send an inconsistent ForkchoiceState with a known payload that belongs to a side chain as head, safe or finalized.
method execute(cs: ForkchoiceUpdatedUnknownblockHashTest, env: TestEnv): bool =
# Wait until TTD is reached by this client
let ok = waitFor env.clMock.waitForTTD()
# Wait until TTD is reached by this client
let ok = waitFor env.clMock.waitForTTD()
testCond ok
# Produce blocks before starting the test
env.clMock.produceBlocks(5, BlockProcessCallbacks())
# Produce blocks before starting the test
testCond env.clMock.produceBlocks(5, BlockProcessCallbacks())
# Generate a random block hash
randomblockHash = common.Hash256()
randomBytes(randomblockHash[:])
# Generate a random block hash
let randomblockHash = Web3Hash.randomBytes()
if cs.Field == HeadblockHash (
if cs.field == HeadblockHash:
let fcu = ForkchoiceStateV1(
headblockHash: randomblockHash,
safeblockHash: env.clMock.latestForkchoice.safeblockHash,
finalizedblockHash: env.clMock.latestForkchoice.finalizedblockHash,
)
forkchoiceStateUnknownHeadHash = ForkchoiceStateV1(
headblockHash: randomblockHash,
safeblockHash: env.clMock.latestForkchoice.safeblockHash,
finalizedblockHash: env.clMock.latestForkchoice.finalizedblockHash,
)
info "forkchoiceStateUnknownHeadHash",
head=fcu.headblockHash.short,
safe=fcu.safeblockHash.short,
final=fcu.finalizedblockHash.short
t.Logf("INFO (%v) forkchoiceStateUnknownHeadHash: %v\n", t.TestName, forkchoiceStateUnknownHeadHash)
# Execution specification::
# - (payloadStatus: (status: SYNCING, latestValidHash: null, validationError: null), payloadId: null)
# if forkchoiceState.headblockHash references an unknown payload or a payload that can't be validated
# because requisite data for the validation is missing
let version = env.engine.version(env.clMock.latestExecutedPayload.timestamp)
var r = env.engine.client.forkchoiceUpdated(version, fcu)
r.expectPayloadStatus(PayloadExecutionStatus.syncing)
# Execution specification::
# - (payloadStatus: (status: SYNCING, latestValidHash: null, validationError: null), payloadId: null)
# if forkchoiceState.headblockHash references an unknown payload or a payload that can't be validated
# because requisite data for the validation is missing
r = env.engine.client.forkchoiceUpdated(forkchoiceStateUnknownHeadHash, nil, env.clMock.latestExecutedPayload.timestamp)
r.expectPayloadStatus(PayloadExecutionStatus.syncing)
var payloadAttributes = env.clMock.latestPayloadAttributes
payloadAttributes.timestamp = w3Qty(payloadAttributes.timestamp, 1)
payloadAttributes = env.clMock.latestPayloadAttributes
payloadAttributes.timestamp += 1
# Test again using PayloadAttributes, should also return SYNCING and no PayloadID
r = env.engine.client.forkchoiceUpdated(version, fcu, some(payloadAttributes))
r.expectPayloadStatus(PayloadExecutionStatus.syncing)
r.expectPayloadID(none(PayloadID))
else:
let pbRes = env.clMock.produceSingleBlock(BlockProcessCallbacks(
# Run test after a new payload has been broadcast
onNewPayloadBroadcast: proc(): bool =
var fcu = ForkchoiceStateV1(
headblockHash: env.clMock.latestExecutedPayload.blockHash,
safeblockHash: env.clMock.latestForkchoice.safeblockHash,
finalizedblockHash: env.clMock.latestForkchoice.finalizedblockHash,
)
# Test again using PayloadAttributes, should also return SYNCING and no PayloadID
r = env.engine.client.forkchoiceUpdated(forkchoiceStateUnknownHeadHash,
&payloadAttributes, env.clMock.latestExecutedPayload.timestamp)
r.expectPayloadStatus(PayloadExecutionStatus.syncing)
r.ExpectPayloadID(nil)
else:
env.clMock.produceSingleBlock(BlockProcessCallbacks(
# Run test after a new payload has been broadcast
onNewPayloadBroadcast: proc(): bool =
if cs.field == SafeblockHash:
fcu.safeblockHash = randomblockHash
elif cs.field == FinalizedblockHash:
fcu.finalizedblockHash = randomblockHash
forkchoiceStateRandomHash = ForkchoiceStateV1(
headblockHash: env.clMock.latestExecutedPayload.blockHash,
safeblockHash: env.clMock.latestForkchoice.safeblockHash,
finalizedblockHash: env.clMock.latestForkchoice.finalizedblockHash,
)
let version = env.engine.version(env.clMock.latestExecutedPayload.timestamp)
var r = env.engine.client.forkchoiceUpdated(version, fcu)
r.expectError()
if cs.Field == SafeblockHash (
forkchoiceStateRandomHash.safeblockHash = randomblockHash
elif cs.Field == FinalizedblockHash (
forkchoiceStateRandomHash.finalizedblockHash = randomblockHash
)
var payloadAttributes = env.clMock.latestPayloadAttributes
payloadAttributes.prevRandao = w3Hash()
payloadAttributes.suggestedFeeRecipient = w3Address()
r = env.engine.client.forkchoiceUpdated(forkchoiceStateRandomHash, nil, env.clMock.latestExecutedPayload.timestamp)
r.expectError()
# Test again using PayloadAttributes, should also return INVALID and no PayloadID
r = env.engine.client.forkchoiceUpdated(version, fcu, some(payloadAttributes))
r.expectError()
return true
))
testCond pbRes
payloadAttributes = env.clMock.latestPayloadAttributes
payloadAttributes.Random = common.Hash256()
payloadAttributes.SuggestedFeeRecipient = common.Address()
# Test again using PayloadAttributes, should also return INVALID and no PayloadID
r = env.engine.client.forkchoiceUpdated(forkchoiceStateRandomHash,
&payloadAttributes, env.clMock.latestExecutedPayload.timestamp)
r.expectError()
),
))
)
)
return true

View File

@ -350,7 +350,7 @@ method execute(cs: NewPayloadOnSyncingClientTest, env: TestEnv): bool =
onGetPayload: proc(): bool =
# Send the new payload from the second client to the first, it won't be able to validate it
r = env.engine.client.newPayload(env.clMock.latestPayloadBuilt)
r.expectStatusEither(test.Accepted, PayloadExecutionStatus.syncing)
r.expectStatusEither(PayloadExecutionStatus.accepted, PayloadExecutionStatus.syncing)
r.expectLatestValidHash(nil)
# Send the forkchoiceUpdated with a reference to the valid payload on the SYNCING client.

View File

@ -10,11 +10,26 @@
import
std/strutils,
eth/common,
chronicles,
./engine_spec
type
PrevRandaoTransactionTest* = ref object of EngineSpec
blockCount int
blockCount*: int
Shadow = ref object
startBlockNumber: uint64
blockCount: int
currentTxIndex: int
txs: seq[Transaction]
proc checkPrevRandaoValue(client: RpcClient, expectedPrevRandao: common.Hash256, blockNumber: uint64): bool =
let storageKey = blockNumber.u256
let r = client.storageAt(prevRandaoContractAddr, storageKey)
let expected = UInt256.fromBytesBE(expectedPrevRandao.data)
r.expectStorageEqual(expected)
return true
method withMainFork(cs: PrevRandaoTransactionTest, fork: EngineFork): BaseSpec =
var res = cs.clone()
@ -22,66 +37,56 @@ method withMainFork(cs: PrevRandaoTransactionTest, fork: EngineFork): BaseSpec =
return res
method getName(cs: PrevRandaoTransactionTest): string =
return "PrevRandao Opcode Transactions Test (%s)", cs.txType)
)
"PrevRandao Opcode Transactions Test ($1)" % [$cs.txType]
method execute(cs: PrevRandaoTransactionTest, env: TestEnv): bool =
let ok = waitFor env.clMock.waitForTTD()
testCond ok
# Create a single block to not having to build on top of genesis
env.clMock.produceSingleBlock(BlockProcessCallbacks())
testCond env.clMock.produceSingleBlock(BlockProcessCallbacks())
startBlockNumber = env.clMock.latestHeader.blockNumber.Uint64() + 1
var shadow = Shadow(
startBlockNumber: env.clMock.latestHeader.blockNumber.truncate(uint64) + 1,
# Send transactions in PoS, the value of the storage in these blocks must match the prevRandao value
blockCount: 10,
currentTxIndex: 0,
)
# Send transactions in PoS, the value of the storage in these blocks must match the prevRandao value
var (
blockCount = 10
currentTxIndex = 0
txs = make([]typ.Transaction, 0)
)
if cs.blockCount > 0 (
blockCount = cs.blockCount
)
env.clMock.produceBlocks(blockCount, BlockProcessCallbacks(
if cs.blockCount > 0:
shadow.blockCount = cs.blockCount
let pbRes = env.clMock.produceBlocks(shadow.blockCount, BlockProcessCallbacks(
onPayloadProducerSelected: proc(): bool =
tx, err = env.sendNextTx(
t.TestContext,
t.Engine,
&BaseTx(
recipient: prevRandaoContractAddr,
amount: big0,
payload: nil,
txType: cs.txType,
gasLimit: 75000,
),
let tc = BaseTx(
recipient: some(prevRandaoContractAddr),
amount: 0.u256,
txType: cs.txType,
gasLimit: 75000,
)
if err != nil (
fatal "Error trying to send transaction: %v", t.TestName, err)
)
txs = append(txs, tx)
currentTxIndex++
),
let tx = env.makeNextTx(tc)
let ok = env.sendTx(tx)
testCond ok:
fatal "Error trying to send transaction"
shadow.txs.add(tx)
inc shadow.currentTxIndex
return true
,
onForkchoiceBroadcast: proc(): bool =
# Check the transaction tracing, which is client specific
expectedPrevRandao = env.clMock.prevRandaoHistory[env.clMock.latestHeader.blockNumber.Uint64()+1]
ctx, cancel = context.WithTimeout(t.TestContext, globals.RPCTimeout)
defer cancel()
if err = DebugPrevRandaoTransaction(ctx, t.Client.RPC(), t.Client.Type, txs[currentTxIndex-1],
&expectedPrevRandao); err != nil (
fatal "Error during transaction tracing: %v", t.TestName, err)
)
),
let expectedPrevRandao = env.clMock.prevRandaoHistory[env.clMock.latestHeader.blockNumber.truncate(uint64)+1]
let res = debugPrevRandaoTransaction(env.engine.client, shadow.txs[shadow.currentTxIndex-1], expectedPrevRandao)
testCond res.isOk:
fatal "Error during transaction tracing", msg=res.error
return true
))
testCond pbRes
for i = uint64(startBlockNumber); i <= env.clMock.latestExecutedPayload.blockNumber; i++ (
checkPrevRandaoValue(t, env.clMock.prevRandaoHistory[i], i)
)
)
for i in shadow.startBlockNumber..env.clMock.latestExecutedPayload.blockNumber.uint64:
if not checkPrevRandaoValue(env.engine.client, env.clMock.prevRandaoHistory[i], i):
fatal "wrong prev randao", index=i
return false
func checkPrevRandaoValue(t *test.Env, expectedPrevRandao common.Hash, blockNumber uint64) (
storageKey = common.Hash256()
storageKey[31] = byte(blockNumber)
r = env.engine.client.TestStorageAt(globals.PrevRandaoContractAddr, storageKey, nil)
r.ExpectStorageEqual(expectedPrevRandao)
)
return true

View File

@ -603,7 +603,7 @@ method execute(cs: ReOrgBackFromSyncingTest, env: TestEnv): bool =
# Re-org to the unavailable sidechain in the middle of block production
# to be able to re-org back to the canonical chain
r = env.engine.client.newPayload(sidechainPayloads[len(sidechainPayloads)-1])
r.expectStatusEither(PayloadExecutionStatus.syncing, test.Accepted)
r.expectStatusEither(PayloadExecutionStatus.syncing, PayloadExecutionStatus.accepted)
r.expectLatestValidHash(nil)
# We are going to send one of the alternative payloads and fcU to it
forkchoiceUpdatedBack = api.ForkchoiceStateV1(
@ -805,7 +805,7 @@ method execute(cs: SafeReOrgToSideChainTest, env: TestEnv): bool =
onGetpayload: proc(): bool =
for _, p = range sidechainPayloads (
r = env.engine.client.newPayload(p)
r.expectStatusEither(PayloadExecutionStatus.valid, test.Accepted)
r.expectStatusEither(PayloadExecutionStatus.valid, PayloadExecutionStatus.accepted)
)
r = env.engine.client.forkchoiceUpdated(api.ForkchoiceStateV1(
headBlockHash: sidechainPayloads[1].blockHash,

View File

@ -13,7 +13,7 @@ import
./engine_spec
type
BlockStatusRPCcheckType = enum
BlockStatusRPCcheckType* = enum
LatestOnNewPayload = "Latest Block on NewPayload"
LatestOnHeadblockHash = "Latest Block on HeadblockHash Update"
SafeOnSafeblockHash = "Safe Block on SafeblockHash Update"
@ -21,7 +21,7 @@ type
type
BlockStatus* = ref object of EngineSpec
checkType: BlockStatusRPCcheckType
checkType*: BlockStatusRPCcheckType
# TODO: Syncing bool
method withMainFork(cs: BlockStatus, fork: EngineFork): BaseSpec =
@ -46,7 +46,7 @@ method execute(cs: BlockStatus, env: TestEnv): bool =
else:
number = Finalized
p = env.engine.client.TestHeaderByNumber(number)
p = env.engine.client.headerByNumber(number)
p.expectError()
)
@ -59,22 +59,19 @@ method execute(cs: BlockStatus, env: TestEnv): bool =
let tc = BaseTx(
recipient: &ZeroAddr,
amount: 1.u256,
payload: nil,
txType: cs.txType,
gasLimit: 75000,
ForkConfig: t.ForkConfig,
),
tx, err = env.sendNextTx(
)
if err != nil (
let ok = env.sendNextTx(tc)
testCond ok:
fatal "Error trying to send transaction: %v", err)
)
),
)
switch b.checkType (
case LatestOnNewPayload:
case b.checkType (
of LatestOnNewPayload:
callbacks.onGetPayload = proc(): bool
r = env.engine.client.latestHeader()
r.expectHash(env.clMock.latestForkchoice.headblockHash)
@ -88,27 +85,22 @@ method execute(cs: BlockStatus, env: TestEnv): bool =
# Check that the receipt for the transaction we just sent is still not available
q = env.engine.client.txReceipt(tx.Hash())
q.expectError()
)
case LatestOnHeadblockHash:
of LatestOnHeadblockHash:
callbacks.onForkchoiceBroadcast = proc(): bool
r = env.engine.client.latestHeader()
r.expectHash(env.clMock.latestForkchoice.headblockHash)
s = env.engine.client.txReceipt(tx.Hash())
s.ExpectTransactionHash(tx.Hash())
)
case SafeOnSafeblockHash:
of SafeOnSafeblockHash:
callbacks.onSafeBlockChange = proc(): bool
r = env.engine.client.TestHeaderByNumber(Safe)
r = env.engine.client.headerByNumber(Safe)
r.expectHash(env.clMock.latestForkchoice.safeblockHash)
)
case FinalizedOnFinalizedblockHash:
of FinalizedOnFinalizedblockHash:
callbacks.onFinalizedBlockChange = proc(): bool
r = env.engine.client.TestHeaderByNumber(Finalized)
r = env.engine.client.headerByNumber(Finalized)
r.expectHash(env.clMock.latestForkchoice.finalizedblockHash)
)
)
# Perform the test
env.clMock.produceSingleBlock(callbacks)
)

View File

@ -10,11 +10,13 @@
import
std/strutils,
./engine_spec
chronicles,
./engine_spec,
../../../../nimbus/transaction
type
SuggestedFeeRecipientTest* = ref object of EngineSpec
transactionCount: int
transactionCount*: int
method withMainFork(cs: SuggestedFeeRecipientTest, fork: EngineFork): BaseSpec =
var res = cs.clone()
@ -38,54 +40,55 @@ method execute(cs: SuggestedFeeRecipientTest, env: TestEnv): bool =
txRecipient = EthAddress.randomBytes()
# Send multiple transactions
for i = 0; i < cs.transactionCount; i++ (
_, err = env.sendNextTx(
t.TestContext,
t.Engine,
&BaseTx(
recipient: &txRecipient,
amount: big0,
payload: nil,
txType: cs.txType,
gasLimit: 75000,
),
for i in 0..<cs.transactionCount:
let tc = BaseTx(
recipient: some(txRecipient),
amount: 0.u256,
txType: cs.txType,
gasLimit: 75000,
)
if err != nil (
fatal "Error trying to send transaction: %v", t.TestName, err)
)
)
let ok = env.sendNextTx(env.engine, tc)
testCond ok:
fatal "Error trying to send transaction"
# Produce the next block with the fee recipient set
env.clMock.nextFeeRecipient = feeRecipient
env.clMock.produceSingleBlock(BlockProcessCallbacks())
testCond env.clMock.produceSingleBlock(BlockProcessCallbacks())
# Calculate the fees and check that they match the balance of the fee recipient
r = env.engine.client.TestBlockByNumber(Head)
r.ExpecttransactionCountEqual(cs.transactionCount)
r.ExpectCoinbase(feeRecipient)
blockIncluded = r.Block
let r = env.engine.client.latestblock()
testCond r.isOk:
error "cannot get latest header", msg=r.error
feeRecipientFees = big.NewInt(0)
for _, tx = range blockIncluded.Transactions() (
effGasTip, err = tx.EffectiveGasTip(blockIncluded.BaseFee())
if err != nil (
fatal "unable to obtain EffectiveGasTip: %v", t.TestName, err)
)
ctx, cancel = context.WithTimeout(t.TestContext, globals.RPCTimeout)
defer cancel()
receipt, err = t.Eth.TransactionReceipt(ctx, tx.Hash())
if err != nil (
fatal "unable to obtain receipt: %v", t.TestName, err)
)
feeRecipientFees = feeRecipientFees.Add(feeRecipientFees, effGasTip.Mul(effGasTip, big.NewInt(int64(receipt.GasUsed))))
)
let blockIncluded = r.get
s = env.engine.client.TestBalanceAt(feeRecipient, nil)
testCond blockIncluded.txs.len == cs.transactionCount:
error "expect transactions", get=blockIncluded.txs.len, expect=cs.transactionCount
testCond feeRecipient == blockIncluded.header.coinbase:
error "expect coinbase",
get=blockIncluded.header.coinbase,
expect=feeRecipient
var feeRecipientFees = 0.u256
for tx in blockIncluded.txs:
let effGasTip = tx.effectiveGasTip(blockIncluded.header.fee)
let r = env.engine.client.txReceipt(tx.rlpHash)
testCond r.isOk:
fatal "unable to obtain receipt", msg=r.error
let receipt = r.get
feeRecipientFees = feeRecipientFees + effGasTip.u256 * receipt.gasUsed.u256
var s = env.engine.client.balanceAt(feeRecipient)
s.expectBalanceEqual(feeRecipientFees)
# Produce another block without txns and get the balance again
env.clMock.nextFeeRecipient = feeRecipient
env.clMock.produceSingleBlock(BlockProcessCallbacks())
testCond env.clMock.produceSingleBlock(BlockProcessCallbacks())
s = env.engine.client.TestBalanceAt(feeRecipient, nil)
s = env.engine.client.balanceAt(feeRecipient)
s.expectBalanceEqual(feeRecipientFees)
)
return true

View File

@ -437,16 +437,18 @@ proc latestHeader*(client: RpcClient): Result[common.BlockHeader, string] =
return err("failed to get latest blockHeader")
return ok(res.get.toBlockHeader)
proc latestBlock*(client: RpcClient, output: var common.EthBlock): Result[void, string] =
proc latestBlock*(client: RpcClient): Result[common.EthBlock, string] =
wrapTry:
let res = waitFor client.eth_getBlockByNumber("latest", true)
if res.isNone:
return err("failed to get latest blockHeader")
let blk = res.get()
output.header = toBlockHeader(blk)
output.txs = toTransactions(blk.transactions)
output.withdrawals = toWithdrawals(blk.withdrawals)
return ok()
let output = EthBlock(
header: toBlockHeader(blk),
txs: toTransactions(blk.transactions),
withdrawals: toWithdrawals(blk.withdrawals),
)
return ok(output)
proc namedHeader*(client: RpcClient, name: string): Result[common.BlockHeader, string] =
wrapTry:

View File

@ -18,11 +18,20 @@ import
../../nimbus/common/chain_config
import
./engine/misc,
./engine/suggested_fee_recipient,
./engine/payload_attributes,
#./engine/payload_execution,
./engine/invalid_ancestor,
./engine/invalid_payload,
./engine/bad_hash
./engine/prev_randao,
#./engine/payload_id,
./engine/forkchoice,
#./engine/versioning,
./engine/bad_hash,
#./engine/fork_id,
#./engine/reorg,
./engine/misc
#./engine/rpc
proc getGenesis(cs: EngineSpec, param: NetworkParams) =
# Set the terminal total difficulty
@ -160,7 +169,48 @@ proc makeEngineTest*(): seq[EngineSpec] =
invalidField: InvalidStateRoot,
)
#[
const forkchoiceStateField = [
HeadBlockHash,
SafeBlockHash,
FinalizedBlockHash,
]
# Register ForkchoiceUpdate tests
for field in forkchoiceStateField:
result.add InconsistentForkchoiceTest(field: field)
result.add ForkchoiceUpdatedUnknownBlockHashTest(field: field)
# PrevRandao opcode tests
result.add PrevRandaoTransactionTest(
txType: some(TxLegacy)
)
result.add PrevRandaoTransactionTest(
txType: some(TxEip1559),
)
# Suggested Fee Recipient Tests
result.add SuggestedFeeRecipientTest(
txType: some(TxLegacy),
transactionCount: 20,
)
result.add SuggestedFeeRecipientTest(
txType: some(TxEip1559),
transactionCount: 20,
)
# Register RPC tests
#[let blockStatusRPCCheckType = [
LatestOnNewPayload,
LatestOnHeadBlockHash,
SafeOnSafeBlockHash,
FinalizedOnFinalizedBlockHash,
]
for field in blockStatusRPCCheckType:
result.add BlockStatus(checkType: field)
const
invalidReorgList = [
InvalidStateRoot,
@ -215,32 +265,6 @@ proc makeEngineTest*(): seq[EngineSpec] =
)
]#
#[
# Register RPC tests
for _, field := range []BlockStatusRPCCheckType(
LatestOnNewPayload,
LatestOnHeadBlockHash,
SafeOnSafeBlockHash,
FinalizedOnFinalizedBlockHash,
) (
result.add BlockStatus(CheckType: field))
)
# Register ForkchoiceUpdate tests
for _, field := range []ForkchoiceStateField(
HeadBlockHash,
SafeBlockHash,
FinalizedBlockHash,
) (
result.add
InconsistentForkchoiceTest(
Field: field,
),
ForkchoiceUpdatedUnknownBlockHashTest(
Field: field,
),
)
)
# Payload ID Tests
for _, payloadAttributeFieldChange := range []PayloadAttributesFieldChange(
PayloadAttributesIncreaseTimestamp,
@ -399,36 +423,6 @@ proc makeEngineTest*(): seq[EngineSpec] =
),
)
# Suggested Fee Recipient Tests
result.add
SuggestedFeeRecipientTest(
BaseSpec: test.BaseSpec(
txType: some( TxLegacy,
),
TransactionCount: 20,
),
SuggestedFeeRecipientTest(
BaseSpec: test.BaseSpec(
txType: some( TxEip1559,
),
TransactionCount: 20,
),
)
# PrevRandao opcode tests
result.add
PrevRandaoTransactionTest(
BaseSpec: test.BaseSpec(
txType: some( TxLegacy,
),
),
PrevRandaoTransactionTest(
BaseSpec: test.BaseSpec(
txType: some( TxEip1559,
),
),
)
# Fork ID Tests
for genesisTimestamp := uint64(0); genesisTimestamp <= 1; genesisTimestamp++ (
for forkTime := uint64(0); forkTime <= 2; forkTime++ (

View File

@ -127,6 +127,9 @@ proc makeTxs*(env: TestEnv, tc: BaseTx, num: int): seq[Transaction] =
for _ in 0..<num:
result.add env.sender.makeNextTx(tc)
proc makeNextTx*(env: TestEnv, tc: BaseTx): Transaction =
env.sender.makeNextTx(tc)
proc sendNextTx*(env: TestEnv, eng: EngineEnv, tc: BaseTx): bool =
env.sender.sendNextTx(eng.client, tc)

View File

@ -228,6 +228,18 @@ template expectHash*(res: untyped, hash: common.Hash256) =
testCond s.blockHash == hash:
error "Unexpected expectHash", expect=hash.short, get=s.blockHash.short
template expectStorageEqual*(res: untyped, expectedValue: UInt256) =
testCond res.isOk:
error "expectStorageEqual", msg=res.error
testCond res.get == expectedValue:
error "invalid storage", get=res.get, expect=expectedValue
template expectBalanceEqual*(res: untyped, expectedBalance: UInt256) =
testCond res.isOk:
error "expectBalanceEqual", msg=res.error
testCond res.get == expectedBalance:
error "invalid balance", expect=expectedBalance, get=res.get
func timestamp*(x: ExecutableData): auto =
x.basePayload.timestamp

View File

@ -26,9 +26,9 @@ proc execute*(ws: BlockValueSpec, env: TestEnv): bool =
testCond WDBaseSpec(ws).execute(env)
# Get the latest block and the transactions included
var blk: EthBlock
let b = env.client.latestBlock(blk)
let b = env.client.latestBlock()
b.expectNoError()
let blk = b.get
var totalValue: UInt256
testCond blk.txs.len > 0: