2018-01-23 18:36:23 +00:00
|
|
|
import
|
|
|
|
strformat, strutils, sequtils, macros,
|
|
|
|
constants, logging, errors, opcode_values, computation, vm/stack, bigints
|
|
|
|
|
2018-01-24 13:31:24 +00:00
|
|
|
template run*(opcode: Opcode, computation: var BaseComputation) =
|
|
|
|
# Hook for performing the actual VM execution
|
2018-01-29 13:56:51 +00:00
|
|
|
computation.gasMeter.consumeGas(opcode.gasCost(computation), reason = $opcode.kind)
|
2018-01-24 13:31:24 +00:00
|
|
|
opcode.runLogic(computation)
|
2018-01-23 18:36:23 +00:00
|
|
|
|
2018-01-24 13:31:24 +00:00
|
|
|
method logger*(opcode: Opcode): Logger =
|
|
|
|
logging.getLogger(&"vm.opcode.{opcode.kind}")
|
2018-01-23 18:36:23 +00:00
|
|
|
|
2018-01-29 13:56:51 +00:00
|
|
|
method gasCost*(opcode: Opcode, computation: var BaseComputation): Int256 =
|
|
|
|
if opcode.kind in VARIABLE_GAS_COST_OPS:
|
|
|
|
opcode.gasCostHandler(computation)
|
|
|
|
else:
|
|
|
|
opcode.gasCostConstant
|
2018-01-23 18:36:23 +00:00
|
|
|
|
2018-01-29 13:56:51 +00:00
|
|
|
template newOpcode*(kind: Op, gasCost: Int256, logic: proc(computation: var BaseComputation)): Opcode =
|
|
|
|
Opcode(kind: kind, gasCostConstant: gasCost, runLogic: logic)
|
|
|
|
|
|
|
|
template newOpcode*(kind: Op, gasHandler: proc(computation: var BaseComputation): Int256, logic: proc(computation: var BaseComputation)): Opcode =
|
|
|
|
Opcode(kind: kind, gasCostHandler: gasHandler, runLogic: logic)
|
2018-01-23 18:36:23 +00:00
|
|
|
|
2018-01-24 13:31:24 +00:00
|
|
|
method `$`*(opcode: Opcode): string =
|
2018-01-29 13:56:51 +00:00
|
|
|
let gasCost = if opcode.kind in VARIABLE_GAS_COST_OPS:
|
|
|
|
"variable"
|
|
|
|
else:
|
|
|
|
$opcode.gasCostConstant
|
|
|
|
&"{opcode.kind}(0x{opcode.kind.int.toHex(2)}: {gasCost})"
|
2018-01-24 13:31:24 +00:00
|
|
|
|
|
|
|
macro initOpcodes*(spec: untyped): untyped =
|
|
|
|
var value = ident("value")
|
2018-01-23 18:36:23 +00:00
|
|
|
result = quote:
|
2018-01-24 13:31:24 +00:00
|
|
|
block:
|
|
|
|
var `value` = initTable[Op, Opcode]()
|
|
|
|
|
|
|
|
for child in spec:
|
|
|
|
let op = child[0]
|
|
|
|
let gasCost = child[1][0][0]
|
|
|
|
let handler = child[1][0][1]
|
2018-01-29 13:56:51 +00:00
|
|
|
let opcode = if gasCost.repr[0].isLowerAscii():
|
|
|
|
quote:
|
|
|
|
`value`[`op`] = Opcode(kind: `op`, gasCostHandler: `gasCost`, runLogic: `handler`)
|
|
|
|
else:
|
|
|
|
quote:
|
|
|
|
`value`[`op`] = Opcode(kind: `op`, gasCostConstant: `gasCost`, runLogic: `handler`)
|
2018-01-24 13:31:24 +00:00
|
|
|
result[1].add(opcode)
|
2018-01-23 18:36:23 +00:00
|
|
|
|
2018-01-24 13:31:24 +00:00
|
|
|
result[1].add(value)
|
|
|
|
|