mirror of
https://github.com/status-im/nimbus-eth1.git
synced 2025-01-11 21:04:11 +00:00
modify hive simulators to run in CI
This commit is contained in:
parent
99eea47dff
commit
6fcd63cb58
@ -8,44 +8,54 @@
|
|||||||
# those terms.
|
# those terms.
|
||||||
|
|
||||||
import
|
import
|
||||||
std/[os, strformat, json],
|
std/[os, json, strutils, times],
|
||||||
eth/[common, trie/db], stew/byteutils,
|
eth/[common, trie/db, p2p], stew/byteutils,
|
||||||
../../../nimbus/db/db_chain,
|
../../../nimbus/db/db_chain,
|
||||||
../../../nimbus/[genesis, config, conf_utils],
|
../../../nimbus/[genesis, chain_config, conf_utils],
|
||||||
../sim_utils
|
../sim_utils,
|
||||||
|
./extract_consensus_data
|
||||||
|
|
||||||
proc processNode(genesisFile, chainFile,
|
proc processChainData(cd: ChainData): TestStatus =
|
||||||
lastBlockHash: string, testStatusIMPL: var TestStatus) =
|
var np: NetworkParams
|
||||||
|
doAssert decodeNetworkParams(cd.genesis, np)
|
||||||
|
|
||||||
let
|
let
|
||||||
conf = makeConfig(@["--custom-network:" & genesisFile])
|
networkId = NetworkId(np.config.chainId)
|
||||||
chainDB = newBaseChainDB(newMemoryDB(),
|
chainDB = newBaseChainDB(newMemoryDB(),
|
||||||
pruneTrie = false,
|
pruneTrie = false,
|
||||||
conf.networkId,
|
networkId,
|
||||||
conf.networkParams
|
np
|
||||||
)
|
)
|
||||||
|
|
||||||
initializeEmptyDb(chainDB)
|
initializeEmptyDb(chainDB)
|
||||||
discard importRlpBlock(chainFile, chainDB)
|
discard importRlpBlock(cd.blocksRlp, chainDB, "consensus_sim")
|
||||||
let head = chainDB.getCanonicalHead()
|
let head = chainDB.getCanonicalHead()
|
||||||
let blockHash = "0x" & head.blockHash.data.toHex
|
let blockHash = "0x" & head.blockHash.data.toHex
|
||||||
check blockHash == lastBlockHash
|
if blockHash == cd.lastBlockHash:
|
||||||
|
TestStatus.OK
|
||||||
|
else:
|
||||||
|
TestStatus.Failed
|
||||||
|
|
||||||
proc main() =
|
proc main() =
|
||||||
let caseFolder = if paramCount() == 0:
|
const basePath = "tests" / "fixtures" / "eth_tests" / "BlockchainTests"
|
||||||
"consensus_data"
|
var stat: SimStat
|
||||||
else:
|
let start = getTime()
|
||||||
paramStr(1)
|
|
||||||
|
|
||||||
if not caseFolder.dirExists:
|
for fileName in walkDirRec(basePath):
|
||||||
# Handy early error message and stop directive
|
if not fileName.endsWith(".json"):
|
||||||
let progname = getAppFilename().extractFilename
|
continue
|
||||||
quit(&"*** {progname}: Not a case folder: {caseFolder}")
|
|
||||||
|
|
||||||
runTest("Consensus", caseFolder):
|
let n = json.parseFile(fileName)
|
||||||
# Variable `fileName` is injected by `runTest()`
|
for name, unit in n:
|
||||||
let node = parseFile(fileName)
|
if "loopMul" in name:
|
||||||
processNode(fileName, node["chainfile"].getStr,
|
inc stat.skipped
|
||||||
node["lastblockhash"].getStr, testStatusIMPL)
|
continue
|
||||||
|
|
||||||
|
let cd = extractChainData(unit)
|
||||||
|
let status = processChainData(cd)
|
||||||
|
stat.inc(name, status)
|
||||||
|
|
||||||
|
let elpd = getTime() - start
|
||||||
|
print(stat, elpd, "consensus")
|
||||||
|
|
||||||
main()
|
main()
|
||||||
|
@ -8,17 +8,14 @@
|
|||||||
# those terms.
|
# those terms.
|
||||||
|
|
||||||
import
|
import
|
||||||
std/[json, os, strutils, parseopt, terminal],
|
std/[json, strutils],
|
||||||
stew/byteutils
|
stew/byteutils
|
||||||
|
|
||||||
type
|
type
|
||||||
ChainData = object
|
ChainData* = object
|
||||||
genesis: JsonNode
|
genesis*: string
|
||||||
blocksRlp: seq[byte]
|
lastBlockHash*: string
|
||||||
|
blocksRlp*: seq[byte]
|
||||||
Config = object
|
|
||||||
outPath: string
|
|
||||||
filter: string
|
|
||||||
|
|
||||||
const genFields = [
|
const genFields = [
|
||||||
"nonce",
|
"nonce",
|
||||||
@ -179,7 +176,7 @@ proc optionalField(n: string, genesis, gen: JsonNode) =
|
|||||||
if n in gen:
|
if n in gen:
|
||||||
genesis[n] = gen[n]
|
genesis[n] = gen[n]
|
||||||
|
|
||||||
proc extractChainData(n: JsonNode, chainFile: string): ChainData =
|
proc extractChainData*(n: JsonNode): ChainData =
|
||||||
let gen = n["genesisBlockHeader"]
|
let gen = n["genesisBlockHeader"]
|
||||||
var genesis = newJObject()
|
var genesis = newJObject()
|
||||||
for x in genFields:
|
for x in genFields:
|
||||||
@ -191,68 +188,11 @@ proc extractChainData(n: JsonNode, chainFile: string): ChainData =
|
|||||||
var ngen = newJObject()
|
var ngen = newJObject()
|
||||||
ngen["genesis"] = genesis
|
ngen["genesis"] = genesis
|
||||||
ngen["config"] = processNetwork(n["network"].getStr)
|
ngen["config"] = processNetwork(n["network"].getStr)
|
||||||
ngen["lastblockhash"] = n["lastblockhash"]
|
result.lastblockhash = n["lastblockhash"].getStr
|
||||||
ngen["chainfile"] = %chainFile
|
result.genesis = $ngen
|
||||||
result.genesis = ngen
|
|
||||||
|
|
||||||
let blks = n["blocks"]
|
let blks = n["blocks"]
|
||||||
for x in blks:
|
for x in blks:
|
||||||
let hex = x["rlp"].getStr
|
let hex = x["rlp"].getStr
|
||||||
let bytes = hexToSeqByte(hex)
|
let bytes = hexToSeqByte(hex)
|
||||||
result.blocksRlp.add bytes
|
result.blocksRlp.add bytes
|
||||||
|
|
||||||
proc processFile(fileName, outPath: string): int =
|
|
||||||
let n = json.parseFile(fileName)
|
|
||||||
let (folder, name) = fileName.splitPath()
|
|
||||||
let last = folder.splitPath().tail
|
|
||||||
|
|
||||||
for name, unit in n:
|
|
||||||
let name = last & "_" & name
|
|
||||||
let cd = extractChainData(unit, outPath / name & "_chain.rlp")
|
|
||||||
writeFile(outPath / name & "_config.json", cd.genesis.pretty)
|
|
||||||
writeFile(outPath / name & "_chain.rlp", cd.blocksRlp)
|
|
||||||
inc result
|
|
||||||
|
|
||||||
proc initConfig(): Config =
|
|
||||||
result.outPath = "consensus_data"
|
|
||||||
|
|
||||||
proc processArguments(conf: var Config) =
|
|
||||||
var opt = initOptParser()
|
|
||||||
|
|
||||||
for kind, key, value in opt.getopt():
|
|
||||||
case kind
|
|
||||||
of cmdArgument:
|
|
||||||
conf.filter = key
|
|
||||||
of cmdLongOption, cmdShortOption:
|
|
||||||
case key.toLowerAscii()
|
|
||||||
of "o": conf.outPath = value
|
|
||||||
else:
|
|
||||||
var msg = "Unknown option " & key
|
|
||||||
if value.len > 0: msg = msg & " : " & value
|
|
||||||
quit(QuitFailure)
|
|
||||||
of cmdEnd:
|
|
||||||
doAssert(false)
|
|
||||||
|
|
||||||
proc main() =
|
|
||||||
const basePath = "tests" / "fixtures" / "eth_tests" / "BlockchainTests"
|
|
||||||
|
|
||||||
var conf = initConfig()
|
|
||||||
processArguments(conf)
|
|
||||||
createDir(conf.outPath)
|
|
||||||
|
|
||||||
var count = 0
|
|
||||||
for fileName in walkDirRec(basePath):
|
|
||||||
if not fileName.endsWith(".json"):
|
|
||||||
continue
|
|
||||||
let (_, name) = fileName.splitPath()
|
|
||||||
if conf.filter notin fileName:
|
|
||||||
continue
|
|
||||||
|
|
||||||
terminal.eraseLine(stdout)
|
|
||||||
stdout.write "\r"
|
|
||||||
stdout.write name
|
|
||||||
count += processFile(fileName, conf.outPath)
|
|
||||||
|
|
||||||
echo "\ntest data generated: ", count
|
|
||||||
|
|
||||||
main()
|
|
||||||
|
@ -1,19 +1,21 @@
|
|||||||
import
|
import
|
||||||
test_env,
|
test_env,
|
||||||
engine_tests,
|
engine_tests,
|
||||||
chronos,
|
unittest2,
|
||||||
unittest2
|
../sim_utils
|
||||||
|
|
||||||
proc runTest(x: TestSpec, testStatusIMPL: var TestStatus) =
|
|
||||||
var t = setupELClient()
|
|
||||||
t.setRealTTD(x.ttd)
|
|
||||||
x.run(t, testStatusIMPL)
|
|
||||||
t.stopELClient()
|
|
||||||
|
|
||||||
proc main() =
|
proc main() =
|
||||||
suite "Engine Tests":
|
var stat: SimStat
|
||||||
|
let start = getTime()
|
||||||
|
|
||||||
for x in engineTestList:
|
for x in engineTestList:
|
||||||
test x.name:
|
var t = setupELClient()
|
||||||
runTest(x, testStatusIMPL)
|
t.setRealTTD(x.ttd)
|
||||||
|
let status = x.run(t)
|
||||||
|
t.stopELClient()
|
||||||
|
stat.inc(x.name, status)
|
||||||
|
|
||||||
|
let elpd = getTime() - start
|
||||||
|
print(stat, elpd, "engine")
|
||||||
|
|
||||||
main()
|
main()
|
||||||
|
@ -14,15 +14,26 @@ import
|
|||||||
type
|
type
|
||||||
TestSpec* = object
|
TestSpec* = object
|
||||||
name*: string
|
name*: string
|
||||||
run*: proc(t: TestEnv, testStatusIMPL: var TestStatus)
|
run*: proc(t: TestEnv): TestStatus
|
||||||
ttd*: int64
|
ttd*: int64
|
||||||
|
|
||||||
const
|
const
|
||||||
prevRandaoContractAddr = hexToByteArray[20]("0000000000000000000000000000000000000316")
|
prevRandaoContractAddr = hexToByteArray[20]("0000000000000000000000000000000000000316")
|
||||||
|
|
||||||
|
template testCond(expr: untyped) =
|
||||||
|
if not (expr):
|
||||||
|
return TestStatus.Failed
|
||||||
|
|
||||||
|
template testCond(expr, body: untyped) =
|
||||||
|
if not (expr):
|
||||||
|
body
|
||||||
|
return TestStatus.Failed
|
||||||
|
|
||||||
# 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.
|
||||||
proc invalidTerminalBlockForkchoiceUpdated(t: TestEnv, testStatusIMPL: var TestStatus) =
|
proc invalidTerminalBlockForkchoiceUpdated(t: TestEnv): TestStatus =
|
||||||
|
result = TestStatus.OK
|
||||||
|
|
||||||
let
|
let
|
||||||
gHash = Web3BlockHash t.gHeader.blockHash.data
|
gHash = Web3BlockHash t.gHeader.blockHash.data
|
||||||
forkchoiceState = ForkchoiceStateV1(
|
forkchoiceState = ForkchoiceStateV1(
|
||||||
@ -36,28 +47,29 @@ proc invalidTerminalBlockForkchoiceUpdated(t: TestEnv, testStatusIMPL: var TestS
|
|||||||
# Execution specification:
|
# Execution specification:
|
||||||
# {payloadStatus: {status: INVALID_TERMINAL_BLOCK, latestValidHash: null, validationError: errorMessage | null}, payloadId: null}
|
# {payloadStatus: {status: INVALID_TERMINAL_BLOCK, latestValidHash: null, validationError: errorMessage | null}, 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
|
||||||
check res.isOk
|
testCond res.isOk
|
||||||
|
|
||||||
if res.isErr:
|
|
||||||
return
|
|
||||||
|
|
||||||
let s = res.get()
|
let s = res.get()
|
||||||
check s.payloadStatus.status == PayloadExecutionStatus.invalid_terminal_block
|
testCond s.payloadStatus.status == PayloadExecutionStatus.invalid_terminal_block
|
||||||
check s.payloadStatus.latestValidHash.isNone
|
testCond s.payloadStatus.latestValidHash.isNone
|
||||||
check s.payloadId.isNone
|
testCond s.payloadId.isNone
|
||||||
|
|
||||||
# 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
|
||||||
|
|
||||||
# Invalid GetPayload Under PoW: Client must reject GetPayload directives under PoW.
|
# Invalid GetPayload Under PoW: Client must reject GetPayload directives under PoW.
|
||||||
proc invalidGetPayloadUnderPoW(t: TestEnv, testStatusIMPL: var TestStatus) =
|
proc invalidGetPayloadUnderPoW(t: TestEnv): TestStatus =
|
||||||
|
result = TestStatus.OK
|
||||||
|
|
||||||
# We start in PoW and try to get an invalid Payload, which should produce an error but nothing should be disrupted.
|
# We start in PoW and try to get an invalid Payload, which should produce an error but nothing should be disrupted.
|
||||||
let id = PayloadID [1.byte, 2,3,4,5,6,7,8]
|
let id = PayloadID [1.byte, 2,3,4,5,6,7,8]
|
||||||
let res = t.rpcClient.getPayloadV1(id)
|
let res = t.rpcClient.getPayloadV1(id)
|
||||||
check res.isErr
|
testCond res.isErr
|
||||||
|
|
||||||
# Invalid Terminal Block in NewPayload:
|
# Invalid Terminal Block in NewPayload:
|
||||||
# Client must reject NewPayload directives if the referenced ParentHash does not meet the TTD requirement.
|
# Client must reject NewPayload directives if the referenced ParentHash does not meet the TTD requirement.
|
||||||
proc invalidTerminalBlockNewPayload(t: TestEnv, testStatusIMPL: var TestStatus) =
|
proc invalidTerminalBlockNewPayload(t: TestEnv): TestStatus =
|
||||||
|
result = TestStatus.OK
|
||||||
|
|
||||||
let gBlock = t.gHeader
|
let gBlock = t.gHeader
|
||||||
let payload = ExecutableData(
|
let payload = ExecutableData(
|
||||||
parentHash: gBlock.blockHash,
|
parentHash: gBlock.blockHash,
|
||||||
@ -75,23 +87,20 @@ proc invalidTerminalBlockNewPayload(t: TestEnv, testStatusIMPL: var TestStatus)
|
|||||||
# Execution specification:
|
# Execution specification:
|
||||||
# {status: INVALID_TERMINAL_BLOCK, latestValidHash: null, validationError: errorMessage | null}
|
# {status: INVALID_TERMINAL_BLOCK, latestValidHash: null, validationError: errorMessage | null}
|
||||||
# if terminal block conditions are not satisfied
|
# if terminal block conditions are not satisfied
|
||||||
check res.isOk
|
testCond res.isOk
|
||||||
if res.isErr:
|
|
||||||
return
|
|
||||||
|
|
||||||
let s = res.get()
|
let s = res.get()
|
||||||
check s.status == PayloadExecutionStatus.invalid_terminal_block
|
testCond s.status == PayloadExecutionStatus.invalid_terminal_block
|
||||||
check s.latestValidHash.isNone
|
testCond s.latestValidHash.isNone
|
||||||
|
|
||||||
|
proc unknownHeadBlockHash(t: TestEnv): TestStatus =
|
||||||
|
result = TestStatus.OK
|
||||||
|
|
||||||
proc unknownHeadBlockHash(t: TestEnv, testStatusIMPL: var TestStatus) =
|
|
||||||
let ok = waitFor t.clMock.waitForTTD()
|
let ok = waitFor t.clMock.waitForTTD()
|
||||||
check ok
|
testCond ok
|
||||||
|
|
||||||
if not ok:
|
|
||||||
return
|
|
||||||
|
|
||||||
var randomHash: Hash256
|
var randomHash: Hash256
|
||||||
check nimcrypto.randomBytes(randomHash.data) == 32
|
testCond nimcrypto.randomBytes(randomHash.data) == 32
|
||||||
|
|
||||||
let clMock = t.clMock
|
let clMock = t.clMock
|
||||||
let forkchoiceStateUnknownHeadHash = ForkchoiceStateV1(
|
let forkchoiceStateUnknownHeadHash = ForkchoiceStateV1(
|
||||||
@ -101,16 +110,14 @@ proc unknownHeadBlockHash(t: TestEnv, testStatusIMPL: var TestStatus) =
|
|||||||
)
|
)
|
||||||
|
|
||||||
var res = t.rpcClient.forkchoiceUpdatedV1(forkchoiceStateUnknownHeadHash)
|
var res = t.rpcClient.forkchoiceUpdatedV1(forkchoiceStateUnknownHeadHash)
|
||||||
check res.isOk
|
testCond res.isOk
|
||||||
if res.isErr:
|
|
||||||
return
|
|
||||||
|
|
||||||
let s = res.get()
|
let s = res.get()
|
||||||
# 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
|
||||||
check s.payloadStatus.status == PayloadExecutionStatus.syncing
|
testCond s.payloadStatus.status == PayloadExecutionStatus.syncing
|
||||||
|
|
||||||
# Test again using PayloadAttributes, should also return SYNCING and no PayloadID
|
# Test again using PayloadAttributes, should also return SYNCING and no PayloadID
|
||||||
let timestamp = uint64 clMock.latestExecutedPayload.timestamp
|
let timestamp = uint64 clMock.latestExecutedPayload.timestamp
|
||||||
@ -119,22 +126,19 @@ proc unknownHeadBlockHash(t: TestEnv, testStatusIMPL: var TestStatus) =
|
|||||||
)
|
)
|
||||||
|
|
||||||
res = t.rpcClient.forkchoiceUpdatedV1(forkchoiceStateUnknownHeadHash, some(payloadAttr))
|
res = t.rpcClient.forkchoiceUpdatedV1(forkchoiceStateUnknownHeadHash, some(payloadAttr))
|
||||||
check res.isOk
|
testCond res.isOk
|
||||||
if res.isErr:
|
testCond s.payloadStatus.status == PayloadExecutionStatus.syncing
|
||||||
return
|
testCond s.payloadId.isNone
|
||||||
check s.payloadStatus.status == PayloadExecutionStatus.syncing
|
|
||||||
check s.payloadId.isNone
|
proc unknownSafeBlockHash(t: TestEnv): TestStatus =
|
||||||
|
result = TestStatus.OK
|
||||||
|
|
||||||
proc unknownSafeBlockHash(t: TestEnv, testStatusIMPL: var TestStatus) =
|
|
||||||
let ok = waitFor t.clMock.waitForTTD()
|
let ok = waitFor t.clMock.waitForTTD()
|
||||||
check ok
|
testCond ok
|
||||||
|
|
||||||
if not ok:
|
|
||||||
return
|
|
||||||
|
|
||||||
# Produce blocks before starting the test
|
# Produce blocks before starting the test
|
||||||
let produce5BlockRes = t.clMock.produceBlocks(5, BlockProcessCallbacks())
|
let produce5BlockRes = t.clMock.produceBlocks(5, BlockProcessCallbacks())
|
||||||
check produce5BlockRes
|
testCond produce5BlockRes
|
||||||
|
|
||||||
let clMock = t.clMock
|
let clMock = t.clMock
|
||||||
let client = t.rpcClient
|
let client = t.rpcClient
|
||||||
@ -157,18 +161,17 @@ proc unknownSafeBlockHash(t: TestEnv, testStatusIMPL: var TestStatus) =
|
|||||||
return res.isErr
|
return res.isErr
|
||||||
))
|
))
|
||||||
|
|
||||||
check produceSingleBlockRes
|
testCond produceSingleBlockRes
|
||||||
|
|
||||||
|
proc unknownFinalizedBlockHash(t: TestEnv): TestStatus =
|
||||||
|
result = TestStatus.OK
|
||||||
|
|
||||||
proc unknownFinalizedBlockHash(t: TestEnv, testStatusIMPL: var TestStatus) =
|
|
||||||
let ok = waitFor t.clMock.waitForTTD()
|
let ok = waitFor t.clMock.waitForTTD()
|
||||||
check ok
|
testCond ok
|
||||||
|
|
||||||
if not ok:
|
|
||||||
return
|
|
||||||
|
|
||||||
# Produce blocks before starting the test
|
# Produce blocks before starting the test
|
||||||
let produce5BlockRes = t.clMock.produceBlocks(5, BlockProcessCallbacks())
|
let produce5BlockRes = t.clMock.produceBlocks(5, BlockProcessCallbacks())
|
||||||
check produce5BlockRes
|
testCond produce5BlockRes
|
||||||
|
|
||||||
let clMock = t.clMock
|
let clMock = t.clMock
|
||||||
let client = t.rpcClient
|
let client = t.rpcClient
|
||||||
@ -200,19 +203,17 @@ proc unknownFinalizedBlockHash(t: TestEnv, testStatusIMPL: var TestStatus) =
|
|||||||
return res.isErr
|
return res.isErr
|
||||||
))
|
))
|
||||||
|
|
||||||
check produceSingleBlockRes
|
testCond produceSingleBlockRes
|
||||||
|
|
||||||
|
proc preTTDFinalizedBlockHash(t: TestEnv): TestStatus =
|
||||||
|
result = TestStatus.OK
|
||||||
|
|
||||||
proc preTTDFinalizedBlockHash(t: TestEnv, testStatusIMPL: var TestStatus) =
|
|
||||||
let ok = waitFor t.clMock.waitForTTD()
|
let ok = waitFor t.clMock.waitForTTD()
|
||||||
check ok
|
testCond ok
|
||||||
if not ok:
|
|
||||||
return
|
|
||||||
|
|
||||||
# Produce blocks before starting the test
|
# Produce blocks before starting the test
|
||||||
let produce5BlockRes = t.clMock.produceBlocks(5, BlockProcessCallbacks())
|
let produce5BlockRes = t.clMock.produceBlocks(5, BlockProcessCallbacks())
|
||||||
check produce5BlockRes
|
testCond produce5BlockRes
|
||||||
if not produce5BlockRes:
|
|
||||||
return
|
|
||||||
|
|
||||||
let
|
let
|
||||||
gHash = Web3BlockHash t.gHeader.blockHash.data
|
gHash = Web3BlockHash t.gHeader.blockHash.data
|
||||||
@ -229,24 +230,19 @@ proc preTTDFinalizedBlockHash(t: TestEnv, testStatusIMPL: var TestStatus) =
|
|||||||
# if not defined on re-orgs to a point before the latest finalized block.
|
# if not defined on re-orgs to a point before the latest finalized block.
|
||||||
|
|
||||||
res = client.forkchoiceUpdatedV1(clMock.latestForkchoice)
|
res = client.forkchoiceUpdatedV1(clMock.latestForkchoice)
|
||||||
check res.isOk
|
testCond res.isOk
|
||||||
if res.isErr:
|
|
||||||
return
|
|
||||||
|
|
||||||
let s = res.get()
|
let s = res.get()
|
||||||
check s.payloadStatus.status == PayloadExecutionStatus.valid
|
testCond s.payloadStatus.status == PayloadExecutionStatus.valid
|
||||||
|
|
||||||
|
proc badHashOnExecPayload(t: TestEnv): TestStatus =
|
||||||
|
result = TestStatus.OK
|
||||||
|
|
||||||
proc badHashOnExecPayload(t: TestEnv, testStatusIMPL: var TestStatus) =
|
|
||||||
let ok = waitFor t.clMock.waitForTTD()
|
let ok = waitFor t.clMock.waitForTTD()
|
||||||
check ok
|
testCond ok
|
||||||
if not ok:
|
|
||||||
return
|
|
||||||
|
|
||||||
# Produce blocks before starting the test
|
# Produce blocks before starting the test
|
||||||
let produce5BlockRes = t.clMock.produceBlocks(5, BlockProcessCallbacks())
|
let produce5BlockRes = t.clMock.produceBlocks(5, BlockProcessCallbacks())
|
||||||
check produce5BlockRes
|
testCond produce5BlockRes
|
||||||
if not produce5BlockRes:
|
|
||||||
return
|
|
||||||
|
|
||||||
type
|
type
|
||||||
Shadow = ref object
|
Shadow = ref object
|
||||||
@ -274,9 +270,7 @@ proc badHashOnExecPayload(t: TestEnv, testStatusIMPL: var TestStatus) =
|
|||||||
let s = res.get()
|
let s = res.get()
|
||||||
s.status == PayloadExecutionStatus.invalid_block_hash
|
s.status == PayloadExecutionStatus.invalid_block_hash
|
||||||
))
|
))
|
||||||
check produceSingleBlockRes
|
testCond produceSingleBlockRes
|
||||||
if not produceSingleBlockRes:
|
|
||||||
return
|
|
||||||
|
|
||||||
# Lastly, attempt to build on top of the invalid payload
|
# Lastly, attempt to build on top of the invalid payload
|
||||||
produceSingleBlockRes = clMock.produceSingleBlock(BlockProcessCallbacks(
|
produceSingleBlockRes = clMock.produceSingleBlock(BlockProcessCallbacks(
|
||||||
@ -295,20 +289,18 @@ proc badHashOnExecPayload(t: TestEnv, testStatusIMPL: var TestStatus) =
|
|||||||
let s = res.get()
|
let s = res.get()
|
||||||
s.status != PayloadExecutionStatus.valid
|
s.status != PayloadExecutionStatus.valid
|
||||||
))
|
))
|
||||||
check produceSingleBlockRes
|
testCond produceSingleBlockRes
|
||||||
|
|
||||||
|
proc parentHashOnExecPayload(t: TestEnv): TestStatus =
|
||||||
|
result = TestStatus.OK
|
||||||
|
|
||||||
proc parentHashOnExecPayload(t: TestEnv, testStatusIMPL: var TestStatus) =
|
|
||||||
# Wait until TTD is reached by this client
|
# Wait until TTD is reached by this client
|
||||||
let ok = waitFor t.clMock.waitForTTD()
|
let ok = waitFor t.clMock.waitForTTD()
|
||||||
check ok
|
testCond ok
|
||||||
if not ok:
|
|
||||||
return
|
|
||||||
|
|
||||||
# Produce blocks before starting the test
|
# Produce blocks before starting the test
|
||||||
let produce5BlockRes = t.clMock.produceBlocks(5, BlockProcessCallbacks())
|
let produce5BlockRes = t.clMock.produceBlocks(5, BlockProcessCallbacks())
|
||||||
check produce5BlockRes
|
testCond produce5BlockRes
|
||||||
if not produce5BlockRes:
|
|
||||||
return
|
|
||||||
|
|
||||||
let clMock = t.clMock
|
let clMock = t.clMock
|
||||||
let client = t.rpcClient
|
let client = t.rpcClient
|
||||||
@ -326,31 +318,29 @@ proc parentHashOnExecPayload(t: TestEnv, testStatusIMPL: var TestStatus) =
|
|||||||
let s = res.get()
|
let s = res.get()
|
||||||
s.status == PayloadExecutionStatus.invalid_block_hash
|
s.status == PayloadExecutionStatus.invalid_block_hash
|
||||||
))
|
))
|
||||||
check produceSingleBlockRes
|
testCond produceSingleBlockRes
|
||||||
|
|
||||||
proc invalidPayloadTestCaseGen(payloadField: string): proc (t: TestEnv, testStatusIMPL: var TestStatus) =
|
proc invalidPayloadTestCaseGen(payloadField: string): proc (t: TestEnv): TestStatus =
|
||||||
return proc (t: TestEnv, testStatusIMPL: var TestStatus) =
|
return proc (t: TestEnv): TestStatus =
|
||||||
discard
|
result = TestStatus.SKIPPED
|
||||||
|
|
||||||
# Test to verify Block information available at the Eth RPC after NewPayload
|
# Test to verify Block information available at the Eth RPC after NewPayload
|
||||||
proc blockStatusExecPayload(t: TestEnv, testStatusIMPL: var TestStatus) =
|
proc blockStatusExecPayload(t: TestEnv): TestStatus =
|
||||||
|
result = TestStatus.OK
|
||||||
|
|
||||||
# Wait until TTD is reached by this client
|
# Wait until TTD is reached by this client
|
||||||
let ok = waitFor t.clMock.waitForTTD()
|
let ok = waitFor t.clMock.waitForTTD()
|
||||||
check ok
|
testCond ok
|
||||||
if not ok:
|
|
||||||
return
|
|
||||||
|
|
||||||
# Produce blocks before starting the test
|
# Produce blocks before starting the test
|
||||||
let produce5BlockRes = t.clMock.produceBlocks(5, BlockProcessCallbacks())
|
let produce5BlockRes = t.clMock.produceBlocks(5, BlockProcessCallbacks())
|
||||||
check produce5BlockRes
|
testCond produce5BlockRes
|
||||||
if not produce5BlockRes:
|
|
||||||
return
|
|
||||||
|
|
||||||
let clMock = t.clMock
|
let clMock = t.clMock
|
||||||
let client = t.rpcClient
|
let client = t.rpcClient
|
||||||
var produceSingleBlockRes = clMock.produceSingleBlock(BlockProcessCallbacks(
|
var produceSingleBlockRes = clMock.produceSingleBlock(BlockProcessCallbacks(
|
||||||
onNewPayloadBroadcast: proc(): bool =
|
onNewPayloadBroadcast: proc(): bool =
|
||||||
# TODO: Ideally, we would need to check that the newPayload returned VALID
|
# TODO: Ideally, we would need to testCond that the newPayload returned VALID
|
||||||
var lastHeader: EthBlockHeader
|
var lastHeader: EthBlockHeader
|
||||||
var hRes = client.latestHeader(lastHeader)
|
var hRes = client.latestHeader(lastHeader)
|
||||||
if hRes.isErr:
|
if hRes.isErr:
|
||||||
@ -381,20 +371,18 @@ proc blockStatusExecPayload(t: TestEnv, testStatusIMPL: var TestStatus) =
|
|||||||
|
|
||||||
return true
|
return true
|
||||||
))
|
))
|
||||||
check produceSingleBlockRes
|
testCond produceSingleBlockRes
|
||||||
|
|
||||||
|
proc blockStatusHeadBlock(t: TestEnv): TestStatus =
|
||||||
|
result = TestStatus.OK
|
||||||
|
|
||||||
proc blockStatusHeadBlock(t: TestEnv, testStatusIMPL: var TestStatus) =
|
|
||||||
# Wait until TTD is reached by this client
|
# Wait until TTD is reached by this client
|
||||||
let ok = waitFor t.clMock.waitForTTD()
|
let ok = waitFor t.clMock.waitForTTD()
|
||||||
check ok
|
testCond ok
|
||||||
if not ok:
|
|
||||||
return
|
|
||||||
|
|
||||||
# Produce blocks before starting the test
|
# Produce blocks before starting the test
|
||||||
let produce5BlockRes = t.clMock.produceBlocks(5, BlockProcessCallbacks())
|
let produce5BlockRes = t.clMock.produceBlocks(5, BlockProcessCallbacks())
|
||||||
check produce5BlockRes
|
testCond produce5BlockRes
|
||||||
if not produce5BlockRes:
|
|
||||||
return
|
|
||||||
|
|
||||||
let clMock = t.clMock
|
let clMock = t.clMock
|
||||||
let client = t.rpcClient
|
let client = t.rpcClient
|
||||||
@ -415,20 +403,18 @@ proc blockStatusHeadBlock(t: TestEnv, testStatusIMPL: var TestStatus) =
|
|||||||
return false
|
return false
|
||||||
return true
|
return true
|
||||||
))
|
))
|
||||||
check produceSingleBlockRes
|
testCond produceSingleBlockRes
|
||||||
|
|
||||||
|
proc blockStatusSafeBlock(t: TestEnv): TestStatus =
|
||||||
|
result = TestStatus.OK
|
||||||
|
|
||||||
proc blockStatusSafeBlock(t: TestEnv, testStatusIMPL: var TestStatus) =
|
|
||||||
# Wait until TTD is reached by this client
|
# Wait until TTD is reached by this client
|
||||||
let ok = waitFor t.clMock.waitForTTD()
|
let ok = waitFor t.clMock.waitForTTD()
|
||||||
check ok
|
testCond ok
|
||||||
if not ok:
|
|
||||||
return
|
|
||||||
|
|
||||||
# Produce blocks before starting the test
|
# Produce blocks before starting the test
|
||||||
let produce5BlockRes = t.clMock.produceBlocks(5, BlockProcessCallbacks())
|
let produce5BlockRes = t.clMock.produceBlocks(5, BlockProcessCallbacks())
|
||||||
check produce5BlockRes
|
testCond produce5BlockRes
|
||||||
if not produce5BlockRes:
|
|
||||||
return
|
|
||||||
|
|
||||||
let clMock = t.clMock
|
let clMock = t.clMock
|
||||||
let client = t.rpcClient
|
let client = t.rpcClient
|
||||||
@ -449,20 +435,18 @@ proc blockStatusSafeBlock(t: TestEnv, testStatusIMPL: var TestStatus) =
|
|||||||
return false
|
return false
|
||||||
return true
|
return true
|
||||||
))
|
))
|
||||||
check produceSingleBlockRes
|
testCond produceSingleBlockRes
|
||||||
|
|
||||||
|
proc blockStatusFinalizedBlock(t: TestEnv): TestStatus =
|
||||||
|
result = TestStatus.OK
|
||||||
|
|
||||||
proc blockStatusFinalizedBlock(t: TestEnv, testStatusIMPL: var TestStatus) =
|
|
||||||
# Wait until TTD is reached by this client
|
# Wait until TTD is reached by this client
|
||||||
let ok = waitFor t.clMock.waitForTTD()
|
let ok = waitFor t.clMock.waitForTTD()
|
||||||
check ok
|
testCond ok
|
||||||
if not ok:
|
|
||||||
return
|
|
||||||
|
|
||||||
# Produce blocks before starting the test
|
# Produce blocks before starting the test
|
||||||
let produce5BlockRes = t.clMock.produceBlocks(5, BlockProcessCallbacks())
|
let produce5BlockRes = t.clMock.produceBlocks(5, BlockProcessCallbacks())
|
||||||
check produce5BlockRes
|
testCond produce5BlockRes
|
||||||
if not produce5BlockRes:
|
|
||||||
return
|
|
||||||
|
|
||||||
let clMock = t.clMock
|
let clMock = t.clMock
|
||||||
let client = t.rpcClient
|
let client = t.rpcClient
|
||||||
@ -483,20 +467,18 @@ proc blockStatusFinalizedBlock(t: TestEnv, testStatusIMPL: var TestStatus) =
|
|||||||
return false
|
return false
|
||||||
return true
|
return true
|
||||||
))
|
))
|
||||||
check produceSingleBlockRes
|
testCond produceSingleBlockRes
|
||||||
|
|
||||||
|
proc blockStatusReorg(t: TestEnv): TestStatus =
|
||||||
|
result = TestStatus.OK
|
||||||
|
|
||||||
proc blockStatusReorg(t: TestEnv, testStatusIMPL: var TestStatus) =
|
|
||||||
# Wait until TTD is reached by this client
|
# Wait until TTD is reached by this client
|
||||||
let ok = waitFor t.clMock.waitForTTD()
|
let ok = waitFor t.clMock.waitForTTD()
|
||||||
check ok
|
testCond ok
|
||||||
if not ok:
|
|
||||||
return
|
|
||||||
|
|
||||||
# Produce blocks before starting the test
|
# Produce blocks before starting the test
|
||||||
let produce5BlockRes = t.clMock.produceBlocks(5, BlockProcessCallbacks())
|
let produce5BlockRes = t.clMock.produceBlocks(5, BlockProcessCallbacks())
|
||||||
check produce5BlockRes
|
testCond produce5BlockRes
|
||||||
if not produce5BlockRes:
|
|
||||||
return
|
|
||||||
|
|
||||||
let clMock = t.clMock
|
let clMock = t.clMock
|
||||||
let client = t.rpcClient
|
let client = t.rpcClient
|
||||||
@ -545,7 +527,7 @@ proc blockStatusReorg(t: TestEnv, testStatusIMPL: var TestStatus) =
|
|||||||
get=latestValidHash.toHex
|
get=latestValidHash.toHex
|
||||||
return false
|
return false
|
||||||
|
|
||||||
# Check that we reorg to the previous block
|
# testCond that we reorg to the previous block
|
||||||
hRes = client.latestHeader(currHeader)
|
hRes = client.latestHeader(currHeader)
|
||||||
if hRes.isErr:
|
if hRes.isErr:
|
||||||
error "unable to get latest header", msg=hRes.error
|
error "unable to get latest header", msg=hRes.error
|
||||||
@ -582,31 +564,27 @@ proc blockStatusReorg(t: TestEnv, testStatusIMPL: var TestStatus) =
|
|||||||
return false
|
return false
|
||||||
return true
|
return true
|
||||||
))
|
))
|
||||||
check produceSingleBlockRes
|
testCond produceSingleBlockRes
|
||||||
|
|
||||||
|
proc reExecPayloads(t: TestEnv): TestStatus =
|
||||||
|
result = TestStatus.OK
|
||||||
|
|
||||||
proc reExecPayloads(t: TestEnv, testStatusIMPL: var TestStatus) =
|
|
||||||
# Wait until this client catches up with latest PoS
|
# Wait until this client catches up with latest PoS
|
||||||
let ok = waitFor t.clMock.waitForTTD()
|
let ok = waitFor t.clMock.waitForTTD()
|
||||||
check ok
|
testCond ok
|
||||||
if not ok:
|
|
||||||
return
|
|
||||||
|
|
||||||
# How many Payloads we are going to re-execute
|
# How many Payloads we are going to re-execute
|
||||||
var payloadReExecCount = 10
|
var payloadReExecCount = 10
|
||||||
|
|
||||||
# Create those blocks
|
# Create those blocks
|
||||||
let produceBlockRes = t.clMock.produceBlocks(payloadReExecCount, BlockProcessCallbacks())
|
let produceBlockRes = t.clMock.produceBlocks(payloadReExecCount, BlockProcessCallbacks())
|
||||||
check produceBlockRes
|
testCond produceBlockRes
|
||||||
if not produceBlockRes:
|
|
||||||
return
|
|
||||||
|
|
||||||
# Re-execute the payloads
|
# Re-execute the payloads
|
||||||
let client = t.rpcClient
|
let client = t.rpcClient
|
||||||
var hRes = client.blockNumber()
|
var hRes = client.blockNumber()
|
||||||
check hRes.isOk
|
testCond hRes.isOk:
|
||||||
if hRes.isErr:
|
|
||||||
error "unable to get blockNumber", msg=hRes.error
|
error "unable to get blockNumber", msg=hRes.error
|
||||||
return
|
|
||||||
|
|
||||||
let lastBlock = int(hRes.get)
|
let lastBlock = int(hRes.get)
|
||||||
info "Started re-executing payloads at block", number=lastBlock
|
info "Started re-executing payloads at block", number=lastBlock
|
||||||
@ -619,33 +597,26 @@ proc reExecPayloads(t: TestEnv, testStatusIMPL: var TestStatus) =
|
|||||||
if clMock.executedPayloadHistory.hasKey(uint64 i):
|
if clMock.executedPayloadHistory.hasKey(uint64 i):
|
||||||
let payload = clMock.executedPayloadHistory[uint64 i]
|
let payload = clMock.executedPayloadHistory[uint64 i]
|
||||||
let res = client.newPayloadV1(payload)
|
let res = client.newPayloadV1(payload)
|
||||||
check res.isOk
|
testCond res.isOk:
|
||||||
if res.isErr:
|
|
||||||
error "FAIL (%s): Unable to re-execute valid payload", msg=res.error
|
error "FAIL (%s): Unable to re-execute valid payload", msg=res.error
|
||||||
return
|
|
||||||
|
|
||||||
let s = res.get()
|
let s = res.get()
|
||||||
check s.status == PayloadExecutionStatus.valid
|
testCond s.status == PayloadExecutionStatus.valid:
|
||||||
if s.status != PayloadExecutionStatus.valid:
|
|
||||||
error "Unexpected status after re-execute valid payload", status=s.status
|
error "Unexpected status after re-execute valid payload", status=s.status
|
||||||
return
|
|
||||||
else:
|
else:
|
||||||
check false
|
testCond true:
|
||||||
error "(test issue) Payload does not exist", index=i
|
error "(test issue) Payload does not exist", index=i
|
||||||
return
|
|
||||||
|
|
||||||
proc multipleNewCanonicalPayloads(t: TestEnv, testStatusIMPL: var TestStatus) =
|
proc multipleNewCanonicalPayloads(t: TestEnv): TestStatus =
|
||||||
|
result = TestStatus.OK
|
||||||
|
|
||||||
# Wait until TTD is reached by this client
|
# Wait until TTD is reached by this client
|
||||||
let ok = waitFor t.clMock.waitForTTD()
|
let ok = waitFor t.clMock.waitForTTD()
|
||||||
check ok
|
testCond ok
|
||||||
if not ok:
|
|
||||||
return
|
|
||||||
|
|
||||||
# Produce blocks before starting the test
|
# Produce blocks before starting the test
|
||||||
let produce5BlockRes = t.clMock.produceBlocks(5, BlockProcessCallbacks())
|
let produce5BlockRes = t.clMock.produceBlocks(5, BlockProcessCallbacks())
|
||||||
check produce5BlockRes
|
testCond produce5BlockRes
|
||||||
if not produce5BlockRes:
|
|
||||||
return
|
|
||||||
|
|
||||||
let clMock = t.clMock
|
let clMock = t.clMock
|
||||||
let client = t.rpcClient
|
let client = t.rpcClient
|
||||||
@ -676,14 +647,14 @@ proc multipleNewCanonicalPayloads(t: TestEnv, testStatusIMPL: var TestStatus) =
|
|||||||
return true
|
return true
|
||||||
))
|
))
|
||||||
# At the end the CLMocker continues to try to execute fcU with the original payload, which should not fail
|
# At the end the CLMocker continues to try to execute fcU with the original payload, which should not fail
|
||||||
check produceSingleBlockRes
|
testCond produceSingleBlockRes
|
||||||
|
|
||||||
|
proc outOfOrderPayloads(t: TestEnv): TestStatus =
|
||||||
|
result = TestStatus.OK
|
||||||
|
|
||||||
proc outOfOrderPayloads(t: TestEnv, testStatusIMPL: var TestStatus) =
|
|
||||||
# Wait until TTD is reached by this client
|
# Wait until TTD is reached by this client
|
||||||
let ok = waitFor t.clMock.waitForTTD()
|
let ok = waitFor t.clMock.waitForTTD()
|
||||||
check ok
|
testCond ok
|
||||||
if not ok:
|
|
||||||
return
|
|
||||||
|
|
||||||
# First prepare payloads on a first client, which will also contain multiple transactions
|
# First prepare payloads on a first client, which will also contain multiple transactions
|
||||||
|
|
||||||
@ -710,38 +681,32 @@ proc outOfOrderPayloads(t: TestEnv, testStatusIMPL: var TestStatus) =
|
|||||||
return false
|
return false
|
||||||
return true
|
return true
|
||||||
))
|
))
|
||||||
check produceBlockRes
|
testCond produceBlockRes
|
||||||
|
|
||||||
let expectedBalance = amountPerTx * u256(payloadCount*txPerPayload)
|
let expectedBalance = amountPerTx * u256(payloadCount*txPerPayload)
|
||||||
|
|
||||||
# Check balance on this first client
|
# testCond balance on this first client
|
||||||
let balRes = client.balanceAt(recipient)
|
let balRes = client.balanceAt(recipient)
|
||||||
check balRes.isOk
|
testCond balRes.isOk:
|
||||||
if balRes.isErr:
|
|
||||||
error "Error while getting balance of funded account"
|
error "Error while getting balance of funded account"
|
||||||
return
|
|
||||||
|
|
||||||
let bal = balRes.get()
|
let bal = balRes.get()
|
||||||
check expectedBalance == bal
|
testCond expectedBalance == bal
|
||||||
if expectedBalance != bal:
|
|
||||||
return
|
|
||||||
|
|
||||||
# TODO: this section need multiple client
|
# TODO: this section need multiple client
|
||||||
|
|
||||||
proc transactionReorg(t: TestEnv, testStatusIMPL: var TestStatus) =
|
proc transactionReorg(t: TestEnv): TestStatus =
|
||||||
|
result = TestStatus.OK
|
||||||
|
|
||||||
# Wait until TTD is reached by this client
|
# Wait until TTD is reached by this client
|
||||||
let ok = waitFor t.clMock.waitForTTD()
|
let ok = waitFor t.clMock.waitForTTD()
|
||||||
check ok
|
testCond ok
|
||||||
if not ok:
|
|
||||||
return
|
|
||||||
|
|
||||||
# Produce blocks before starting the test
|
# Produce blocks before starting the test
|
||||||
let produce5BlockRes = t.clMock.produceBlocks(5, BlockProcessCallbacks())
|
let produce5BlockRes = t.clMock.produceBlocks(5, BlockProcessCallbacks())
|
||||||
check produce5BlockRes
|
testCond produce5BlockRes
|
||||||
if not produce5BlockRes:
|
|
||||||
return
|
|
||||||
|
|
||||||
# Create transactions that modify the state in order to check after the reorg.
|
# Create transactions that modify the state in order to testCond after the reorg.
|
||||||
const
|
const
|
||||||
txCount = 5
|
txCount = 5
|
||||||
contractAddr = hexToByteArray[20]("0000000000000000000000000000000000000317")
|
contractAddr = hexToByteArray[20]("0000000000000000000000000000000000000317")
|
||||||
@ -762,23 +727,17 @@ proc transactionReorg(t: TestEnv, testStatusIMPL: var TestStatus) =
|
|||||||
|
|
||||||
# Send the transaction
|
# Send the transaction
|
||||||
let res = client.sendTransaction(tx)
|
let res = client.sendTransaction(tx)
|
||||||
check res.isOk
|
testCond res.isOk:
|
||||||
if res.isErr:
|
|
||||||
error "Unable to send transaction", msg=res.error
|
error "Unable to send transaction", msg=res.error
|
||||||
return
|
|
||||||
|
|
||||||
# Produce the block containing the transaction
|
# Produce the block containing the transaction
|
||||||
var blockRes = clMock.produceSingleBlock(BlockProcessCallbacks())
|
var blockRes = clMock.produceSingleBlock(BlockProcessCallbacks())
|
||||||
check blockRes
|
testCond blockRes
|
||||||
if not blockRes:
|
|
||||||
return
|
|
||||||
|
|
||||||
# Get the receipt
|
# Get the receipt
|
||||||
let rr = client.txReceipt(rlpHash(tx))
|
let rr = client.txReceipt(rlpHash(tx))
|
||||||
check rr.isOk
|
testCond rr.isOk:
|
||||||
if rr.isErr:
|
|
||||||
error "Unable to obtain transaction receipt", msg=rr.error
|
error "Unable to obtain transaction receipt", msg=rr.error
|
||||||
return
|
|
||||||
|
|
||||||
receipts[i] = rr.get()
|
receipts[i] = rr.get()
|
||||||
|
|
||||||
@ -787,13 +746,11 @@ proc transactionReorg(t: TestEnv, testStatusIMPL: var TestStatus) =
|
|||||||
let storageKey = i.u256
|
let storageKey = i.u256
|
||||||
|
|
||||||
var rr = client.storageAt(contractAddr, storageKey)
|
var rr = client.storageAt(contractAddr, storageKey)
|
||||||
check rr.isOk
|
testCond rr.isOk:
|
||||||
if rr.isErr:
|
|
||||||
error "Could not get storage", msg=rr.error
|
error "Could not get storage", msg=rr.error
|
||||||
return
|
|
||||||
|
|
||||||
let valueWithTxApplied = rr.get()
|
let valueWithTxApplied = rr.get()
|
||||||
check valueWithTxApplied == 1.u256
|
testCond valueWithTxApplied == 1.u256
|
||||||
if valueWithTxApplied != 1.u256:
|
if valueWithTxApplied != 1.u256:
|
||||||
error "Expected storage not set after transaction", valueWithTxApplied
|
error "Expected storage not set after transaction", valueWithTxApplied
|
||||||
return
|
return
|
||||||
@ -803,16 +760,12 @@ proc transactionReorg(t: TestEnv, testStatusIMPL: var TestStatus) =
|
|||||||
var reorgBlock: EthBlockHeader
|
var reorgBlock: EthBlockHeader
|
||||||
let blockRes = client.headerByNumber(number - 1, reorgBlock)
|
let blockRes = client.headerByNumber(number - 1, reorgBlock)
|
||||||
rr = client.storageAt(contractAddr, storageKey, reorgBlock.blockNumber)
|
rr = client.storageAt(contractAddr, storageKey, reorgBlock.blockNumber)
|
||||||
check rr.isOk
|
testCond rr.isOk:
|
||||||
if rr.isErr:
|
|
||||||
error "could not get storage", msg= rr.error
|
error "could not get storage", msg= rr.error
|
||||||
return
|
|
||||||
|
|
||||||
let valueWithoutTxApplied = rr.get()
|
let valueWithoutTxApplied = rr.get()
|
||||||
check valueWithoutTxApplied == 0.u256
|
testCond valueWithoutTxApplied == 0.u256:
|
||||||
if valueWithoutTxApplied != 0.u256:
|
|
||||||
error "Storage not unset before transaction!", valueWithoutTxApplied
|
error "Storage not unset before transaction!", valueWithoutTxApplied
|
||||||
return
|
|
||||||
|
|
||||||
# Re-org back to a previous block where the tx is not included using forkchoiceUpdated
|
# Re-org back to a previous block where the tx is not included using forkchoiceUpdated
|
||||||
let rHash = Web3BlockHash reorgBlock.blockHash.data
|
let rHash = Web3BlockHash reorgBlock.blockHash.data
|
||||||
@ -823,44 +776,32 @@ proc transactionReorg(t: TestEnv, testStatusIMPL: var TestStatus) =
|
|||||||
)
|
)
|
||||||
|
|
||||||
var res = client.forkchoiceUpdatedV1(reorgForkchoice)
|
var res = client.forkchoiceUpdatedV1(reorgForkchoice)
|
||||||
check res.isOk
|
testCond res.isOk:
|
||||||
if res.isErr:
|
|
||||||
error "Could not send forkchoiceUpdatedV1", msg=res.error
|
error "Could not send forkchoiceUpdatedV1", msg=res.error
|
||||||
return
|
|
||||||
|
|
||||||
var s = res.get()
|
var s = res.get()
|
||||||
check s.payloadStatus.status == PayloadExecutionStatus.valid
|
testCond s.payloadStatus.status == PayloadExecutionStatus.valid:
|
||||||
if s.payloadStatus.status != PayloadExecutionStatus.valid:
|
|
||||||
error "Could not send forkchoiceUpdatedV1", status=s.payloadStatus.status
|
error "Could not send forkchoiceUpdatedV1", status=s.payloadStatus.status
|
||||||
return
|
|
||||||
|
|
||||||
# Check storage again using `latest`, should be unset
|
# testCond storage again using `latest`, should be unset
|
||||||
rr = client.storageAt( contractAddr, storageKey)
|
rr = client.storageAt( contractAddr, storageKey)
|
||||||
check rr.isOk
|
testCond rr.isOk:
|
||||||
if rr.isErr:
|
|
||||||
error "could not get storage", msg= rr.error
|
error "could not get storage", msg= rr.error
|
||||||
return
|
|
||||||
|
|
||||||
let valueAfterReOrgBeforeTxApplied = rr.get()
|
let valueAfterReOrgBeforeTxApplied = rr.get()
|
||||||
check valueAfterReOrgBeforeTxApplied == 0.u256
|
testCond valueAfterReOrgBeforeTxApplied == 0.u256:
|
||||||
if valueAfterReOrgBeforeTxApplied != 0.u256:
|
|
||||||
error "Storage not unset after re-org", valueAfterReOrgBeforeTxApplied
|
error "Storage not unset after re-org", valueAfterReOrgBeforeTxApplied
|
||||||
return
|
|
||||||
|
|
||||||
# Re-send latest forkchoice to test next transaction
|
# Re-send latest forkchoice to test next transaction
|
||||||
res = client.forkchoiceUpdatedV1(clMock.latestForkchoice)
|
res = client.forkchoiceUpdatedV1(clMock.latestForkchoice)
|
||||||
check res.isOk
|
testCond res.isOk:
|
||||||
if res.isErr:
|
|
||||||
error "Could not send forkchoiceUpdatedV1", msg=res.error
|
error "Could not send forkchoiceUpdatedV1", msg=res.error
|
||||||
return
|
|
||||||
|
|
||||||
s = res.get()
|
s = res.get()
|
||||||
check s.payloadStatus.status == PayloadExecutionStatus.valid
|
testCond s.payloadStatus.status == PayloadExecutionStatus.valid:
|
||||||
if s.payloadStatus.status != PayloadExecutionStatus.valid:
|
|
||||||
error "Could not send forkchoiceUpdatedV1", status=s.payloadStatus.status
|
error "Could not send forkchoiceUpdatedV1", status=s.payloadStatus.status
|
||||||
return
|
|
||||||
|
|
||||||
proc checkPrevRandaoValue(t: TestEnv, expectedPrevRandao: Hash256, blockNumber: uint64): bool =
|
proc testCondPrevRandaoValue(t: TestEnv, expectedPrevRandao: Hash256, blockNumber: uint64): bool =
|
||||||
let storageKey = blockNumber.u256
|
let storageKey = blockNumber.u256
|
||||||
let client = t.rpcClient
|
let client = t.rpcClient
|
||||||
|
|
||||||
@ -877,32 +818,28 @@ proc checkPrevRandaoValue(t: TestEnv, expectedPrevRandao: Hash256, blockNumber:
|
|||||||
return false
|
return false
|
||||||
true
|
true
|
||||||
|
|
||||||
proc sidechainReorg(t: TestEnv, testStatusIMPL: var TestStatus) =
|
proc sidechainReorg(t: TestEnv): TestStatus =
|
||||||
|
result = TestStatus.OK
|
||||||
|
|
||||||
# Wait until TTD is reached by this client
|
# Wait until TTD is reached by this client
|
||||||
let ok = waitFor t.clMock.waitForTTD()
|
let ok = waitFor t.clMock.waitForTTD()
|
||||||
check ok
|
testCond ok
|
||||||
if not ok:
|
|
||||||
return
|
|
||||||
|
|
||||||
# Produce blocks before starting the test
|
# Produce blocks before starting the test
|
||||||
let produce5BlockRes = t.clMock.produceBlocks(5, BlockProcessCallbacks())
|
let produce5BlockRes = t.clMock.produceBlocks(5, BlockProcessCallbacks())
|
||||||
check produce5BlockRes
|
testCond produce5BlockRes
|
||||||
if not produce5BlockRes:
|
|
||||||
return
|
|
||||||
|
|
||||||
let
|
let
|
||||||
client = t.rpcClient
|
client = t.rpcClient
|
||||||
clMock = t.clMock
|
clMock = t.clMock
|
||||||
|
|
||||||
# Produce two payloads, send fcU with first payload, check transaction outcome, then reorg, check 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)
|
let tx = t.makeNextTransaction(prevRandaoContractAddr, 0.u256)
|
||||||
let rr = client.sendTransaction(tx)
|
let rr = client.sendTransaction(tx)
|
||||||
check rr.isOk
|
testCond rr.isOk:
|
||||||
if rr.isErr:
|
|
||||||
error "Unable to send transaction", msg=rr.error
|
error "Unable to send transaction", msg=rr.error
|
||||||
return
|
|
||||||
|
|
||||||
let singleBlockRes = clMock.produceSingleBlock(BlockProcessCallbacks(
|
let singleBlockRes = clMock.produceSingleBlock(BlockProcessCallbacks(
|
||||||
onNewPayloadBroadcast: proc(): bool =
|
onNewPayloadBroadcast: proc(): bool =
|
||||||
@ -966,21 +903,21 @@ proc sidechainReorg(t: TestEnv, testStatusIMPL: var TestStatus) =
|
|||||||
return false
|
return false
|
||||||
|
|
||||||
# PrevRandao should be the alternative prevRandao we sent
|
# PrevRandao should be the alternative prevRandao we sent
|
||||||
return checkPrevRandaoValue(t, alternativePrevRandao, uint64 alternativePayload.blockNumber)
|
return testCondPrevRandaoValue(t, alternativePrevRandao, uint64 alternativePayload.blockNumber)
|
||||||
))
|
))
|
||||||
|
|
||||||
check singleBlockRes
|
testCond singleBlockRes
|
||||||
# The reorg actually happens after the CLMocker continues,
|
# The reorg actually happens after the CLMocker continues,
|
||||||
# verify here that the reorg was successful
|
# verify here that the reorg was successful
|
||||||
let latestBlockNum = cLMock.latestFinalizedNumber.uint64
|
let latestBlockNum = cLMock.latestFinalizedNumber.uint64
|
||||||
check checkPrevRandaoValue(t, clMock.prevRandaoHistory[latestBlockNum], latestBlockNum)
|
testCond testCondPrevRandaoValue(t, clMock.prevRandaoHistory[latestBlockNum], latestBlockNum)
|
||||||
|
|
||||||
|
proc suggestedFeeRecipient(t: TestEnv): TestStatus =
|
||||||
|
result = TestStatus.OK
|
||||||
|
|
||||||
proc suggestedFeeRecipient(t: TestEnv, testStatusIMPL: var TestStatus) =
|
|
||||||
# Wait until TTD is reached by this client
|
# Wait until TTD is reached by this client
|
||||||
let ok = waitFor t.clMock.waitForTTD()
|
let ok = waitFor t.clMock.waitForTTD()
|
||||||
check ok
|
testCond ok
|
||||||
if not ok:
|
|
||||||
return
|
|
||||||
|
|
||||||
# Amount of transactions to send
|
# Amount of transactions to send
|
||||||
const
|
const
|
||||||
@ -988,7 +925,7 @@ proc suggestedFeeRecipient(t: TestEnv, testStatusIMPL: var TestStatus) =
|
|||||||
|
|
||||||
# Verify that, in a block with transactions, fees are accrued by the suggestedFeeRecipient
|
# Verify that, in a block with transactions, fees are accrued by the suggestedFeeRecipient
|
||||||
var feeRecipient: EthAddress
|
var feeRecipient: EthAddress
|
||||||
check nimcrypto.randomBytes(feeRecipient) == 20
|
testCond nimcrypto.randomBytes(feeRecipient) == 20
|
||||||
|
|
||||||
let
|
let
|
||||||
client = t.rpcClient
|
client = t.rpcClient
|
||||||
@ -999,130 +936,107 @@ proc suggestedFeeRecipient(t: TestEnv, testStatusIMPL: var TestStatus) =
|
|||||||
# Empty self tx
|
# Empty self tx
|
||||||
let tx = t.makeNextTransaction(vaultAccountAddr, 0.u256)
|
let tx = t.makeNextTransaction(vaultAccountAddr, 0.u256)
|
||||||
let res = client.sendTransaction(tx)
|
let res = client.sendTransaction(tx)
|
||||||
check res.isOk
|
testCond res.isOk:
|
||||||
if res.isErr:
|
|
||||||
error "unable to send transaction", msg=res.error
|
error "unable to send transaction", msg=res.error
|
||||||
return
|
|
||||||
|
|
||||||
# Produce the next block with the fee recipient set
|
# Produce the next block with the fee recipient set
|
||||||
clMock.nextFeeRecipient = feeRecipient
|
clMock.nextFeeRecipient = feeRecipient
|
||||||
check clMock.produceSingleBlock(BlockProcessCallbacks())
|
testCond clMock.produceSingleBlock(BlockProcessCallbacks())
|
||||||
|
|
||||||
# Calculate the fees and check that they match the balance of the fee recipient
|
# Calculate the fees and testCond that they match the balance of the fee recipient
|
||||||
var blockIncluded: EthBlock
|
var blockIncluded: EthBlock
|
||||||
var rr = client.latestBlock(blockIncluded)
|
var rr = client.latestBlock(blockIncluded)
|
||||||
check rr.isOk
|
testCond rr.isOk:
|
||||||
if rr.isErr:
|
|
||||||
error "unable to get latest block", msg=rr.error
|
error "unable to get latest block", msg=rr.error
|
||||||
return
|
|
||||||
|
|
||||||
check blockIncluded.txs.len == txCount
|
testCond blockIncluded.txs.len == txCount:
|
||||||
if blockIncluded.txs.len != txCount:
|
|
||||||
error "not all transactions were included in block",
|
error "not all transactions were included in block",
|
||||||
expected=txCount,
|
expected=txCount,
|
||||||
get=blockIncluded.txs.len
|
get=blockIncluded.txs.len
|
||||||
return
|
|
||||||
|
|
||||||
check blockIncluded.header.coinbase == feeRecipient
|
testCond blockIncluded.header.coinbase == feeRecipient:
|
||||||
if blockIncluded.header.coinbase != feeRecipient:
|
|
||||||
error "feeRecipient was not set as coinbase",
|
error "feeRecipient was not set as coinbase",
|
||||||
expected=feeRecipient.toHex,
|
expected=feeRecipient.toHex,
|
||||||
get=blockIncluded.header.coinbase.toHex
|
get=blockIncluded.header.coinbase.toHex
|
||||||
return
|
|
||||||
|
|
||||||
var feeRecipientFees = 0.u256
|
var feeRecipientFees = 0.u256
|
||||||
for tx in blockIncluded.txs:
|
for tx in blockIncluded.txs:
|
||||||
let effGasTip = tx.effectiveGasTip(blockIncluded.header.fee)
|
let effGasTip = tx.effectiveGasTip(blockIncluded.header.fee)
|
||||||
let tr = client.txReceipt(rlpHash(tx))
|
let tr = client.txReceipt(rlpHash(tx))
|
||||||
check tr.isOk
|
testCond tr.isOk:
|
||||||
if tr.isErr:
|
|
||||||
error "unable to obtain receipt", msg=tr.error
|
error "unable to obtain receipt", msg=tr.error
|
||||||
return
|
|
||||||
|
|
||||||
let rec = tr.get()
|
let rec = tr.get()
|
||||||
let gasUsed = UInt256.fromHex(rec.gasUsed.string)
|
let gasUsed = UInt256.fromHex(rec.gasUsed.string)
|
||||||
feeRecipientFees = feeRecipientFees + effGasTip.u256 * gasUsed
|
feeRecipientFees = feeRecipientFees + effGasTip.u256 * gasUsed
|
||||||
|
|
||||||
var br = client.balanceAt(feeRecipient)
|
var br = client.balanceAt(feeRecipient)
|
||||||
check br.isOk
|
testCond br.isOk
|
||||||
|
|
||||||
var feeRecipientBalance = br.get()
|
var feeRecipientBalance = br.get()
|
||||||
check feeRecipientBalance == feeRecipientFees
|
testCond feeRecipientBalance == feeRecipientFees:
|
||||||
if feeRecipientBalance != feeRecipientFees:
|
|
||||||
error "balance does not match fees",
|
error "balance does not match fees",
|
||||||
feeRecipientBalance, feeRecipientFees
|
feeRecipientBalance, feeRecipientFees
|
||||||
|
|
||||||
# Produce another block without txns and get the balance again
|
# Produce another block without txns and get the balance again
|
||||||
clMock.nextFeeRecipient = feeRecipient
|
clMock.nextFeeRecipient = feeRecipient
|
||||||
check clMock.produceSingleBlock(BlockProcessCallbacks())
|
testCond clMock.produceSingleBlock(BlockProcessCallbacks())
|
||||||
|
|
||||||
br = client.balanceAt(feeRecipient)
|
br = client.balanceAt(feeRecipient)
|
||||||
check br.isOk
|
testCond br.isOk
|
||||||
feeRecipientBalance = br.get()
|
feeRecipientBalance = br.get()
|
||||||
check feeRecipientBalance == feeRecipientFees
|
testCond feeRecipientBalance == feeRecipientFees:
|
||||||
if feeRecipientBalance != feeRecipientFees:
|
|
||||||
error "balance does not match fees",
|
error "balance does not match fees",
|
||||||
feeRecipientBalance, feeRecipientFees
|
feeRecipientBalance, feeRecipientFees
|
||||||
|
|
||||||
proc prevRandaoOpcodeTx(t: TestEnv, testStatusIMPL: var TestStatus) =
|
proc prevRandaoOpcodeTx(t: TestEnv): TestStatus =
|
||||||
|
result = TestStatus.OK
|
||||||
|
|
||||||
let
|
let
|
||||||
client = t.rpcClient
|
client = t.rpcClient
|
||||||
clMock = t.clMock
|
clMock = t.clMock
|
||||||
tx = t.makeNextTransaction(prevRandaoContractAddr, 0.u256)
|
tx = t.makeNextTransaction(prevRandaoContractAddr, 0.u256)
|
||||||
rr = client.sendTransaction(tx)
|
rr = client.sendTransaction(tx)
|
||||||
|
|
||||||
check rr.isOk
|
testCond rr.isOk:
|
||||||
if rr.isErr:
|
|
||||||
error "Unable to send transaction", msg=rr.error
|
error "Unable to send transaction", msg=rr.error
|
||||||
return
|
|
||||||
|
|
||||||
# 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()
|
||||||
check ok
|
testCond ok
|
||||||
if not ok:
|
|
||||||
return
|
|
||||||
|
|
||||||
# Ideally all blocks up until TTD must have a DIFFICULTY opcode tx in it
|
# Ideally all blocks up until TTD must have a DIFFICULTY opcode tx in it
|
||||||
let nr = client.blockNumber()
|
let nr = client.blockNumber()
|
||||||
check nr.isOk
|
testCond nr.isOk:
|
||||||
if nr.isErr:
|
|
||||||
error "Unable to get latest block number", msg=nr.error
|
error "Unable to get latest block number", msg=nr.error
|
||||||
return
|
|
||||||
|
|
||||||
let ttdBlockNumber = nr.get()
|
let ttdBlockNumber = nr.get()
|
||||||
|
|
||||||
# Start
|
# Start
|
||||||
for i in ttdBlockNumber..ttdBlockNumber:
|
for i in ttdBlockNumber..ttdBlockNumber:
|
||||||
# First check that the block actually contained the transaction
|
# First testCond that the block actually contained the transaction
|
||||||
var blk: EthBlock
|
var blk: EthBlock
|
||||||
let res = client.blockByNumber(i, blk)
|
let res = client.blockByNumber(i, blk)
|
||||||
check res.isOk
|
testCond res.isOk:
|
||||||
if res.isErr:
|
|
||||||
error "Unable to get block", msg=res.error
|
error "Unable to get block", msg=res.error
|
||||||
return
|
|
||||||
|
|
||||||
check blk.txs.len > 0
|
testCond blk.txs.len > 0:
|
||||||
if blk.txs.len == 0:
|
|
||||||
error "(Test issue) no transactions went in block"
|
error "(Test issue) no transactions went in block"
|
||||||
return
|
|
||||||
|
|
||||||
let storageKey = i.u256
|
let storageKey = i.u256
|
||||||
let rr = client.storageAt(prevRandaoContractAddr, storageKey)
|
let rr = client.storageAt(prevRandaoContractAddr, storageKey)
|
||||||
check rr.isOk
|
testCond rr.isOk:
|
||||||
if rr.isErr:
|
|
||||||
error "Unable to get storage", msg=rr.error
|
error "Unable to get storage", msg=rr.error
|
||||||
return
|
|
||||||
|
|
||||||
let opcodeValueAtBlock = rr.get()
|
let opcodeValueAtBlock = rr.get()
|
||||||
if opcodeValueAtBlock != 2.u256:
|
testCond opcodeValueAtBlock == 2.u256:
|
||||||
error "Incorrect difficulty value in block",
|
error "Incorrect difficulty value in block",
|
||||||
expect=2,
|
expect=2,
|
||||||
get=opcodeValueAtBlock
|
get=opcodeValueAtBlock
|
||||||
return
|
|
||||||
|
|
||||||
proc postMergeSync(t: TestEnv, testStatusIMPL: var TestStatus) =
|
proc postMergeSync(t: TestEnv): TestStatus =
|
||||||
|
result = TestStatus.SKIPPED
|
||||||
# TODO: need multiple client
|
# TODO: need multiple client
|
||||||
discard
|
|
||||||
|
|
||||||
const engineTestList* = [
|
const engineTestList* = [
|
||||||
TestSpec(
|
TestSpec(
|
||||||
@ -1165,7 +1079,7 @@ const engineTestList* = [
|
|||||||
name: "ParentHash==BlockHash on NewPayload",
|
name: "ParentHash==BlockHash on NewPayload",
|
||||||
run: parentHashOnExecPayload,
|
run: parentHashOnExecPayload,
|
||||||
),
|
),
|
||||||
#[TestSpec(
|
TestSpec(
|
||||||
name: "Invalid ParentHash NewPayload",
|
name: "Invalid ParentHash NewPayload",
|
||||||
run: invalidPayloadTestCaseGen("ParentHash"),
|
run: invalidPayloadTestCaseGen("ParentHash"),
|
||||||
),
|
),
|
||||||
@ -1220,7 +1134,7 @@ const engineTestList* = [
|
|||||||
TestSpec(
|
TestSpec(
|
||||||
name: "Invalid Transaction Value NewPayload",
|
name: "Invalid Transaction Value NewPayload",
|
||||||
run: invalidPayloadTestCaseGen("Transaction/Value"),
|
run: invalidPayloadTestCaseGen("Transaction/Value"),
|
||||||
),]#
|
),
|
||||||
|
|
||||||
# Eth RPC Status on ForkchoiceUpdated Events
|
# Eth RPC Status on ForkchoiceUpdated Events
|
||||||
TestSpec(
|
TestSpec(
|
||||||
@ -1276,11 +1190,11 @@ const engineTestList* = [
|
|||||||
|
|
||||||
# TODO: debug and fix
|
# TODO: debug and fix
|
||||||
# PrevRandao opcode tests
|
# PrevRandao opcode tests
|
||||||
#TestSpec(
|
TestSpec(
|
||||||
# name: "PrevRandao Opcode Transactions",
|
name: "PrevRandao Opcode Transactions",
|
||||||
# run: prevRandaoOpcodeTx,
|
run: prevRandaoOpcodeTx,
|
||||||
# ttd: 10,
|
ttd: 10,
|
||||||
#),
|
),
|
||||||
|
|
||||||
# Multi-Client Sync tests
|
# Multi-Client Sync tests
|
||||||
TestSpec(
|
TestSpec(
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
# those terms.
|
# those terms.
|
||||||
|
|
||||||
import
|
import
|
||||||
std/[os, json],
|
std/[os, json, times],
|
||||||
eth/[p2p, trie/db], ../../../nimbus/db/db_chain,
|
eth/[p2p, trie/db], ../../../nimbus/db/db_chain,
|
||||||
../../../nimbus/sync/protocol_ethxx,
|
../../../nimbus/sync/protocol_ethxx,
|
||||||
../../../nimbus/[genesis, config, conf_utils, context],
|
../../../nimbus/[genesis, config, conf_utils, context],
|
||||||
@ -22,7 +22,11 @@ const
|
|||||||
genesisFile = baseFolder / "init" / "genesis.json"
|
genesisFile = baseFolder / "init" / "genesis.json"
|
||||||
caseFolder = baseFolder / "testcases"
|
caseFolder = baseFolder / "testcases"
|
||||||
|
|
||||||
proc processNode(ctx: GraphqlRef, node: JsonNode, fileName: string, testStatusIMPL: var TestStatus) =
|
template testCond(expr: untyped) =
|
||||||
|
if not (expr):
|
||||||
|
result = TestStatus.Failed
|
||||||
|
|
||||||
|
proc processNode(ctx: GraphqlRef, node: JsonNode, fileName: string): TestStatus =
|
||||||
let request = node["request"]
|
let request = node["request"]
|
||||||
let responses = node["responses"]
|
let responses = node["responses"]
|
||||||
let statusCode = node["statusCode"].getInt()
|
let statusCode = node["statusCode"].getInt()
|
||||||
@ -30,11 +34,12 @@ proc processNode(ctx: GraphqlRef, node: JsonNode, fileName: string, testStatusIM
|
|||||||
let savePoint = ctx.getNameCounter()
|
let savePoint = ctx.getNameCounter()
|
||||||
let res = ctx.parseQuery(request.getStr())
|
let res = ctx.parseQuery(request.getStr())
|
||||||
|
|
||||||
|
result = TestStatus.OK
|
||||||
block:
|
block:
|
||||||
if res.isErr:
|
if res.isErr:
|
||||||
if statusCode == 200:
|
if statusCode == 200:
|
||||||
debugEcho res.error
|
debugEcho res.error
|
||||||
check statusCode != 200
|
testCond statusCode != 200
|
||||||
break
|
break
|
||||||
|
|
||||||
let resp = JsonRespStream.new()
|
let resp = JsonRespStream.new()
|
||||||
@ -42,11 +47,11 @@ proc processNode(ctx: GraphqlRef, node: JsonNode, fileName: string, testStatusIM
|
|||||||
if r.isErr:
|
if r.isErr:
|
||||||
if statusCode == 200:
|
if statusCode == 200:
|
||||||
debugEcho r.error
|
debugEcho r.error
|
||||||
check statusCode != 200
|
testCond statusCode != 200
|
||||||
break
|
break
|
||||||
|
|
||||||
check statusCode == 200
|
testCond statusCode == 200
|
||||||
check r.isOk
|
testCond r.isOk
|
||||||
|
|
||||||
let nimbus = resp.getString()
|
let nimbus = resp.getString()
|
||||||
var resultOK = false
|
var resultOK = false
|
||||||
@ -56,7 +61,7 @@ proc processNode(ctx: GraphqlRef, node: JsonNode, fileName: string, testStatusIM
|
|||||||
resultOK = true
|
resultOK = true
|
||||||
break
|
break
|
||||||
|
|
||||||
check resultOK
|
testCond resultOK
|
||||||
if not resultOK:
|
if not resultOK:
|
||||||
debugEcho "NIMBUS RESULT: ", nimbus
|
debugEcho "NIMBUS RESULT: ", nimbus
|
||||||
for x in responses:
|
for x in responses:
|
||||||
@ -83,8 +88,19 @@ proc main() =
|
|||||||
discard importRlpBlock(blocksFile, chainDB)
|
discard importRlpBlock(blocksFile, chainDB)
|
||||||
let ctx = setupGraphqlContext(chainDB, ethNode, txPool)
|
let ctx = setupGraphqlContext(chainDB, ethNode, txPool)
|
||||||
|
|
||||||
runTest("GraphQL", caseFolder):
|
var stat: SimStat
|
||||||
|
let start = getTime()
|
||||||
|
for fileName {.inject.} in walkDirRec(
|
||||||
|
caseFolder, yieldFilter = {pcFile,pcLinkToFile}):
|
||||||
|
if not fileName.endsWith(".json"):
|
||||||
|
continue
|
||||||
|
|
||||||
|
let (folder, name) = fileName.splitPath()
|
||||||
let node = parseFile(fileName)
|
let node = parseFile(fileName)
|
||||||
ctx.processNode(node, fileName, testStatusIMPL)
|
let status = ctx.processNode(node, fileName)
|
||||||
|
stat.inc(name, status)
|
||||||
|
|
||||||
|
let elpd = getTime() - start
|
||||||
|
print(stat, elpd, "graphql")
|
||||||
|
|
||||||
main()
|
main()
|
||||||
|
@ -1,18 +0,0 @@
|
|||||||
# Nimbus
|
|
||||||
# Copyright (c) 2021 Status Research & Development GmbH
|
|
||||||
# Licensed under either of
|
|
||||||
# * Apache License, version 2.0, ([LICENSE-APACHE](LICENSE-APACHE))
|
|
||||||
# * MIT license ([LICENSE-MIT](LICENSE-MIT))
|
|
||||||
# at your option.
|
|
||||||
# This file may not be copied, modified, or distributed except according to
|
|
||||||
# those terms.
|
|
||||||
|
|
||||||
import
|
|
||||||
std/[os, strutils],
|
|
||||||
eth/[common],
|
|
||||||
json_rpc/[rpcclient],
|
|
||||||
../../../nimbus/rpc/[hexstrings, rpc_types]
|
|
||||||
|
|
||||||
template sourceDir: string = currentSourcePath.rsplit(DirSep, 1)[0]
|
|
||||||
const sigPath = sourceDir / ".." / ".." / ".." / "tests" / "rpcclient" / "ethcallsigs.nim"
|
|
||||||
createRpcSigs(RpcClient, sigPath)
|
|
@ -15,7 +15,9 @@ import
|
|||||||
json_rpc/[rpcclient],
|
json_rpc/[rpcclient],
|
||||||
../../../nimbus/[utils, transaction],
|
../../../nimbus/[utils, transaction],
|
||||||
../../../nimbus/rpc/hexstrings,
|
../../../nimbus/rpc/hexstrings,
|
||||||
"."/[callsigs]
|
../../../tests/rpcclient/eth_api
|
||||||
|
|
||||||
|
export eth_api
|
||||||
|
|
||||||
proc fromHex(x: type Hash256, hex: EthHashStr): Hash256 =
|
proc fromHex(x: type Hash256, hex: EthHashStr): Hash256 =
|
||||||
hexToByteArray(hex.string, result.data)
|
hexToByteArray(hex.string, result.data)
|
||||||
|
@ -13,8 +13,11 @@ import
|
|||||||
stew/byteutils,
|
stew/byteutils,
|
||||||
stint,
|
stint,
|
||||||
chronos,
|
chronos,
|
||||||
|
unittest2,
|
||||||
json_rpc/[rpcclient],
|
json_rpc/[rpcclient],
|
||||||
"."/[vault, client, callsigs]
|
"."/[vault, client]
|
||||||
|
|
||||||
|
export client
|
||||||
|
|
||||||
const
|
const
|
||||||
gasPrice* = 30000000000 # 30 Gwei or 30 * pow(10, 9)
|
gasPrice* = 30000000000 # 30 Gwei or 30 * pow(10, 9)
|
||||||
@ -25,6 +28,10 @@ type
|
|||||||
vault*: Vault
|
vault*: Vault
|
||||||
client*: RpcClient
|
client*: RpcClient
|
||||||
|
|
||||||
|
TestSpec* = object
|
||||||
|
name*: string
|
||||||
|
run*: proc(t: TestEnv): Future[TestStatus]
|
||||||
|
|
||||||
func eth(n: int): UInt256 {.compileTime.} =
|
func eth(n: int): UInt256 {.compileTime.} =
|
||||||
n.u256 * pow(10.u256, 18)
|
n.u256 * pow(10.u256, 18)
|
||||||
|
|
||||||
@ -35,7 +42,7 @@ func ethAddr(x: string): EthAddress =
|
|||||||
hexToByteArray[20](x)
|
hexToByteArray[20](x)
|
||||||
|
|
||||||
# envTest make sure the env is set up properly for subsequent tests
|
# envTest make sure the env is set up properly for subsequent tests
|
||||||
proc envTest*(t: TestEnv): Future[bool] {.async.} =
|
proc envTest(t: TestEnv): Future[TestStatus] {.async.} =
|
||||||
let client = t.client
|
let client = t.client
|
||||||
let res = await client.web3_clientVersion()
|
let res = await client.web3_clientVersion()
|
||||||
|
|
||||||
@ -52,14 +59,14 @@ proc envTest*(t: TestEnv): Future[bool] {.async.} =
|
|||||||
let expected = u256(x[1])
|
let expected = u256(x[1])
|
||||||
if res != expected:
|
if res != expected:
|
||||||
debugEcho "expected: $1, got $2" % [x[0], $res]
|
debugEcho "expected: $1, got $2" % [x[0], $res]
|
||||||
return false
|
return TestStatus.Failed
|
||||||
|
|
||||||
result = true
|
result = TestStatus.OK
|
||||||
|
|
||||||
# balanceAndNonceAtTest creates a new account and transfers funds to it.
|
# balanceAndNonceAtTest creates a new account and transfers funds to it.
|
||||||
# It then tests if the balance and nonce of the sender and receiver
|
# It then tests if the balance and nonce of the sender and receiver
|
||||||
# address are updated correct.
|
# address are updated correct.
|
||||||
proc balanceAndNonceAtTest*(t: TestEnv) {.async.} =
|
proc balanceAndNonceAtTest(t: TestEnv): Future[TestStatus] {.async.} =
|
||||||
let
|
let
|
||||||
sourceAddr = await t.vault.createAccount(1.eth)
|
sourceAddr = await t.vault.createAccount(1.eth)
|
||||||
sourceNonce = 0.AccountNonce
|
sourceNonce = 0.AccountNonce
|
||||||
@ -69,3 +76,15 @@ proc balanceAndNonceAtTest*(t: TestEnv) {.async.} =
|
|||||||
let sourceAddressBalanceBefore = t.client.balanceAt(sourceAddr)
|
let sourceAddressBalanceBefore = t.client.balanceAt(sourceAddr)
|
||||||
|
|
||||||
# TODO: complete this test
|
# TODO: complete this test
|
||||||
|
result = TestStatus.OK
|
||||||
|
|
||||||
|
const testList* = [
|
||||||
|
TestSpec(
|
||||||
|
name: "env is set up properly for subsequent tests",
|
||||||
|
run: envTest
|
||||||
|
),
|
||||||
|
TestSpec(
|
||||||
|
name: "balance and nonce update correctly",
|
||||||
|
run: balanceAndNonceAtTest
|
||||||
|
)
|
||||||
|
]
|
||||||
|
@ -8,18 +8,19 @@
|
|||||||
# those terms.
|
# those terms.
|
||||||
|
|
||||||
import
|
import
|
||||||
std/os, asynctest,
|
std/[os, times],
|
||||||
eth/[trie/db],
|
eth/[trie/db],
|
||||||
eth/p2p as ethP2p,
|
eth/p2p as ethp2p,
|
||||||
stew/shims/net as stewNet,
|
stew/shims/net as stewNet,
|
||||||
stew/results,
|
stew/results,
|
||||||
chronos, json_rpc/[rpcserver, rpcclient],
|
chronos, json_rpc/[rpcserver, rpcclient],
|
||||||
../../../nimbus/db/db_chain,
|
../../../nimbus/db/db_chain,
|
||||||
../../../nimbus/p2p/protocol_ethxx,
|
../../../nimbus/sync/protocol_ethxx,
|
||||||
../../../nimbus/[config, context, genesis],
|
../../../nimbus/[config, context, genesis, utils/tx_pool],
|
||||||
../../../nimbus/rpc/[common, p2p, debug],
|
../../../nimbus/rpc/[common, p2p, debug],
|
||||||
../../../tests/test_helpers,
|
../../../tests/test_helpers,
|
||||||
"."/[callsigs, ethclient, vault, client]
|
"."/[ethclient, vault, client],
|
||||||
|
../sim_utils
|
||||||
|
|
||||||
const
|
const
|
||||||
initPath = "hive_integration" / "nodocker" / "rpc" / "init"
|
initPath = "hive_integration" / "nodocker" / "rpc" / "init"
|
||||||
@ -31,18 +32,22 @@ proc manageAccounts(ctx: EthContext, conf: NimbusConf) =
|
|||||||
echo res.error()
|
echo res.error()
|
||||||
quit(QuitFailure)
|
quit(QuitFailure)
|
||||||
|
|
||||||
proc setupRpcServer(ctx: EthContext, chainDB: BaseChainDB, ethNode: EthereumNode, conf: NimbusConf): RpcServer =
|
proc setupRpcServer(ctx: EthContext, chainDB: BaseChainDB,
|
||||||
|
ethNode: EthereumNode, txPool: TxPoolRef,
|
||||||
|
conf: NimbusConf): RpcServer =
|
||||||
let rpcServer = newRpcHttpServer([initTAddress(conf.rpcAddress, conf.rpcPort)])
|
let rpcServer = newRpcHttpServer([initTAddress(conf.rpcAddress, conf.rpcPort)])
|
||||||
setupCommonRpc(ethNode, conf, rpcServer)
|
setupCommonRpc(ethNode, conf, rpcServer)
|
||||||
setupEthRpc(ethNode, ctx, chainDB, rpcServer)
|
setupEthRpc(ethNode, ctx, chainDB, txPool, rpcServer)
|
||||||
|
|
||||||
rpcServer.start()
|
rpcServer.start()
|
||||||
rpcServer
|
rpcServer
|
||||||
|
|
||||||
proc setupWsRpcServer(ctx: EthContext, chainDB: BaseChainDB, ethNode: EthereumNode, conf: NimbusConf): RpcServer =
|
proc setupWsRpcServer(ctx: EthContext, chainDB: BaseChainDB,
|
||||||
|
ethNode: EthereumNode, txPool: TxPoolRef,
|
||||||
|
conf: NimbusConf): RpcServer =
|
||||||
let rpcServer = newRpcWebSocketServer(initTAddress(conf.wsAddress, conf.wsPort))
|
let rpcServer = newRpcWebSocketServer(initTAddress(conf.wsAddress, conf.wsPort))
|
||||||
setupCommonRpc(ethNode, conf, rpcServer)
|
setupCommonRpc(ethNode, conf, rpcServer)
|
||||||
setupEthRpc(ethNode, ctx, chainDB, rpcServer)
|
setupEthRpc(ethNode, ctx, chainDB, txPool, rpcServer)
|
||||||
|
|
||||||
rpcServer.start()
|
rpcServer.start()
|
||||||
rpcServer
|
rpcServer
|
||||||
@ -56,9 +61,18 @@ proc runRpcTest() =
|
|||||||
vault : newVault(chainID, gasPrice, client)
|
vault : newVault(chainID, gasPrice, client)
|
||||||
)
|
)
|
||||||
|
|
||||||
suite "JSON RPC Test Over HTTP":
|
var stat: SimStat
|
||||||
test "env test":
|
let start = getTime()
|
||||||
check await envTest(testEnv)
|
for x in testList:
|
||||||
|
try:
|
||||||
|
let status = waitFor x.run(testEnv)
|
||||||
|
stat.inc(x.name, status)
|
||||||
|
except ValueError as ex:
|
||||||
|
stat.inc(x.name, TestStatus.Failed)
|
||||||
|
echo ex.msg
|
||||||
|
|
||||||
|
let elpd = getTime() - start
|
||||||
|
print(stat, elpd, "rpc")
|
||||||
|
|
||||||
proc main() =
|
proc main() =
|
||||||
let conf = makeConfig(@[
|
let conf = makeConfig(@[
|
||||||
@ -89,7 +103,9 @@ proc main() =
|
|||||||
|
|
||||||
chainDB.populateProgress()
|
chainDB.populateProgress()
|
||||||
chainDB.initializeEmptyDb()
|
chainDB.initializeEmptyDb()
|
||||||
let rpcServer = setupRpcServer(ethCtx, chainDB, ethNode, conf)
|
|
||||||
|
let txPool = TxPoolRef.new(chainDB, conf.engineSigner)
|
||||||
|
let rpcServer = setupRpcServer(ethCtx, chainDB, ethNode, txPool, conf)
|
||||||
runRpcTest()
|
runRpcTest()
|
||||||
|
|
||||||
main()
|
main()
|
||||||
|
@ -8,35 +8,36 @@
|
|||||||
# those terms.
|
# those terms.
|
||||||
|
|
||||||
import
|
import
|
||||||
std/[tables, strutils, unittest],
|
std/[tables, strutils, times],
|
||||||
testutils/markdown_reports
|
unittest2
|
||||||
|
|
||||||
export
|
export
|
||||||
tables, strutils, unittest,
|
tables, strutils, unittest2
|
||||||
markdown_reports
|
|
||||||
|
|
||||||
template runTest*(suiteName: string, caseFolder: string, body: untyped) =
|
type
|
||||||
disableParamFiltering()
|
SimStat* = object
|
||||||
suite suiteName:
|
ok*: int
|
||||||
var status = initOrderedTable[string, OrderedTable[string, Status]]()
|
skipped*: int
|
||||||
for fileName {.inject.} in walkDirRec(
|
failed*: int
|
||||||
caseFolder, yieldFilter = {pcFile,pcLinkToFile}):
|
|
||||||
|
|
||||||
if not fileName.endsWith(".json"):
|
proc inc*(stat: var SimStat, name: string, status: TestStatus) =
|
||||||
continue
|
echo name, ", ", status
|
||||||
|
if status == OK:
|
||||||
|
inc stat.ok
|
||||||
|
elif status == SKIPPED:
|
||||||
|
inc stat.skipped
|
||||||
|
else:
|
||||||
|
inc stat.failed
|
||||||
|
|
||||||
let (folder, name) = fileName.splitPath()
|
proc `$`*(stat: SimStat): string =
|
||||||
let last = folder.splitPath().tail
|
"ok: $1, skipped: $2, failed: $3" % [$stat.ok, $stat.skipped, $stat.failed]
|
||||||
if last notin status:
|
|
||||||
status[last] = initOrderedTable[string, Status]()
|
|
||||||
|
|
||||||
test fileName:
|
proc print*(stat: SimStat, dur: Duration, name: string) =
|
||||||
# we set this here because exceptions might be raised in the handler
|
var f = open(name & ".md", fmWrite)
|
||||||
status[last][name] = Status.Fail
|
f.write("* " & name)
|
||||||
body
|
f.write("\n")
|
||||||
if testStatusIMPL == OK:
|
f.write(" - " & $stat)
|
||||||
status[last][name] = Status.OK
|
f.write("\n")
|
||||||
elif testStatusIMPL == SKIPPED:
|
f.write(" - " & $dur)
|
||||||
status[last][name] = Status.Skip
|
f.write("\n")
|
||||||
|
f.close()
|
||||||
generateReport(suiteName, status)
|
|
||||||
|
@ -17,16 +17,10 @@ type
|
|||||||
EthHeader = object
|
EthHeader = object
|
||||||
header: BlockHeader
|
header: BlockHeader
|
||||||
|
|
||||||
proc importRlpBlock*(importFile: string; chainDB: BaseChainDB): bool =
|
proc importRlpBlock*(blocksRlp: openArray[byte]; chainDB: BaseChainDB; importFile: string = ""): bool =
|
||||||
let res = io2.readAllBytes(importFile)
|
|
||||||
if res.isErr:
|
|
||||||
error "failed to import",
|
|
||||||
fileName = importFile
|
|
||||||
return false
|
|
||||||
|
|
||||||
var
|
var
|
||||||
# the encoded rlp can contains one or more blocks
|
# the encoded rlp can contains one or more blocks
|
||||||
rlp = rlpFromBytes(res.get)
|
rlp = rlpFromBytes(blocksRlp)
|
||||||
chain = newChain(chainDB, extraValidation = true)
|
chain = newChain(chainDB, extraValidation = true)
|
||||||
errorCount = 0
|
errorCount = 0
|
||||||
let
|
let
|
||||||
@ -57,3 +51,13 @@ proc importRlpBlock*(importFile: string; chainDB: BaseChainDB): bool =
|
|||||||
errorCount.inc
|
errorCount.inc
|
||||||
|
|
||||||
return errorCount == 0
|
return errorCount == 0
|
||||||
|
|
||||||
|
proc importRlpBlock*(importFile: string; chainDB: BaseChainDB): bool =
|
||||||
|
let res = io2.readAllBytes(importFile)
|
||||||
|
if res.isErr:
|
||||||
|
error "failed to import",
|
||||||
|
fileName = importFile
|
||||||
|
return false
|
||||||
|
|
||||||
|
importRlpBlock(res.get, chainDB, importFile)
|
||||||
|
|
@ -7,6 +7,7 @@ export kvstore
|
|||||||
# be reconsidered when making more changes here.
|
# be reconsidered when making more changes here.
|
||||||
|
|
||||||
type DbBackend = enum
|
type DbBackend = enum
|
||||||
|
none,
|
||||||
sqlite,
|
sqlite,
|
||||||
rocksdb,
|
rocksdb,
|
||||||
lmdb
|
lmdb
|
||||||
@ -55,5 +56,8 @@ elif dbBackend == lmdb:
|
|||||||
# https://github.com/status-im/nim-beacon-chain/pull/809
|
# https://github.com/status-im/nim-beacon-chain/pull/809
|
||||||
|
|
||||||
{.error: "lmdb deprecated, needs reimplementing".}
|
{.error: "lmdb deprecated, needs reimplementing".}
|
||||||
|
elif dbBackend == none:
|
||||||
|
discard
|
||||||
|
|
||||||
export database_backend
|
when dbBackend != none:
|
||||||
|
export database_backend
|
||||||
|
Loading…
x
Reference in New Issue
Block a user