2018-04-06 14:52:10 +00:00
|
|
|
# Nimbus
|
|
|
|
# Copyright (c) 2018 Status Research & Development GmbH
|
|
|
|
# Licensed under either of
|
|
|
|
# * Apache License, version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0)
|
|
|
|
# * MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT)
|
|
|
|
# at your option. This file may not be copied, modified, or distributed except according to those terms.
|
|
|
|
|
2018-01-17 11:24:09 +00:00
|
|
|
import
|
2022-12-02 04:39:12 +00:00
|
|
|
os, macros, json, strformat, strutils, os, tables,
|
|
|
|
stew/byteutils, net, eth/[keys, rlp, p2p], unittest2,
|
2020-03-10 11:30:27 +00:00
|
|
|
testutils/markdown_reports,
|
2022-12-02 04:39:12 +00:00
|
|
|
../nimbus/[constants, config, transaction, errors],
|
2020-07-20 06:50:05 +00:00
|
|
|
../nimbus/db/accounts_cache,
|
2022-12-02 04:39:12 +00:00
|
|
|
../nimbus/common/[context, common]
|
2018-01-17 11:24:09 +00:00
|
|
|
|
2022-12-02 04:39:12 +00:00
|
|
|
func revmap(x: Table[EVMFork, string]): Table[string, EVMFork] =
|
|
|
|
result = initTable[string, EVMFork]()
|
2019-08-26 15:19:18 +00:00
|
|
|
for k, v in x:
|
|
|
|
result[v] = k
|
|
|
|
|
2018-11-28 19:02:21 +00:00
|
|
|
const
|
|
|
|
# from https://ethereum-tests.readthedocs.io/en/latest/test_types/state_tests.html
|
|
|
|
forkNames* = {
|
|
|
|
FkFrontier: "Frontier",
|
|
|
|
FkHomestead: "Homestead",
|
|
|
|
FkTangerine: "EIP150",
|
|
|
|
FkSpurious: "EIP158",
|
|
|
|
FkByzantium: "Byzantium",
|
2020-03-04 09:32:30 +00:00
|
|
|
FkConstantinople: "Constantinople",
|
|
|
|
FkPetersburg: "ConstantinopleFix",
|
2021-01-06 10:02:19 +00:00
|
|
|
FkIstanbul: "Istanbul",
|
2021-06-30 13:41:29 +00:00
|
|
|
FkBerlin: "Berlin",
|
2022-09-26 16:14:12 +00:00
|
|
|
FkLondon: "London",
|
|
|
|
FkParis: "Merge"
|
2018-11-28 19:02:21 +00:00
|
|
|
}.toTable
|
|
|
|
|
2019-08-26 15:19:18 +00:00
|
|
|
nameToFork* = revmap(forkNames)
|
|
|
|
|
2019-11-20 15:25:09 +00:00
|
|
|
func skipNothing*(folder: string, name: string): bool = false
|
2018-02-27 18:10:34 +00:00
|
|
|
|
2019-05-30 16:42:55 +00:00
|
|
|
var status = initOrderedTable[string, OrderedTable[string, Status]]()
|
|
|
|
|
2020-04-21 03:44:35 +00:00
|
|
|
proc jsonTestImpl*(inputFolder, outputName: string, handler, skipTest: NimNode): NimNode {.compileTime.} =
|
2018-07-06 15:08:31 +00:00
|
|
|
let
|
|
|
|
testStatusIMPL = ident("testStatusIMPL")
|
|
|
|
# workaround for strformat in quote do: https://github.com/nim-lang/Nim/issues/8220
|
2020-04-15 11:09:49 +00:00
|
|
|
symbol {.used.} = newIdentNode"symbol"
|
|
|
|
final {.used.} = newIdentNode"final"
|
|
|
|
name {.used.} = newIdentNode"name"
|
|
|
|
formatted {.used.} = newStrLitNode"{symbol[final]} {name:<64}{$final}{'\n'}"
|
2018-11-28 19:02:21 +00:00
|
|
|
|
2018-02-13 17:18:08 +00:00
|
|
|
result = quote:
|
2019-05-30 16:42:55 +00:00
|
|
|
var filenames: seq[string] = @[]
|
2022-12-02 04:39:12 +00:00
|
|
|
let inputPath = "tests" / "fixtures" / `inputFolder`
|
|
|
|
for filename in walkDirRec(inputPath):
|
2018-11-28 19:02:21 +00:00
|
|
|
if not filename.endsWith(".json"):
|
|
|
|
continue
|
2018-02-27 18:10:34 +00:00
|
|
|
var (folder, name) = filename.splitPath()
|
|
|
|
let last = folder.splitPath().tail
|
|
|
|
if not status.hasKey(last):
|
|
|
|
status[last] = initOrderedTable[string, Status]()
|
|
|
|
status[last][name] = Status.Skip
|
2019-11-20 15:25:09 +00:00
|
|
|
if `skipTest`(last, name):
|
|
|
|
continue
|
|
|
|
filenames.add(filename)
|
2021-04-08 09:29:25 +00:00
|
|
|
|
|
|
|
doAssert(filenames.len > 0)
|
2019-05-30 16:42:55 +00:00
|
|
|
for fname in filenames:
|
2022-12-02 04:39:12 +00:00
|
|
|
test fname.subStr(inputPath.len + 1):
|
2019-05-30 16:42:55 +00:00
|
|
|
{.gcsafe.}:
|
|
|
|
let
|
2022-12-02 04:39:12 +00:00
|
|
|
filename = fname
|
2019-05-30 16:42:55 +00:00
|
|
|
(folder, name) = filename.splitPath()
|
|
|
|
last = folder.splitPath().tail
|
|
|
|
# we set this here because exceptions might be raised in the handler:
|
|
|
|
status[last][name] = Status.Fail
|
2022-04-08 04:54:11 +00:00
|
|
|
let fixtures = parseJson(readFile(filename))
|
2022-12-02 04:39:12 +00:00
|
|
|
`handler`(fixtures, `testStatusIMPL`)
|
|
|
|
if `testStatusIMPL` == OK:
|
|
|
|
status[last][name] = Status.OK
|
|
|
|
elif `testStatusIMPL` == SKIPPED:
|
2019-05-30 16:42:55 +00:00
|
|
|
status[last][name] = Status.Skip
|
|
|
|
|
|
|
|
suiteTeardown:
|
|
|
|
status.sort do (a: (string, OrderedTable[string, Status]),
|
|
|
|
b: (string, OrderedTable[string, Status])) -> int: cmp(a[0], b[0])
|
|
|
|
|
2020-04-21 03:44:35 +00:00
|
|
|
generateReport(`outputName`, status)
|
2019-05-30 16:42:55 +00:00
|
|
|
status.clear()
|
2018-01-17 11:24:09 +00:00
|
|
|
|
2020-04-21 03:44:35 +00:00
|
|
|
macro jsonTest*(inputFolder, outputName: static[string], handler: untyped, skipTest: untyped = skipNothing): untyped =
|
|
|
|
result = jsonTestImpl(inputFolder, outputName, handler, skipTest)
|
|
|
|
|
|
|
|
macro jsonTest*(inputFolder: static[string], handler: untyped, skipTest: untyped = skipNothing): untyped =
|
|
|
|
result = jsonTestImpl(inputFolder, inputFolder, handler, skipTest)
|
|
|
|
|
2018-09-13 15:00:23 +00:00
|
|
|
func ethAddressFromHex*(s: string): EthAddress = hexToByteArray(s, result)
|
2018-05-30 16:11:15 +00:00
|
|
|
|
2018-09-15 20:39:30 +00:00
|
|
|
func safeHexToSeqByte*(hexStr: string): seq[byte] =
|
|
|
|
if hexStr == "":
|
|
|
|
@[]
|
|
|
|
else:
|
|
|
|
hexStr.hexToSeqByte
|
|
|
|
|
2019-08-17 14:48:45 +00:00
|
|
|
func getHexadecimalInt*(j: JsonNode): int64 =
|
|
|
|
# parseutils.parseHex works with int which will overflow in 32 bit
|
2022-04-08 04:54:11 +00:00
|
|
|
var data: StUint[64]
|
|
|
|
data = fromHex(StUint[64], j.getStr)
|
2019-08-17 14:48:45 +00:00
|
|
|
result = cast[int64](data)
|
|
|
|
|
2018-12-31 03:28:12 +00:00
|
|
|
proc verifyStateDB*(wantedState: JsonNode, stateDB: ReadOnlyStateDB) =
|
2018-07-05 12:41:01 +00:00
|
|
|
for ac, accountData in wantedState:
|
|
|
|
let account = ethAddressFromHex(ac)
|
|
|
|
for slot, value in accountData{"storage"}:
|
|
|
|
let
|
2018-07-17 08:57:14 +00:00
|
|
|
slotId = UInt256.fromHex slot
|
2018-07-05 12:41:01 +00:00
|
|
|
wantedValue = UInt256.fromHex value.getStr
|
|
|
|
|
2020-05-30 03:14:59 +00:00
|
|
|
let actualValue = stateDB.getStorage(account, slotId)
|
|
|
|
#if not found:
|
|
|
|
# raise newException(ValidationError, "account not found: " & ac)
|
2019-09-23 15:50:13 +00:00
|
|
|
if actualValue != wantedValue:
|
2019-09-25 13:05:33 +00:00
|
|
|
raise newException(ValidationError, &"{ac} storageDiff: [{slot}] {actualValue.toHex} != {wantedValue.toHex}")
|
2018-07-05 12:41:01 +00:00
|
|
|
|
|
|
|
let
|
2020-04-20 18:12:44 +00:00
|
|
|
wantedCode = hexToSeqByte(accountData{"code"}.getStr)
|
2018-07-17 08:57:14 +00:00
|
|
|
wantedBalance = UInt256.fromHex accountData{"balance"}.getStr
|
2019-09-23 15:50:13 +00:00
|
|
|
wantedNonce = accountData{"nonce"}.getHexadecimalInt.AccountNonce
|
2018-07-05 12:41:01 +00:00
|
|
|
|
|
|
|
actualCode = stateDB.getCode(account)
|
|
|
|
actualBalance = stateDB.getBalance(account)
|
|
|
|
actualNonce = stateDB.getNonce(account)
|
|
|
|
|
2019-09-23 15:50:13 +00:00
|
|
|
if wantedCode != actualCode:
|
2021-01-13 11:17:38 +00:00
|
|
|
raise newException(ValidationError, &"{ac} codeDiff {wantedCode.toHex} != {actualCode.toHex}")
|
2019-09-23 15:50:13 +00:00
|
|
|
if wantedBalance != actualBalance:
|
2019-09-25 13:05:33 +00:00
|
|
|
raise newException(ValidationError, &"{ac} balanceDiff {wantedBalance.toHex} != {actualBalance.toHex}")
|
2019-09-23 15:50:13 +00:00
|
|
|
if wantedNonce != actualNonce:
|
2019-09-25 13:05:33 +00:00
|
|
|
raise newException(ValidationError, &"{ac} nonceDiff {wantedNonce.toHex} != {actualNonce.toHex}")
|
2018-07-05 12:41:01 +00:00
|
|
|
|
2023-01-10 17:02:21 +00:00
|
|
|
proc hashLogEntries*(logs: seq[Log]): Hash256 =
|
|
|
|
keccakHash(rlp.encode(logs))
|
2019-04-24 20:45:29 +00:00
|
|
|
|
2022-03-16 08:01:35 +00:00
|
|
|
proc setupEthNode*(
|
|
|
|
conf: NimbusConf, ctx: EthContext,
|
|
|
|
capabilities: varargs[ProtocolInfo, `protocolInfo`]): EthereumNode =
|
2022-07-27 16:07:54 +00:00
|
|
|
let keypair = ctx.getNetKeys(conf.netKey, conf.dataDir.string).tryGet()
|
2022-03-16 08:01:35 +00:00
|
|
|
let srvAddress = Address(
|
|
|
|
ip: conf.listenAddress, tcpPort: conf.tcpPort, udpPort: conf.udpPort)
|
|
|
|
|
|
|
|
var node = newEthereumNode(
|
2021-09-11 14:58:01 +00:00
|
|
|
keypair, srvAddress,
|
2021-09-16 15:59:46 +00:00
|
|
|
conf.networkId,
|
2022-10-10 02:31:28 +00:00
|
|
|
conf.agentString,
|
2022-03-16 08:01:35 +00:00
|
|
|
addAllCapabilities = false,
|
|
|
|
bindUdpPort = conf.udpPort, bindTcpPort = conf.tcpPort)
|
|
|
|
|
2019-04-24 20:45:29 +00:00
|
|
|
for capability in capabilities:
|
2022-03-16 08:01:35 +00:00
|
|
|
node.addCapability capability
|
|
|
|
|
|
|
|
node
|
2021-09-16 15:59:46 +00:00
|
|
|
|
|
|
|
proc makeTestConfig*(): NimbusConf =
|
|
|
|
# commandLineParams() will not works inside all_tests
|
|
|
|
makeConfig(@[])
|