Prepare state test and blockchain test for Cancun (#1772)

This commit is contained in:
andri lim 2023-09-25 06:53:20 +07:00 committed by GitHub
parent dc1dcfb206
commit 990718aa07
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 168 additions and 113 deletions

View File

@ -117,6 +117,9 @@ proc parseBlockHeader*(n: JsonNode): BlockHeader =
n.fromJson "nonce", result.nonce n.fromJson "nonce", result.nonce
n.fromJson "baseFeePerGas", result.fee n.fromJson "baseFeePerGas", result.fee
n.fromJson "withdrawalsRoot", result.withdrawalsRoot n.fromJson "withdrawalsRoot", result.withdrawalsRoot
n.fromJson "blobGasUsed", result.blobGasUsed
n.fromJson "excessBlobGas", result.excessBlobGas
n.fromJson "parentBeaconBlockRoot", result.parentBeaconBlockRoot
if result.baseFee == 0.u256: if result.baseFee == 0.u256:
# probably geth bug # probably geth bug

View File

@ -9,7 +9,7 @@
# according to those terms. # according to those terms.
import import
std/[json, os, tables, strutils, options], std/[json, os, tables, strutils, options, streams],
unittest2, unittest2,
eth/rlp, eth/trie/trie_defs, eth/common/eth_types_rlp, eth/rlp, eth/trie/trie_defs, eth/common/eth_types_rlp,
stew/byteutils, stew/byteutils,
@ -19,11 +19,13 @@ import
../nimbus/db/accounts_cache, ../nimbus/db/accounts_cache,
../nimbus/utils/[utils, debug], ../nimbus/utils/[utils, debug],
../nimbus/evm/tracer/legacy_tracer, ../nimbus/evm/tracer/legacy_tracer,
../nimbus/evm/tracer/json_tracer,
../nimbus/core/[executor, validate, pow/header], ../nimbus/core/[executor, validate, pow/header],
../stateless/[tree_from_witness, witness_types], ../stateless/[tree_from_witness, witness_types],
../tools/common/helpers as chp, ../tools/common/helpers as chp,
../tools/evmstate/helpers, ../tools/evmstate/helpers,
../nimbus/common/common ../nimbus/common/common,
../nimbus/core/eip4844
type type
SealEngine = enum SealEngine = enum
@ -38,7 +40,7 @@ type
hasException: bool hasException: bool
withdrawals: Option[seq[Withdrawal]] withdrawals: Option[seq[Withdrawal]]
Tester = object TestCtx = object
lastBlockHash: Hash256 lastBlockHash: Hash256
genesisHeader: BlockHeader genesisHeader: BlockHeader
blocks : seq[TestBlock] blocks : seq[TestBlock]
@ -49,6 +51,10 @@ type
debugData : JsonNode debugData : JsonNode
network : string network : string
postStateHash: Hash256 postStateHash: Hash256
json : bool
var
trustedSetupLoaded = false
proc testFixture(node: JsonNode, testStatusIMPL: var TestStatus, debugMode = false, trace = false) proc testFixture(node: JsonNode, testStatusIMPL: var TestStatus, debugMode = false, trace = false)
@ -142,7 +148,7 @@ proc parseBlocks(blocks: JsonNode): seq[TestBlock] =
result.add t result.add t
proc parseTester(fixture: JsonNode, testStatusIMPL: var TestStatus): Tester = proc parseTestCtx(fixture: JsonNode, testStatusIMPL: var TestStatus): TestCtx =
result.blocks = parseBlocks(fixture["blocks"]) result.blocks = parseBlocks(fixture["blocks"])
fixture.fromJson "lastblockhash", result.lastBlockHash fixture.fromJson "lastblockhash", result.lastBlockHash
@ -185,23 +191,48 @@ proc blockWitness(vmState: BaseVMState, chainDB: CoreDbRef) =
if root != rootHash: if root != rootHash:
raise newException(ValidationError, "Invalid trie generated from block witness") raise newException(ValidationError, "Invalid trie generated from block witness")
proc importBlock(tester: var Tester, com: CommonRef, proc setupTracer(ctx: TestCtx): TracerRef =
if ctx.trace:
if ctx.json:
var tracerFlags = {
TracerFlags.DisableMemory,
TracerFlags.DisableStorage,
TracerFlags.DisableState,
TracerFlags.DisableStateDiff,
TracerFlags.DisableReturnData
}
let stream = newFileStream(stdout)
newJsonTracer(stream, tracerFlags, false)
else:
newLegacyTracer({})
else:
TracerRef()
proc importBlock(ctx: var TestCtx, com: CommonRef,
tb: TestBlock, checkSeal, validation: bool) = tb: TestBlock, checkSeal, validation: bool) =
let parentHeader = com.db.getBlockHeader(tb.header.parentHash) let parentHeader = com.db.getBlockHeader(tb.header.parentHash)
let td = some(com.db.getScore(tb.header.parentHash)) let td = some(com.db.getScore(tb.header.parentHash))
com.hardForkTransition(tb.header.blockNumber, td, some(tb.header.timestamp)) com.hardForkTransition(tb.header.blockNumber, td, some(tb.header.timestamp))
let tracerInst = if tester.trace:
newLegacyTracer({})
else:
LegacyTracer(nil)
tester.vmState = BaseVMState.new( if com.isCancunOrLater(tb.header.timestamp):
if not trustedSetupLoaded:
let res = loadKzgTrustedSetup()
if res.isErr:
echo "FATAL: ", res.error
quit(QuitFailure)
trustedSetupLoaded = true
if ctx.vmState.isNil or ctx.vmState.stateDB.isTopLevelClean.not:
let tracerInst = ctx.setupTracer()
ctx.vmState = BaseVMState.new(
parentHeader, parentHeader,
tb.header, tb.header,
com, com,
tracerInst, tracerInst,
) )
else:
doAssert(ctx.vmState.reinit(parentHeader, tb.header))
if validation: if validation:
let rc = com.validateHeaderAndKinship( let rc = com.validateHeaderAndKinship(
@ -210,52 +241,52 @@ proc importBlock(tester: var Tester, com: CommonRef,
raise newException( raise newException(
ValidationError, "validateHeaderAndKinship: " & rc.error) ValidationError, "validateHeaderAndKinship: " & rc.error)
let res = tester.vmState.processBlockNotPoA(tb.header, tb.body) let res = ctx.vmState.processBlockNotPoA(tb.header, tb.body)
if res == ValidationResult.Error: if res == ValidationResult.Error:
if not (tb.hasException or (not tb.goodBlock)): if not (tb.hasException or (not tb.goodBlock)):
raise newException(ValidationError, "process block validation") raise newException(ValidationError, "process block validation")
else: else:
if tester.vmState.generateWitness(): if ctx.vmState.generateWitness():
blockWitness(tester.vmState, com.db) blockWitness(ctx.vmState, com.db)
discard com.db.persistHeaderToDb(tb.header, discard com.db.persistHeaderToDb(tb.header,
com.consensus == ConsensusType.POS) com.consensus == ConsensusType.POS)
proc applyFixtureBlockToChain(tester: var Tester, tb: var TestBlock, proc applyFixtureBlockToChain(ctx: var TestCtx, tb: var TestBlock,
com: CommonRef, checkSeal, validation: bool) = com: CommonRef, checkSeal, validation: bool) =
decompose(tb.blockRLP, tb.header, tb.body) decompose(tb.blockRLP, tb.header, tb.body)
tester.importBlock(com, tb, checkSeal, validation) ctx.importBlock(com, tb, checkSeal, validation)
func shouldCheckSeal(tester: Tester): bool = func shouldCheckSeal(ctx: TestCtx): bool =
if tester.sealEngine.isSome: if ctx.sealEngine.isSome:
result = tester.sealEngine.get() != NoProof result = ctx.sealEngine.get() != NoProof
proc collectDebugData(tester: var Tester) = proc collectDebugData(ctx: var TestCtx) =
if tester.vmState.isNil: if ctx.vmState.isNil:
return return
let vmState = tester.vmState let vmState = ctx.vmState
let tracerInst = LegacyTracer(vmState.tracer) let tracerInst = LegacyTracer(vmState.tracer)
let tracingResult = if tester.trace: tracerInst.getTracingResult() else: %[] let tracingResult = if ctx.trace: tracerInst.getTracingResult() else: %[]
tester.debugData.add %{ ctx.debugData.add %{
"blockNumber": %($vmState.blockNumber), "blockNumber": %($vmState.blockNumber),
"structLogs": tracingResult, "structLogs": tracingResult,
} }
proc runTester(tester: var Tester, com: CommonRef, testStatusIMPL: var TestStatus) = proc runTestCtx(ctx: var TestCtx, com: CommonRef, testStatusIMPL: var TestStatus) =
discard com.db.persistHeaderToDb(tester.genesisHeader, discard com.db.persistHeaderToDb(ctx.genesisHeader,
com.consensus == ConsensusType.POS) com.consensus == ConsensusType.POS)
check com.db.getCanonicalHead().blockHash == tester.genesisHeader.blockHash check com.db.getCanonicalHead().blockHash == ctx.genesisHeader.blockHash
let checkSeal = tester.shouldCheckSeal let checkSeal = ctx.shouldCheckSeal
if tester.debugMode: if ctx.debugMode:
tester.debugData = newJArray() ctx.debugData = newJArray()
for idx, tb in tester.blocks: for idx, tb in ctx.blocks:
if tb.goodBlock: if tb.goodBlock:
try: try:
tester.applyFixtureBlockToChain( ctx.applyFixtureBlockToChain(
tester.blocks[idx], com, checkSeal, validation = false) ctx.blocks[idx], com, checkSeal, validation = false)
# manually validating # manually validating
let res = com.validateHeaderAndKinship( let res = com.validateHeaderAndKinship(
@ -274,14 +305,14 @@ proc runTester(tester: var Tester, com: CommonRef, testStatusIMPL: var TestStatu
else: else:
var noError = true var noError = true
try: try:
tester.applyFixtureBlockToChain(tester.blocks[idx], ctx.applyFixtureBlockToChain(ctx.blocks[idx],
com, checkSeal, validation = true) com, checkSeal, validation = true)
except ValueError, ValidationError, BlockNotFound, RlpError: except ValueError, ValidationError, BlockNotFound, RlpError:
# failure is expected on this bad block # failure is expected on this bad block
check (tb.hasException or (not tb.goodBlock)) check (tb.hasException or (not tb.goodBlock))
noError = false noError = false
if tester.debugMode: if ctx.debugMode:
tester.debugData.add %{ ctx.debugData.add %{
"exception": %($getCurrentException().name), "exception": %($getCurrentException().name),
"msg": %getCurrentExceptionMsg() "msg": %getCurrentExceptionMsg()
} }
@ -289,32 +320,32 @@ proc runTester(tester: var Tester, com: CommonRef, testStatusIMPL: var TestStatu
# Block should have caused a validation error # Block should have caused a validation error
check noError == false check noError == false
if tester.debugMode: if ctx.debugMode and not ctx.json:
tester.collectDebugData() ctx.collectDebugData()
proc debugDataFromAccountList(tester: Tester): JsonNode = proc debugDataFromAccountList(ctx: TestCtx): JsonNode =
let vmState = tester.vmState let vmState = ctx.vmState
result = %{"debugData": tester.debugData} result = %{"debugData": ctx.debugData}
if not vmState.isNil: if not vmState.isNil:
result["accounts"] = vmState.dumpAccounts() result["accounts"] = vmState.dumpAccounts()
proc debugDataFromPostStateHash(tester: Tester): JsonNode = proc debugDataFromPostStateHash(ctx: TestCtx): JsonNode =
let vmState = tester.vmState let vmState = ctx.vmState
%{ %{
"debugData": tester.debugData, "debugData": ctx.debugData,
"postStateHash": %($vmState.readOnlyStateDB.rootHash), "postStateHash": %($vmState.readOnlyStateDB.rootHash),
"expectedStateHash": %($tester.postStateHash), "expectedStateHash": %($ctx.postStateHash),
"accounts": vmState.dumpAccounts() "accounts": vmState.dumpAccounts()
} }
proc dumpDebugData(tester: Tester, fixtureName: string, fixtureIndex: int, success: bool) = proc dumpDebugData(ctx: TestCtx, fixtureName: string, fixtureIndex: int, success: bool) =
let debugData = if tester.postStateHash != Hash256(): let debugData = if ctx.postStateHash != Hash256():
debugDataFromPostStateHash(tester) debugDataFromPostStateHash(ctx)
else: else:
debugDataFromAccountList(tester) debugDataFromAccountList(ctx)
let status = if success: "_success" else: "_failed" let status = if success: "_success" else: "_failed"
let name = fixtureName.replace('/', '-') let name = fixtureName.replace('/', '-').replace(':', '-')
writeFile("debug_" & name & "_" & $fixtureIndex & status & ".json", debugData.pretty()) writeFile("debug_" & name & "_" & $fixtureIndex & status & ".json", debugData.pretty())
proc testFixture(node: JsonNode, testStatusIMPL: var TestStatus, debugMode = false, trace = false) = proc testFixture(node: JsonNode, testStatusIMPL: var TestStatus, debugMode = false, trace = false) =
@ -333,50 +364,51 @@ proc testFixture(node: JsonNode, testStatusIMPL: var TestStatus, debugMode = fal
if specifyIndex > 0 and fixtureIndex != specifyIndex: if specifyIndex > 0 and fixtureIndex != specifyIndex:
continue continue
var tester = parseTester(fixture, testStatusIMPL) var ctx = parseTestCtx(fixture, testStatusIMPL)
let let
pruneTrie = test_config.getConfiguration().pruning pruneTrie = test_config.getConfiguration().pruning
memDB = newCoreDbRef LegacyDbMemory memDB = newCoreDbRef LegacyDbMemory
stateDB = AccountsCache.init(memDB, emptyRlpHash, pruneTrie) stateDB = AccountsCache.init(memDB, emptyRlpHash, pruneTrie)
config = getChainConfig(tester.network) config = getChainConfig(ctx.network)
com = CommonRef.new(memDB, config, pruneTrie) com = CommonRef.new(memDB, config, pruneTrie)
setupStateDB(fixture["pre"], stateDB) setupStateDB(fixture["pre"], stateDB)
stateDB.persist() stateDB.persist()
check stateDB.rootHash == tester.genesisHeader.stateRoot check stateDB.rootHash == ctx.genesisHeader.stateRoot
tester.debugMode = debugMode ctx.debugMode = debugMode
tester.trace = trace ctx.trace = trace
ctx.json = test_config.getConfiguration().json
var success = true var success = true
try: try:
tester.runTester(com, testStatusIMPL) ctx.runTestCtx(com, testStatusIMPL)
let header = com.db.getCanonicalHead() let header = com.db.getCanonicalHead()
let lastBlockHash = header.blockHash let lastBlockHash = header.blockHash
check lastBlockHash == tester.lastBlockHash check lastBlockHash == ctx.lastBlockHash
success = lastBlockHash == tester.lastBlockHash success = lastBlockHash == ctx.lastBlockHash
if tester.postStateHash != Hash256(): if ctx.postStateHash != Hash256():
let rootHash = tester.vmState.stateDB.rootHash let rootHash = ctx.vmState.stateDB.rootHash
if tester.postStateHash != rootHash: if ctx.postStateHash != rootHash:
raise newException(ValidationError, "incorrect postStateHash, expect=" & raise newException(ValidationError, "incorrect postStateHash, expect=" &
$rootHash & ", get=" & $rootHash & ", get=" &
$tester.postStateHash $ctx.postStateHash
) )
elif lastBlockHash == tester.lastBlockHash: elif lastBlockHash == ctx.lastBlockHash:
# multiple chain, we are using the last valid canonical # multiple chain, we are using the last valid canonical
# state root to test against 'postState' # state root to test against 'postState'
let stateDB = AccountsCache.init(memDB, header.stateRoot, pruneTrie) let stateDB = AccountsCache.init(memDB, header.stateRoot, pruneTrie)
verifyStateDB(fixture["postState"], ReadOnlyStateDB(stateDB)) verifyStateDB(fixture["postState"], ReadOnlyStateDB(stateDB))
success = lastBlockHash == tester.lastBlockHash success = lastBlockHash == ctx.lastBlockHash
except ValidationError as E: except ValidationError as E:
echo fixtureName, " ERROR: ", E.msg echo fixtureName, " ERROR: ", E.msg
success = false success = false
if tester.debugMode: if ctx.debugMode:
tester.dumpDebugData(fixtureName, fixtureIndex, success) ctx.dumpDebugData(fixtureName, fixtureIndex, success)
fixtureTested = true fixtureTested = true
check success == true check success == true
@ -388,8 +420,10 @@ proc testFixture(node: JsonNode, testStatusIMPL: var TestStatus, debugMode = fal
proc blockchainJsonMain*(debugMode = false) = proc blockchainJsonMain*(debugMode = false) =
const const
legacyFolder = "eth_tests" / "LegacyTests" / "Constantinople" / "BlockchainTests" legacyFolder = "eth_tests/LegacyTests/Constantinople/BlockchainTests"
newFolder = "eth_tests" / "BlockchainTests" newFolder = "eth_tests/BlockchainTests"
#newFolder = "eth_tests/EIPTests/BlockchainTests"
#newFolder = "eth_tests/EIPTests/Pyspecs/cancun"
let config = test_config.getConfiguration() let config = test_config.getConfiguration()
if config.testSubject == "" or not debugMode: if config.testSubject == "" or not debugMode:
@ -407,7 +441,7 @@ proc blockchainJsonMain*(debugMode = false) =
quit(QuitFailure) quit(QuitFailure)
let folder = if config.legacy: legacyFolder else: newFolder let folder = if config.legacy: legacyFolder else: newFolder
let path = "tests" / "fixtures" / folder let path = "tests/fixtures/" & folder
let n = json.parseFile(path / config.testSubject) let n = json.parseFile(path / config.testSubject)
var testStatusIMPL: TestStatus var testStatusIMPL: TestStatus
testFixture(n, testStatusIMPL, debugMode = true, config.trace) testFixture(n, testStatusIMPL, debugMode = true, config.trace)

View File

@ -18,6 +18,7 @@ type
trace*: bool trace*: bool
legacy*: bool legacy*: bool
pruning*: bool pruning*: bool
json*: bool
var testConfig {.threadvar.}: Configuration var testConfig {.threadvar.}: Configuration
@ -48,6 +49,7 @@ proc processArguments*(msg: var string): ConfigStatus =
of "trace": config.trace = parseBool(value) of "trace": config.trace = parseBool(value)
of "legacy": config.legacy = parseBool(value) of "legacy": config.legacy = parseBool(value)
of "pruning": config.pruning = parseBool(value) of "pruning": config.pruning = parseBool(value)
of "json": config.json = parseBool(value)
else: else:
msg = "Unknown option " & key msg = "Unknown option " & key
if value.len > 0: msg = msg & " : " & value if value.len > 0: msg = msg & " : " & value

View File

@ -15,6 +15,7 @@ import
../nimbus/common/common, ../nimbus/common/common,
../nimbus/utils/[utils, debug], ../nimbus/utils/[utils, debug],
../nimbus/evm/tracer/legacy_tracer, ../nimbus/evm/tracer/legacy_tracer,
../nimbus/core/eip4844,
../tools/common/helpers as chp, ../tools/common/helpers as chp,
../tools/evmstate/helpers, ../tools/evmstate/helpers,
../tools/common/state_clearing, ../tools/common/state_clearing,
@ -23,8 +24,9 @@ import
stew/[results, byteutils] stew/[results, byteutils]
type type
Tester = object TestCtx = object
name: string name: string
parent: BlockHeader
header: BlockHeader header: BlockHeader
pre: JsonNode pre: JsonNode
tx: Transaction tx: Transaction
@ -36,6 +38,9 @@ type
index: int index: int
fork: string fork: string
var
trustedSetupLoaded = false
proc toBytes(x: string): seq[byte] = proc toBytes(x: string): seq[byte] =
result = newSeq[byte](x.len) result = newSeq[byte](x.len)
for i in 0..<x.len: result[i] = x[i].byte for i in 0..<x.len: result[i] = x[i].byte
@ -50,39 +55,47 @@ method getAncestorHash*(vmState: BaseVMState; blockNumber: BlockNumber): Hash256
else: else:
return keccakHash(toBytes($blockNumber)) return keccakHash(toBytes($blockNumber))
proc dumpDebugData(tester: Tester, vmState: BaseVMState, gasUsed: GasInt, success: bool) = proc dumpDebugData(ctx: TestCtx, vmState: BaseVMState, gasUsed: GasInt, success: bool) =
let tracerInst = LegacyTracer(vmState.tracer) let tracerInst = LegacyTracer(vmState.tracer)
let tracingResult = if tester.trace: tracerInst.getTracingResult() else: %[] let tracingResult = if ctx.trace: tracerInst.getTracingResult() else: %[]
let debugData = %{ let debugData = %{
"gasUsed": %gasUsed, "gasUsed": %gasUsed,
"structLogs": tracingResult, "structLogs": tracingResult,
"accounts": vmState.dumpAccounts() "accounts": vmState.dumpAccounts()
} }
let status = if success: "_success" else: "_failed" let status = if success: "_success" else: "_failed"
writeFile(tester.name & "_" & tester.fork & "_" & $tester.index & status & ".json", debugData.pretty()) writeFile(ctx.name & "_" & ctx.fork & "_" & $ctx.index & status & ".json", debugData.pretty())
proc testFixtureIndexes(tester: Tester, testStatusIMPL: var TestStatus) = proc testFixtureIndexes(ctx: var TestCtx, testStatusIMPL: var TestStatus) =
let let
com = CommonRef.new(newCoreDbRef LegacyDbMemory, tester.chainConfig, getConfiguration().pruning) com = CommonRef.new(newCoreDbRef LegacyDbMemory, ctx.chainConfig, getConfiguration().pruning)
parent = BlockHeader(stateRoot: emptyRlpHash) parent = BlockHeader(stateRoot: emptyRlpHash)
tracer = if tester.trace: tracer = if ctx.trace:
newLegacyTracer({}) newLegacyTracer({})
else: else:
LegacyTracer(nil) LegacyTracer(nil)
if com.isCancunOrLater(ctx.header.timestamp):
if not trustedSetupLoaded:
let res = loadKzgTrustedSetup()
if res.isErr:
echo "FATAL: ", res.error
quit(QuitFailure)
trustedSetupLoaded = true
let vmState = BaseVMState.new( let vmState = BaseVMState.new(
parent = parent, parent = parent,
header = tester.header, header = ctx.header,
com = com, com = com,
tracer = tracer, tracer = tracer,
) )
var gasUsed: GasInt var gasUsed: GasInt
let sender = tester.tx.getSender() let sender = ctx.tx.getSender()
let fork = com.toEVMFork(tester.header.forkDeterminationInfoForHeader) let fork = com.toEVMFork(ctx.header.forkDeterminationInfoForHeader)
vmState.mutateStateDB: vmState.mutateStateDB:
setupStateDB(tester.pre, db) setupStateDB(ctx.pre, db)
# this is an important step when using accounts_cache # this is an important step when using accounts_cache
# it will affect the account storage's location # it will affect the account storage's location
@ -91,35 +104,36 @@ proc testFixtureIndexes(tester: Tester, testStatusIMPL: var TestStatus) =
defer: defer:
let obtainedHash = vmState.readOnlyStateDB.rootHash let obtainedHash = vmState.readOnlyStateDB.rootHash
check obtainedHash == tester.expectedHash check obtainedHash == ctx.expectedHash
let logEntries = vmState.getAndClearLogEntries() let logEntries = vmState.getAndClearLogEntries()
let actualLogsHash = rlpHash(logEntries) let actualLogsHash = rlpHash(logEntries)
check(tester.expectedLogs == actualLogsHash) check(ctx.expectedLogs == actualLogsHash)
if tester.debugMode: if ctx.debugMode:
let success = tester.expectedLogs == actualLogsHash and obtainedHash == tester.expectedHash let success = ctx.expectedLogs == actualLogsHash and obtainedHash == ctx.expectedHash
tester.dumpDebugData(vmState, gasUsed, success) ctx.dumpDebugData(vmState, gasUsed, success)
let rc = vmState.processTransaction( let rc = vmState.processTransaction(
tester.tx, sender, tester.header, fork) ctx.tx, sender, ctx.header, fork)
if rc.isOk: if rc.isOk:
gasUsed = rc.value gasUsed = rc.value
let miner = tester.header.coinbase let miner = ctx.header.coinbase
coinbaseStateClearing(vmState, miner, fork) coinbaseStateClearing(vmState, miner, fork)
proc testFixture(fixtures: JsonNode, testStatusIMPL: var TestStatus, proc testFixture(fixtures: JsonNode, testStatusIMPL: var TestStatus,
trace = false, debugMode = false) = trace = false, debugMode = false) =
var tester: Tester var ctx: TestCtx
var fixture: JsonNode var fixture: JsonNode
for label, child in fixtures: for label, child in fixtures:
fixture = child fixture = child
tester.name = label ctx.name = label
break break
tester.pre = fixture["pre"] ctx.pre = fixture["pre"]
tester.header = parseHeader(fixture["env"]) ctx.parent = parseParentHeader(fixture["env"])
tester.trace = trace ctx.header = parseHeader(fixture["env"])
tester.debugMode = debugMode ctx.trace = trace
ctx.debugMode = debugMode
let let
post = fixture["post"] post = fixture["post"]
@ -128,51 +142,53 @@ proc testFixture(fixtures: JsonNode, testStatusIMPL: var TestStatus,
template prepareFork(forkName: string) = template prepareFork(forkName: string) =
try: try:
tester.chainConfig = getChainConfig(forkName) ctx.chainConfig = getChainConfig(forkName)
except ValueError as ex: except ValueError as ex:
debugEcho ex.msg debugEcho ex.msg
testStatusIMPL = TestStatus.Failed
return return
template runSubTest(subTest: JsonNode) = template runSubTest(subTest: JsonNode) =
tester.expectedHash = Hash256.fromJson(subTest["hash"]) ctx.expectedHash = Hash256.fromJson(subTest["hash"])
tester.expectedLogs = Hash256.fromJson(subTest["logs"]) ctx.expectedLogs = Hash256.fromJson(subTest["logs"])
tester.tx = parseTx(txData, subTest["indexes"]) ctx.tx = parseTx(txData, subTest["indexes"])
tester.testFixtureIndexes(testStatusIMPL) ctx.testFixtureIndexes(testStatusIMPL)
if conf.fork.len > 0: if conf.fork.len > 0:
if not post.hasKey(conf.fork): if not post.hasKey(conf.fork):
debugEcho "selected fork not available: " & conf.fork debugEcho "selected fork not available: " & conf.fork
return return
tester.fork = conf.fork ctx.fork = conf.fork
let forkData = post[conf.fork] let forkData = post[conf.fork]
prepareFork(conf.fork) prepareFork(conf.fork)
if conf.index.isNone: if conf.index.isNone:
for subTest in forkData: for subTest in forkData:
runSubTest(subTest) runSubTest(subTest)
inc tester.index inc ctx.index
else: else:
tester.index = conf.index.get() ctx.index = conf.index.get()
if tester.index > forkData.len or tester.index < 0: if ctx.index > forkData.len or ctx.index < 0:
debugEcho "selected index out of range(0-$1), requested $2" % debugEcho "selected index out of range(0-$1), requested $2" %
[$forkData.len, $tester.index] [$forkData.len, $ctx.index]
return return
let subTest = forkData[tester.index] let subTest = forkData[ctx.index]
runSubTest(subTest) runSubTest(subTest)
else: else:
for forkName, forkData in post: for forkName, forkData in post:
prepareFork(forkName) prepareFork(forkName)
tester.fork = forkName ctx.fork = forkName
tester.index = 0 ctx.index = 0
for subTest in forkData: for subTest in forkData:
runSubTest(subTest) runSubTest(subTest)
inc tester.index inc ctx.index
proc generalStateJsonMain*(debugMode = false) = proc generalStateJsonMain*(debugMode = false) =
const const
legacyFolder = "eth_tests" / "LegacyTests" / "Constantinople" / "GeneralStateTests" legacyFolder = "eth_tests/LegacyTests/Constantinople/GeneralStateTests"
newFolder = "eth_tests" / "GeneralStateTests" newFolder = "eth_tests/GeneralStateTests"
#newFolder = "eth_tests/EIPTests/StateTests"
let config = getConfiguration() let config = getConfiguration()
if config.testSubject == "" or not debugMode: if config.testSubject == "" or not debugMode: