integrated current op handlers into opcodes_impl.nim (tbc.)

why:
  integration tests will verify op code handlers which wher rephrased
  from the very opcodes_impl module into the handler tables.
This commit is contained in:
Jordan Hrycaj 2021-04-13 17:23:39 +01:00 committed by zah
parent 5e7d4ac9c5
commit fda676062f
4 changed files with 67 additions and 204 deletions

View File

@ -17,6 +17,7 @@ const
isNoisy {.used.} = noisy > 0
import
strformat,
./op_codes,
./op_handlers/[oph_defs,
oph_arithmetic, oph_hash,
@ -30,13 +31,28 @@ const
allForksTable = block:
var rc: array[Op, Vm2OpExec]
proc complain(rec: Vm2OpExec; s: string): bool =
var
op = rec.opCode
oInfo = rc[op].info
nInfo = rec.info
if oInfo != "":
echo &"*** {s}: duplicate <{op}> entry: \"{oInfo}\" vs. \"{nInfo}\""
return true
for w in vm2OpExecArithmetic:
if w.complain("Arithmetic"):
doAssert rc[w.opCode].info == ""
rc[w.opCode] = w
for w in vm2OpExecHash:
if w.complain("Hash"):
doAssert rc[w.opCode].info == ""
rc[w.opCode] = w
for w in vm2OpExecSysOP:
if w.complain("SysOp"):
doAssert rc[w.opCode].info == ""
rc[w.opCode] = w
rc
@ -44,7 +60,7 @@ const
proc mkOpTable(select: Fork): array[Op, Vm2OpExec] {.compileTime.} =
for op in Op:
var w = allForksTable[op]
if FkFrontier in w.forks:
if select in w.forks:
result[op] = w
else:
result[op] = allForksTable[Invalid]
@ -81,8 +97,8 @@ when isMainModule and isNoisy:
dummy.inc
const
a = vm2OpTabFrontier
b = a[Stop].info
a = vm2OpTabBerlin
b = a[Shl].info
gdbBPSink()
echo ">>> ", b

View File

@ -86,6 +86,7 @@ const
let (lhs, rhs) = k.cpt.stack.popInt(2)
k.cpt.stack.push:
if rhs == 0:
# EVM special casing of div by 0
zero(Uint256)
else:
lhs div rhs

View File

@ -105,7 +105,7 @@ const
const
vm2OpExecHash*: seq[Vm2OpExec] = @[
(opCode: Add, ## 0x20, Keccak-256
(opCode: Op.Sha3, ## 0x20, Keccak-256
forks: Vm2OpAllForks,
info: "Compute Keccak-256 hash",
exec: (prep: vm2OpIgnore,

View File

@ -16,7 +16,7 @@ import
# verify that experimental op table compiles
import
./op_handlers
./op_handlers, ./op_handlers/oph_defs
logScope:
topics = "opcode impl"
@ -38,190 +38,59 @@ template push(x: typed) {.dirty.} =
## Push an expression on the computation stack
c.stack.push x
var gdbBPHook_counter = 0
proc gdbBPHook*() =
gdbBPHook_counter.inc
stderr.write &"*** Hello {gdbBPHook_counter}\n"
stderr.flushFile
template opHandlerX(callName: untyped; opCode: Op) =
proc callName*(c: Computation) =
gdbBPHook()
var desc: Vm2Ctx
desc.cpt = c
vm2OpTabBerlin[opCode].exec.run(desc)
template opHandler(callName: untyped; opCode: Op) =
proc callName*(c: Computation) =
var desc: Vm2Ctx
desc.cpt = c
vm2OpTabBerlin[opCode].exec.run(desc)
# ##################################
# 0s: Stop and Arithmetic Operations
op add, inline = true, lhs, rhs:
## 0x01, Addition
push: lhs + rhs
op mul, inline = true, lhs, rhs:
## 0x02, Multiplication
push: lhs * rhs
op sub, inline = true, lhs, rhs:
## 0x03, Substraction
push: lhs - rhs
op divide, inline = true, lhs, rhs:
## 0x04, Division
push:
if rhs == 0: zero(Uint256) # EVM special casing of div by 0
else: lhs div rhs
op sdiv, inline = true, lhs, rhs:
## 0x05, Signed division
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)
push(r)
op modulo, inline = true, lhs, rhs:
## 0x06, Modulo
push:
if rhs == 0: zero(Uint256)
else: lhs mod rhs
op smod, inline = true, lhs, rhs:
## 0x07, Signed modulo
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)
push(r)
op addmod, inline = true, lhs, rhs, modulus:
## 0x08, Modulo addition
## Intermediate computations do not roll over at 2^256
push:
if modulus == 0: zero(UInt256) # EVM special casing of div by 0
else: addmod(lhs, rhs, modulus)
op mulmod, inline = true, lhs, rhs, modulus:
## 0x09, Modulo multiplication
## Intermediate computations do not roll over at 2^256
push:
if modulus == 0: zero(UInt256) # EVM special casing of div by 0
else: mulmod(lhs, rhs, modulus)
op exp, inline = true, base, exponent:
## 0x0A, Exponentiation
c.gasMeter.consumeGas(
c.gasCosts[Exp].d_handler(exponent),
reason="EXP: exponent bytes"
)
push:
if base.isZero:
if 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)
else:
base.pow(exponent)
op signExtend, inline = false, bits, value:
## 0x0B, Sign extend
## Extend length of twos complement signed integer.
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
push: res
opHandler add, Op.Add
opHandler mul, Op.Mul
opHandler sub, Op.Sub
opHandler divide, Op.Div
opHandler sdiv, Op.Sdiv
opHandler modulo, Op.Mod
opHandler smod, Op.Smod
opHandler addmod, Op.AddMod
opHandler mulmod, Op.MulMod
opHandler exp, Op.Exp
opHandler signExtend, Op.SignExtend
# ##########################################
# 10s: Comparison & Bitwise Logic Operations
op lt, inline = true, lhs, rhs:
## 0x10, Less-than comparison
push: (lhs < rhs).uint.u256
op gt, inline = true, lhs, rhs:
## 0x11, Greater-than comparison
push: (lhs > rhs).uint.u256
op slt, inline = true, lhs, rhs:
## 0x12, Signed less-than comparison
push: (cast[Int256](lhs) < cast[Int256](rhs)).uint.u256
op sgt, inline = true, lhs, rhs:
## 0x13, Signed greater-than comparison
push: (cast[Int256](lhs) > cast[Int256](rhs)).uint.u256
op eq, inline = true, lhs, rhs:
## 0x14, Signed greater-than comparison
push: (lhs == rhs).uint.u256
op isZero, inline = true, value:
## 0x15, Check if zero
push: value.isZero.uint.u256
op andOp, inline = true, lhs, rhs:
## 0x16, Bitwise AND
push: lhs and rhs
op orOp, inline = true, lhs, rhs:
## 0x17, Bitwise AND
push: lhs or rhs
op xorOp, inline = true, lhs, rhs:
## 0x18, Bitwise AND
push: lhs xor rhs
op notOp, inline = true, value:
## 0x19, Check if zero
push: value.not
op byteOp, inline = true, position, value:
## 0x20, Retrieve single byte from word.
let pos = position.truncate(int)
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
opHandler lt, Op.Lt
opHandler gt, Op.Gt
opHandler slt, Op.Slt
opHandler sgt, Op.Sgt
opHandler eq, Op.Eq
opHandler isZero, Op.IsZero
opHandler andOp, Op.And
opHandler orOp, Op.Or
opHandler xorOp, Op.Xor
opHandler notOp, Op.Not
opHandler byteOp, Op.Byte
# ##########################################
# 20s: SHA3
op sha3, inline = true, startPos, length:
## 0x20, Compute Keccak-256 hash.
let (pos, len) = (startPos.safeInt, length.safeInt)
if pos < 0 or len < 0 or pos > 2147483648:
raise newException(OutOfBoundsRead, "Out of bounds memory access")
c.gasMeter.consumeGas(
c.gasCosts[Op.Sha3].m_handler(c.memory.len, pos, len),
reason="SHA3: word gas cost"
)
c.memory.extend(pos, len)
let endRange = min(pos + len, c.memory.len) - 1
if endRange == -1 or pos >= c.memory.len:
push(EMPTY_SHA3)
else:
push:
keccak256.digest c.memory.bytes.toOpenArray(pos, endRange)
opHandler sha3, Op.Sha3
# ##########################################
# 30s: Environmental Information
@ -876,33 +745,10 @@ op selfDestructEip161, inline = false:
c.selfDestruct(beneficiary)
# Constantinople's new opcodes
op shlOp, inline = true, shift, num:
let shiftLen = shift.safeInt
if shiftLen >= 256:
push: 0
else:
push: num shl shiftLen
op shrOp, inline = true, shift, num:
let shiftLen = shift.safeInt
if shiftLen >= 256:
push: 0
else:
# uint version of `shr`
push: num shr shiftLen
op sarOp, inline = true:
let shiftLen = c.stack.popInt().safeInt
let num = cast[Int256](c.stack.popInt())
if shiftLen >= 256:
if num.isNegative:
push: cast[Uint256]((-1).i256)
else:
push: 0
else:
# int version of `shr` then force the result
# into uint256
push: cast[Uint256](num shr shiftLen)
opHandler shlOp, Op.Shl
opHandler shrOp, Op.Shr
opHandler sarOp, Op.Sar
op extCodeHash, inline = true:
let address = c.stack.popAddress()