mirror of
https://github.com/status-im/nimbus-eth1.git
synced 2025-01-12 21:34:33 +00:00
fix engine api and angine api test
This commit is contained in:
parent
9e8d2d0550
commit
d07ef2ee56
@ -327,3 +327,6 @@ proc isBlockPoS*(cl: CLMocker, bn: common.BlockNumber): bool =
|
|||||||
return false
|
return false
|
||||||
|
|
||||||
return true
|
return true
|
||||||
|
|
||||||
|
proc posBlockNumber*(cl: CLMocker): uint64 =
|
||||||
|
cl.firstPoSBlockNumber.get(0'u64)
|
||||||
|
@ -9,7 +9,7 @@ proc main() =
|
|||||||
let start = getTime()
|
let start = getTime()
|
||||||
|
|
||||||
for x in engineTestList:
|
for x in engineTestList:
|
||||||
var t = setupELClient()
|
var t = setupELClient(x.chainFile)
|
||||||
t.setRealTTD(x.ttd)
|
t.setRealTTD(x.ttd)
|
||||||
let status = x.run(t)
|
let status = x.run(t)
|
||||||
t.stopELClient()
|
t.stopELClient()
|
||||||
@ -17,5 +17,6 @@ proc main() =
|
|||||||
|
|
||||||
let elpd = getTime() - start
|
let elpd = getTime() - start
|
||||||
print(stat, elpd, "engine")
|
print(stat, elpd, "engine")
|
||||||
|
echo stat
|
||||||
|
|
||||||
main()
|
main()
|
||||||
|
@ -16,18 +16,91 @@ type
|
|||||||
name*: string
|
name*: string
|
||||||
run*: proc(t: TestEnv): TestStatus
|
run*: proc(t: TestEnv): TestStatus
|
||||||
ttd*: int64
|
ttd*: int64
|
||||||
|
chainFile*: string
|
||||||
|
|
||||||
const
|
const
|
||||||
prevRandaoContractAddr = hexToByteArray[20]("0000000000000000000000000000000000000316")
|
prevRandaoContractAddr = hexToByteArray[20]("0000000000000000000000000000000000000316")
|
||||||
|
|
||||||
template testCond(expr: untyped) =
|
template testCond(expr: untyped) =
|
||||||
if not (expr):
|
if not (expr):
|
||||||
return TestStatus.Failed
|
when result is bool:
|
||||||
|
return false
|
||||||
|
else:
|
||||||
|
return TestStatus.Failed
|
||||||
|
|
||||||
template testCond(expr, body: untyped) =
|
template testCond(expr, body: untyped) =
|
||||||
if not (expr):
|
if not (expr):
|
||||||
body
|
body
|
||||||
return TestStatus.Failed
|
when result is bool:
|
||||||
|
return false
|
||||||
|
else:
|
||||||
|
return TestStatus.Failed
|
||||||
|
|
||||||
|
proc `$`(x: Option[Hash256]): string =
|
||||||
|
if x.isNone:
|
||||||
|
"none"
|
||||||
|
else:
|
||||||
|
x.get().data.toHex
|
||||||
|
|
||||||
|
proc `$`(x: Option[BlockHash]): string =
|
||||||
|
if x.isNone:
|
||||||
|
"none"
|
||||||
|
else:
|
||||||
|
x.get().toHex
|
||||||
|
|
||||||
|
proc `$`(x: Option[PayloadID]): string =
|
||||||
|
if x.isNone:
|
||||||
|
"none"
|
||||||
|
else:
|
||||||
|
x.get().toHex
|
||||||
|
|
||||||
|
proc `==`(a: Option[BlockHash], b: Option[Hash256]): bool =
|
||||||
|
if a.isNone or b.isNone:
|
||||||
|
return false
|
||||||
|
a.get() == b.get().data.BlockHash
|
||||||
|
|
||||||
|
template testFCU(res, cond: untyped, validHash: Option[Hash256], id = none(PayloadID)) =
|
||||||
|
testCond res.isOk
|
||||||
|
let s = res.get()
|
||||||
|
testCond s.payloadStatus.status == PayloadExecutionStatus.cond:
|
||||||
|
error "Unexpected FCU status", expect=PayloadExecutionStatus.cond, get=s.payloadStatus.status
|
||||||
|
testCond s.payloadStatus.latestValidHash == validHash:
|
||||||
|
error "Unexpected FCU latestValidHash", expect=validHash, get=s.payloadStatus.latestValidHash
|
||||||
|
testCond s.payloadId == id:
|
||||||
|
error "Unexpected FCU payloadID", expect=id, get=s.payloadId
|
||||||
|
|
||||||
|
template testFCU(res, cond: untyped) =
|
||||||
|
testCond res.isOk
|
||||||
|
let s = res.get()
|
||||||
|
testCond s.payloadStatus.status == PayloadExecutionStatus.cond:
|
||||||
|
error "Unexpected FCU status", expect=PayloadExecutionStatus.cond, get=s.payloadStatus.status
|
||||||
|
|
||||||
|
template testNP(res, cond: untyped, validHash = none(Hash256)) =
|
||||||
|
testCond res.isOk
|
||||||
|
let s = res.get()
|
||||||
|
testCond s.status == PayloadExecutionStatus.cond:
|
||||||
|
error "Unexpected NewPayload status", expect=PayloadExecutionStatus.cond, get=s.status
|
||||||
|
testCond s.latestValidHash == validHash:
|
||||||
|
error "Unexpected NewPayload latestValidHash", expect=validHash, get=s.latestValidHash
|
||||||
|
|
||||||
|
template testNPEither(res, cond: untyped, validHash = none(Hash256)) =
|
||||||
|
testCond res.isOk
|
||||||
|
let s = res.get()
|
||||||
|
testCond s.status in cond:
|
||||||
|
error "Unexpected NewPayload status", expect=cond, get=s.status
|
||||||
|
testCond s.latestValidHash == validHash:
|
||||||
|
error "Unexpected NewPayload latestValidHash", expect=validHash, get=s.latestValidHash
|
||||||
|
|
||||||
|
proc sendTx(t: TestEnv, recipient: EthAddress, val: UInt256, data: openArray[byte] = []): bool =
|
||||||
|
t.tx = t.makeNextTransaction(recipient, val, data)
|
||||||
|
let rr = t.rpcClient.sendTransaction(t.tx)
|
||||||
|
if rr.isErr:
|
||||||
|
error "Unable to send transaction", msg=rr.error
|
||||||
|
return false
|
||||||
|
return true
|
||||||
|
|
||||||
|
proc sendTx(t: TestEnv, val: UInt256): bool =
|
||||||
|
t.sendTx(prevRandaoContractAddr, val)
|
||||||
|
|
||||||
# Invalid Terminal Block in ForkchoiceUpdated:
|
# Invalid Terminal Block in ForkchoiceUpdated:
|
||||||
# Client must reject ForkchoiceUpdated directives if the referenced HeadBlockHash does not meet the TTD requirement.
|
# Client must reject ForkchoiceUpdated directives if the referenced HeadBlockHash does not meet the TTD requirement.
|
||||||
@ -43,17 +116,11 @@ proc invalidTerminalBlockForkchoiceUpdated(t: TestEnv): TestStatus =
|
|||||||
)
|
)
|
||||||
|
|
||||||
let res = t.rpcClient.forkchoiceUpdatedV1(forkchoiceState)
|
let res = t.rpcClient.forkchoiceUpdatedV1(forkchoiceState)
|
||||||
|
|
||||||
# Execution specification:
|
# Execution specification:
|
||||||
# {payloadStatus: {status: INVALID, latestValidHash=0x00..00}, payloadId: null}
|
# {payloadStatus: {status: INVALID, latestValidHash=0x00..00}, payloadId: null}
|
||||||
# either obtained from the Payload validation process or as a result of validating a PoW block referenced by forkchoiceState.headBlockHash
|
# either obtained from the Payload validation process or as a result of validating a PoW block referenced by forkchoiceState.headBlockHash
|
||||||
testCond res.isOk
|
|
||||||
|
|
||||||
let s = res.get()
|
|
||||||
testCond s.payloadStatus.status == PayloadExecutionStatus.invalid
|
|
||||||
testCond s.payloadStatus.latestValidHash.isNone
|
|
||||||
testCond s.payloadId.isNone
|
|
||||||
|
|
||||||
|
testFCU(res, invalid, some(Hash256()))
|
||||||
# ValidationError is not validated since it can be either null or a string message
|
# ValidationError is not validated since it can be either null or a string message
|
||||||
|
|
||||||
# Check that PoW chain progresses
|
# Check that PoW chain progresses
|
||||||
@ -91,13 +158,9 @@ proc invalidTerminalBlockNewPayload(t: TestEnv): TestStatus =
|
|||||||
let res = t.rpcClient.newPayloadV1(hashedPayload)
|
let res = t.rpcClient.newPayloadV1(hashedPayload)
|
||||||
|
|
||||||
# Execution specification:
|
# Execution specification:
|
||||||
# {status: INVALID_TERMINAL_BLOCK, latestValidHash: null, validationError: errorMessage | null}
|
# {status: INVALID, latestValidHash=0x00..00}
|
||||||
# if terminal block conditions are not satisfied
|
# if terminal block conditions are not satisfied
|
||||||
testCond res.isOk
|
testNP(res, invalid, some(Hash256()))
|
||||||
|
|
||||||
let s = res.get()
|
|
||||||
testCond s.status == PayloadExecutionStatus.invalid
|
|
||||||
testCond s.latestValidHash.isNone
|
|
||||||
|
|
||||||
# Check that PoW chain progresses
|
# Check that PoW chain progresses
|
||||||
testCond t.verifyPoWProgress(t.gHeader.blockHash)
|
testCond t.verifyPoWProgress(t.gHeader.blockHash)
|
||||||
@ -346,7 +409,6 @@ template invalidPayloadAttributesGen(procname: untyped, syncingCond: bool) =
|
|||||||
else:
|
else:
|
||||||
let r = client.forkchoiceUpdatedV1(fcu, some(attr))
|
let r = client.forkchoiceUpdatedV1(fcu, some(attr))
|
||||||
if r.isOk:
|
if r.isOk:
|
||||||
debugEcho "EEEE"
|
|
||||||
return false
|
return false
|
||||||
|
|
||||||
# Check that the forkchoice was applied, regardless of the error
|
# Check that the forkchoice was applied, regardless of the error
|
||||||
@ -385,13 +447,10 @@ proc preTTDFinalizedBlockHash(t: TestEnv): TestStatus =
|
|||||||
clMock = t.clMock
|
clMock = t.clMock
|
||||||
|
|
||||||
var res = client.forkchoiceUpdatedV1(forkchoiceState)
|
var res = client.forkchoiceUpdatedV1(forkchoiceState)
|
||||||
# TBD: Behavior on this edge-case is undecided, as behavior of the Execution client
|
testFCU(res, invalid, some(Hash256()))
|
||||||
# if not defined on re-orgs to a point before the latest finalized block.
|
|
||||||
|
|
||||||
res = client.forkchoiceUpdatedV1(clMock.latestForkchoice)
|
res = client.forkchoiceUpdatedV1(clMock.latestForkchoice)
|
||||||
testCond res.isOk
|
testFCU(res, valid)
|
||||||
let s = res.get()
|
|
||||||
testCond s.payloadStatus.status == PayloadExecutionStatus.valid
|
|
||||||
|
|
||||||
# Corrupt the hash of a valid payload, client should reject the payload.
|
# Corrupt the hash of a valid payload, client should reject the payload.
|
||||||
# All possible scenarios:
|
# All possible scenarios:
|
||||||
@ -548,6 +607,55 @@ proc parentHashOnExecPayload(t: TestEnv): TestStatus =
|
|||||||
))
|
))
|
||||||
testCond produceSingleBlockRes
|
testCond produceSingleBlockRes
|
||||||
|
|
||||||
|
# Attempt to re-org to a chain containing an invalid transition payload
|
||||||
|
proc invalidTransitionPayload(t: TestEnv): TestStatus =
|
||||||
|
result = TestStatus.OK
|
||||||
|
|
||||||
|
# Wait until TTD is reached by main client
|
||||||
|
let ok = waitFor t.clMock.waitForTTD()
|
||||||
|
testCond ok
|
||||||
|
|
||||||
|
let clMock = t.clMock
|
||||||
|
let client = t.rpcClient
|
||||||
|
|
||||||
|
# Produce two blocks before trying to re-org
|
||||||
|
t.nonce = 2 # Initial PoW chain already contains 2 transactions
|
||||||
|
var pbRes = clMock.produceBlocks(2, BlockProcessCallbacks(
|
||||||
|
onPayloadProducerSelected: proc(): bool =
|
||||||
|
t.sendTx(1.u256)
|
||||||
|
))
|
||||||
|
|
||||||
|
testCond pbRes
|
||||||
|
|
||||||
|
# Introduce the invalid transition payload
|
||||||
|
pbRes = clMock.produceSingleBlock(BlockProcessCallbacks(
|
||||||
|
# This is being done in the middle of the block building
|
||||||
|
# process simply to be able to re-org back.
|
||||||
|
onGetPayload: proc(): bool =
|
||||||
|
let basePayload = clMock.executedPayloadHistory[clMock.posBlockNumber]
|
||||||
|
let alteredPayload = generateInvalidPayload(basePayload, InvalidStateRoot)
|
||||||
|
|
||||||
|
let res = client.newPayloadV1(alteredPayload)
|
||||||
|
let cond = {PayloadExecutionStatus.invalid, PayloadExecutionStatus.accepted}
|
||||||
|
testNPEither(res, cond, some(Hash256()))
|
||||||
|
|
||||||
|
let rr = client.forkchoiceUpdatedV1(
|
||||||
|
ForkchoiceStateV1(headBlockHash: alteredPayload.blockHash)
|
||||||
|
)
|
||||||
|
testFCU(rr, invalid, some(Hash256()))
|
||||||
|
|
||||||
|
var header: EthBlockHeader
|
||||||
|
let rz = client.latestHeader(header)
|
||||||
|
if rz.isErr:
|
||||||
|
error "unable to get header", msg=rz.error
|
||||||
|
return false
|
||||||
|
|
||||||
|
let blockHash = BlockHash header.blockHash.data
|
||||||
|
blockHash == clMock.latestExecutedPayload.blockHash
|
||||||
|
))
|
||||||
|
|
||||||
|
testCond pbRes
|
||||||
|
|
||||||
template invalidPayloadTestCaseGen(procName: untyped, payloadField: InvalidPayloadField, emptyTxs: bool = false) =
|
template invalidPayloadTestCaseGen(procName: untyped, payloadField: InvalidPayloadField, emptyTxs: bool = false) =
|
||||||
proc procName(t: TestEnv): TestStatus =
|
proc procName(t: TestEnv): TestStatus =
|
||||||
result = TestStatus.OK
|
result = TestStatus.OK
|
||||||
@ -559,22 +667,17 @@ template invalidPayloadTestCaseGen(procName: untyped, payloadField: InvalidPaylo
|
|||||||
let clMock = t.clMock
|
let clMock = t.clMock
|
||||||
let client = t.rpcClient
|
let client = t.rpcClient
|
||||||
|
|
||||||
template txProc() =
|
template txProc(): bool =
|
||||||
when not emptyTxs:
|
when not emptyTxs:
|
||||||
let
|
t.sendTx(0.u256)
|
||||||
tx = t.makeNextTransaction(prevRandaoContractAddr, 0.u256)
|
else:
|
||||||
rr = client.sendTransaction(tx)
|
true
|
||||||
|
|
||||||
if rr.isErr:
|
|
||||||
error "Unable to send transaction", msg=rr.error
|
|
||||||
return false
|
|
||||||
|
|
||||||
# Produce blocks before starting the test
|
# Produce blocks before starting the test
|
||||||
var pbRes = clMock.produceBlocks(5, BlockProcessCallbacks(
|
var pbRes = clMock.produceBlocks(5, BlockProcessCallbacks(
|
||||||
# Make sure at least one transaction is included in each block
|
# Make sure at least one transaction is included in each block
|
||||||
onPayloadProducerSelected: proc(): bool =
|
onPayloadProducerSelected: proc(): bool =
|
||||||
txProc()
|
txProc()
|
||||||
return true
|
|
||||||
))
|
))
|
||||||
|
|
||||||
testCond pbRes
|
testCond pbRes
|
||||||
@ -585,7 +688,6 @@ template invalidPayloadTestCaseGen(procName: untyped, payloadField: InvalidPaylo
|
|||||||
# Make sure at least one transaction is included in the payload
|
# Make sure at least one transaction is included in the payload
|
||||||
onPayloadProducerSelected: proc(): bool =
|
onPayloadProducerSelected: proc(): bool =
|
||||||
txProc()
|
txProc()
|
||||||
return true
|
|
||||||
,
|
,
|
||||||
# Run test after the new payload has been obtained
|
# Run test after the new payload has been obtained
|
||||||
onGetPayload: proc(): bool =
|
onGetPayload: proc(): bool =
|
||||||
@ -598,8 +700,7 @@ template invalidPayloadTestCaseGen(procName: untyped, payloadField: InvalidPaylo
|
|||||||
error "No transactions in the base payload"
|
error "No transactions in the base payload"
|
||||||
return false
|
return false
|
||||||
|
|
||||||
let execData = clMock.latestPayloadBuilt.toExecutableData
|
let alteredPayload = generateInvalidPayload(clMock.latestPayloadBuilt, payloadField, t.vaultKey)
|
||||||
let alteredPayload = generateInvalidPayload(execData, payloadField, t.vaultKey)
|
|
||||||
invalidPayload.hash = hash256(alteredPayload.blockHash)
|
invalidPayload.hash = hash256(alteredPayload.blockHash)
|
||||||
|
|
||||||
# Depending on the field we modified, we expect a different status
|
# Depending on the field we modified, we expect a different status
|
||||||
@ -735,13 +836,8 @@ template blockStatusExecPayloadGen(procname: untyped, transitionBlock: bool) =
|
|||||||
var produceSingleBlockRes = clMock.produceSingleBlock(BlockProcessCallbacks(
|
var produceSingleBlockRes = clMock.produceSingleBlock(BlockProcessCallbacks(
|
||||||
onPayloadProducerSelected: proc(): bool =
|
onPayloadProducerSelected: proc(): bool =
|
||||||
var address: EthAddress
|
var address: EthAddress
|
||||||
let tx = t.makeNextTransaction(address, 1.u256)
|
testCond t.sendTx(address, 1.u256)
|
||||||
let res = client.sendTransaction(tx)
|
shadow.hash = rlpHash(t.tx)
|
||||||
if res.isErr:
|
|
||||||
error "Unable to send transaction"
|
|
||||||
return false
|
|
||||||
|
|
||||||
shadow.hash = rlpHash(tx)
|
|
||||||
return true
|
return true
|
||||||
,
|
,
|
||||||
onNewPayloadBroadcast: proc(): bool =
|
onNewPayloadBroadcast: proc(): bool =
|
||||||
@ -804,13 +900,8 @@ template blockStatusHeadBlockGen(procname: untyped, transitionBlock: bool) =
|
|||||||
var produceSingleBlockRes = clMock.produceSingleBlock(BlockProcessCallbacks(
|
var produceSingleBlockRes = clMock.produceSingleBlock(BlockProcessCallbacks(
|
||||||
onPayloadProducerSelected: proc(): bool =
|
onPayloadProducerSelected: proc(): bool =
|
||||||
var address: EthAddress
|
var address: EthAddress
|
||||||
let tx = t.makeNextTransaction(address, 1.u256)
|
testCond t.sendTx(address, 1.u256)
|
||||||
let res = client.sendTransaction(tx)
|
shadow.hash = rlpHash(t.tx)
|
||||||
if res.isErr:
|
|
||||||
error "Unable to send transaction"
|
|
||||||
return false
|
|
||||||
|
|
||||||
shadow.hash = rlpHash(tx)
|
|
||||||
return true
|
return true
|
||||||
,
|
,
|
||||||
# Run test after a forkchoice with new HeadBlockHash has been broadcasted
|
# Run test after a forkchoice with new HeadBlockHash has been broadcasted
|
||||||
@ -858,13 +949,8 @@ template blockStatusSafeBlockGen(procname: untyped, transitionBlock: bool) =
|
|||||||
var produceSingleBlockRes = clMock.produceSingleBlock(BlockProcessCallbacks(
|
var produceSingleBlockRes = clMock.produceSingleBlock(BlockProcessCallbacks(
|
||||||
onPayloadProducerSelected: proc(): bool =
|
onPayloadProducerSelected: proc(): bool =
|
||||||
var address: EthAddress
|
var address: EthAddress
|
||||||
let tx = t.makeNextTransaction(address, 1.u256)
|
testCond t.sendTx(address, 1.u256)
|
||||||
let res = client.sendTransaction(tx)
|
shadow.hash = rlpHash(t.tx)
|
||||||
if res.isErr:
|
|
||||||
error "Unable to send transaction"
|
|
||||||
return false
|
|
||||||
|
|
||||||
shadow.hash = rlpHash(tx)
|
|
||||||
return true
|
return true
|
||||||
,
|
,
|
||||||
# Run test after a forkchoice with new HeadBlockHash has been broadcasted
|
# Run test after a forkchoice with new HeadBlockHash has been broadcasted
|
||||||
@ -911,13 +997,8 @@ template blockStatusFinalizedBlockGen(procname: untyped, transitionBlock: bool)
|
|||||||
var produceSingleBlockRes = clMock.produceSingleBlock(BlockProcessCallbacks(
|
var produceSingleBlockRes = clMock.produceSingleBlock(BlockProcessCallbacks(
|
||||||
onPayloadProducerSelected: proc(): bool =
|
onPayloadProducerSelected: proc(): bool =
|
||||||
var address: EthAddress
|
var address: EthAddress
|
||||||
let tx = t.makeNextTransaction(address, 1.u256)
|
testCond t.sendTx(address, 1.u256)
|
||||||
let res = client.sendTransaction(tx)
|
shadow.hash = rlpHash(t.tx)
|
||||||
if res.isErr:
|
|
||||||
error "Unable to send transaction"
|
|
||||||
return false
|
|
||||||
|
|
||||||
shadow.hash = rlpHash(tx)
|
|
||||||
return true
|
return true
|
||||||
,
|
,
|
||||||
# Run test after a forkchoice with new HeadBlockHash has been broadcasted
|
# Run test after a forkchoice with new HeadBlockHash has been broadcasted
|
||||||
@ -1149,11 +1230,7 @@ proc outOfOrderPayloads(t: TestEnv): TestStatus =
|
|||||||
# We send the transactions after we got the Payload ID, before the clMocker gets the prepared Payload
|
# We send the transactions after we got the Payload ID, before the clMocker gets the prepared Payload
|
||||||
onPayloadProducerSelected: proc(): bool =
|
onPayloadProducerSelected: proc(): bool =
|
||||||
for i in 0..<txPerPayload:
|
for i in 0..<txPerPayload:
|
||||||
let tx = t.makeNextTransaction(recipient, amountPerTx)
|
testCond t.sendTx(recipient, amountPerTx)
|
||||||
let res = client.sendTransaction(tx)
|
|
||||||
if res.isErr:
|
|
||||||
error "Unable to send transaction"
|
|
||||||
return false
|
|
||||||
return true
|
return true
|
||||||
))
|
))
|
||||||
testCond produceBlockRes
|
testCond produceBlockRes
|
||||||
@ -1293,8 +1370,7 @@ proc transactionReorg(t: TestEnv): TestStatus =
|
|||||||
testCond ok
|
testCond ok
|
||||||
|
|
||||||
# Produce blocks before starting the test
|
# Produce blocks before starting the test
|
||||||
let produce5BlockRes = t.clMock.produceBlocks(5, BlockProcessCallbacks())
|
testCond t.clMock.produceBlocks(5, BlockProcessCallbacks())
|
||||||
testCond produce5BlockRes
|
|
||||||
|
|
||||||
# Create transactions that modify the state in order to testCond after the reorg.
|
# Create transactions that modify the state in order to testCond after the reorg.
|
||||||
const
|
const
|
||||||
@ -1312,20 +1388,14 @@ proc transactionReorg(t: TestEnv): TestStatus =
|
|||||||
for i in 0..<txCount:
|
for i in 0..<txCount:
|
||||||
# Data is the key where a `1` will be stored
|
# Data is the key where a `1` will be stored
|
||||||
let data = i.u256
|
let data = i.u256
|
||||||
let tx = t.makeNextTransaction(contractAddr, 0.u256, data.toBytesBE)
|
testCond t.sendTx(contractAddr, 0.u256, data.toBytesBE)
|
||||||
txs[i] = tx
|
txs[i] = t.tx
|
||||||
|
|
||||||
# Send the transaction
|
|
||||||
let res = client.sendTransaction(tx)
|
|
||||||
testCond res.isOk:
|
|
||||||
error "Unable to send transaction", msg=res.error
|
|
||||||
|
|
||||||
# Produce the block containing the transaction
|
# Produce the block containing the transaction
|
||||||
var blockRes = clMock.produceSingleBlock(BlockProcessCallbacks())
|
testCond clMock.produceSingleBlock(BlockProcessCallbacks())
|
||||||
testCond blockRes
|
|
||||||
|
|
||||||
# Get the receipt
|
# Get the receipt
|
||||||
let rr = client.txReceipt(rlpHash(tx))
|
let rr = client.txReceipt(rlpHash(t.tx))
|
||||||
testCond rr.isOk:
|
testCond rr.isOk:
|
||||||
error "Unable to obtain transaction receipt", msg=rr.error
|
error "Unable to obtain transaction receipt", msg=rr.error
|
||||||
|
|
||||||
@ -1416,8 +1486,7 @@ proc sidechainReorg(t: TestEnv): TestStatus =
|
|||||||
testCond ok
|
testCond ok
|
||||||
|
|
||||||
# Produce blocks before starting the test
|
# Produce blocks before starting the test
|
||||||
let produce5BlockRes = t.clMock.produceBlocks(5, BlockProcessCallbacks())
|
testCond t.clMock.produceBlocks(5, BlockProcessCallbacks())
|
||||||
testCond produce5BlockRes
|
|
||||||
|
|
||||||
let
|
let
|
||||||
client = t.rpcClient
|
client = t.rpcClient
|
||||||
@ -1426,10 +1495,7 @@ proc sidechainReorg(t: TestEnv): TestStatus =
|
|||||||
# Produce two payloads, send fcU with first payload, testCond transaction outcome, then reorg, testCond transaction outcome again
|
# Produce two payloads, send fcU with first payload, testCond transaction outcome, then reorg, testCond transaction outcome again
|
||||||
|
|
||||||
# This single transaction will change its outcome based on the payload
|
# This single transaction will change its outcome based on the payload
|
||||||
let tx = t.makeNextTransaction(prevRandaoContractAddr, 0.u256)
|
testCond t.sendTx(0.u256)
|
||||||
let rr = client.sendTransaction(tx)
|
|
||||||
testCond rr.isOk:
|
|
||||||
error "Unable to send transaction", msg=rr.error
|
|
||||||
|
|
||||||
let singleBlockRes = clMock.produceSingleBlock(BlockProcessCallbacks(
|
let singleBlockRes = clMock.produceSingleBlock(BlockProcessCallbacks(
|
||||||
onNewPayloadBroadcast: proc(): bool =
|
onNewPayloadBroadcast: proc(): bool =
|
||||||
@ -1524,10 +1590,7 @@ proc suggestedFeeRecipient(t: TestEnv): TestStatus =
|
|||||||
# Send multiple transactions
|
# Send multiple transactions
|
||||||
for i in 0..<txCount:
|
for i in 0..<txCount:
|
||||||
# Empty self tx
|
# Empty self tx
|
||||||
let tx = t.makeNextTransaction(vaultAccountAddr, 0.u256)
|
discard t.sendTx(vaultAccountAddr, 0.u256)
|
||||||
let res = client.sendTransaction(tx)
|
|
||||||
testCond res.isOk:
|
|
||||||
error "unable to send transaction", msg=res.error
|
|
||||||
|
|
||||||
# Produce the next block with the fee recipient set
|
# Produce the next block with the fee recipient set
|
||||||
clMock.nextFeeRecipient = feeRecipient
|
clMock.nextFeeRecipient = feeRecipient
|
||||||
@ -1579,21 +1642,14 @@ proc suggestedFeeRecipient(t: TestEnv): TestStatus =
|
|||||||
error "balance does not match fees",
|
error "balance does not match fees",
|
||||||
feeRecipientBalance, feeRecipientFees
|
feeRecipientBalance, feeRecipientFees
|
||||||
|
|
||||||
proc sendTx(t: TestEnv): Future[void] {.async.} =
|
proc sendTxAsync(t: TestEnv): Future[void] {.async.} =
|
||||||
let
|
let
|
||||||
client = t.rpcClient
|
|
||||||
clMock = t.clMock
|
clMock = t.clMock
|
||||||
period = chronos.milliseconds(500)
|
period = chronos.milliseconds(500)
|
||||||
|
|
||||||
while not clMock.ttdReached:
|
while not clMock.ttdReached:
|
||||||
await sleepAsync(period)
|
await sleepAsync(period)
|
||||||
|
discard t.sendTx(0.u256)
|
||||||
let
|
|
||||||
tx = t.makeNextTransaction(prevRandaoContractAddr, 0.u256)
|
|
||||||
rr = client.sendTransaction(tx)
|
|
||||||
|
|
||||||
if rr.isErr:
|
|
||||||
error "Unable to send transaction", msg=rr.error
|
|
||||||
|
|
||||||
proc prevRandaoOpcodeTx(t: TestEnv): TestStatus =
|
proc prevRandaoOpcodeTx(t: TestEnv): TestStatus =
|
||||||
result = TestStatus.OK
|
result = TestStatus.OK
|
||||||
@ -1601,7 +1657,7 @@ proc prevRandaoOpcodeTx(t: TestEnv): TestStatus =
|
|||||||
let
|
let
|
||||||
client = t.rpcClient
|
client = t.rpcClient
|
||||||
clMock = t.clMock
|
clMock = t.clMock
|
||||||
sendTxFuture = sendTx(t)
|
sendTxFuture = sendTxAsync(t)
|
||||||
|
|
||||||
# Wait until TTD is reached by this client
|
# Wait until TTD is reached by this client
|
||||||
let ok = waitFor clMock.waitForTTD()
|
let ok = waitFor clMock.waitForTTD()
|
||||||
@ -1646,15 +1702,8 @@ proc prevRandaoOpcodeTx(t: TestEnv): TestStatus =
|
|||||||
|
|
||||||
let produceBlockRes = clMock.produceBlocks(10, BlockProcessCallbacks(
|
let produceBlockRes = clMock.produceBlocks(10, BlockProcessCallbacks(
|
||||||
onPayloadProducerSelected: proc(): bool =
|
onPayloadProducerSelected: proc(): bool =
|
||||||
let
|
testCond t.sendTx(0.u256)
|
||||||
tx = t.makeNextTransaction(prevRandaoContractAddr, 0.u256)
|
shadow.txs.add t.tx
|
||||||
rr = client.sendTransaction(tx)
|
|
||||||
|
|
||||||
if rr.isErr:
|
|
||||||
error "Unable to send transaction", msg=rr.error
|
|
||||||
return false
|
|
||||||
|
|
||||||
shadow.txs.add tx
|
|
||||||
inc shadow.currentTxIndex
|
inc shadow.currentTxIndex
|
||||||
return true
|
return true
|
||||||
,
|
,
|
||||||
@ -1764,6 +1813,12 @@ const engineTestList* = [
|
|||||||
name: "ParentHash==BlockHash on NewPayload",
|
name: "ParentHash==BlockHash on NewPayload",
|
||||||
run: parentHashOnExecPayload,
|
run: parentHashOnExecPayload,
|
||||||
),
|
),
|
||||||
|
TestSpec(
|
||||||
|
name: "Invalid Transition Payload",
|
||||||
|
run: invalidTransitionPayload,
|
||||||
|
ttd: 393504,
|
||||||
|
chainFile: "blocks_2_td_393504.rlp",
|
||||||
|
),
|
||||||
TestSpec(
|
TestSpec(
|
||||||
name: "Invalid ParentHash NewPayload",
|
name: "Invalid ParentHash NewPayload",
|
||||||
run: invalidPayload1,
|
run: invalidPayload1,
|
||||||
|
@ -263,7 +263,10 @@ proc modifyHash(x: Hash256): Hash256 =
|
|||||||
result = x
|
result = x
|
||||||
result.data[^1] = byte(255 - x.data[^1].int)
|
result.data[^1] = byte(255 - x.data[^1].int)
|
||||||
|
|
||||||
proc generateInvalidPayload*(basePayload: ExecutableData, payloadField: InvalidPayloadField, vaultKey: PrivateKey): ExecutionPayloadV1 =
|
proc generateInvalidPayload*(basePayload: ExecutableData,
|
||||||
|
payloadField: InvalidPayloadField,
|
||||||
|
vaultKey: PrivateKey): ExecutionPayloadV1 =
|
||||||
|
|
||||||
var customPayload: CustomPayload
|
var customPayload: CustomPayload
|
||||||
|
|
||||||
case payloadField
|
case payloadField
|
||||||
@ -324,3 +327,8 @@ proc generateInvalidPayload*(basePayload: ExecutableData, payloadField: InvalidP
|
|||||||
customPayload.transactions = some(@[modTx])
|
customPayload.transactions = some(@[modTx])
|
||||||
|
|
||||||
customizePayload(basePayload, customPayload)
|
customizePayload(basePayload, customPayload)
|
||||||
|
|
||||||
|
proc generateInvalidPayload*(basePayload: ExecutionPayloadV1,
|
||||||
|
payloadField: InvalidPayloadField,
|
||||||
|
vaultKey = default(PrivateKey)): ExecutionPayloadV1 =
|
||||||
|
generateInvalidPayload(basePayload.toExecutableData, payloadField, vaultKey)
|
||||||
|
@ -8,6 +8,7 @@ import
|
|||||||
json_rpc/[rpcserver, rpcclient],
|
json_rpc/[rpcserver, rpcclient],
|
||||||
../../../nimbus/[
|
../../../nimbus/[
|
||||||
config,
|
config,
|
||||||
|
conf_utils,
|
||||||
genesis,
|
genesis,
|
||||||
context,
|
context,
|
||||||
constants,
|
constants,
|
||||||
@ -48,8 +49,9 @@ type
|
|||||||
gHeader*: EthBlockHeader
|
gHeader*: EthBlockHeader
|
||||||
ttd*: DifficultyInt
|
ttd*: DifficultyInt
|
||||||
clMock*: CLMocker
|
clMock*: CLMocker
|
||||||
nonce: uint64
|
nonce*: uint64
|
||||||
vaultKey*: PrivateKey
|
vaultKey*: PrivateKey
|
||||||
|
tx*: Transaction
|
||||||
|
|
||||||
Web3BlockHash* = web3types.BlockHash
|
Web3BlockHash* = web3types.BlockHash
|
||||||
Web3Address* = web3types.Address
|
Web3Address* = web3types.Address
|
||||||
@ -62,12 +64,17 @@ const
|
|||||||
baseFolder = "hive_integration" / "nodocker" / "engine"
|
baseFolder = "hive_integration" / "nodocker" / "engine"
|
||||||
genesisFile = baseFolder / "genesis.json"
|
genesisFile = baseFolder / "genesis.json"
|
||||||
sealerKey = baseFolder / "sealer.key"
|
sealerKey = baseFolder / "sealer.key"
|
||||||
|
chainFolder = baseFolder / "chains"
|
||||||
|
|
||||||
# This is the account that sends vault funding transactions.
|
# This is the account that sends vault funding transactions.
|
||||||
vaultAccountAddr* = hexToByteArray[20]("0xcf49fda3be353c69b41ed96333cd24302da4556f")
|
vaultAccountAddr* = hexToByteArray[20]("0xcf49fda3be353c69b41ed96333cd24302da4556f")
|
||||||
vaultKeyHex = "63b508a03c3b5937ceb903af8b1b0c191012ef6eb7e9c3fb7afa94e5d214d376"
|
vaultKeyHex = "63b508a03c3b5937ceb903af8b1b0c191012ef6eb7e9c3fb7afa94e5d214d376"
|
||||||
|
|
||||||
proc setupELClient*(t: TestEnv) =
|
proc setupELClient*(t: TestEnv, chainFile: string) =
|
||||||
|
if chainFile.len > 0:
|
||||||
|
# disable clique if we are using PoW chain
|
||||||
|
t.conf.networkParams.config.poaEngine = false
|
||||||
|
|
||||||
t.ctx = newEthContext()
|
t.ctx = newEthContext()
|
||||||
let res = t.ctx.am.importPrivateKey(sealerKey)
|
let res = t.ctx.am.importPrivateKey(sealerKey)
|
||||||
if res.isErr:
|
if res.isErr:
|
||||||
@ -96,7 +103,13 @@ proc setupELClient*(t: TestEnv) =
|
|||||||
setupEngineAPI(t.sealingEngine, t.rpcServer)
|
setupEngineAPI(t.sealingEngine, t.rpcServer)
|
||||||
setupDebugRpc(t.chainDB, t.rpcServer)
|
setupDebugRpc(t.chainDB, t.rpcServer)
|
||||||
|
|
||||||
t.sealingEngine.start()
|
# Do not start clique sealing engine if we are using a Proof of Work chain file
|
||||||
|
if chainFile.len > 0:
|
||||||
|
if not importRlpBlock(chainFolder / chainFile, t.chainDB):
|
||||||
|
quit(QuitFailure)
|
||||||
|
else:
|
||||||
|
t.sealingEngine.start()
|
||||||
|
|
||||||
t.rpcServer.start()
|
t.rpcServer.start()
|
||||||
|
|
||||||
t.rpcClient = newRpcSocketClient()
|
t.rpcClient = newRpcSocketClient()
|
||||||
@ -110,11 +123,11 @@ proc setupELClient*(t: TestEnv) =
|
|||||||
|
|
||||||
t.vaultKey = kRes.get
|
t.vaultKey = kRes.get
|
||||||
|
|
||||||
proc setupELClient*(): TestEnv =
|
proc setupELClient*(chainFile: string): TestEnv =
|
||||||
result = TestEnv(
|
result = TestEnv(
|
||||||
conf: makeConfig(@["--engine-signer:658bdf435d810c91414ec09147daa6db62406379", "--custom-network:" & genesisFile])
|
conf: makeConfig(@["--engine-signer:658bdf435d810c91414ec09147daa6db62406379", "--custom-network:" & genesisFile])
|
||||||
)
|
)
|
||||||
setupELClient(result)
|
setupELClient(result, chainFile)
|
||||||
|
|
||||||
proc stopELClient*(t: TestEnv) =
|
proc stopELClient*(t: TestEnv) =
|
||||||
waitFor t.rpcClient.close()
|
waitFor t.rpcClient.close()
|
||||||
|
@ -19,6 +19,7 @@ type
|
|||||||
ok*: int
|
ok*: int
|
||||||
skipped*: int
|
skipped*: int
|
||||||
failed*: int
|
failed*: int
|
||||||
|
failingCases*: seq[string]
|
||||||
|
|
||||||
proc inc*(stat: var SimStat, name: string, status: TestStatus) =
|
proc inc*(stat: var SimStat, name: string, status: TestStatus) =
|
||||||
echo name, ", ", status
|
echo name, ", ", status
|
||||||
@ -28,9 +29,13 @@ proc inc*(stat: var SimStat, name: string, status: TestStatus) =
|
|||||||
inc stat.skipped
|
inc stat.skipped
|
||||||
else:
|
else:
|
||||||
inc stat.failed
|
inc stat.failed
|
||||||
|
stat.failingCases.add name
|
||||||
|
|
||||||
proc `$`*(stat: SimStat): string =
|
proc `$`*(stat: SimStat): string =
|
||||||
"ok: $1, skipped: $2, failed: $3" % [$stat.ok, $stat.skipped, $stat.failed]
|
result.add "Failing Cases:\n"
|
||||||
|
for c in stat.failingCases:
|
||||||
|
result.add "- $1 \n" % [c]
|
||||||
|
result.add "ok: $1, skipped: $2, failed: $3" % [$stat.ok, $stat.skipped, $stat.failed]
|
||||||
|
|
||||||
proc print*(stat: SimStat, dur: Duration, name: string) =
|
proc print*(stat: SimStat, dur: Duration, name: string) =
|
||||||
var f = open(name & ".md", fmWrite)
|
var f = open(name & ".md", fmWrite)
|
||||||
|
@ -75,6 +75,14 @@ proc simpleFCU*(status: PayloadExecutionStatus): ForkchoiceUpdatedResponse =
|
|||||||
proc simpleFCU*(status: PayloadExecutionStatus, msg: string): ForkchoiceUpdatedResponse =
|
proc simpleFCU*(status: PayloadExecutionStatus, msg: string): ForkchoiceUpdatedResponse =
|
||||||
ForkchoiceUpdatedResponse(payloadStatus: PayloadStatusV1(status: status, validationError: some(msg)))
|
ForkchoiceUpdatedResponse(payloadStatus: PayloadStatusV1(status: status, validationError: some(msg)))
|
||||||
|
|
||||||
|
proc invalidFCU*(hash: Hash256 = Hash256()): ForkchoiceUpdatedResponse =
|
||||||
|
ForkchoiceUpdatedResponse(payloadStatus:
|
||||||
|
PayloadStatusV1(
|
||||||
|
status: PayloadExecutionStatus.invalid,
|
||||||
|
latestValidHash: some(BlockHash hash.data)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
proc validFCU*(id: Option[PayloadID], validHash: Hash256): ForkchoiceUpdatedResponse =
|
proc validFCU*(id: Option[PayloadID], validHash: Hash256): ForkchoiceUpdatedResponse =
|
||||||
ForkchoiceUpdatedResponse(
|
ForkchoiceUpdatedResponse(
|
||||||
payloadStatus: PayloadStatusV1(
|
payloadStatus: PayloadStatusV1(
|
||||||
@ -91,8 +99,13 @@ proc invalidStatus*(validHash: Hash256, msg: string): PayloadStatusV1 =
|
|||||||
validationError: some(msg)
|
validationError: some(msg)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
proc invalidStatus*(validHash: Hash256 = Hash256()): PayloadStatusV1 =
|
||||||
|
PayloadStatusV1(
|
||||||
|
status: PayloadExecutionStatus.invalid,
|
||||||
|
latestValidHash: some(BlockHash validHash.data)
|
||||||
|
)
|
||||||
|
|
||||||
proc toBlockBody*(payload: ExecutionPayloadV1): BlockBody =
|
proc toBlockBody*(payload: ExecutionPayloadV1): BlockBody =
|
||||||
# TODO the transactions from the payload have to be converted here
|
|
||||||
result.transactions.setLen(payload.transactions.len)
|
result.transactions.setLen(payload.transactions.len)
|
||||||
for i, tx in payload.transactions:
|
for i, tx in payload.transactions:
|
||||||
result.transactions[i] = rlp.decode(distinctBase tx, Transaction)
|
result.transactions[i] = rlp.decode(distinctBase tx, Transaction)
|
||||||
|
@ -84,7 +84,7 @@ proc setupEngineAPI*(
|
|||||||
if td < ttd:
|
if td < ttd:
|
||||||
warn "Ignoring pre-merge payload",
|
warn "Ignoring pre-merge payload",
|
||||||
number = header.blockNumber, hash = blockHash.data.toHex, td, ttd
|
number = header.blockNumber, hash = blockHash.data.toHex, td, ttd
|
||||||
return PayloadStatusV1(status: PayloadExecutionStatus.invalid)
|
return invalidStatus()
|
||||||
|
|
||||||
if header.timestamp <= parent.timestamp:
|
if header.timestamp <= parent.timestamp:
|
||||||
warn "Invalid timestamp",
|
warn "Invalid timestamp",
|
||||||
@ -96,7 +96,14 @@ proc setupEngineAPI*(
|
|||||||
let body = toBlockBody(payload)
|
let body = toBlockBody(payload)
|
||||||
let vres = sealingEngine.chain.insertBlockWithoutSetHead(header, body)
|
let vres = sealingEngine.chain.insertBlockWithoutSetHead(header, body)
|
||||||
if vres != ValidationResult.OK:
|
if vres != ValidationResult.OK:
|
||||||
return invalidStatus(db.getHeadBlockHash(), "Failed to insert block")
|
let ptd = db.getScore(parent.parentHash)
|
||||||
|
let blockHash = if ptd >= ttd:
|
||||||
|
db.getHeadBlockHash()
|
||||||
|
else:
|
||||||
|
# If the most recent valid ancestor is a PoW block,
|
||||||
|
# latestValidHash MUST be set to ZERO
|
||||||
|
Hash256()
|
||||||
|
return invalidStatus(blockHash, "Failed to insert block")
|
||||||
|
|
||||||
# We've accepted a valid payload from the beacon client. Mark the local
|
# We've accepted a valid payload from the beacon client. Mark the local
|
||||||
# chain transitions to notify other subsystems (e.g. downloader) of the
|
# chain transitions to notify other subsystems (e.g. downloader) of the
|
||||||
@ -231,7 +238,7 @@ proc setupEngineAPI*(
|
|||||||
ptd = ptd,
|
ptd = ptd,
|
||||||
ttd = ttd
|
ttd = ttd
|
||||||
|
|
||||||
return simpleFCU(PayloadExecutionStatus.invalid)
|
return invalidFCU()
|
||||||
|
|
||||||
# If the head block is already in our canonical chain, the beacon client is
|
# If the head block is already in our canonical chain, the beacon client is
|
||||||
# probably resyncing. Ignore the update.
|
# probably resyncing. Ignore the update.
|
||||||
|
Loading…
x
Reference in New Issue
Block a user