More Engine API tests
This commit is contained in:
parent
682b160777
commit
69254e614f
|
@ -10,10 +10,12 @@
|
|||
|
||||
import
|
||||
std/strutils,
|
||||
./engine_spec
|
||||
chronicles,
|
||||
./engine_spec,
|
||||
../cancun/customizer
|
||||
|
||||
type
|
||||
ForkchoiceStateField = enum
|
||||
ForkchoiceStateField* = enum
|
||||
HeadblockHash = "Head"
|
||||
SafeblockHash = "Safe"
|
||||
FinalizedblockHash = "Finalized"
|
||||
|
@ -22,14 +24,17 @@ type
|
|||
InconsistentForkchoiceTest* = ref object of EngineSpec
|
||||
field*: ForkchoiceStateField
|
||||
|
||||
Shadow = ref object
|
||||
canon: seq[ExecutableData]
|
||||
alt: seq[ExecutableData]
|
||||
|
||||
method withMainFork(cs: InconsistentForkchoiceTest, fork: EngineFork): BaseSpec =
|
||||
var res = cs.clone()
|
||||
res.mainFork = fork
|
||||
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 =
|
||||
|
@ -37,55 +42,59 @@ method execute(cs: InconsistentForkchoiceTest, env: TestEnv): bool =
|
|||
let ok = waitFor env.clMock.waitForTTD()
|
||||
testCond ok
|
||||
|
||||
shadow.canon = make([]*ExecutableData, 0)
|
||||
shadow.alt = make([]*ExecutableData, 0)
|
||||
var shadow = Shadow()
|
||||
|
||||
# Produce blocks before starting the test
|
||||
env.clMock.produceBlocks(3, BlockProcessCallbacks(
|
||||
let pbRes = 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
|
||||
var customData = CustomPayloadData(
|
||||
extraData: some(@[0x01.byte])
|
||||
)
|
||||
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)
|
||||
|
||||
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
|
||||
r = env.engine.client.newPayload(alternativePayload)
|
||||
r.expectStatusEither(PayloadExecutionStatus.valid, test.Accepted)
|
||||
),
|
||||
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
|
||||
inconsistentFcU = ForkchoiceStateV1(
|
||||
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,
|
||||
)
|
||||
switch cs.Field (
|
||||
case HeadblockHash:
|
||||
|
||||
case cs.field
|
||||
of HeadblockHash:
|
||||
inconsistentFcU.headblockHash = shadow.alt[len(shadow.alt)-1].blockHash
|
||||
case SafeblockHash:
|
||||
of SafeblockHash:
|
||||
inconsistentFcU.safeblockHash = shadow.alt[len(shadow.canon)-2].blockHash
|
||||
case FinalizedblockHash:
|
||||
of FinalizedblockHash:
|
||||
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()
|
||||
|
||||
# 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)
|
||||
)
|
||||
return true
|
||||
|
||||
type
|
||||
ForkchoiceUpdatedUnknownblockHashTest* = ref object of EngineSpec
|
||||
field: ForkchoiceStateField
|
||||
field*: ForkchoiceStateField
|
||||
|
||||
method withMainFork(cs: ForkchoiceUpdatedUnknownblockHashTest, fork: EngineFork): BaseSpec =
|
||||
var res = cs.clone()
|
||||
|
@ -93,8 +102,7 @@ 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 =
|
||||
|
@ -103,67 +111,66 @@ method execute(cs: ForkchoiceUpdatedUnknownblockHashTest, env: TestEnv): bool =
|
|||
testCond ok
|
||||
|
||||
# Produce blocks before starting the test
|
||||
env.clMock.produceBlocks(5, BlockProcessCallbacks())
|
||||
testCond env.clMock.produceBlocks(5, BlockProcessCallbacks())
|
||||
|
||||
# Generate a random block hash
|
||||
randomblockHash = common.Hash256()
|
||||
randomBytes(randomblockHash[:])
|
||||
let randomblockHash = Web3Hash.randomBytes()
|
||||
|
||||
if cs.Field == HeadblockHash (
|
||||
|
||||
forkchoiceStateUnknownHeadHash = ForkchoiceStateV1(
|
||||
if cs.field == HeadblockHash:
|
||||
let fcu = ForkchoiceStateV1(
|
||||
headblockHash: randomblockHash,
|
||||
safeblockHash: env.clMock.latestForkchoice.safeblockHash,
|
||||
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::
|
||||
# - (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)
|
||||
let version = env.engine.version(env.clMock.latestExecutedPayload.timestamp)
|
||||
var r = env.engine.client.forkchoiceUpdated(version, fcu)
|
||||
r.expectPayloadStatus(PayloadExecutionStatus.syncing)
|
||||
|
||||
payloadAttributes = env.clMock.latestPayloadAttributes
|
||||
payloadAttributes.timestamp += 1
|
||||
var payloadAttributes = env.clMock.latestPayloadAttributes
|
||||
payloadAttributes.timestamp = w3Qty(payloadAttributes.timestamp, 1)
|
||||
|
||||
# Test again using PayloadAttributes, should also return SYNCING and no PayloadID
|
||||
r = env.engine.client.forkchoiceUpdated(forkchoiceStateUnknownHeadHash,
|
||||
&payloadAttributes, env.clMock.latestExecutedPayload.timestamp)
|
||||
r = env.engine.client.forkchoiceUpdated(version, fcu, some(payloadAttributes))
|
||||
r.expectPayloadStatus(PayloadExecutionStatus.syncing)
|
||||
r.ExpectPayloadID(nil)
|
||||
r.expectPayloadID(none(PayloadID))
|
||||
else:
|
||||
env.clMock.produceSingleBlock(BlockProcessCallbacks(
|
||||
let pbRes = env.clMock.produceSingleBlock(BlockProcessCallbacks(
|
||||
# Run test after a new payload has been broadcast
|
||||
onNewPayloadBroadcast: proc(): bool =
|
||||
|
||||
forkchoiceStateRandomHash = ForkchoiceStateV1(
|
||||
var fcu = ForkchoiceStateV1(
|
||||
headblockHash: env.clMock.latestExecutedPayload.blockHash,
|
||||
safeblockHash: env.clMock.latestForkchoice.safeblockHash,
|
||||
finalizedblockHash: env.clMock.latestForkchoice.finalizedblockHash,
|
||||
)
|
||||
|
||||
if cs.Field == SafeblockHash (
|
||||
forkchoiceStateRandomHash.safeblockHash = randomblockHash
|
||||
elif cs.Field == FinalizedblockHash (
|
||||
forkchoiceStateRandomHash.finalizedblockHash = randomblockHash
|
||||
)
|
||||
if cs.field == SafeblockHash:
|
||||
fcu.safeblockHash = randomblockHash
|
||||
elif cs.field == FinalizedblockHash:
|
||||
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()
|
||||
|
||||
payloadAttributes = env.clMock.latestPayloadAttributes
|
||||
payloadAttributes.Random = common.Hash256()
|
||||
payloadAttributes.SuggestedFeeRecipient = common.Address()
|
||||
var payloadAttributes = env.clMock.latestPayloadAttributes
|
||||
payloadAttributes.prevRandao = w3Hash()
|
||||
payloadAttributes.suggestedFeeRecipient = w3Address()
|
||||
|
||||
# Test again using PayloadAttributes, should also return INVALID and no PayloadID
|
||||
r = env.engine.client.forkchoiceUpdated(forkchoiceStateRandomHash,
|
||||
&payloadAttributes, env.clMock.latestExecutedPayload.timestamp)
|
||||
r = env.engine.client.forkchoiceUpdated(version, fcu, some(payloadAttributes))
|
||||
r.expectError()
|
||||
|
||||
),
|
||||
return true
|
||||
))
|
||||
)
|
||||
)
|
||||
testCond pbRes
|
||||
|
||||
return true
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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())
|
||||
|
||||
startBlockNumber = env.clMock.latestHeader.blockNumber.Uint64() + 1
|
||||
testCond env.clMock.produceSingleBlock(BlockProcessCallbacks())
|
||||
|
||||
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
|
||||
var (
|
||||
blockCount = 10
|
||||
currentTxIndex = 0
|
||||
txs = make([]typ.Transaction, 0)
|
||||
blockCount: 10,
|
||||
currentTxIndex: 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,
|
||||
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
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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)
|
||||
)
|
||||
|
||||
|
|
|
@ -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,
|
||||
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
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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++ (
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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:
|
||||
|
|
Loading…
Reference in New Issue