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:
Jamie Lokier 2021-05-21 06:24:09 +01:00
parent 168e69080b
commit 43b66a3a05
No known key found for this signature in database
GPG Key ID: CBC25C68435C30A2
2 changed files with 65 additions and 1 deletions

View File

@ -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

View File

@ -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