experimental op handlers table (tbc.)
details: the op handler table is accessible via op_handlers.nim module op handler function implementations are found in the op_handlers/ sub-directory kludge: for development and pre-testing, any new module can be individually compiled setting the kludge flag using -d:kludge:1. this causes some proc/func replacements in turn allowing for omitting imports that would otherwise cause a circular dependency. otherwise individual compilation would fail. in order to prove the overall correctness of the code, the op_handlers.nim is imported by opcodes_impl.nim when compiling all, nimbus or test.
This commit is contained in:
parent
f37591ca35
commit
5e7d4ac9c5
|
@ -0,0 +1,92 @@
|
|||
# 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.
|
||||
|
||||
## EVM Opcode Handler Tables
|
||||
## =========================
|
||||
##
|
||||
|
||||
const
|
||||
noisy {.intdefine.}: int = 0
|
||||
isNoisy {.used.} = noisy > 0
|
||||
|
||||
import
|
||||
./op_codes,
|
||||
./op_handlers/[oph_defs,
|
||||
oph_arithmetic, oph_hash,
|
||||
oph_sysops]
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# Helper
|
||||
# ------------------------------------------------------------------------------
|
||||
|
||||
const
|
||||
allForksTable = block:
|
||||
var rc: array[Op, Vm2OpExec]
|
||||
|
||||
for w in vm2OpExecArithmetic:
|
||||
rc[w.opCode] = w
|
||||
|
||||
for w in vm2OpExecHash:
|
||||
rc[w.opCode] = w
|
||||
|
||||
for w in vm2OpExecSysOP:
|
||||
rc[w.opCode] = w
|
||||
|
||||
rc
|
||||
|
||||
proc mkOpTable(select: Fork): array[Op, Vm2OpExec] {.compileTime.} =
|
||||
for op in Op:
|
||||
var w = allForksTable[op]
|
||||
if FkFrontier in w.forks:
|
||||
result[op] = w
|
||||
else:
|
||||
result[op] = allForksTable[Invalid]
|
||||
result[op].opCode = op
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# Public handler tables
|
||||
# ------------------------------------------------------------------------------
|
||||
|
||||
const
|
||||
vm2OpHandlers* = block:
|
||||
var rc: array[Fork, array[Op, Vm2OpExec]]
|
||||
for w in Fork:
|
||||
rc[w] = w.mkOpTable
|
||||
rc
|
||||
|
||||
vm2OpTabFrontier* = vm2OpHandlers[FkFrontier]
|
||||
vm2OpTabHomestead* = vm2OpHandlers[FkHomestead]
|
||||
vm2OpTabTangerine* = vm2OpHandlers[FkTangerine]
|
||||
vm2OpTabSpurious* = vm2OpHandlers[FkSpurious]
|
||||
vm2OpTabByzantium* = vm2OpHandlers[FkByzantium]
|
||||
vm2OpTabConstantinople* = vm2OpHandlers[FkConstantinople]
|
||||
vm2OpTabPetersburg* = vm2OpHandlers[FkPetersburg]
|
||||
vm2OpTabIstanbul* = vm2OpHandlers[FkIstanbul]
|
||||
vm2OpTabBerlin* = vm2OpHandlers[FkBerlin]
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# Debugging ...
|
||||
# ------------------------------------------------------------------------------
|
||||
|
||||
when isMainModule and isNoisy:
|
||||
var dummy = 0
|
||||
proc gdbBPSink() =
|
||||
dummy.inc
|
||||
|
||||
const
|
||||
a = vm2OpTabFrontier
|
||||
b = a[Stop].info
|
||||
|
||||
gdbBPSink()
|
||||
echo ">>> ", b
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# End
|
||||
# ------------------------------------------------------------------------------
|
|
@ -0,0 +1,467 @@
|
|||
# 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.
|
||||
|
||||
## EVM Opcode Handlers: Arithmetic and Logic Operators
|
||||
## ===================================================
|
||||
##
|
||||
|
||||
const
|
||||
kludge {.intdefine.}: int = 0
|
||||
breakCircularDependency {.used.} = kludge > 0
|
||||
|
||||
import
|
||||
./oph_defs,
|
||||
stint
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# Kludge BEGIN
|
||||
# ------------------------------------------------------------------------------
|
||||
|
||||
when not breakCircularDependency:
|
||||
import
|
||||
../../../constants,
|
||||
../../stack,
|
||||
../../v2computation,
|
||||
../../v2types,
|
||||
../gas_meter,
|
||||
../utils/v2utils_numeric,
|
||||
../v2gas_costs,
|
||||
chronicles,
|
||||
eth/common,
|
||||
options,
|
||||
sets
|
||||
|
||||
else:
|
||||
import macros
|
||||
|
||||
# copied from stack.nim
|
||||
macro genTupleType(len: static[int], elemType: untyped): untyped =
|
||||
result = nnkTupleConstr.newNimNode()
|
||||
for i in 0 ..< len: result.add(elemType)
|
||||
|
||||
# function stubs from stack.nim (to satisfy compiler logic)
|
||||
proc push[T](x: Stack; n: T) = discard
|
||||
proc popInt(x: var Stack): UInt256 = discard
|
||||
proc popInt(x: var Stack, n: static[int]): auto =
|
||||
var rc: genTupleType(n, UInt256)
|
||||
return rc
|
||||
|
||||
# function stubs from v2utils_numeric.nim
|
||||
proc extractSign(v: var UInt256, sign: var bool) = discard
|
||||
proc setSign(v: var UInt256, sign: bool) = discard
|
||||
func safeInt(x: Uint256): int = discard
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# Kludge END
|
||||
# ------------------------------------------------------------------------------
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# Private, op handlers implementation
|
||||
# ------------------------------------------------------------------------------
|
||||
|
||||
const
|
||||
addOp: Vm2OpFn = proc (k: Vm2Ctx) =
|
||||
let (lhs, rhs) = k.cpt.stack.popInt(2)
|
||||
k.cpt.stack.push:
|
||||
lhs + rhs
|
||||
|
||||
mulOp: Vm2OpFn = proc(k: Vm2Ctx) =
|
||||
let (lhs, rhs) = k.cpt.stack.popInt(2)
|
||||
k.cpt.stack.push:
|
||||
lhs * rhs
|
||||
|
||||
subOp: Vm2OpFn = proc(k: Vm2Ctx) =
|
||||
let (lhs, rhs) = k.cpt.stack.popInt(2)
|
||||
k.cpt.stack.push:
|
||||
lhs - rhs
|
||||
|
||||
divideOp: Vm2OpFn = proc(k: Vm2Ctx) =
|
||||
let (lhs, rhs) = k.cpt.stack.popInt(2)
|
||||
k.cpt.stack.push:
|
||||
if rhs == 0:
|
||||
zero(Uint256)
|
||||
else:
|
||||
lhs div rhs
|
||||
|
||||
sdivOp: Vm2OpFn = proc(k: Vm2Ctx) =
|
||||
let (lhs, rhs) = k.cpt.stack.popInt(2)
|
||||
var r: UInt256
|
||||
if rhs != 0:
|
||||
var a = lhs
|
||||
var b = rhs
|
||||
var signA, signB: bool
|
||||
extractSign(a, signA)
|
||||
extractSign(b, signB)
|
||||
r = a div b
|
||||
setSign(r, signA xor signB)
|
||||
k.cpt.stack.push(r)
|
||||
|
||||
moduloOp: Vm2OpFn = proc(k: Vm2Ctx) =
|
||||
let (lhs, rhs) = k.cpt.stack.popInt(2)
|
||||
k.cpt.stack.push:
|
||||
if rhs == 0:
|
||||
zero(Uint256)
|
||||
else:
|
||||
lhs mod rhs
|
||||
|
||||
smodOp: Vm2OpFn = proc(k: Vm2Ctx) =
|
||||
let (lhs, rhs) = k.cpt.stack.popInt(2)
|
||||
var r: UInt256
|
||||
if rhs != 0:
|
||||
var sign: bool
|
||||
var v = lhs
|
||||
var m = rhs
|
||||
extractSign(m, sign)
|
||||
extractSign(v, sign)
|
||||
r = v mod m
|
||||
setSign(r, sign)
|
||||
k.cpt.stack.push(r)
|
||||
|
||||
addmodOp: Vm2OpFn = proc(k: Vm2Ctx) =
|
||||
let (lhs, rhs, modulus) = k.cpt.stack.popInt(3)
|
||||
k.cpt.stack.push:
|
||||
if modulus == 0:
|
||||
zero(UInt256)
|
||||
else:
|
||||
addmod(lhs, rhs, modulus)
|
||||
|
||||
mulmodOp: Vm2OpFn = proc(k: Vm2Ctx) =
|
||||
let (lhs, rhs, modulus) = k.cpt.stack.popInt(3)
|
||||
k.cpt.stack.push:
|
||||
if modulus == 0:
|
||||
zero(UInt256)
|
||||
else:
|
||||
mulmod(lhs, rhs, modulus)
|
||||
|
||||
expOp: Vm2OpFn = proc(k: Vm2Ctx) =
|
||||
let (base, exponent) = k.cpt.stack.popInt(2)
|
||||
when not breakCircularDependency:
|
||||
k.cpt.gasMeter.consumeGas(
|
||||
k.cpt.gasCosts[Exp].d_handler(exponent),
|
||||
reason = "EXP: exponent bytes")
|
||||
k.cpt.stack.push:
|
||||
if not base.isZero:
|
||||
base.pow(exponent)
|
||||
elif exponent.isZero:
|
||||
# https://github.com/ethereum/yellowpaper/issues/257
|
||||
# https://github.com/ethereum/tests/pull/460
|
||||
# https://github.com/ewasm/evm2wasm/issues/137
|
||||
1.u256
|
||||
else:
|
||||
zero(UInt256)
|
||||
|
||||
signExtendOp: Vm2OpFn = proc(k: Vm2Ctx) =
|
||||
let (bits, value) = k.cpt.stack.popInt(2)
|
||||
var res: UInt256
|
||||
if bits <= 31.u256:
|
||||
let
|
||||
one = 1.u256
|
||||
testBit = bits.truncate(int) * 8 + 7
|
||||
bitPos = one shl testBit
|
||||
mask = bitPos - one
|
||||
if not isZero(value and bitPos):
|
||||
res = value or (not mask)
|
||||
else:
|
||||
res = value and mask
|
||||
else:
|
||||
res = value
|
||||
k.cpt.stack.push:
|
||||
res
|
||||
|
||||
ltOp: Vm2OpFn = proc(k: Vm2Ctx) =
|
||||
let (lhs, rhs) = k.cpt.stack.popInt(2)
|
||||
k.cpt.stack.push:
|
||||
(lhs < rhs).uint.u256
|
||||
|
||||
gtOp: Vm2OpFn = proc(k: Vm2Ctx) =
|
||||
let (lhs, rhs) = k.cpt.stack.popInt(2)
|
||||
k.cpt.stack.push:
|
||||
(lhs > rhs).uint.u256
|
||||
|
||||
sltOp: Vm2OpFn = proc(k: Vm2Ctx) =
|
||||
let (lhs, rhs) = k.cpt.stack.popInt(2)
|
||||
k.cpt.stack.push:
|
||||
(cast[Int256](lhs) < cast[Int256](rhs)).uint.u256
|
||||
|
||||
sgtOp: Vm2OpFn = proc(k: Vm2Ctx) =
|
||||
let (lhs, rhs) = k.cpt.stack.popInt(2)
|
||||
k.cpt.stack.push:
|
||||
(cast[Int256](lhs) > cast[Int256](rhs)).uint.u256
|
||||
|
||||
eqOp: Vm2OpFn = proc(k: Vm2Ctx) =
|
||||
let (lhs, rhs) = k.cpt.stack.popInt(2)
|
||||
k.cpt.stack.push:
|
||||
(lhs == rhs).uint.u256
|
||||
|
||||
isZeroOp: Vm2OpFn = proc(k: Vm2Ctx) =
|
||||
let (value) = k.cpt.stack.popInt(1)
|
||||
k.cpt.stack.push:
|
||||
value.isZero.uint.u256
|
||||
|
||||
andOp: Vm2OpFn = proc(k: Vm2Ctx) =
|
||||
let (lhs, rhs) = k.cpt.stack.popInt(2)
|
||||
k.cpt.stack.push:
|
||||
lhs and rhs
|
||||
|
||||
orOp: Vm2OpFn = proc(k: Vm2Ctx) =
|
||||
let (lhs, rhs) = k.cpt.stack.popInt(2)
|
||||
k.cpt.stack.push:
|
||||
lhs or rhs
|
||||
|
||||
xorOp: Vm2OpFn = proc(k: Vm2Ctx) =
|
||||
let (lhs, rhs) = k.cpt.stack.popInt(2)
|
||||
k.cpt.stack.push:
|
||||
lhs xor rhs
|
||||
|
||||
notOp: Vm2OpFn = proc(k: Vm2Ctx) =
|
||||
let (value) = k.cpt.stack.popInt(1)
|
||||
k.cpt.stack.push:
|
||||
value.not
|
||||
|
||||
byteOp: Vm2OpFn = proc(k: Vm2Ctx) =
|
||||
let (position, value) = k.cpt.stack.popInt(2)
|
||||
let pos = position.truncate(int)
|
||||
k.cpt.stack.push:
|
||||
if pos >= 32 or pos < 0:
|
||||
zero(Uint256)
|
||||
else:
|
||||
when system.cpuEndian == bigEndian:
|
||||
cast[array[32, byte]](value)[pos].u256
|
||||
else:
|
||||
cast[array[32, byte]](value)[31 - pos].u256
|
||||
|
||||
# Constantinople's new opcodes
|
||||
|
||||
shlOp: Vm2OpFn = proc(k: Vm2Ctx) =
|
||||
let (shift, num) = k.cpt.stack.popInt(2)
|
||||
let shiftLen = shift.safeInt
|
||||
if shiftLen >= 256:
|
||||
k.cpt.stack.push:
|
||||
0
|
||||
else:
|
||||
k.cpt.stack.push:
|
||||
num shl shiftLen
|
||||
|
||||
shrOp: Vm2OpFn = proc(k: Vm2Ctx) =
|
||||
let (shift, num) = k.cpt.stack.popInt(2)
|
||||
let shiftLen = shift.safeInt
|
||||
if shiftLen >= 256:
|
||||
k.cpt.stack.push:
|
||||
0
|
||||
else:
|
||||
# uint version of `shr`
|
||||
k.cpt.stack.push:
|
||||
num shr shiftLen
|
||||
|
||||
sarOp: Vm2OpFn = proc(k: Vm2Ctx) =
|
||||
let shiftLen = k.cpt.stack.popInt().safeInt
|
||||
let num = cast[Int256](k.cpt.stack.popInt())
|
||||
if shiftLen >= 256:
|
||||
if num.isNegative:
|
||||
k.cpt.stack.push:
|
||||
cast[Uint256]((-1).i256)
|
||||
else:
|
||||
k.cpt.stack. push:
|
||||
0
|
||||
else:
|
||||
# int version of `shr` then force the result
|
||||
# into uint256
|
||||
k.cpt.stack.push:
|
||||
cast[Uint256](num shr shiftLen)
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# Public, op exec table entries
|
||||
# ------------------------------------------------------------------------------
|
||||
|
||||
const
|
||||
vm2OpExecArithmetic*: seq[Vm2OpExec] = @[
|
||||
|
||||
(opCode: Add, ## 0x01, Addition
|
||||
forks: Vm2OpAllForks,
|
||||
info: "Addition operation",
|
||||
exec: (prep: vm2OpIgnore,
|
||||
run: addOp,
|
||||
post: vm2OpIgnore)),
|
||||
|
||||
(opCode: Mul, ## 0x02, Multiplication
|
||||
forks: Vm2OpAllForks,
|
||||
info: "Multiplication operation",
|
||||
exec: (prep: vm2OpIgnore,
|
||||
run: mulOp,
|
||||
post: vm2OpIgnore)),
|
||||
|
||||
(opCode: Sub, ## 0x03, Subtraction
|
||||
forks: Vm2OpAllForks,
|
||||
info: "Subtraction operation",
|
||||
exec: (prep: vm2OpIgnore,
|
||||
run: subOp,
|
||||
post: vm2OpIgnore)),
|
||||
|
||||
(opCode: Div, ## 0x04, Division
|
||||
forks: Vm2OpAllForks,
|
||||
info: "Integer division operation",
|
||||
exec: (prep: vm2OpIgnore,
|
||||
run: divideOp,
|
||||
post: vm2OpIgnore)),
|
||||
|
||||
(opCode: Sdiv, ## 0x05, Signed division
|
||||
forks: Vm2OpAllForks,
|
||||
info: "Signed integer division operation (truncated)",
|
||||
exec: (prep: vm2OpIgnore,
|
||||
run: sdivOp,
|
||||
post: vm2OpIgnore)),
|
||||
|
||||
(opCode: Mod, ## 0x06, Modulo
|
||||
forks: Vm2OpAllForks,
|
||||
info: "Modulo remainder operation",
|
||||
exec: (prep: vm2OpIgnore,
|
||||
run: moduloOp,
|
||||
post: vm2OpIgnore)),
|
||||
|
||||
(opCode: Smod, ## 0x07, Signed modulo
|
||||
forks: Vm2OpAllForks,
|
||||
info: "Signed modulo remainder operation",
|
||||
exec: (prep: vm2OpIgnore,
|
||||
run: smodOp,
|
||||
post: vm2OpIgnore)),
|
||||
|
||||
(opCode: AddMod, ## 0x08, Modulo addition, Intermediate
|
||||
## computations do not roll over at 2^256
|
||||
forks: Vm2OpAllForks,
|
||||
info: "Modulo addition operation",
|
||||
exec: (prep: vm2OpIgnore,
|
||||
run: addmodOp,
|
||||
post: vm2OpIgnore)),
|
||||
|
||||
(opCode: MulMod, ## 0x09, Modulo multiplication, Intermediate
|
||||
## computations do not roll over at 2^256
|
||||
forks: Vm2OpAllForks,
|
||||
info: "Modulo multiplication operation",
|
||||
exec: (prep: vm2OpIgnore,
|
||||
run: mulmodOp,
|
||||
post: vm2OpIgnore)),
|
||||
|
||||
(opCode: Exp, ## 0x0a, Exponentiation
|
||||
forks: Vm2OpAllForks,
|
||||
info: "Exponentiation operation",
|
||||
exec: (prep: vm2OpIgnore,
|
||||
run: expOp,
|
||||
post: vm2OpIgnore)),
|
||||
|
||||
(opCode: SignExtend, ## 0x0b, Extend 2's complemet length
|
||||
forks: Vm2OpAllForks,
|
||||
info: "Extend length of two’s complement signed integer",
|
||||
exec: (prep: vm2OpIgnore,
|
||||
run: signExtendOp,
|
||||
post: vm2OpIgnore)),
|
||||
|
||||
(opCode: Lt, ## 0x10, Less-than
|
||||
forks: Vm2OpAllForks,
|
||||
info: "Less-than comparison",
|
||||
exec: (prep: vm2OpIgnore,
|
||||
run: ltOp,
|
||||
post: vm2OpIgnore)),
|
||||
|
||||
(opCode: Gt, ## 0x11, Greater-than
|
||||
forks: Vm2OpAllForks,
|
||||
info: "Greater-than comparison",
|
||||
exec: (prep: vm2OpIgnore,
|
||||
run: gtOp,
|
||||
post: vm2OpIgnore)),
|
||||
|
||||
(opCode: Slt, ## 0x12, Signed less-than
|
||||
forks: Vm2OpAllForks,
|
||||
info: "Signed less-than comparison",
|
||||
exec: (prep: vm2OpIgnore,
|
||||
run: sltOp,
|
||||
post: vm2OpIgnore)),
|
||||
|
||||
(opCode: Sgt, ## 0x13, Signed greater-than
|
||||
forks: Vm2OpAllForks,
|
||||
info: "Signed greater-than comparison",
|
||||
exec: (prep: vm2OpIgnore,
|
||||
run: sgtOp,
|
||||
post: vm2OpIgnore)),
|
||||
|
||||
(opCode: Eq, ## 0x14, Equality
|
||||
forks: Vm2OpAllForks,
|
||||
info: "Equality comparison",
|
||||
exec: (prep: vm2OpIgnore,
|
||||
run: eqOp,
|
||||
post: vm2OpIgnore)),
|
||||
|
||||
(opCode: IsZero, ## 0x15, Not operator
|
||||
forks: Vm2OpAllForks,
|
||||
info: "Simple not operator (Note: real Yellow Paper description)",
|
||||
exec: (prep: vm2OpIgnore,
|
||||
run: isZeroOp,
|
||||
post: vm2OpIgnore)),
|
||||
|
||||
(opCode: And, ## 0x16, AND
|
||||
forks: Vm2OpAllForks,
|
||||
info: "Bitwise AND operation",
|
||||
exec: (prep: vm2OpIgnore,
|
||||
run: andOp,
|
||||
post: vm2OpIgnore)),
|
||||
|
||||
(opCode: Or, ## 0x17, OR
|
||||
forks: Vm2OpAllForks,
|
||||
info: "Bitwise OR operation",
|
||||
exec: (prep: vm2OpIgnore,
|
||||
run: orOp,
|
||||
post: vm2OpIgnore)),
|
||||
|
||||
(opCode: Xor, ## 0x18, XOR
|
||||
forks: Vm2OpAllForks,
|
||||
info: "Bitwise XOR operation",
|
||||
exec: (prep: vm2OpIgnore,
|
||||
run: xorOp,
|
||||
post: vm2OpIgnore)),
|
||||
|
||||
(opCode: Not, ## 0x19, NOT
|
||||
forks: Vm2OpAllForks,
|
||||
info: "Bitwise NOT operation",
|
||||
exec: (prep: vm2OpIgnore,
|
||||
run: notOp,
|
||||
post: vm2OpIgnore)),
|
||||
|
||||
(opCode: Byte, ## 0x1a, Retrieve byte
|
||||
forks: Vm2OpAllForks,
|
||||
info: "Retrieve single byte from word",
|
||||
exec: (prep: vm2OpIgnore,
|
||||
run: byteOp,
|
||||
post: vm2OpIgnore)),
|
||||
|
||||
# Constantinople's new opcodes
|
||||
|
||||
(opCode: Shl, ## 0x1b, Shift left
|
||||
forks: Vm2OpConstantinopleAndLater,
|
||||
info: "Shift left",
|
||||
exec: (prep: vm2OpIgnore,
|
||||
run: shlOp,
|
||||
post: vm2OpIgnore)),
|
||||
|
||||
(opCode: Shr, ## 0x1c, Shift right logical
|
||||
forks: Vm2OpConstantinopleAndLater,
|
||||
info: "Logical shift right",
|
||||
exec: (prep: vm2OpIgnore,
|
||||
run: shrOp,
|
||||
post: vm2OpIgnore)),
|
||||
|
||||
(opCode: Sar, ## 0x1d, Shift right arithmetic
|
||||
forks: Vm2OpConstantinopleAndLater,
|
||||
info: "Arithmetic shift right",
|
||||
exec: (prep: vm2OpIgnore,
|
||||
run: sarOp,
|
||||
post: vm2OpIgnore))]
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# End
|
||||
# ------------------------------------------------------------------------------
|
|
@ -0,0 +1,113 @@
|
|||
# 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.
|
||||
|
||||
## EVM Opcodes, Definitons
|
||||
## =======================
|
||||
##
|
||||
|
||||
const
|
||||
kludge {.intdefine.}: int = 0
|
||||
breakCircularDependency {.used.} = kludge > 0
|
||||
|
||||
import
|
||||
../forks_list,
|
||||
../op_codes,
|
||||
../../memory_defs,
|
||||
../../stack_defs
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# Kludge BEGIN
|
||||
# ------------------------------------------------------------------------------
|
||||
|
||||
when not breakCircularDependency:
|
||||
import
|
||||
../../v2types
|
||||
else:
|
||||
{.warning: "Circular dependency breaker kludge -- "&
|
||||
"no production code".}
|
||||
when defined(vm2_enabled):
|
||||
{.fatal: "Flag \"vm2_enabled\" must be unset "&
|
||||
"while circular dependency breaker kludge is activated".}
|
||||
type
|
||||
Computation* = ref object
|
||||
stack*: Stack
|
||||
memory*: Memory
|
||||
code: int
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# Kludge END
|
||||
# ------------------------------------------------------------------------------
|
||||
|
||||
export
|
||||
Op, Fork, Computation, Memory, Stack, UInt256
|
||||
|
||||
type
|
||||
Vm2Ctx* = object of RootObj
|
||||
cpt*: Computation ## computation text
|
||||
rc*: int ## return code from op handler
|
||||
|
||||
Vm2OpFn* = ## general op handler, return codes are passed
|
||||
## back via argument descriptor ``k``
|
||||
proc(k: Vm2Ctx) {.gcsafe.}
|
||||
|
||||
|
||||
Vm2OpHanders* = tuple ## three step op code execution, typically
|
||||
## only the ``run`` entry is activated
|
||||
prep: Vm2OpFn
|
||||
run: Vm2OpFn
|
||||
post: Vm2OpFn
|
||||
|
||||
|
||||
Vm2OpExec* = tuple ## op code handler entry
|
||||
opCode: Op ## index back-reference
|
||||
forks: set[Fork] ## forks applicable for this operation
|
||||
info: string ## pretty option name, info
|
||||
exec: Vm2OpHanders
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# Public
|
||||
# ------------------------------------------------------------------------------
|
||||
|
||||
const
|
||||
vm2OpIgnore*: Vm2OpFn = ## No operation, placeholder function
|
||||
proc(k: Vm2Ctx) {.gcsafe.} =
|
||||
discard
|
||||
|
||||
# similar to: toSeq(Fork).mapIt({it}).foldl(a+b)
|
||||
Vm2OpAllForks* =
|
||||
{Fork.low .. Fork.high}
|
||||
|
||||
Vm2OpHomesteadAndLater* = ## Set of all fork symbols
|
||||
Vm2OpAllForks - {FkFrontier}
|
||||
|
||||
Vm2OpTangerineAndLater* = ## Set of fork symbols starting from Homestead
|
||||
Vm2OpHomesteadAndLater - {FkHomestead}
|
||||
|
||||
Vm2OpSpuriousAndLater* = ## ditto ...
|
||||
Vm2OpTangerineAndLater - {FkTangerine}
|
||||
|
||||
Vm2OpByzantiumAndLater* =
|
||||
Vm2OpSpuriousAndLater - {FkSpurious}
|
||||
|
||||
Vm2OpConstantinopleAndLater* =
|
||||
Vm2OpByzantiumAndLater - {FkByzantium}
|
||||
|
||||
Vm2OpPetersburgAndLater* =
|
||||
Vm2OpConstantinopleAndLater - {FkConstantinople}
|
||||
|
||||
Vm2OpIstanbulAndLater* =
|
||||
Vm2OpPetersburgAndLater - {FkPetersburg}
|
||||
|
||||
Vm2OpBerlinAndLater* =
|
||||
Vm2OpIstanbulAndLater - {FkIstanbul}
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# End
|
||||
# ------------------------------------------------------------------------------
|
|
@ -0,0 +1,117 @@
|
|||
# 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.
|
||||
|
||||
## EVM Opcode Handlers: Hashes
|
||||
## ===========================
|
||||
##
|
||||
|
||||
const
|
||||
kludge {.intdefine.}: int = 0
|
||||
breakCircularDependency {.used.} = kludge > 0
|
||||
|
||||
import
|
||||
./oph_defs,
|
||||
../../../errors,
|
||||
stint
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# Kludge BEGIN
|
||||
# ------------------------------------------------------------------------------
|
||||
|
||||
when not breakCircularDependency:
|
||||
import
|
||||
../../../constants,
|
||||
../../stack,
|
||||
../../v2computation,
|
||||
../../v2memory,
|
||||
../../v2types,
|
||||
../gas_meter,
|
||||
../utils/v2utils_numeric,
|
||||
../v2gas_costs,
|
||||
chronicles,
|
||||
eth/common,
|
||||
nimcrypto,
|
||||
options,
|
||||
sets
|
||||
|
||||
else:
|
||||
import macros
|
||||
|
||||
# copied from stack.nim
|
||||
macro genTupleType(len: static[int], elemType: untyped): untyped =
|
||||
result = nnkTupleConstr.newNimNode()
|
||||
for i in 0 ..< len: result.add(elemType)
|
||||
|
||||
# function stubs from stack.nim (to satisfy compiler logic)
|
||||
proc push[T](x: Stack; n: T) = discard
|
||||
proc popInt(x: var Stack, n: static[int]): auto =
|
||||
var rc: genTupleType(n, UInt256)
|
||||
return rc
|
||||
|
||||
# function stubs from v2utils_numeric.nim
|
||||
func safeInt(x: Uint256): int = discard
|
||||
|
||||
# function stubs from v2memory.nim
|
||||
proc len(mem: Memory): int = 0
|
||||
proc extend(mem: var Memory; startPos: Natural; size: Natural) = discard
|
||||
|
||||
# dummy stubs from constants
|
||||
const EMPTY_SHA3 = 0xdeadbeef.u256
|
||||
|
||||
# function stubs from nimcrypto/hash.nim and nimcrypto/keccak.nim
|
||||
const keccak256 = 0xfeedbeef
|
||||
proc digest(dummy: int64, data: openarray[byte]): UInt256 = EMPTY_SHA3
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# Kludge END
|
||||
# ------------------------------------------------------------------------------
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# Private, op handlers implementation
|
||||
# ------------------------------------------------------------------------------
|
||||
|
||||
const
|
||||
sha3Op: Vm2OpFn = proc (k: Vm2Ctx) =
|
||||
let (startPos, length) = k.cpt.stack.popInt(2)
|
||||
|
||||
let (pos, len) = (startPos.safeInt, length.safeInt)
|
||||
if pos < 0 or len < 0 or pos > 2147483648'i64:
|
||||
raise newException(OutOfBoundsRead, "Out of bounds memory access")
|
||||
|
||||
when not breakCircularDependency:
|
||||
k.cpt.gasMeter.consumeGas(
|
||||
k.cpt.gasCosts[Op.Sha3].m_handler(k.cpt.memory.len, pos, len),
|
||||
reason = "SHA3: word gas cost")
|
||||
|
||||
k.cpt.memory.extend(pos, len)
|
||||
let endRange = min(pos + len, k.cpt.memory.len) - 1
|
||||
if endRange == -1 or pos >= k.cpt.memory.len:
|
||||
k.cpt.stack.push(EMPTY_SHA3)
|
||||
else:
|
||||
k.cpt.stack.push:
|
||||
keccak256.digest k.cpt.memory.bytes.toOpenArray(pos, endRange)
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# Public, op exec table entries
|
||||
# ------------------------------------------------------------------------------
|
||||
|
||||
const
|
||||
vm2OpExecHash*: seq[Vm2OpExec] = @[
|
||||
|
||||
(opCode: Add, ## 0x20, Keccak-256
|
||||
forks: Vm2OpAllForks,
|
||||
info: "Compute Keccak-256 hash",
|
||||
exec: (prep: vm2OpIgnore,
|
||||
run: sha3Op,
|
||||
post: vm2OpIgnore))]
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# End
|
||||
# ------------------------------------------------------------------------------
|
|
@ -0,0 +1,45 @@
|
|||
# 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.
|
||||
|
||||
## EVM Opcode Handlers: System Operations
|
||||
## ======================================
|
||||
##
|
||||
|
||||
import
|
||||
../op_codes, ./oph_defs, ../../../errors.nim
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# Private
|
||||
# ------------------------------------------------------------------------------
|
||||
|
||||
const
|
||||
invalidOp: Vm2OpFn =
|
||||
proc(k: Vm2Ctx) {.gcsafe.} =
|
||||
raise newException(InvalidInstruction,
|
||||
"Invalid instruction, received an opcode " &
|
||||
"not implemented in the current fork.")
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# Public, op exec table entries
|
||||
# ------------------------------------------------------------------------------
|
||||
|
||||
const
|
||||
vm2OpExecSysOP*: seq[Vm2OpExec] = @[
|
||||
|
||||
(opCode: Invalid, ## 0xfe, invalid instruction.
|
||||
forks: Vm2OpAllForks,
|
||||
info: "Designated invalid instruction",
|
||||
exec: (prep: vm2OpIgnore,
|
||||
run: invalidOp,
|
||||
post: vm2OpIgnore))]
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# End
|
||||
# ------------------------------------------------------------------------------
|
|
@ -7,13 +7,17 @@
|
|||
|
||||
import
|
||||
strformat, times, sets, sequtils, options,
|
||||
chronicles, stint, nimcrypto, stew/ranges/ptr_arith, eth/common,
|
||||
chronicles, stint, nimcrypto, eth/common,
|
||||
./utils/[macros_procs_opcodes, v2utils_numeric],
|
||||
./gas_meter, ./v2gas_costs, ./v2opcode_values, ./v2forks,
|
||||
../v2memory, ../stack, ../code_stream, ../v2computation, ../v2state, ../v2types,
|
||||
../../errors, ../../constants,
|
||||
../../db/[db_chain, accounts_cache]
|
||||
|
||||
# verify that experimental op table compiles
|
||||
import
|
||||
./op_handlers
|
||||
|
||||
logScope:
|
||||
topics = "opcode impl"
|
||||
|
||||
|
|
Loading…
Reference in New Issue