nimbus-eth1/nimbus/evm/interpreter/op_dispatcher.nim

173 lines
5.6 KiB
Nim
Raw Normal View History

# 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.
const
# debugging flag, dump macro info when asked for
noisy {.intdefine.}: int = 0
# isNoisy {.used.} = noisy > 0
isChatty {.used.} = noisy > 1
import
../code_stream,
../computation,
2022-12-02 04:35:41 +00:00
../../common/evmforks,
./gas_costs,
./gas_meter,
./op_codes,
./op_handlers,
./op_handlers/oph_defs,
chronicles,
macros
export
2022-12-02 04:35:41 +00:00
EVMFork, Op,
oph_defs,
gas_meter
# ------------------------------------------------------------------------------
# Helpers
# ------------------------------------------------------------------------------
template handleStopDirective(k: var Vm2Ctx) =
Tracing: Remove some trace messages that occur a lot during sync Disable some trace messages which appeared a lot in the output and probably aren't so useful any more, when block processing is functioning well at high speed. Turning on the trace level globally is useful to get a feel for what's happening, but only if each category is kept to a reasonable amount. As well as overwhelming the output so that it's hard to see general activity, some of these messages happen so much they severely slow down processing. Ones called every time an EVM opcode uses some gas are particularly extreme. These messages have all been chosen as things which are probably not useful any more (the relevant functionality has been debugged and is tested plenty). These have been commented out rather than removed. It may be that turning trace topics on/off, or other selection, is a better longer term solution, but that will require better command line options and good defaults for sure. (I think higher levels `tracev` and `tracevv` levels (extra verbose) would be more useful for this sort of deep tracing on request.) For now, enabling `--log-level:TRACE` on the command line is quite useful as long as we keep each category reasonable, and this patch tries to keep that balance. - Don't show "has transactions" on virtually every block imported. - Don't show "Sender" and "txHash" lines on every transaction processed. - Don't show "GAS CONSUMPTION" on every opcode executed", this is way too much. - Don't show "GAS RETURNED" and "GAS REFUND" on each contract call. - Don't show "op: Stop" on every Stop opcode, which means every transaction. - Don't show "Insufficient funds" whenever a contract can't call another. - Don't show "ECRecover", "SHA256 precompile", "RIPEMD160", "Identity" or even "Call precompile" every time a precompile is called. These are very well tested now. - Don't show "executeOpcodes error" whenever a contract returns an error. (This is changed to `trace` too, it's a normal event that is well tested.) Signed-off-by: Jamie Lokier <jamie@shareable.org>
2021-07-22 13:35:41 +00:00
#trace "op: Stop"
if not k.cpt.code.atEnd() and k.cpt.tracingEnabled:
# we only trace `REAL STOP` and ignore `FAKE STOP`
k.cpt.opIndex = k.cpt.traceOpCodeStarted(Op.Stop)
k.cpt.traceOpCodeEnded(Op.Stop, k.cpt.opIndex)
2022-12-02 04:35:41 +00:00
template handleFixedGasCostsDirective(fork: EVMFork; op: Op; k: var Vm2Ctx) =
if k.cpt.tracingEnabled:
k.cpt.opIndex = k.cpt.traceOpCodeStarted(op)
k.cpt.gasMeter.consumeGas(k.cpt.gasCosts[op].cost, reason = $op)
vmOpHandlers[fork][op].run(k)
# If continuation is not nil, traceOpCodeEnded will be called in executeOpcodes.
if k.cpt.tracingEnabled and k.cpt.continuation.isNil:
k.cpt.traceOpCodeEnded(op, k.cpt.opIndex)
2022-12-02 04:35:41 +00:00
template handleOtherDirective(fork: EVMFork; op: Op; k: var Vm2Ctx) =
if k.cpt.tracingEnabled:
k.cpt.opIndex = k.cpt.traceOpCodeStarted(op)
vmOpHandlers[fork][op].run(k)
# If continuation is not nil, traceOpCodeEnded will be called in executeOpcodes.
if k.cpt.tracingEnabled and k.cpt.continuation.isNil:
k.cpt.traceOpCodeEnded(op, k.cpt.opIndex)
# ------------------------------------------------------------------------------
# Private, big nasty doubly nested case matrix generator
# ------------------------------------------------------------------------------
# reminiscent of Mamy's opTableToCaseStmt() from original VM
proc toCaseStmt(forkArg, opArg, k: NimNode): NimNode =
# Outer case/switch => Op
let branchOnOp = quote do: `opArg`
result = nnkCaseStmt.newTree(branchOnOp)
for op in Op:
let asOp = quote do: Op(`op`)
# Inner case/switch => Fork
let branchOnFork = quote do: `forkArg`
var forkCaseSubExpr = nnkCaseStmt.newTree(branchOnFork)
2022-12-02 04:35:41 +00:00
for fork in EVMFork:
let asFork = quote do: EVMFork(`fork`)
let branchStmt = block:
if op == Op.Stop:
quote do:
handleStopDirective(`k`)
elif BaseGasCosts[op].kind == GckFixed:
quote do:
handleFixedGasCostsDirective(`asFork`,`asOp`,`k`)
else:
quote do:
handleOtherDirective(`asFork`,`asOp`,`k`)
forkCaseSubExpr.add nnkOfBranch.newTree(asFork, branchStmt)
# Wrap innner case/switch into outer case/switch
let branchStmt = block:
case op
of Op.Stop, Return, Revert, SelfDestruct:
quote do:
`forkCaseSubExpr`
break
else:
# FIXME-manyOpcodesNowRequireContinuations
# We used to have another clause in this case statement for various
# opcodes that *don't* need to check for a continuation. But now
# there are many opcodes that need to, because they call asyncChainTo
# (and so they set a pendingAsyncOperation and a continuation that
# needs to be noticed by the interpreter_dispatch loop). And that
# will become even more true once we implement speculative execution,
# because that will mean that even reading from the stack might
# require waiting.
#
# Anyway, the point is that now we might as well just do this check
# for *every* opcode (other than Return/Revert/etc, which need to
# break no matter what).
quote do:
`forkCaseSubExpr`
if not `k`.cpt.continuation.isNil:
break
result.add nnkOfBranch.newTree(asOp, branchStmt)
when isChatty:
echo ">>> ", result.repr
# ------------------------------------------------------------------------------
# Public macros/functions
# ------------------------------------------------------------------------------
2022-12-02 04:35:41 +00:00
macro genOptimisedDispatcher*(fork: EVMFork; op: Op; k: Vm2Ctx): untyped =
result = fork.toCaseStmt(op, k)
2022-12-02 04:35:41 +00:00
template genLowMemDispatcher*(fork: EVMFork; op: Op; k: Vm2Ctx) =
if op == Op.Stop:
handleStopDirective(k)
break
if BaseGasCosts[op].kind == GckFixed:
handleFixedGasCostsDirective(fork, op, k)
else:
handleOtherDirective(fork, op, k)
case c.instr
of Return, Revert, SelfDestruct:
break
else:
# FIXME-manyOpcodesNowRequireContinuations
if not k.cpt.continuation.isNil:
break
# ------------------------------------------------------------------------------
# Debugging ...
# ------------------------------------------------------------------------------
when isMainModule and isChatty:
import ../types
2022-12-02 04:35:41 +00:00
proc optimised(c: Computation, fork: EVMFork) {.compileTime.} =
var desc: Vm2Ctx
while true:
genOptimisedDispatcher(fork, desc.cpt.instr, desc)
# ------------------------------------------------------------------------------
# End
# ------------------------------------------------------------------------------