mirror of
https://github.com/status-im/nimbus-eth1.git
synced 2025-01-28 04:55:33 +00:00
a31db89e0e
t8n: a silly bug contract address generator, should use original tx nonce instead of read the nonce from sender address in state db. Although in EVM contract address generated by reading nonce from state db is correct, outside EVM that nonce value might have been modified, thus generating incorrect contract address. accounts cache: when clearing account storage, the originalValue cache is not cleared, only the storageRoot set to empty storage root, this will cause getStorage and getCommitedStorage return wrong value if the originalValue cache contains old value.
462 lines
13 KiB
Nim
462 lines
13 KiB
Nim
# Nimbus
|
|
# Copyright (c) 2022 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.
|
|
|
|
import
|
|
std/[os, osproc, strutils, json, tables],
|
|
unittest2,
|
|
"."/[types]
|
|
|
|
type
|
|
T8nInput = object
|
|
inAlloc : string
|
|
inTxs : string
|
|
inEnv : string
|
|
stFork : string
|
|
stReward: string
|
|
|
|
T8nOutput = object
|
|
alloc : bool
|
|
result: bool
|
|
body : bool
|
|
|
|
TestSpec = object
|
|
name : string
|
|
base : string
|
|
input : T8nInput
|
|
output : T8nOutput
|
|
expExitCode: int
|
|
expOut : string
|
|
|
|
JsonComparator = object
|
|
path: string
|
|
error: string
|
|
|
|
proc t8nInput(alloc, txs, env, fork, reward: string): T8nInput =
|
|
T8nInput(
|
|
inAlloc : alloc,
|
|
inTxs : txs,
|
|
inEnv : env,
|
|
stFork : fork,
|
|
stReward: reward
|
|
)
|
|
|
|
proc get(opt: T8nInput, base : string): string =
|
|
result.add(" --input.alloc " & (base / opt.inAlloc))
|
|
result.add(" --input.txs " & (base / opt.inTxs))
|
|
result.add(" --input.env " & (base / opt.inEnv))
|
|
result.add(" --state.fork " & opt.stFork)
|
|
if opt.stReward.len > 0:
|
|
result.add(" --state.reward " & opt.stReward)
|
|
|
|
proc get(opt: T8nOutput): string =
|
|
if opt.alloc:
|
|
result.add(" --output.alloc stdout")
|
|
else:
|
|
result.add(" --output.alloc")
|
|
|
|
if opt.result:
|
|
result.add(" --output.result stdout")
|
|
else:
|
|
result.add(" --output.result")
|
|
|
|
if opt.body:
|
|
result.add(" --output.body stdout")
|
|
else:
|
|
result.add(" --output.body")
|
|
|
|
template exit(jsc: var JsonComparator, msg: string) =
|
|
jsc.path = path
|
|
jsc.error = msg
|
|
return false
|
|
|
|
proc cmp(jsc: var JsonComparator; a, b: JsonNode, path: string): bool =
|
|
## Check two nodes for equality
|
|
if a.isNil:
|
|
if b.isNil: return true
|
|
jsc.exit("A nil, but B not nil")
|
|
elif b.isNil:
|
|
jsc.exit("A not nil, but B nil")
|
|
elif a.kind != b.kind:
|
|
jsc.exit("A($1) != B($2)" % [$a.kind, $b.kind])
|
|
else:
|
|
result = true
|
|
case a.kind
|
|
of JString:
|
|
if a.str != b.str:
|
|
jsc.exit("STRING A($1) != B($2)" % [a.str, b.str])
|
|
of JInt:
|
|
if a.num != b.num:
|
|
jsc.exit("INT A($1) != B($2)" % [$a.num, $b.num])
|
|
of JFloat:
|
|
if a.fnum != b.fnum:
|
|
jsc.exit("FLOAT A($1) != B($2)" % [$a.fnum, $b.fnum])
|
|
of JBool:
|
|
if a.bval != b.bval:
|
|
jsc.exit("BOOL A($1) != B($2)" % [$a.bval, $b.bval])
|
|
of JNull:
|
|
result = true
|
|
of JArray:
|
|
for i, x in a.elems:
|
|
if not jsc.cmp(x, b.elems[i], path & "/" & $i):
|
|
return false
|
|
of JObject:
|
|
# we cannot use OrderedTable's equality here as
|
|
# the order does not matter for equality here.
|
|
if a.fields.len != b.fields.len:
|
|
jsc.exit("OBJ LEN A($1) != B($2)" % [$a.fields.len, $b.fields.len])
|
|
for key, val in a.fields:
|
|
if not b.fields.hasKey(key):
|
|
jsc.exit("OBJ FIELD A($1) != B(none)" % [key])
|
|
if not jsc.cmp(val, b.fields[key], path & "/" & key):
|
|
return false
|
|
|
|
proc notRejectedError(path: string): bool =
|
|
# we only check error status, and not the error message
|
|
# because each implementation can have different error
|
|
# message
|
|
not (path.startsWith("root/result/rejected/") and
|
|
path.endsWith("/error"))
|
|
|
|
proc runTest(appDir: string, spec: TestSpec): bool =
|
|
let base = appDir / spec.base
|
|
let args = spec.input.get(base) & spec.output.get()
|
|
let cmd = appDir / "t8n" & args
|
|
let (res, exitCode) = execCmdEx(cmd)
|
|
|
|
if exitCode != spec.expExitCode:
|
|
echo "test $1: wrong exit code, have $2, want $3" %
|
|
[spec.name, $exitCode, $spec.expExitCode]
|
|
echo res
|
|
return false
|
|
|
|
if spec.expOut.len > 0:
|
|
let path = base / spec.expOut
|
|
let want = json.parseFile(path)
|
|
let have = json.parseJson(res)
|
|
var jsc = JsonComparator()
|
|
if not jsc.cmp(want, have, "root") and notRejectedError(jsc.path):
|
|
echo "test $1: output wrong, have \n$2\nwant\n$3\n" %
|
|
[spec.name, have.pretty, want.pretty]
|
|
echo "path: $1, error: $2" %
|
|
[jsc.path, jsc.error]
|
|
return false
|
|
return true
|
|
|
|
const
|
|
testSpec = [
|
|
TestSpec(
|
|
name : "Test exit (3) on bad config",
|
|
base : "testdata/1",
|
|
input : t8nInput(
|
|
"alloc.json", "txs.json", "env.json", "Frontier+1346", "",
|
|
),
|
|
output: T8nOutput(alloc: true, result: true),
|
|
expExitCode: ErrorConfig.int,
|
|
),
|
|
TestSpec(
|
|
name : "baseline test",
|
|
base : "testdata/1",
|
|
input : t8nInput(
|
|
"alloc.json", "txs.json", "env.json", "Byzantium", "",
|
|
),
|
|
output: T8nOutput(alloc: true, result: true),
|
|
expOut: "exp.json",
|
|
),
|
|
TestSpec(
|
|
name : "blockhash test",
|
|
base : "testdata/3",
|
|
input : t8nInput(
|
|
"alloc.json", "txs.json", "env.json", "Berlin", ""
|
|
),
|
|
output: T8nOutput(alloc: true, result: true),
|
|
expOut: "exp.json"
|
|
),
|
|
TestSpec(
|
|
name : "missing blockhash test",
|
|
base : "testdata/4",
|
|
input : t8nInput(
|
|
"alloc.json", "txs.json", "env.json", "Berlin", "",
|
|
),
|
|
output: T8nOutput(alloc: true, result: true),
|
|
expExitCode: ErrorMissingBlockhash.int,
|
|
),
|
|
TestSpec(
|
|
name : "Uncle test",
|
|
base : "testdata/5",
|
|
input : t8nInput(
|
|
"alloc.json", "txs.json", "env.json", "Byzantium", "0x80",
|
|
),
|
|
output: T8nOutput(alloc: true, result: true),
|
|
expOut: "exp.json",
|
|
),
|
|
TestSpec(
|
|
name : "Sign json transactions",
|
|
base : "testdata/13",
|
|
input : t8nInput(
|
|
"alloc.json", "txs.json", "env.json", "London", "",
|
|
),
|
|
output: T8nOutput(body: true),
|
|
expOut: "exp.json",
|
|
),
|
|
TestSpec(
|
|
name : "Already signed transactions",
|
|
base : "testdata/13",
|
|
input : t8nInput(
|
|
"alloc.json", "signed_txs.rlp", "env.json", "London", "",
|
|
),
|
|
output: T8nOutput(result: true),
|
|
expOut: "exp2.json",
|
|
),
|
|
TestSpec(
|
|
name : "Difficulty calculation - no uncles",
|
|
base : "testdata/14",
|
|
input : t8nInput(
|
|
"alloc.json", "txs.json", "env.json", "London", "",
|
|
),
|
|
output: T8nOutput(result: true),
|
|
expOut: "exp.json",
|
|
),
|
|
TestSpec(
|
|
name : "Difficulty calculation - with uncles",
|
|
base : "testdata/14",
|
|
input : t8nInput(
|
|
"alloc.json", "txs.json", "env.uncles.json", "London", "",
|
|
),
|
|
output: T8nOutput(result: true),
|
|
expOut: "exp2.json",
|
|
),
|
|
TestSpec(
|
|
name : "Difficulty calculation - with ommers + Berlin",
|
|
base : "testdata/14",
|
|
input : t8nInput(
|
|
"alloc.json", "txs.json", "env.uncles.json", "Berlin", "",
|
|
),
|
|
output: T8nOutput(result: true),
|
|
expOut: "exp_berlin.json",
|
|
),
|
|
TestSpec(
|
|
name : "Difficulty calculation on london",
|
|
base : "testdata/19",
|
|
input : t8nInput(
|
|
"alloc.json", "txs.json", "env.json", "London", "",
|
|
),
|
|
output: T8nOutput(result: true),
|
|
expOut: "exp_london.json",
|
|
),
|
|
TestSpec(
|
|
name : "Difficulty calculation on arrow glacier",
|
|
base : "testdata/19",
|
|
input : t8nInput(
|
|
"alloc.json", "txs.json", "env.json", "ArrowGlacier", "",
|
|
),
|
|
output: T8nOutput(result: true),
|
|
expOut: "exp_arrowglacier.json",
|
|
),
|
|
TestSpec(
|
|
name : "Difficulty calculation on gray glacier",
|
|
base : "testdata/19",
|
|
input : t8nInput(
|
|
"alloc.json", "txs.json", "env.json", "GrayGlacier", "",
|
|
),
|
|
output: T8nOutput(result: true),
|
|
expOut: "exp_grayglacier.json",
|
|
),
|
|
TestSpec(
|
|
name : "Sign unprotected (pre-EIP155) transaction",
|
|
base : "testdata/23",
|
|
input : t8nInput(
|
|
"alloc.json", "txs.json", "env.json", "Berlin", "",
|
|
),
|
|
output: T8nOutput(result: true),
|
|
expOut: "exp.json",
|
|
),
|
|
TestSpec(
|
|
name : "Test post-merge transition",
|
|
base : "testdata/24",
|
|
input : t8nInput(
|
|
"alloc.json", "txs.json", "env.json", "Merge", "",
|
|
),
|
|
output: T8nOutput(alloc: true, result: true),
|
|
expOut: "exp.json",
|
|
),
|
|
TestSpec(
|
|
name : "Test post-merge transition where input is missing random",
|
|
base : "testdata/24",
|
|
input : t8nInput(
|
|
"alloc.json", "txs.json", "env-missingrandom.json", "Merge", "",
|
|
),
|
|
output: T8nOutput(alloc: false, result: false),
|
|
expExitCode: ErrorConfig.int,
|
|
),
|
|
TestSpec(
|
|
name : "Test state-reward -1",
|
|
base : "testdata/3",
|
|
input : t8nInput(
|
|
"alloc.json", "txs.json", "env.json", "Berlin", "-1"
|
|
),
|
|
output: T8nOutput(alloc: true, result: true),
|
|
expOut: "exp.json",
|
|
),
|
|
TestSpec(
|
|
name : "0-touch reward on pre EIP150 networks -1(txs.rlp)",
|
|
base : "testdata/00-501",
|
|
input : t8nInput(
|
|
"alloc.json", "txs.rlp", "env.json", "EIP150", "-1"
|
|
),
|
|
output: T8nOutput(alloc: true, result: true),
|
|
expOut: "exp.json",
|
|
),
|
|
TestSpec(
|
|
name : "0-touch reward on pre EIP150 networks(txs.rlp)",
|
|
base : "testdata/00-502",
|
|
input : t8nInput(
|
|
"alloc.json", "txs.rlp", "env.json", "EIP150", ""
|
|
),
|
|
output: T8nOutput(alloc: true, result: true),
|
|
expOut: "exp.json",
|
|
),
|
|
TestSpec(
|
|
name : "0-touch reward on pre EIP150 networks(txs.json)",
|
|
base : "testdata/00-502",
|
|
input : t8nInput(
|
|
"alloc.json", "txs.json", "env.json", "EIP150", ""
|
|
),
|
|
output: T8nOutput(alloc: true, result: true),
|
|
expOut: "exp.json",
|
|
),
|
|
TestSpec(
|
|
name : "calculate basefee from parentBaseFee -1",
|
|
base : "testdata/00-503",
|
|
input : t8nInput(
|
|
"alloc.json", "txs.json", "env.json", "London", "-1"
|
|
),
|
|
output: T8nOutput(alloc: true, result: true),
|
|
expOut: "exp.json",
|
|
),
|
|
TestSpec(
|
|
name : "calculate basefee from parentBaseFee",
|
|
base : "testdata/00-504",
|
|
input : t8nInput(
|
|
"alloc.json", "txs.json", "env.json", "London", ""
|
|
),
|
|
output: T8nOutput(alloc: true, result: true),
|
|
expOut: "exp.json",
|
|
),
|
|
TestSpec(
|
|
name : "BLOCKHASH opcode -1",
|
|
base : "testdata/00-505",
|
|
input : t8nInput(
|
|
"alloc.json", "txs.json", "env.json", "London", "-1"
|
|
),
|
|
output: T8nOutput(alloc: true, result: true),
|
|
expOut: "exp.json",
|
|
),
|
|
TestSpec(
|
|
name : "BLOCKHASH opcode",
|
|
base : "testdata/00-506",
|
|
input : t8nInput(
|
|
"alloc.json", "txs.json", "env.json", "London", ""
|
|
),
|
|
output: T8nOutput(alloc: true, result: true),
|
|
expOut: "exp.json",
|
|
),
|
|
TestSpec(
|
|
name : "testOpcode 40 Berlin",
|
|
base : "testdata/00-507",
|
|
input : t8nInput(
|
|
"alloc.json", "txs.json", "env.json", "Berlin", "2000000000000000000"
|
|
),
|
|
output: T8nOutput(alloc: true, result: true),
|
|
expOut: "exp.json",
|
|
),
|
|
TestSpec(
|
|
name : "suicideCoinbaseState Berlin",
|
|
base : "testdata/00-508",
|
|
input : t8nInput(
|
|
"alloc.json", "txs.json", "env.json", "Berlin", "2000000000000000000"
|
|
),
|
|
output: T8nOutput(alloc: true, result: true),
|
|
expOut: "exp.json",
|
|
),
|
|
TestSpec(
|
|
name : "BLOCKHASH Bounds",
|
|
base : "testdata/00-509",
|
|
input : t8nInput(
|
|
"alloc.json", "txs.json", "env.json", "Berlin", "2000000000000000000"
|
|
),
|
|
output: T8nOutput(alloc: true, result: true),
|
|
expOut: "exp.json",
|
|
),
|
|
TestSpec(
|
|
name : "Suicides Mixing Coinbase",
|
|
base : "testdata/00-510",
|
|
input : t8nInput(
|
|
"alloc.json", "txs.json", "env.json", "Berlin", "2000000000000000000"
|
|
),
|
|
output: T8nOutput(alloc: true, result: true),
|
|
expOut: "exp.json",
|
|
),
|
|
TestSpec(
|
|
name : "Legacy Byzantium State Clearing",
|
|
base : "testdata/00-511",
|
|
input : t8nInput(
|
|
"alloc.json", "txs.rlp", "env.json", "Byzantium", "-1"
|
|
),
|
|
output: T8nOutput(alloc: true, result: true),
|
|
expOut: "exp.json",
|
|
),
|
|
TestSpec(
|
|
name : "Test withdrawals transition",
|
|
base : "testdata/26",
|
|
input : t8nInput(
|
|
"alloc.json", "txs.json", "env.json", "Shanghai", ""
|
|
),
|
|
output: T8nOutput(alloc: true, result: true),
|
|
expOut: "exp.json",
|
|
),
|
|
TestSpec(
|
|
name : "Revert In Create In Init Create2",
|
|
base : "testdata/00-512",
|
|
input : t8nInput(
|
|
"alloc.json", "txs.rlp", "env.json", "Berlin", "0"
|
|
),
|
|
output: T8nOutput(alloc: true, result: true),
|
|
expOut: "exp.json",
|
|
),
|
|
TestSpec(
|
|
name : "Revert In Create In Init",
|
|
base : "testdata/00-513",
|
|
input : t8nInput(
|
|
"alloc.json", "txs.rlp", "env.json", "Berlin", "0"
|
|
),
|
|
output: T8nOutput(alloc: true, result: true),
|
|
expOut: "exp.json",
|
|
),
|
|
TestSpec(
|
|
name : "Init collision 3",
|
|
base : "testdata/00-514",
|
|
input : t8nInput(
|
|
"alloc.json", "txs.rlp", "env.json", "Berlin", "0"
|
|
),
|
|
output: T8nOutput(alloc: true, result: true),
|
|
expOut: "exp.json",
|
|
),
|
|
]
|
|
|
|
proc main() =
|
|
suite "Transition tool (t8n) test suite":
|
|
let appDir = getAppDir()
|
|
for x in testSpec:
|
|
test x.name:
|
|
check runTest(appDir, x)
|
|
|
|
when isMainModule:
|
|
main()
|