More Engine API tests
This commit is contained in:
parent
682b160777
commit
69254e614f
|
@ -10,10 +10,12 @@
|
||||||
|
|
||||||
import
|
import
|
||||||
std/strutils,
|
std/strutils,
|
||||||
./engine_spec
|
chronicles,
|
||||||
|
./engine_spec,
|
||||||
|
../cancun/customizer
|
||||||
|
|
||||||
type
|
type
|
||||||
ForkchoiceStateField = enum
|
ForkchoiceStateField* = enum
|
||||||
HeadblockHash = "Head"
|
HeadblockHash = "Head"
|
||||||
SafeblockHash = "Safe"
|
SafeblockHash = "Safe"
|
||||||
FinalizedblockHash = "Finalized"
|
FinalizedblockHash = "Finalized"
|
||||||
|
@ -22,14 +24,17 @@ type
|
||||||
InconsistentForkchoiceTest* = ref object of EngineSpec
|
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 =
|
method withMainFork(cs: InconsistentForkchoiceTest, fork: EngineFork): BaseSpec =
|
||||||
var res = cs.clone()
|
var res = cs.clone()
|
||||||
res.mainFork = fork
|
res.mainFork = fork
|
||||||
return res
|
return res
|
||||||
|
|
||||||
method getName(cs: InconsistentForkchoiceTest): string =
|
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.
|
# 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 =
|
method execute(cs: InconsistentForkchoiceTest, env: TestEnv): bool =
|
||||||
|
@ -37,55 +42,59 @@ method execute(cs: InconsistentForkchoiceTest, env: TestEnv): bool =
|
||||||
let ok = waitFor env.clMock.waitForTTD()
|
let ok = waitFor env.clMock.waitForTTD()
|
||||||
testCond ok
|
testCond ok
|
||||||
|
|
||||||
shadow.canon = make([]*ExecutableData, 0)
|
var shadow = Shadow()
|
||||||
shadow.alt = make([]*ExecutableData, 0)
|
|
||||||
# Produce blocks before starting the test
|
# Produce blocks before starting the test
|
||||||
env.clMock.produceBlocks(3, BlockProcessCallbacks(
|
let pbRes = env.clMock.produceBlocks(3, BlockProcessCallbacks(
|
||||||
onGetPayload: proc(): bool =
|
onGetPayload: proc(): bool =
|
||||||
# Generate and send an alternative side chain
|
# Generate and send an alternative side chain
|
||||||
customData = CustomPayloadData()
|
var customData = CustomPayloadData(
|
||||||
customData.ExtraData = &([]byte(0x01))
|
extraData: some(@[0x01.byte])
|
||||||
if len(shadow.alt) > 0 (
|
|
||||||
customData.parentHash = &shadow.alt[len(shadow.alt)-1].blockHash
|
|
||||||
)
|
)
|
||||||
alternativePayload, err = customData.CustomizePayload(env.clMock.latestPayloadBuilt)
|
|
||||||
if err != nil (
|
if shadow.alt.len > 0:
|
||||||
fatal "Unable to construct alternative payload: %v", t.TestName, err)
|
customData.parentHash = some(ethHash shadow.alt[^1].blockHash)
|
||||||
)
|
|
||||||
shadow.alt = append(shadow.alt, alternativePayload)
|
let altPayload = customData.customizePayload(env.clMock.latestExecutableData)
|
||||||
latestCanonicalPayload = env.clMock.latestPayloadBuilt
|
shadow.alt.add altPayload
|
||||||
shadow.canon = append(shadow.canon, &latestCanonicalPayload)
|
shadow.canon.add env.clMock.latestExecutableData
|
||||||
|
|
||||||
# Send the alternative payload
|
# Send the alternative payload
|
||||||
r = env.engine.client.newPayload(alternativePayload)
|
let version = env.engine.version(altPayload.timestamp)
|
||||||
r.expectStatusEither(PayloadExecutionStatus.valid, test.Accepted)
|
let r = env.engine.client.newPayload(version, altPayload)
|
||||||
),
|
r.expectStatusEither([PayloadExecutionStatus.valid, PayloadExecutionStatus.accepted])
|
||||||
|
return true
|
||||||
))
|
))
|
||||||
|
|
||||||
|
testCond pbRes
|
||||||
|
|
||||||
# Send the invalid ForkchoiceStates
|
# Send the invalid ForkchoiceStates
|
||||||
inconsistentFcU = ForkchoiceStateV1(
|
var inconsistentFcU = ForkchoiceStateV1(
|
||||||
headblockHash: shadow.canon[len(shadow.alt)-1].blockHash,
|
headblockHash: shadow.canon[len(shadow.alt)-1].blockHash,
|
||||||
safeblockHash: shadow.canon[len(shadow.alt)-2].blockHash,
|
safeblockHash: shadow.canon[len(shadow.alt)-2].blockHash,
|
||||||
finalizedblockHash: shadow.canon[len(shadow.alt)-3].blockHash,
|
finalizedblockHash: shadow.canon[len(shadow.alt)-3].blockHash,
|
||||||
)
|
)
|
||||||
switch cs.Field (
|
|
||||||
case HeadblockHash:
|
case cs.field
|
||||||
|
of HeadblockHash:
|
||||||
inconsistentFcU.headblockHash = shadow.alt[len(shadow.alt)-1].blockHash
|
inconsistentFcU.headblockHash = shadow.alt[len(shadow.alt)-1].blockHash
|
||||||
case SafeblockHash:
|
of SafeblockHash:
|
||||||
inconsistentFcU.safeblockHash = shadow.alt[len(shadow.canon)-2].blockHash
|
inconsistentFcU.safeblockHash = shadow.alt[len(shadow.canon)-2].blockHash
|
||||||
case FinalizedblockHash:
|
of FinalizedblockHash:
|
||||||
inconsistentFcU.finalizedblockHash = shadow.alt[len(shadow.canon)-3].blockHash
|
inconsistentFcU.finalizedblockHash = shadow.alt[len(shadow.canon)-3].blockHash
|
||||||
)
|
|
||||||
r = env.engine.client.forkchoiceUpdated(inconsistentFcU, nil, env.clMock.latestPayloadBuilt.timestamp)
|
let version = env.engine.version(env.clMock.latestPayloadBuilt.timestamp)
|
||||||
|
var r = env.engine.client.forkchoiceUpdated(version, inconsistentFcU)
|
||||||
r.expectError()
|
r.expectError()
|
||||||
|
|
||||||
# Return to the canonical chain
|
# Return to the canonical chain
|
||||||
r = env.engine.client.forkchoiceUpdated(env.clMock.latestForkchoice, nil, env.clMock.latestPayloadBuilt.timestamp)
|
r = env.engine.client.forkchoiceUpdated(version, env.clMock.latestForkchoice)
|
||||||
r.expectPayloadStatus(PayloadExecutionStatus.valid)
|
r.expectPayloadStatus(PayloadExecutionStatus.valid)
|
||||||
)
|
return true
|
||||||
|
|
||||||
type
|
type
|
||||||
ForkchoiceUpdatedUnknownblockHashTest* = ref object of EngineSpec
|
ForkchoiceUpdatedUnknownblockHashTest* = ref object of EngineSpec
|
||||||
field: ForkchoiceStateField
|
field*: ForkchoiceStateField
|
||||||
|
|
||||||
method withMainFork(cs: ForkchoiceUpdatedUnknownblockHashTest, fork: EngineFork): BaseSpec =
|
method withMainFork(cs: ForkchoiceUpdatedUnknownblockHashTest, fork: EngineFork): BaseSpec =
|
||||||
var res = cs.clone()
|
var res = cs.clone()
|
||||||
|
@ -93,8 +102,7 @@ method withMainFork(cs: ForkchoiceUpdatedUnknownblockHashTest, fork: EngineFork)
|
||||||
return res
|
return res
|
||||||
|
|
||||||
method getName(cs: ForkchoiceUpdatedUnknownblockHashTest): string =
|
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.
|
# 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 =
|
method execute(cs: ForkchoiceUpdatedUnknownblockHashTest, env: TestEnv): bool =
|
||||||
|
@ -103,67 +111,66 @@ method execute(cs: ForkchoiceUpdatedUnknownblockHashTest, env: TestEnv): bool =
|
||||||
testCond ok
|
testCond ok
|
||||||
|
|
||||||
# Produce blocks before starting the test
|
# Produce blocks before starting the test
|
||||||
env.clMock.produceBlocks(5, BlockProcessCallbacks())
|
testCond env.clMock.produceBlocks(5, BlockProcessCallbacks())
|
||||||
|
|
||||||
# Generate a random block hash
|
# Generate a random block hash
|
||||||
randomblockHash = common.Hash256()
|
let randomblockHash = Web3Hash.randomBytes()
|
||||||
randomBytes(randomblockHash[:])
|
|
||||||
|
|
||||||
if cs.Field == HeadblockHash (
|
if cs.field == HeadblockHash:
|
||||||
|
let fcu = ForkchoiceStateV1(
|
||||||
forkchoiceStateUnknownHeadHash = ForkchoiceStateV1(
|
|
||||||
headblockHash: randomblockHash,
|
headblockHash: randomblockHash,
|
||||||
safeblockHash: env.clMock.latestForkchoice.safeblockHash,
|
safeblockHash: env.clMock.latestForkchoice.safeblockHash,
|
||||||
finalizedblockHash: env.clMock.latestForkchoice.finalizedblockHash,
|
finalizedblockHash: env.clMock.latestForkchoice.finalizedblockHash,
|
||||||
)
|
)
|
||||||
|
|
||||||
t.Logf("INFO (%v) forkchoiceStateUnknownHeadHash: %v\n", t.TestName, forkchoiceStateUnknownHeadHash)
|
info "forkchoiceStateUnknownHeadHash",
|
||||||
|
head=fcu.headblockHash.short,
|
||||||
|
safe=fcu.safeblockHash.short,
|
||||||
|
final=fcu.finalizedblockHash.short
|
||||||
|
|
||||||
# Execution specification::
|
# Execution specification::
|
||||||
# - (payloadStatus: (status: SYNCING, latestValidHash: null, validationError: null), payloadId: null)
|
# - (payloadStatus: (status: SYNCING, latestValidHash: null, validationError: null), payloadId: null)
|
||||||
# if forkchoiceState.headblockHash references an unknown payload or a payload that can't be validated
|
# if forkchoiceState.headblockHash references an unknown payload or a payload that can't be validated
|
||||||
# because requisite data for the validation is missing
|
# because requisite data for the validation is missing
|
||||||
r = env.engine.client.forkchoiceUpdated(forkchoiceStateUnknownHeadHash, nil, env.clMock.latestExecutedPayload.timestamp)
|
let version = env.engine.version(env.clMock.latestExecutedPayload.timestamp)
|
||||||
|
var r = env.engine.client.forkchoiceUpdated(version, fcu)
|
||||||
r.expectPayloadStatus(PayloadExecutionStatus.syncing)
|
r.expectPayloadStatus(PayloadExecutionStatus.syncing)
|
||||||
|
|
||||||
payloadAttributes = env.clMock.latestPayloadAttributes
|
var payloadAttributes = env.clMock.latestPayloadAttributes
|
||||||
payloadAttributes.timestamp += 1
|
payloadAttributes.timestamp = w3Qty(payloadAttributes.timestamp, 1)
|
||||||
|
|
||||||
# Test again using PayloadAttributes, should also return SYNCING and no PayloadID
|
# Test again using PayloadAttributes, should also return SYNCING and no PayloadID
|
||||||
r = env.engine.client.forkchoiceUpdated(forkchoiceStateUnknownHeadHash,
|
r = env.engine.client.forkchoiceUpdated(version, fcu, some(payloadAttributes))
|
||||||
&payloadAttributes, env.clMock.latestExecutedPayload.timestamp)
|
|
||||||
r.expectPayloadStatus(PayloadExecutionStatus.syncing)
|
r.expectPayloadStatus(PayloadExecutionStatus.syncing)
|
||||||
r.ExpectPayloadID(nil)
|
r.expectPayloadID(none(PayloadID))
|
||||||
else:
|
else:
|
||||||
env.clMock.produceSingleBlock(BlockProcessCallbacks(
|
let pbRes = env.clMock.produceSingleBlock(BlockProcessCallbacks(
|
||||||
# Run test after a new payload has been broadcast
|
# Run test after a new payload has been broadcast
|
||||||
onNewPayloadBroadcast: proc(): bool =
|
onNewPayloadBroadcast: proc(): bool =
|
||||||
|
var fcu = ForkchoiceStateV1(
|
||||||
forkchoiceStateRandomHash = ForkchoiceStateV1(
|
|
||||||
headblockHash: env.clMock.latestExecutedPayload.blockHash,
|
headblockHash: env.clMock.latestExecutedPayload.blockHash,
|
||||||
safeblockHash: env.clMock.latestForkchoice.safeblockHash,
|
safeblockHash: env.clMock.latestForkchoice.safeblockHash,
|
||||||
finalizedblockHash: env.clMock.latestForkchoice.finalizedblockHash,
|
finalizedblockHash: env.clMock.latestForkchoice.finalizedblockHash,
|
||||||
)
|
)
|
||||||
|
|
||||||
if cs.Field == SafeblockHash (
|
if cs.field == SafeblockHash:
|
||||||
forkchoiceStateRandomHash.safeblockHash = randomblockHash
|
fcu.safeblockHash = randomblockHash
|
||||||
elif cs.Field == FinalizedblockHash (
|
elif cs.field == FinalizedblockHash:
|
||||||
forkchoiceStateRandomHash.finalizedblockHash = randomblockHash
|
fcu.finalizedblockHash = randomblockHash
|
||||||
)
|
|
||||||
|
|
||||||
r = env.engine.client.forkchoiceUpdated(forkchoiceStateRandomHash, nil, env.clMock.latestExecutedPayload.timestamp)
|
let version = env.engine.version(env.clMock.latestExecutedPayload.timestamp)
|
||||||
|
var r = env.engine.client.forkchoiceUpdated(version, fcu)
|
||||||
r.expectError()
|
r.expectError()
|
||||||
|
|
||||||
payloadAttributes = env.clMock.latestPayloadAttributes
|
var payloadAttributes = env.clMock.latestPayloadAttributes
|
||||||
payloadAttributes.Random = common.Hash256()
|
payloadAttributes.prevRandao = w3Hash()
|
||||||
payloadAttributes.SuggestedFeeRecipient = common.Address()
|
payloadAttributes.suggestedFeeRecipient = w3Address()
|
||||||
|
|
||||||
# Test again using PayloadAttributes, should also return INVALID and no PayloadID
|
# Test again using PayloadAttributes, should also return INVALID and no PayloadID
|
||||||
r = env.engine.client.forkchoiceUpdated(forkchoiceStateRandomHash,
|
r = env.engine.client.forkchoiceUpdated(version, fcu, some(payloadAttributes))
|
||||||
&payloadAttributes, env.clMock.latestExecutedPayload.timestamp)
|
|
||||||
r.expectError()
|
r.expectError()
|
||||||
|
return true
|
||||||
),
|
|
||||||
))
|
))
|
||||||
)
|
testCond pbRes
|
||||||
)
|
|
||||||
|
return true
|
||||||
|
|
|
@ -350,7 +350,7 @@ method execute(cs: NewPayloadOnSyncingClientTest, env: TestEnv): bool =
|
||||||
onGetPayload: proc(): bool =
|
onGetPayload: proc(): bool =
|
||||||
# Send the new payload from the second client to the first, it won't be able to validate it
|
# 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 = env.engine.client.newPayload(env.clMock.latestPayloadBuilt)
|
||||||
r.expectStatusEither(test.Accepted, PayloadExecutionStatus.syncing)
|
r.expectStatusEither(PayloadExecutionStatus.accepted, PayloadExecutionStatus.syncing)
|
||||||
r.expectLatestValidHash(nil)
|
r.expectLatestValidHash(nil)
|
||||||
|
|
||||||
# Send the forkchoiceUpdated with a reference to the valid payload on the SYNCING client.
|
# Send the forkchoiceUpdated with a reference to the valid payload on the SYNCING client.
|
||||||
|
|
|
@ -10,11 +10,26 @@
|
||||||
|
|
||||||
import
|
import
|
||||||
std/strutils,
|
std/strutils,
|
||||||
|
eth/common,
|
||||||
|
chronicles,
|
||||||
./engine_spec
|
./engine_spec
|
||||||
|
|
||||||
type
|
type
|
||||||
PrevRandaoTransactionTest* = ref object of EngineSpec
|
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 =
|
method withMainFork(cs: PrevRandaoTransactionTest, fork: EngineFork): BaseSpec =
|
||||||
var res = cs.clone()
|
var res = cs.clone()
|
||||||
|
@ -22,66 +37,56 @@ method withMainFork(cs: PrevRandaoTransactionTest, fork: EngineFork): BaseSpec =
|
||||||
return res
|
return res
|
||||||
|
|
||||||
method getName(cs: PrevRandaoTransactionTest): string =
|
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 =
|
method execute(cs: PrevRandaoTransactionTest, env: TestEnv): bool =
|
||||||
let ok = waitFor env.clMock.waitForTTD()
|
let ok = waitFor env.clMock.waitForTTD()
|
||||||
testCond ok
|
testCond ok
|
||||||
|
|
||||||
# Create a single block to not having to build on top of genesis
|
# 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
|
# Send transactions in PoS, the value of the storage in these blocks must match the prevRandao value
|
||||||
var (
|
blockCount: 10,
|
||||||
blockCount = 10
|
currentTxIndex: 0,
|
||||||
currentTxIndex = 0
|
|
||||||
txs = make([]typ.Transaction, 0)
|
|
||||||
)
|
)
|
||||||
if cs.blockCount > 0 (
|
|
||||||
blockCount = cs.blockCount
|
if cs.blockCount > 0:
|
||||||
)
|
shadow.blockCount = cs.blockCount
|
||||||
env.clMock.produceBlocks(blockCount, BlockProcessCallbacks(
|
|
||||||
|
let pbRes = env.clMock.produceBlocks(shadow.blockCount, BlockProcessCallbacks(
|
||||||
onPayloadProducerSelected: proc(): bool =
|
onPayloadProducerSelected: proc(): bool =
|
||||||
tx, err = env.sendNextTx(
|
let tc = BaseTx(
|
||||||
t.TestContext,
|
recipient: some(prevRandaoContractAddr),
|
||||||
t.Engine,
|
amount: 0.u256,
|
||||||
&BaseTx(
|
|
||||||
recipient: prevRandaoContractAddr,
|
|
||||||
amount: big0,
|
|
||||||
payload: nil,
|
|
||||||
txType: cs.txType,
|
txType: cs.txType,
|
||||||
gasLimit: 75000,
|
gasLimit: 75000,
|
||||||
),
|
|
||||||
)
|
)
|
||||||
if err != nil (
|
let tx = env.makeNextTx(tc)
|
||||||
fatal "Error trying to send transaction: %v", t.TestName, err)
|
let ok = env.sendTx(tx)
|
||||||
)
|
testCond ok:
|
||||||
txs = append(txs, tx)
|
fatal "Error trying to send transaction"
|
||||||
currentTxIndex++
|
|
||||||
),
|
shadow.txs.add(tx)
|
||||||
|
inc shadow.currentTxIndex
|
||||||
|
return true
|
||||||
|
,
|
||||||
onForkchoiceBroadcast: proc(): bool =
|
onForkchoiceBroadcast: proc(): bool =
|
||||||
# Check the transaction tracing, which is client specific
|
# Check the transaction tracing, which is client specific
|
||||||
expectedPrevRandao = env.clMock.prevRandaoHistory[env.clMock.latestHeader.blockNumber.Uint64()+1]
|
let expectedPrevRandao = env.clMock.prevRandaoHistory[env.clMock.latestHeader.blockNumber.truncate(uint64)+1]
|
||||||
ctx, cancel = context.WithTimeout(t.TestContext, globals.RPCTimeout)
|
let res = debugPrevRandaoTransaction(env.engine.client, shadow.txs[shadow.currentTxIndex-1], expectedPrevRandao)
|
||||||
defer cancel()
|
testCond res.isOk:
|
||||||
if err = DebugPrevRandaoTransaction(ctx, t.Client.RPC(), t.Client.Type, txs[currentTxIndex-1],
|
fatal "Error during transaction tracing", msg=res.error
|
||||||
&expectedPrevRandao); err != nil (
|
|
||||||
fatal "Error during transaction tracing: %v", t.TestName, err)
|
return true
|
||||||
)
|
|
||||||
),
|
|
||||||
))
|
))
|
||||||
|
testCond pbRes
|
||||||
|
|
||||||
for i = uint64(startBlockNumber); i <= env.clMock.latestExecutedPayload.blockNumber; i++ (
|
for i in shadow.startBlockNumber..env.clMock.latestExecutedPayload.blockNumber.uint64:
|
||||||
checkPrevRandaoValue(t, env.clMock.prevRandaoHistory[i], i)
|
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) (
|
return true
|
||||||
storageKey = common.Hash256()
|
|
||||||
storageKey[31] = byte(blockNumber)
|
|
||||||
r = env.engine.client.TestStorageAt(globals.PrevRandaoContractAddr, storageKey, nil)
|
|
||||||
r.ExpectStorageEqual(expectedPrevRandao)
|
|
||||||
)
|
|
||||||
|
|
|
@ -603,7 +603,7 @@ method execute(cs: ReOrgBackFromSyncingTest, env: TestEnv): bool =
|
||||||
# Re-org to the unavailable sidechain in the middle of block production
|
# Re-org to the unavailable sidechain in the middle of block production
|
||||||
# to be able to re-org back to the canonical chain
|
# to be able to re-org back to the canonical chain
|
||||||
r = env.engine.client.newPayload(sidechainPayloads[len(sidechainPayloads)-1])
|
r = env.engine.client.newPayload(sidechainPayloads[len(sidechainPayloads)-1])
|
||||||
r.expectStatusEither(PayloadExecutionStatus.syncing, test.Accepted)
|
r.expectStatusEither(PayloadExecutionStatus.syncing, PayloadExecutionStatus.accepted)
|
||||||
r.expectLatestValidHash(nil)
|
r.expectLatestValidHash(nil)
|
||||||
# We are going to send one of the alternative payloads and fcU to it
|
# We are going to send one of the alternative payloads and fcU to it
|
||||||
forkchoiceUpdatedBack = api.ForkchoiceStateV1(
|
forkchoiceUpdatedBack = api.ForkchoiceStateV1(
|
||||||
|
@ -805,7 +805,7 @@ method execute(cs: SafeReOrgToSideChainTest, env: TestEnv): bool =
|
||||||
onGetpayload: proc(): bool =
|
onGetpayload: proc(): bool =
|
||||||
for _, p = range sidechainPayloads (
|
for _, p = range sidechainPayloads (
|
||||||
r = env.engine.client.newPayload(p)
|
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(
|
r = env.engine.client.forkchoiceUpdated(api.ForkchoiceStateV1(
|
||||||
headBlockHash: sidechainPayloads[1].blockHash,
|
headBlockHash: sidechainPayloads[1].blockHash,
|
||||||
|
|
|
@ -13,7 +13,7 @@ import
|
||||||
./engine_spec
|
./engine_spec
|
||||||
|
|
||||||
type
|
type
|
||||||
BlockStatusRPCcheckType = enum
|
BlockStatusRPCcheckType* = enum
|
||||||
LatestOnNewPayload = "Latest Block on NewPayload"
|
LatestOnNewPayload = "Latest Block on NewPayload"
|
||||||
LatestOnHeadblockHash = "Latest Block on HeadblockHash Update"
|
LatestOnHeadblockHash = "Latest Block on HeadblockHash Update"
|
||||||
SafeOnSafeblockHash = "Safe Block on SafeblockHash Update"
|
SafeOnSafeblockHash = "Safe Block on SafeblockHash Update"
|
||||||
|
@ -21,7 +21,7 @@ type
|
||||||
|
|
||||||
type
|
type
|
||||||
BlockStatus* = ref object of EngineSpec
|
BlockStatus* = ref object of EngineSpec
|
||||||
checkType: BlockStatusRPCcheckType
|
checkType*: BlockStatusRPCcheckType
|
||||||
# TODO: Syncing bool
|
# TODO: Syncing bool
|
||||||
|
|
||||||
method withMainFork(cs: BlockStatus, fork: EngineFork): BaseSpec =
|
method withMainFork(cs: BlockStatus, fork: EngineFork): BaseSpec =
|
||||||
|
@ -46,7 +46,7 @@ method execute(cs: BlockStatus, env: TestEnv): bool =
|
||||||
else:
|
else:
|
||||||
number = Finalized
|
number = Finalized
|
||||||
|
|
||||||
p = env.engine.client.TestHeaderByNumber(number)
|
p = env.engine.client.headerByNumber(number)
|
||||||
p.expectError()
|
p.expectError()
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -59,22 +59,19 @@ method execute(cs: BlockStatus, env: TestEnv): bool =
|
||||||
let tc = BaseTx(
|
let tc = BaseTx(
|
||||||
recipient: &ZeroAddr,
|
recipient: &ZeroAddr,
|
||||||
amount: 1.u256,
|
amount: 1.u256,
|
||||||
payload: nil,
|
|
||||||
txType: cs.txType,
|
txType: cs.txType,
|
||||||
gasLimit: 75000,
|
gasLimit: 75000,
|
||||||
ForkConfig: t.ForkConfig,
|
|
||||||
),
|
),
|
||||||
|
|
||||||
tx, err = env.sendNextTx(
|
let ok = env.sendNextTx(tc)
|
||||||
)
|
testCond ok:
|
||||||
if err != nil (
|
|
||||||
fatal "Error trying to send transaction: %v", err)
|
fatal "Error trying to send transaction: %v", err)
|
||||||
)
|
)
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
switch b.checkType (
|
case b.checkType (
|
||||||
case LatestOnNewPayload:
|
of LatestOnNewPayload:
|
||||||
callbacks.onGetPayload = proc(): bool
|
callbacks.onGetPayload = proc(): bool
|
||||||
r = env.engine.client.latestHeader()
|
r = env.engine.client.latestHeader()
|
||||||
r.expectHash(env.clMock.latestForkchoice.headblockHash)
|
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
|
# Check that the receipt for the transaction we just sent is still not available
|
||||||
q = env.engine.client.txReceipt(tx.Hash())
|
q = env.engine.client.txReceipt(tx.Hash())
|
||||||
q.expectError()
|
q.expectError()
|
||||||
)
|
of LatestOnHeadblockHash:
|
||||||
case LatestOnHeadblockHash:
|
|
||||||
callbacks.onForkchoiceBroadcast = proc(): bool
|
callbacks.onForkchoiceBroadcast = proc(): bool
|
||||||
r = env.engine.client.latestHeader()
|
r = env.engine.client.latestHeader()
|
||||||
r.expectHash(env.clMock.latestForkchoice.headblockHash)
|
r.expectHash(env.clMock.latestForkchoice.headblockHash)
|
||||||
|
|
||||||
s = env.engine.client.txReceipt(tx.Hash())
|
s = env.engine.client.txReceipt(tx.Hash())
|
||||||
s.ExpectTransactionHash(tx.Hash())
|
s.ExpectTransactionHash(tx.Hash())
|
||||||
)
|
of SafeOnSafeblockHash:
|
||||||
case SafeOnSafeblockHash:
|
|
||||||
callbacks.onSafeBlockChange = proc(): bool
|
callbacks.onSafeBlockChange = proc(): bool
|
||||||
r = env.engine.client.TestHeaderByNumber(Safe)
|
r = env.engine.client.headerByNumber(Safe)
|
||||||
r.expectHash(env.clMock.latestForkchoice.safeblockHash)
|
r.expectHash(env.clMock.latestForkchoice.safeblockHash)
|
||||||
)
|
of FinalizedOnFinalizedblockHash:
|
||||||
case FinalizedOnFinalizedblockHash:
|
|
||||||
callbacks.onFinalizedBlockChange = proc(): bool
|
callbacks.onFinalizedBlockChange = proc(): bool
|
||||||
r = env.engine.client.TestHeaderByNumber(Finalized)
|
r = env.engine.client.headerByNumber(Finalized)
|
||||||
r.expectHash(env.clMock.latestForkchoice.finalizedblockHash)
|
r.expectHash(env.clMock.latestForkchoice.finalizedblockHash)
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
# Perform the test
|
# Perform the test
|
||||||
env.clMock.produceSingleBlock(callbacks)
|
env.clMock.produceSingleBlock(callbacks)
|
||||||
)
|
|
||||||
|
|
|
@ -10,11 +10,13 @@
|
||||||
|
|
||||||
import
|
import
|
||||||
std/strutils,
|
std/strutils,
|
||||||
./engine_spec
|
chronicles,
|
||||||
|
./engine_spec,
|
||||||
|
../../../../nimbus/transaction
|
||||||
|
|
||||||
type
|
type
|
||||||
SuggestedFeeRecipientTest* = ref object of EngineSpec
|
SuggestedFeeRecipientTest* = ref object of EngineSpec
|
||||||
transactionCount: int
|
transactionCount*: int
|
||||||
|
|
||||||
method withMainFork(cs: SuggestedFeeRecipientTest, fork: EngineFork): BaseSpec =
|
method withMainFork(cs: SuggestedFeeRecipientTest, fork: EngineFork): BaseSpec =
|
||||||
var res = cs.clone()
|
var res = cs.clone()
|
||||||
|
@ -38,54 +40,55 @@ method execute(cs: SuggestedFeeRecipientTest, env: TestEnv): bool =
|
||||||
txRecipient = EthAddress.randomBytes()
|
txRecipient = EthAddress.randomBytes()
|
||||||
|
|
||||||
# Send multiple transactions
|
# Send multiple transactions
|
||||||
for i = 0; i < cs.transactionCount; i++ (
|
for i in 0..<cs.transactionCount:
|
||||||
_, err = env.sendNextTx(
|
let tc = BaseTx(
|
||||||
t.TestContext,
|
recipient: some(txRecipient),
|
||||||
t.Engine,
|
amount: 0.u256,
|
||||||
&BaseTx(
|
|
||||||
recipient: &txRecipient,
|
|
||||||
amount: big0,
|
|
||||||
payload: nil,
|
|
||||||
txType: cs.txType,
|
txType: cs.txType,
|
||||||
gasLimit: 75000,
|
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
|
# Produce the next block with the fee recipient set
|
||||||
env.clMock.nextFeeRecipient = feeRecipient
|
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
|
# Calculate the fees and check that they match the balance of the fee recipient
|
||||||
r = env.engine.client.TestBlockByNumber(Head)
|
let r = env.engine.client.latestblock()
|
||||||
r.ExpecttransactionCountEqual(cs.transactionCount)
|
testCond r.isOk:
|
||||||
r.ExpectCoinbase(feeRecipient)
|
error "cannot get latest header", msg=r.error
|
||||||
blockIncluded = r.Block
|
|
||||||
|
|
||||||
feeRecipientFees = big.NewInt(0)
|
let blockIncluded = r.get
|
||||||
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))))
|
|
||||||
)
|
|
||||||
|
|
||||||
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)
|
s.expectBalanceEqual(feeRecipientFees)
|
||||||
|
|
||||||
# Produce another block without txns and get the balance again
|
# Produce another block without txns and get the balance again
|
||||||
env.clMock.nextFeeRecipient = feeRecipient
|
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)
|
s.expectBalanceEqual(feeRecipientFees)
|
||||||
)
|
return true
|
||||||
|
|
|
@ -437,16 +437,18 @@ proc latestHeader*(client: RpcClient): Result[common.BlockHeader, string] =
|
||||||
return err("failed to get latest blockHeader")
|
return err("failed to get latest blockHeader")
|
||||||
return ok(res.get.toBlockHeader)
|
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:
|
wrapTry:
|
||||||
let res = waitFor client.eth_getBlockByNumber("latest", true)
|
let res = waitFor client.eth_getBlockByNumber("latest", true)
|
||||||
if res.isNone:
|
if res.isNone:
|
||||||
return err("failed to get latest blockHeader")
|
return err("failed to get latest blockHeader")
|
||||||
let blk = res.get()
|
let blk = res.get()
|
||||||
output.header = toBlockHeader(blk)
|
let output = EthBlock(
|
||||||
output.txs = toTransactions(blk.transactions)
|
header: toBlockHeader(blk),
|
||||||
output.withdrawals = toWithdrawals(blk.withdrawals)
|
txs: toTransactions(blk.transactions),
|
||||||
return ok()
|
withdrawals: toWithdrawals(blk.withdrawals),
|
||||||
|
)
|
||||||
|
return ok(output)
|
||||||
|
|
||||||
proc namedHeader*(client: RpcClient, name: string): Result[common.BlockHeader, string] =
|
proc namedHeader*(client: RpcClient, name: string): Result[common.BlockHeader, string] =
|
||||||
wrapTry:
|
wrapTry:
|
||||||
|
|
|
@ -18,11 +18,20 @@ import
|
||||||
../../nimbus/common/chain_config
|
../../nimbus/common/chain_config
|
||||||
|
|
||||||
import
|
import
|
||||||
./engine/misc,
|
./engine/suggested_fee_recipient,
|
||||||
./engine/payload_attributes,
|
./engine/payload_attributes,
|
||||||
|
#./engine/payload_execution,
|
||||||
./engine/invalid_ancestor,
|
./engine/invalid_ancestor,
|
||||||
./engine/invalid_payload,
|
./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) =
|
proc getGenesis(cs: EngineSpec, param: NetworkParams) =
|
||||||
# Set the terminal total difficulty
|
# Set the terminal total difficulty
|
||||||
|
@ -160,7 +169,48 @@ proc makeEngineTest*(): seq[EngineSpec] =
|
||||||
invalidField: InvalidStateRoot,
|
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
|
const
|
||||||
invalidReorgList = [
|
invalidReorgList = [
|
||||||
InvalidStateRoot,
|
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
|
# Payload ID Tests
|
||||||
for _, payloadAttributeFieldChange := range []PayloadAttributesFieldChange(
|
for _, payloadAttributeFieldChange := range []PayloadAttributesFieldChange(
|
||||||
PayloadAttributesIncreaseTimestamp,
|
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
|
# Fork ID Tests
|
||||||
for genesisTimestamp := uint64(0); genesisTimestamp <= 1; genesisTimestamp++ (
|
for genesisTimestamp := uint64(0); genesisTimestamp <= 1; genesisTimestamp++ (
|
||||||
for forkTime := uint64(0); forkTime <= 2; forkTime++ (
|
for forkTime := uint64(0); forkTime <= 2; forkTime++ (
|
||||||
|
|
|
@ -127,6 +127,9 @@ proc makeTxs*(env: TestEnv, tc: BaseTx, num: int): seq[Transaction] =
|
||||||
for _ in 0..<num:
|
for _ in 0..<num:
|
||||||
result.add env.sender.makeNextTx(tc)
|
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 =
|
proc sendNextTx*(env: TestEnv, eng: EngineEnv, tc: BaseTx): bool =
|
||||||
env.sender.sendNextTx(eng.client, tc)
|
env.sender.sendNextTx(eng.client, tc)
|
||||||
|
|
||||||
|
|
|
@ -228,6 +228,18 @@ template expectHash*(res: untyped, hash: common.Hash256) =
|
||||||
testCond s.blockHash == hash:
|
testCond s.blockHash == hash:
|
||||||
error "Unexpected expectHash", expect=hash.short, get=s.blockHash.short
|
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 =
|
func timestamp*(x: ExecutableData): auto =
|
||||||
x.basePayload.timestamp
|
x.basePayload.timestamp
|
||||||
|
|
||||||
|
|
|
@ -26,9 +26,9 @@ proc execute*(ws: BlockValueSpec, env: TestEnv): bool =
|
||||||
testCond WDBaseSpec(ws).execute(env)
|
testCond WDBaseSpec(ws).execute(env)
|
||||||
|
|
||||||
# Get the latest block and the transactions included
|
# Get the latest block and the transactions included
|
||||||
var blk: EthBlock
|
let b = env.client.latestBlock()
|
||||||
let b = env.client.latestBlock(blk)
|
|
||||||
b.expectNoError()
|
b.expectNoError()
|
||||||
|
let blk = b.get
|
||||||
|
|
||||||
var totalValue: UInt256
|
var totalValue: UInt256
|
||||||
testCond blk.txs.len > 0:
|
testCond blk.txs.len > 0:
|
||||||
|
|
Loading…
Reference in New Issue