EVMC: `{.show.}` pragma to show EVMC host call arguments and results
New pragma `{.show.}` on a proc definition turns on tracing for that proc. Every call to it shows the name, arguments and results, if `show_tx_calls` is manually set to true. This is to trace calls from EVM to host. This started as a template which took a block expression, but the closure it used led to illegal capture errors. It was easier to write a macro. Signed-off-by: Jamie Lokier <jamie@shareable.org>
This commit is contained in:
parent
168e69080b
commit
43b66a3a05
|
@ -9,7 +9,7 @@
|
|||
#{.push raises: [Defect].}
|
||||
|
||||
import
|
||||
sets, times, stint, chronicles, stew/byteutils,
|
||||
sets, times, stint, chronicles,
|
||||
eth/common/eth_types, ../db/accounts_cache, ../forks,
|
||||
".."/[vm_types, vm_state, vm_computation, vm_internals],
|
||||
./host_types
|
||||
|
|
|
@ -0,0 +1,64 @@
|
|||
# Nimbus - Services available to EVM code that is run for a transaction
|
||||
#
|
||||
# Copyright (c) 2021 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 macros, strformat, stew/byteutils, stint, ./host_types
|
||||
|
||||
const show_tx_calls = false
|
||||
|
||||
# Don't use both types in the overload, as Nim <= 1.2.x gives "ambiguous call".
|
||||
#func `$`(n: HostKey | HostValue): string = toHex(n)
|
||||
func `$`(n: HostKey): string = toHex(n)
|
||||
|
||||
func `$`(address: HostAddress): string = toHex(address)
|
||||
func `$`(txc: EvmcTxContext): string = &"gas_price={txc.tx_gas_price.fromEvmc}"
|
||||
func `$`(n: typeof(EvmcMessage().sender)): string = $n.fromEvmc
|
||||
func `$`(n: typeof(EvmcMessage().value)): string = $n.fromEvmc
|
||||
|
||||
macro show*(fn: untyped): auto =
|
||||
if not show_tx_calls:
|
||||
return fn
|
||||
var args: seq[NimNode] = newSeq[NimNode]()
|
||||
var types: seq[NimNode] = newSeq[NimNode]()
|
||||
for i in 1 ..< fn.params.len:
|
||||
let idents = fn.params[i]
|
||||
for j in 0 ..< idents.len-2:
|
||||
args.add idents[j]
|
||||
types.add idents[^2]
|
||||
|
||||
let procName = $fn.name
|
||||
let msgVar = genSym(nskLet, "msg")
|
||||
var msgExpr = quote do:
|
||||
"tx." & `procName`
|
||||
var skip = 0
|
||||
for i in 1 ..< args.len:
|
||||
if i == skip:
|
||||
continue
|
||||
var arg = args[i]
|
||||
let argNameString = " " & $arg & "="
|
||||
if (types[i].repr == "ptr byte" or types[i].repr == "ptr HostTopic") and
|
||||
(i < args.len-1 and types[i+1].repr == "HostSize"):
|
||||
skip = i+1
|
||||
arg = newPar(args[i], args[i+1])
|
||||
msgExpr = quote do:
|
||||
`msgExpr` & `argNameString` & $(`arg`)
|
||||
let call = newCall(fn.name, args)
|
||||
|
||||
let wrapFn = newProc(name = fn.name)
|
||||
wrapFn.params = fn.params.copy
|
||||
wrapFn.body.add fn
|
||||
if fn.params[0].kind == nnkEmpty:
|
||||
wrapFn.body.add quote do:
|
||||
echo `msgExpr`
|
||||
`call`
|
||||
else:
|
||||
wrapFn.body.add quote do:
|
||||
let `msgVar` = `msgExpr`
|
||||
let res = `call`
|
||||
echo `msgVar` & " -> result=" & $res
|
||||
res
|
||||
return wrapFn
|
Loading…
Reference in New Issue