mirror of
https://github.com/status-im/nimbus-eth1.git
synced 2025-01-24 19:19:21 +00:00
Fix EVM tracer crash bug when serializing nil stack (#1697)
* Fix EVM tracer crash bug when serializing nil stack * Fix t8n tracer doc add following description to reflect new functionality `stdout` - into the stdout output. `stderr` - into the stderr output. <file> - into the file <file>-<txIndex>.jsonl. none - output.basedir/trace-<txIndex>-<txhash>.jsonl.
This commit is contained in:
parent
bf65378006
commit
fd79c5c264
@ -88,7 +88,10 @@ proc captureOpImpl(ctx: JsonTracer, pc: int,
|
||||
res["memory"] = mem
|
||||
|
||||
if TracerFlags.DisableStack notin ctx.flags:
|
||||
res["stack"] = ctx.stack
|
||||
if ctx.stack.isNil:
|
||||
res["stack"] = newJArray()
|
||||
else:
|
||||
res["stack"] = ctx.stack
|
||||
|
||||
if TracerFlags.DisableReturnData notin ctx.flags:
|
||||
res["returnData"] = %(rData)
|
||||
|
@ -28,9 +28,15 @@ type
|
||||
|
||||
T8NConf* = object of RootObj
|
||||
traceEnabled* {.
|
||||
desc: "Output full trace logs to files trace-<txIndex>-<txhash>.jsonl"
|
||||
defaultValue: false
|
||||
name: "trace" }: bool
|
||||
desc: "Enable and set where to put full EVM trace logs"
|
||||
longDesc:
|
||||
"`stdout` - into the stdout output\n" &
|
||||
"`stderr` - into the stderr output\n" &
|
||||
"<file> - into the file <file>-<txIndex>.jsonl\n" &
|
||||
"none - output.basedir/trace-<txIndex>-<txhash>.jsonl\n"
|
||||
defaultValue: none(string)
|
||||
defaultValueDesc: "disabled"
|
||||
name: "trace" }: Option[string]
|
||||
|
||||
traceMemory* {.
|
||||
desc: "Enable full memory dump in traces"
|
||||
@ -166,7 +172,7 @@ proc convertToNimStyle(cmds: openArray[string]): seq[string] =
|
||||
|
||||
const
|
||||
Copyright = "Copyright (c) 2022 Status Research & Development GmbH"
|
||||
Version = "Nimbus-t8n 0.1.2"
|
||||
Version = "Nimbus-t8n 0.2.2"
|
||||
|
||||
# force the compiler to instantiate T8NConf.load
|
||||
# rather than have to export parseCmdArg
|
||||
|
@ -36,7 +36,11 @@ t8n [OPTIONS]...
|
||||
|
||||
The following options are available:
|
||||
|
||||
--trace Output full trace logs to files trace-<txIndex>-<txhash>.jsonl [=false].
|
||||
--trace Enable and set where to put full EVM trace logs [=disabled].
|
||||
`stdout` - into the stdout output.
|
||||
`stderr` - into the stderr output.
|
||||
<file> - into the file <file>-<txIndex>.jsonl.
|
||||
none - output.basedir/trace-<txIndex>-<txhash>.jsonl.
|
||||
--trace.memory Enable full memory dump in traces [=false].
|
||||
--trace.nostack Disable stack output in traces [=false].
|
||||
--trace.returndata Enable return data output in traces [=false].
|
||||
|
@ -25,6 +25,7 @@ type
|
||||
alloc : bool
|
||||
result: bool
|
||||
body : bool
|
||||
trace : bool
|
||||
|
||||
TestSpec = object
|
||||
name : string
|
||||
@ -71,6 +72,9 @@ proc get(opt: T8nOutput): string =
|
||||
else:
|
||||
result.add(" --output.body")
|
||||
|
||||
if opt.trace:
|
||||
result.add(" --trace stdout")
|
||||
|
||||
template exit(jsc: var JsonComparator, msg: string) =
|
||||
jsc.path = path
|
||||
jsc.error = msg
|
||||
@ -137,16 +141,25 @@ proc runTest(appDir: string, spec: TestSpec): bool =
|
||||
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
|
||||
if spec.expOut.endsWith(".json"):
|
||||
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
|
||||
else:
|
||||
# compare as regular text
|
||||
let path = base / spec.expOut
|
||||
let want = readFile(path)
|
||||
if want.replace("\x0D\x0A", "\n") != res:
|
||||
echo "test $1: output wrong, have \n$2\nwant\n$3\n" %
|
||||
[spec.name, res, want]
|
||||
return false
|
||||
return true
|
||||
|
||||
const
|
||||
@ -484,6 +497,15 @@ const
|
||||
output: T8nOutput(alloc: true, result: true),
|
||||
expOut: "exp.json",
|
||||
),
|
||||
TestSpec(
|
||||
name : "EVM tracer crash bug",
|
||||
base : "testdata/00-519",
|
||||
input : t8nInput(
|
||||
"alloc.json", "txs.json", "env.json", "Shanghai", "0",
|
||||
),
|
||||
output: T8nOutput(trace: true),
|
||||
expOut: "exp.txt",
|
||||
),
|
||||
]
|
||||
|
||||
proc main() =
|
||||
|
5
tools/t8n/testdata/00-519/alloc.json
vendored
Normal file
5
tools/t8n/testdata/00-519/alloc.json
vendored
Normal file
@ -0,0 +1,5 @@
|
||||
{
|
||||
"0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b": {
|
||||
"balance": "0x3635c9adc5dea00000"
|
||||
}
|
||||
}
|
20
tools/t8n/testdata/00-519/env.json
vendored
Normal file
20
tools/t8n/testdata/00-519/env.json
vendored
Normal file
@ -0,0 +1,20 @@
|
||||
{
|
||||
"currentCoinbase": "0x2adc25665018aa1fe0e6bc666dac8fc2697ff9ba",
|
||||
"currentGasLimit": "100000000000000000",
|
||||
"currentNumber": "2",
|
||||
"currentTimestamp": "24",
|
||||
"currentRandom": "0",
|
||||
"currentDifficulty": "0",
|
||||
"blockHashes": {
|
||||
"0": "0xea2d7e0192d890c222f0302d972a02db0bf0c6d08257d73aa1210d08d24f30c3",
|
||||
"1": "0x068f4313da4cb34b1b6b18ff37eb6ca9f7ad9d294357db81c75cb7790d25dd67"
|
||||
},
|
||||
"ommers": [],
|
||||
"withdrawals": [],
|
||||
"parentDifficulty": "0",
|
||||
"parentTimestamp": "12",
|
||||
"parentBaseFee": "7",
|
||||
"parentGasUsed": "0",
|
||||
"parentGasLimit": "100000000000000000",
|
||||
"parentUncleHash": "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347"
|
||||
}
|
2
tools/t8n/testdata/00-519/exp.txt
vendored
Normal file
2
tools/t8n/testdata/00-519/exp.txt
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
{"pc":0,"op":0,"gas":"0x0","gasCost":"0xfffffffffffecb68","memSize":0,"stack":[],"depth":1,"refund":0,"opName":"STOP","error":"Blake2b F function invalid input"}
|
||||
{"output":"0x","gasUsed":"0x13498","error":"Blake2b F function invalid input"}
|
16
tools/t8n/testdata/00-519/txs.json
vendored
Normal file
16
tools/t8n/testdata/00-519/txs.json
vendored
Normal file
@ -0,0 +1,16 @@
|
||||
[
|
||||
{
|
||||
"type": "0x0",
|
||||
"chainId": "0x1",
|
||||
"nonce": "0x0",
|
||||
"gasPrice": "0xa",
|
||||
"gas": "0x186a0",
|
||||
"to": "0x0000000000000000000000000000000000000009",
|
||||
"value": "0x0",
|
||||
"input": "0x",
|
||||
"v": "0x26",
|
||||
"r": "0x803b06b78b7bd29d0faf9401f2df5d71e8a445ad1ac0a45d2e5256ba23c43ed1",
|
||||
"s": "0x6634f86b79da86a904b1900a52e470847ffe730ef4ec32a3b0f7eece7bfaae96",
|
||||
"sender": "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b"
|
||||
}
|
||||
]
|
@ -147,18 +147,22 @@ proc calcLogsHash(receipts: openArray[Receipt]): Hash256 =
|
||||
logs.add rec.logs
|
||||
rlpHash(logs)
|
||||
|
||||
template stripLeadingZeros(value: string): string =
|
||||
var cidx = 0
|
||||
# ignore the last character so we retain '0' on zero value
|
||||
while cidx < value.len - 1 and value[cidx] == '0':
|
||||
cidx.inc
|
||||
value[cidx .. ^1]
|
||||
proc defaultTraceStream(conf: T8NConf, txIndex: int, txHash: Hash256): Stream =
|
||||
let
|
||||
txHash = "0x" & toLowerAscii($txHash)
|
||||
baseDir = if conf.outputBaseDir.len > 0:
|
||||
conf.outputBaseDir
|
||||
else:
|
||||
"."
|
||||
fName = "$1/trace-$2-$3.jsonl" % [baseDir, $txIndex, txHash]
|
||||
newFileStream(fName, fmWrite)
|
||||
|
||||
proc encodeHexInt(x: SomeInteger): JsonNode =
|
||||
%("0x" & x.toHex.stripLeadingZeros.toLowerAscii)
|
||||
|
||||
proc toHex(x: Hash256): string =
|
||||
"0x" & x.data.toHex
|
||||
proc traceToFileStream(path: string, txIndex: int): Stream =
|
||||
# replace whatever `.ext` to `-${txIndex}.jsonl`
|
||||
let
|
||||
file = path.splitFile
|
||||
fName = "$1/$2-$3.jsonl" % [file.dir, file.name, $txIndex]
|
||||
newFileStream(fName, fmWrite)
|
||||
|
||||
proc setupTrace(conf: T8NConf, txIndex: int, txHash: Hash256, vmState: BaseVMstate) =
|
||||
var tracerFlags = {
|
||||
@ -169,22 +173,20 @@ proc setupTrace(conf: T8NConf, txIndex: int, txHash: Hash256, vmState: BaseVMsta
|
||||
TracerFlags.DisableReturnData
|
||||
}
|
||||
|
||||
if conf.traceEnabled:
|
||||
if conf.traceMemory: tracerFlags.excl TracerFlags.DisableMemory
|
||||
if conf.traceNostack: tracerFlags.incl TracerFlags.DisableStack
|
||||
if conf.traceReturnData: tracerFlags.excl TracerFlags.DisableReturnData
|
||||
if conf.traceMemory: tracerFlags.excl TracerFlags.DisableMemory
|
||||
if conf.traceNostack: tracerFlags.incl TracerFlags.DisableStack
|
||||
if conf.traceReturnData: tracerFlags.excl TracerFlags.DisableReturnData
|
||||
|
||||
let
|
||||
txHash = "0x" & toLowerAscii($txHash)
|
||||
baseDir = if conf.outputBaseDir.len > 0:
|
||||
conf.outputBaseDir
|
||||
else:
|
||||
"."
|
||||
fName = "$1/trace-$2-$3.jsonl" % [baseDir, $txIndex, txHash]
|
||||
stream = newFileStream(fName, fmWrite)
|
||||
tracerInst = newJsonTracer(stream, tracerFlags, false)
|
||||
|
||||
vmState.tracer = tracerInst
|
||||
let traceMode = conf.traceEnabled.get
|
||||
let stream = if traceMode == "stdout":
|
||||
newFileStream(stdout)
|
||||
elif traceMode == "stderr":
|
||||
newFileStream(stderr)
|
||||
elif traceMode.len > 0:
|
||||
traceToFileStream(traceMode, txIndex)
|
||||
else:
|
||||
defaultTraceStream(conf, txIndex, txHash)
|
||||
vmState.tracer = newJsonTracer(stream, tracerFlags, false)
|
||||
|
||||
proc closeTrace(vmState: BaseVMstate) =
|
||||
let tracer = JsonTracer(vmState.tracer)
|
||||
@ -233,12 +235,12 @@ proc exec(ctx: var TransContext,
|
||||
)
|
||||
continue
|
||||
|
||||
if conf.traceEnabled:
|
||||
if conf.traceEnabled.isSome:
|
||||
setupTrace(conf, txIndex, rlpHash(tx), vmState)
|
||||
|
||||
let rc = vmState.processTransaction(tx, sender, header)
|
||||
|
||||
if conf.traceEnabled:
|
||||
if conf.traceEnabled.isSome:
|
||||
closeTrace(vmState)
|
||||
|
||||
if rc.isErr:
|
||||
|
Loading…
x
Reference in New Issue
Block a user