re-integrated 0x60..0xaf (push, dup, swap, log) op handlers
This commit is contained in:
parent
f4bc9c4561
commit
716bd64419
|
@ -21,7 +21,7 @@ import
|
||||||
./op_codes,
|
./op_codes,
|
||||||
./op_handlers/[oph_defs,
|
./op_handlers/[oph_defs,
|
||||||
oph_arithmetic, oph_hash, oph_envinfo, oph_blockdata,
|
oph_arithmetic, oph_hash, oph_envinfo, oph_blockdata,
|
||||||
oph_memory,
|
oph_memory, oph_push, oph_dup, oph_swap, oph_log,
|
||||||
oph_sysops]
|
oph_sysops]
|
||||||
|
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
|
@ -47,6 +47,10 @@ proc mkOpTable(select: Fork): array[Op,Vm2OpExec] {.compileTime.} =
|
||||||
result.importList(select, vm2OpExecEnvInfo, "EnvInfo")
|
result.importList(select, vm2OpExecEnvInfo, "EnvInfo")
|
||||||
result.importList(select, vm2OpExecBlockData, "BlockData")
|
result.importList(select, vm2OpExecBlockData, "BlockData")
|
||||||
result.importList(select, vm2OpExecMemory, "Memory")
|
result.importList(select, vm2OpExecMemory, "Memory")
|
||||||
|
result.importList(select, vm2OpExecPush, "Push")
|
||||||
|
result.importList(select, vm2OpExecDup, "Dup")
|
||||||
|
result.importList(select, vm2OpExecSwap, "Swap")
|
||||||
|
result.importList(select, vm2OpExecLog, "Log")
|
||||||
result.importList(select, vm2OpExecSysOP, "SysOp")
|
result.importList(select, vm2OpExecSysOP, "SysOp")
|
||||||
|
|
||||||
for op in Op:
|
for op in Op:
|
||||||
|
@ -88,6 +92,18 @@ when isMainModule and isNoisy:
|
||||||
echo ">>> berlin[shl]: ",
|
echo ">>> berlin[shl]: ",
|
||||||
vm2OpHandlers[FkBerlin][Shl].info
|
vm2OpHandlers[FkBerlin][Shl].info
|
||||||
|
|
||||||
|
echo ">>> berlin[push32]: ",
|
||||||
|
vm2OpHandlers[FkBerlin][Push32].info
|
||||||
|
|
||||||
|
echo ">>> berlin[dup16]: ",
|
||||||
|
vm2OpHandlers[FkBerlin][Dup16].info
|
||||||
|
|
||||||
|
echo ">>> berlin[swap16]: ",
|
||||||
|
vm2OpHandlers[FkBerlin][Swap16].info
|
||||||
|
|
||||||
|
echo ">>> berlin[log4]: ",
|
||||||
|
vm2OpHandlers[FkBerlin][Log4].info
|
||||||
|
|
||||||
echo ">>> frontier[sstore]: ",
|
echo ">>> frontier[sstore]: ",
|
||||||
vm2OpHandlers[FkFrontier][Sstore].info
|
vm2OpHandlers[FkFrontier][Sstore].info
|
||||||
|
|
||||||
|
|
|
@ -20,7 +20,8 @@ import
|
||||||
../forks_list,
|
../forks_list,
|
||||||
../op_codes,
|
../op_codes,
|
||||||
../../memory_defs,
|
../../memory_defs,
|
||||||
../../stack_defs
|
../../stack_defs,
|
||||||
|
eth/common/eth_types
|
||||||
|
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
# Kludge BEGIN
|
# Kludge BEGIN
|
||||||
|
@ -50,7 +51,7 @@ else:
|
||||||
accountDb*: ReadOnlyStateDB
|
accountDb*: ReadOnlyStateDB
|
||||||
|
|
||||||
Message* = ref object
|
Message* = ref object
|
||||||
contractAddress*: UInt256
|
contractAddress*: EthAddress
|
||||||
sender*: UInt256
|
sender*: UInt256
|
||||||
value*: UInt256
|
value*: UInt256
|
||||||
data*: seq[byte]
|
data*: seq[byte]
|
||||||
|
@ -71,7 +72,7 @@ else:
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
|
|
||||||
export
|
export
|
||||||
Op, Fork, Computation, Memory, Stack, UInt256, Message
|
Op, Fork, Computation, Memory, Stack, UInt256, Message, EthAddress
|
||||||
|
|
||||||
type
|
type
|
||||||
Vm2Ctx* = object of RootObj
|
Vm2Ctx* = object of RootObj
|
||||||
|
|
|
@ -0,0 +1,82 @@
|
||||||
|
# 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: Duplication Operations
|
||||||
|
## ===========================================
|
||||||
|
##
|
||||||
|
|
||||||
|
|
||||||
|
const
|
||||||
|
kludge {.intdefine.}: int = 0
|
||||||
|
breakCircularDependency {.used.} = kludge > 0
|
||||||
|
|
||||||
|
import
|
||||||
|
./oph_defs,
|
||||||
|
./oph_helpers,
|
||||||
|
sequtils,
|
||||||
|
strformat,
|
||||||
|
stint
|
||||||
|
|
||||||
|
# ------------------------------------------------------------------------------
|
||||||
|
# Kludge BEGIN
|
||||||
|
# ------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
when not breakCircularDependency:
|
||||||
|
import
|
||||||
|
../../stack
|
||||||
|
|
||||||
|
else:
|
||||||
|
# function stubs from stack.nim (to satisfy compiler logic)
|
||||||
|
proc dup(stack: var Stack, position: int | UInt256) = discard
|
||||||
|
|
||||||
|
# ------------------------------------------------------------------------------
|
||||||
|
# Kludge END
|
||||||
|
# ------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
# ------------------------------------------------------------------------------
|
||||||
|
# Private helpers
|
||||||
|
# ------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
proc fnName(n: int): string {.compileTime.} =
|
||||||
|
&"dup{n}Op"
|
||||||
|
|
||||||
|
proc opName(n: int): string {.compileTime.} =
|
||||||
|
&"Dup{n}"
|
||||||
|
|
||||||
|
proc fnInfo(n: int): string {.compileTime.} =
|
||||||
|
var blurb = case n
|
||||||
|
of 1: "first"
|
||||||
|
of 2: "second"
|
||||||
|
of 3: "third"
|
||||||
|
else: &"{n}th"
|
||||||
|
&"Duplicate {blurb} item in the stack"
|
||||||
|
|
||||||
|
|
||||||
|
proc dupImpl(k: Vm2Ctx; n: int) =
|
||||||
|
k.cpt.stack.dup(n)
|
||||||
|
|
||||||
|
const
|
||||||
|
inxRange = toSeq(1 .. 16)
|
||||||
|
|
||||||
|
# ------------------------------------------------------------------------------
|
||||||
|
# Private, op handlers implementation
|
||||||
|
# ------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
genOphHandlers fnName, fnInfo, inxRange, dupImpl
|
||||||
|
|
||||||
|
# ------------------------------------------------------------------------------
|
||||||
|
# Public, op exec table entries
|
||||||
|
# ------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
genOphList fnName, fnInfo, inxRange, "vm2OpExecDup", opName
|
||||||
|
|
||||||
|
# ------------------------------------------------------------------------------
|
||||||
|
# End
|
||||||
|
# ------------------------------------------------------------------------------
|
|
@ -0,0 +1,153 @@
|
||||||
|
# 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: Helper Functions & Macros
|
||||||
|
## ==============================================
|
||||||
|
##
|
||||||
|
|
||||||
|
const
|
||||||
|
kludge {.intdefine.}: int = 0
|
||||||
|
breakCircularDependency {.used.} = kludge > 0
|
||||||
|
|
||||||
|
import
|
||||||
|
../../../errors,
|
||||||
|
./oph_defs,
|
||||||
|
macros,
|
||||||
|
stint
|
||||||
|
|
||||||
|
type
|
||||||
|
OphNumToTextFn* = proc(n: int): string
|
||||||
|
OpHanldlerImplFn* = proc(k: Vm2Ctx; n: int)
|
||||||
|
|
||||||
|
const
|
||||||
|
recForkSet = "Vm2OpAllForks"
|
||||||
|
|
||||||
|
# ------------------------------------------------------------------------------
|
||||||
|
# Kludge BEGIN
|
||||||
|
# ------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
when not breakCircularDependency:
|
||||||
|
import
|
||||||
|
../../v2types
|
||||||
|
|
||||||
|
else:
|
||||||
|
const
|
||||||
|
emvcStatic = 1
|
||||||
|
|
||||||
|
# ------------------------------------------------------------------------------
|
||||||
|
# Kludge END
|
||||||
|
# ------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
# ------------------------------------------------------------------------------
|
||||||
|
# Private helpers
|
||||||
|
# ------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
proc asIdent(id, name: string): NimNode {.compileTime.} =
|
||||||
|
result = nnkExprColonExpr.newTree(
|
||||||
|
newIdentNode(id),
|
||||||
|
newIdentNode(name))
|
||||||
|
|
||||||
|
proc asText(id, name: string): NimNode {.compileTime.} =
|
||||||
|
result = nnkExprColonExpr.newTree(
|
||||||
|
newIdentNode(id),
|
||||||
|
newLit(name))
|
||||||
|
|
||||||
|
# ------------------------------------------------------------------------------
|
||||||
|
# Public
|
||||||
|
# ------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
template checkInStaticContext*(c: Computation) =
|
||||||
|
## Verify static context in handler function, raise an error otherwise
|
||||||
|
if emvcStatic == c.msg.flags:
|
||||||
|
# TODO: if possible, this check only appear
|
||||||
|
# when fork >= FkByzantium
|
||||||
|
raise newException(
|
||||||
|
StaticContextError,
|
||||||
|
"Cannot modify state while inside of STATICCALL context")
|
||||||
|
|
||||||
|
|
||||||
|
macro genOphHandlers*(runHandler: static[OphNumToTextFn];
|
||||||
|
itemInfo: static[OphNumToTextFn];
|
||||||
|
inxList: static[openArray[int]];
|
||||||
|
body: static[OpHanldlerImplFn]): untyped =
|
||||||
|
## Generate the equivalent of
|
||||||
|
## ::
|
||||||
|
## const <runHandler>: Vm2OpFn = proc (k: Vm2Ctx) =
|
||||||
|
## ## <itemInfo(n)>,
|
||||||
|
## <body(k,n)>
|
||||||
|
##
|
||||||
|
## for all `n` in `inxList`
|
||||||
|
##
|
||||||
|
result = newStmtList()
|
||||||
|
|
||||||
|
for n in inxList:
|
||||||
|
let
|
||||||
|
fnName = ident(n.runHandler)
|
||||||
|
comment = newCommentStmtNode(n.itemInfo)
|
||||||
|
|
||||||
|
# => push##Op: Vm2OpFn = proc (k: Vm2Ctx) = ...
|
||||||
|
result.add quote do:
|
||||||
|
const `fnName`: Vm2OpFn = proc(k: Vm2Ctx) =
|
||||||
|
`comment`
|
||||||
|
`body`(k,`n`)
|
||||||
|
# echo ">>>", result.repr
|
||||||
|
|
||||||
|
|
||||||
|
macro genOphList*(runHandler: static[OphNumToTextFn];
|
||||||
|
handlerInfo: static[OphNumToTextFn];
|
||||||
|
inxList: static[openArray[int]];
|
||||||
|
varName: static[string];
|
||||||
|
opCode: static[OphNumToTextFn]): untyped =
|
||||||
|
## Generate
|
||||||
|
## ::
|
||||||
|
## const <varName>*: seq[Vm2OpExec] = @[ <records> ]
|
||||||
|
##
|
||||||
|
## where <records> is a sequence of <record(n)> items like
|
||||||
|
## ::
|
||||||
|
## (opCode: <opCode(n)>,
|
||||||
|
## forks: Vm2OpAllForks,
|
||||||
|
## info: <handlerInfo(n)>,
|
||||||
|
## exec: (prep: vm2OpIgnore,
|
||||||
|
## run: <runHandler(n)>,
|
||||||
|
## post: vm2OpIgnore))
|
||||||
|
##
|
||||||
|
## for all `n` in `inxList`
|
||||||
|
##
|
||||||
|
var records = nnkBracket.newTree()
|
||||||
|
for n in inxList:
|
||||||
|
records.add nnkPar.newTree(
|
||||||
|
"opCode".asIdent(n.opCode),
|
||||||
|
"forks".asIdent(recForkSet),
|
||||||
|
"info".asText(n.handlerInfo),
|
||||||
|
nnkExprColonExpr.newTree(
|
||||||
|
newIdentNode("exec"),
|
||||||
|
nnkPar.newTree(
|
||||||
|
"prep".asIdent("vm2OpIgnore"),
|
||||||
|
"run".asIdent(n.runHandler),
|
||||||
|
"post".asIdent("vm2OpIgnore"))))
|
||||||
|
|
||||||
|
# => const <varName>*: seq[Vm2OpExec] = @[ <records> ]
|
||||||
|
result = nnkStmtList.newTree(
|
||||||
|
nnkConstSection.newTree(
|
||||||
|
nnkConstDef.newTree(
|
||||||
|
nnkPostfix.newTree(
|
||||||
|
newIdentNode("*"),
|
||||||
|
newIdentNode(varName)),
|
||||||
|
nnkBracketExpr.newTree(
|
||||||
|
newIdentNode("seq"),
|
||||||
|
newIdentNode("Vm2OpExec")),
|
||||||
|
nnkPrefix.newTree(
|
||||||
|
newIdentNode("@"), records))))
|
||||||
|
# echo ">>> ", result.repr
|
||||||
|
|
||||||
|
# ------------------------------------------------------------------------------
|
||||||
|
# End
|
||||||
|
# ------------------------------------------------------------------------------
|
||||||
|
|
|
@ -0,0 +1,151 @@
|
||||||
|
# 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: Logging Operations
|
||||||
|
## =======================================
|
||||||
|
##
|
||||||
|
|
||||||
|
|
||||||
|
const
|
||||||
|
kludge {.intdefine.}: int = 0
|
||||||
|
breakCircularDependency {.used.} = kludge > 0
|
||||||
|
|
||||||
|
import
|
||||||
|
../../../errors,
|
||||||
|
./oph_defs,
|
||||||
|
./oph_helpers,
|
||||||
|
sequtils,
|
||||||
|
eth/common,
|
||||||
|
strformat,
|
||||||
|
stint
|
||||||
|
|
||||||
|
# ------------------------------------------------------------------------------
|
||||||
|
# Kludge BEGIN
|
||||||
|
# ------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
when not breakCircularDependency:
|
||||||
|
import
|
||||||
|
../../../constants,
|
||||||
|
../../stack,
|
||||||
|
../../v2computation,
|
||||||
|
../../v2memory,
|
||||||
|
../../v2state,
|
||||||
|
../../v2types,
|
||||||
|
../gas_meter,
|
||||||
|
../utils/v2utils_numeric,
|
||||||
|
../v2gas_costs,
|
||||||
|
eth/common
|
||||||
|
|
||||||
|
else:
|
||||||
|
import
|
||||||
|
macros
|
||||||
|
|
||||||
|
var blindGasCosts: array[Op,int]
|
||||||
|
var blindTopic: Topic
|
||||||
|
|
||||||
|
# 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 popTopic(x: var Stack): Topic = blindTopic
|
||||||
|
proc popInt(x: var Stack, n: static[int]): auto =
|
||||||
|
var rc: genTupleType(n, UInt256)
|
||||||
|
return rc
|
||||||
|
|
||||||
|
# function stubs from v2computation.nim (to satisfy compiler logic)
|
||||||
|
proc gasCosts(c: Computation): array[Op,int] = blindGasCosts
|
||||||
|
proc addLogEntry(c: Computation, log: Log) = discard
|
||||||
|
|
||||||
|
# function stubs from v2utils_numeric.nim
|
||||||
|
func cleanMemRef(x: UInt256): int = 0
|
||||||
|
|
||||||
|
# function stubs from v2memory.nim
|
||||||
|
proc len(mem: Memory): int = 0
|
||||||
|
proc extend(mem: var Memory; startPos: Natural; size: Natural) = discard
|
||||||
|
proc read(mem: var Memory, startPos: Natural, size: Natural): seq[byte] = @[]
|
||||||
|
|
||||||
|
# function stubs from gas_meter.nim
|
||||||
|
proc consumeGas(gasMeter: var GasMeter; amount: int; reason: string) = discard
|
||||||
|
|
||||||
|
# stubs from v2gas_costs.nim
|
||||||
|
proc m_handler(x: int; curMemSize, memOffset, memLen: int64): int = 0
|
||||||
|
|
||||||
|
# ------------------------------------------------------------------------------
|
||||||
|
# Kludge END
|
||||||
|
# ------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
# ------------------------------------------------------------------------------
|
||||||
|
# Private, names & settings
|
||||||
|
# ------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
proc fnName(n: int): string {.compileTime.} =
|
||||||
|
&"Log{n}Op"
|
||||||
|
|
||||||
|
proc opName(n: int): string {.compileTime.} =
|
||||||
|
&"Log{n}"
|
||||||
|
|
||||||
|
proc fnInfo(n: int): string {.compileTime.} =
|
||||||
|
var blurb = case n
|
||||||
|
of 1: "topic"
|
||||||
|
else: "topics"
|
||||||
|
&"Append log record with {n} {blurb}"
|
||||||
|
|
||||||
|
|
||||||
|
proc logImpl(c: Computation, opcode: Op, topicCount: int) =
|
||||||
|
doAssert(topicCount in 0 .. 4)
|
||||||
|
checkInStaticContext(c)
|
||||||
|
let (memStartPosition, size) = c.stack.popInt(2)
|
||||||
|
let (memPos, len) = (memStartPosition.cleanMemRef, size.cleanMemRef)
|
||||||
|
|
||||||
|
if memPos < 0 or len < 0:
|
||||||
|
raise newException(OutOfBoundsRead, "Out of bounds memory access")
|
||||||
|
|
||||||
|
c.gasMeter.consumeGas(
|
||||||
|
c.gasCosts[opcode].m_handler(c.memory.len, memPos, len),
|
||||||
|
reason = "Memory expansion, Log topic and data gas cost")
|
||||||
|
c.memory.extend(memPos, len)
|
||||||
|
|
||||||
|
var log: Log
|
||||||
|
log.topics = newSeqOfCap[Topic](topicCount)
|
||||||
|
for i in 0 ..< topicCount:
|
||||||
|
log.topics.add(c.stack.popTopic())
|
||||||
|
|
||||||
|
log.data = c.memory.read(memPos, len)
|
||||||
|
log.address = c.msg.contractAddress
|
||||||
|
c.addLogEntry(log)
|
||||||
|
|
||||||
|
const
|
||||||
|
inxRange = toSeq(0 .. 4)
|
||||||
|
logOpArg = block:
|
||||||
|
var rc: array[inxRange.len + 1, Op]
|
||||||
|
for n in inxRange:
|
||||||
|
rc[n] = Op(Log0.int + n)
|
||||||
|
rc
|
||||||
|
|
||||||
|
# ------------------------------------------------------------------------------
|
||||||
|
# Private, op handlers implementation
|
||||||
|
# ------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
proc wrapperFn(k: Vm2Ctx; n: int) =
|
||||||
|
logImpl(k.cpt, logOpArg[n], n)
|
||||||
|
|
||||||
|
genOphHandlers fnName, fnInfo, inxRange, wrapperFn
|
||||||
|
|
||||||
|
# ------------------------------------------------------------------------------
|
||||||
|
# Public, op exec table entries
|
||||||
|
# ------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
genOphList fnName, fnInfo, inxRange, "vm2OpExecLog", opName
|
||||||
|
|
||||||
|
# ------------------------------------------------------------------------------
|
||||||
|
# End
|
||||||
|
# ------------------------------------------------------------------------------
|
|
@ -19,6 +19,7 @@ const
|
||||||
import
|
import
|
||||||
../../../errors,
|
../../../errors,
|
||||||
./oph_defs,
|
./oph_defs,
|
||||||
|
./oph_helpers,
|
||||||
strformat,
|
strformat,
|
||||||
stint
|
stint
|
||||||
|
|
||||||
|
@ -44,7 +45,6 @@ when not breakCircularDependency:
|
||||||
else:
|
else:
|
||||||
import macros
|
import macros
|
||||||
|
|
||||||
const emvcStatic = 1
|
|
||||||
var blindGasCosts: array[Op,int]
|
var blindGasCosts: array[Op,int]
|
||||||
|
|
||||||
# copied from stack.nim
|
# copied from stack.nim
|
||||||
|
@ -97,7 +97,7 @@ else:
|
||||||
proc m_handler(x: int; curMemSize, memOffset, memLen: int64): int = 0
|
proc m_handler(x: int; curMemSize, memOffset, memLen: int64): int = 0
|
||||||
|
|
||||||
# function stubs from state_db.nim
|
# function stubs from state_db.nim
|
||||||
proc getCommittedStorage(x: ReadOnlyStateDB; y,z: Uint256): Uint256 = 0.u256
|
proc getCommittedStorage[A,B](x: A; y: B; z: Uint256): Uint256 = 0.u256
|
||||||
|
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
# Kludge END
|
# Kludge END
|
||||||
|
@ -107,14 +107,6 @@ else:
|
||||||
# Private helpers
|
# Private helpers
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
|
|
||||||
template checkInStaticContext(c: Computation) =
|
|
||||||
# TODO: if possible, this check only appear
|
|
||||||
# when fork >= FkByzantium
|
|
||||||
if emvcStatic == c.msg.flags:
|
|
||||||
raise newException(
|
|
||||||
StaticContextError,
|
|
||||||
"Cannot modify state while inside of STATICCALL context")
|
|
||||||
|
|
||||||
proc sstoreNetGasMeteringImpl(c: Computation; slot, newValue: Uint256) =
|
proc sstoreNetGasMeteringImpl(c: Computation; slot, newValue: Uint256) =
|
||||||
let
|
let
|
||||||
stateDB = c.vmState.readOnlyStateDB
|
stateDB = c.vmState.readOnlyStateDB
|
||||||
|
|
|
@ -0,0 +1,85 @@
|
||||||
|
# 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: Push Operations
|
||||||
|
## ====================================
|
||||||
|
##
|
||||||
|
|
||||||
|
|
||||||
|
const
|
||||||
|
kludge {.intdefine.}: int = 0
|
||||||
|
breakCircularDependency {.used.} = kludge > 0
|
||||||
|
|
||||||
|
import
|
||||||
|
./oph_defs,
|
||||||
|
./oph_helpers,
|
||||||
|
sequtils,
|
||||||
|
strformat,
|
||||||
|
stint
|
||||||
|
|
||||||
|
# ------------------------------------------------------------------------------
|
||||||
|
# Kludge BEGIN
|
||||||
|
# ------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
when not breakCircularDependency:
|
||||||
|
import
|
||||||
|
../../code_stream,
|
||||||
|
../../stack
|
||||||
|
|
||||||
|
else:
|
||||||
|
# function stubs from stack.nim (to satisfy compiler logic)
|
||||||
|
proc push[T](x: Stack; n: T) = discard
|
||||||
|
|
||||||
|
# function stubs from code_stream.nim
|
||||||
|
proc readVmWord(c: var CodeStream, n: int): UInt256 = 0.u256
|
||||||
|
|
||||||
|
# ------------------------------------------------------------------------------
|
||||||
|
# Kludge END
|
||||||
|
# ------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
# ------------------------------------------------------------------------------
|
||||||
|
# Private helpers
|
||||||
|
# ------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
proc fnName(n: int): string {.compileTime.} =
|
||||||
|
&"push{n}Op"
|
||||||
|
|
||||||
|
proc opName(n: int): string {.compileTime.} =
|
||||||
|
&"Push{n}"
|
||||||
|
|
||||||
|
proc fnInfo(n: int): string {.compileTime.} =
|
||||||
|
var blurb = case n
|
||||||
|
of 1: "byte"
|
||||||
|
else: &"{n} bytes"
|
||||||
|
&"Push {blurb} on the stack"
|
||||||
|
|
||||||
|
|
||||||
|
proc pushImpl(k: Vm2Ctx; n: int) =
|
||||||
|
k.cpt.stack.push:
|
||||||
|
k.cpt.code.readVmWord(n)
|
||||||
|
|
||||||
|
const
|
||||||
|
inxRange = toSeq(1 .. 32)
|
||||||
|
|
||||||
|
# ------------------------------------------------------------------------------
|
||||||
|
# Private, op handlers implementation
|
||||||
|
# ------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
genOphHandlers fnName, fnInfo, inxRange, pushImpl
|
||||||
|
|
||||||
|
# ------------------------------------------------------------------------------
|
||||||
|
# Public, op exec table entries
|
||||||
|
# ------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
genOphList fnName, fnInfo, inxRange, "vm2OpExecPush", opName
|
||||||
|
|
||||||
|
# ------------------------------------------------------------------------------
|
||||||
|
# End
|
||||||
|
# ------------------------------------------------------------------------------
|
|
@ -0,0 +1,81 @@
|
||||||
|
# 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: Swap Operations
|
||||||
|
## ====================================
|
||||||
|
##
|
||||||
|
|
||||||
|
|
||||||
|
const
|
||||||
|
kludge {.intdefine.}: int = 0
|
||||||
|
breakCircularDependency {.used.} = kludge > 0
|
||||||
|
|
||||||
|
import
|
||||||
|
./oph_defs,
|
||||||
|
./oph_helpers,
|
||||||
|
sequtils,
|
||||||
|
strformat
|
||||||
|
|
||||||
|
# ------------------------------------------------------------------------------
|
||||||
|
# Kludge BEGIN
|
||||||
|
# ------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
when not breakCircularDependency:
|
||||||
|
import
|
||||||
|
../../stack
|
||||||
|
|
||||||
|
else:
|
||||||
|
# function stubs from stack.nim (to satisfy compiler logic)
|
||||||
|
proc swap(stack: var Stack, position: int) = discard
|
||||||
|
|
||||||
|
# ------------------------------------------------------------------------------
|
||||||
|
# Kludge END
|
||||||
|
# ------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
# ------------------------------------------------------------------------------
|
||||||
|
# Private, names & settings
|
||||||
|
# ------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
proc fnName(n: int): string {.compileTime.} =
|
||||||
|
&"swap{n}Op"
|
||||||
|
|
||||||
|
proc opName(n: int): string {.compileTime.} =
|
||||||
|
&"Swap{n}"
|
||||||
|
|
||||||
|
proc fnInfo(n: int): string {.compileTime.} =
|
||||||
|
var blurb = case n+1
|
||||||
|
of 1: "first"
|
||||||
|
of 2: "second"
|
||||||
|
of 3: "third"
|
||||||
|
else: &"{n+1}th"
|
||||||
|
&"Exchange first and {blurb} stack items"
|
||||||
|
|
||||||
|
|
||||||
|
proc swapImpl(k: Vm2Ctx; n: int) =
|
||||||
|
k.cpt.stack.swap(n)
|
||||||
|
|
||||||
|
const
|
||||||
|
inxRange = toSeq(1 .. 16)
|
||||||
|
|
||||||
|
# ------------------------------------------------------------------------------
|
||||||
|
# Private, op handlers implementation
|
||||||
|
# ------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
genOphHandlers fnName, fnInfo, inxRange, swapImpl
|
||||||
|
|
||||||
|
# ------------------------------------------------------------------------------
|
||||||
|
# Public, op exec table entries
|
||||||
|
# ------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
genOphList fnName, fnInfo, inxRange, "vm2OpExecSwap", opName
|
||||||
|
|
||||||
|
# ------------------------------------------------------------------------------
|
||||||
|
# End
|
||||||
|
# ------------------------------------------------------------------------------
|
|
@ -118,9 +118,15 @@ opHandler orOp, Op.Or
|
||||||
opHandler xorOp, Op.Xor
|
opHandler xorOp, Op.Xor
|
||||||
opHandler notOp, Op.Not
|
opHandler notOp, Op.Not
|
||||||
opHandler byteOp, Op.Byte
|
opHandler byteOp, Op.Byte
|
||||||
|
opHandler shlOp, Op.Shl
|
||||||
|
opHandler shrOp, Op.Shr
|
||||||
|
opHandler sarOp, Op.Sar
|
||||||
opHandler sha3, Op.Sha3
|
opHandler sha3, Op.Sha3
|
||||||
opHandler address, Op.Address
|
opHandler address, Op.Address
|
||||||
opHandler balance, Op.Balance
|
|
||||||
|
opHandler balance, Op.Balance, FkFrontier
|
||||||
|
opHandler balanceEIP2929, Op.Balance
|
||||||
|
|
||||||
opHandler origin, Op.Origin
|
opHandler origin, Op.Origin
|
||||||
opHandler caller, Op.Caller
|
opHandler caller, Op.Caller
|
||||||
opHandler callValue, Op.CallValue
|
opHandler callValue, Op.CallValue
|
||||||
|
@ -130,8 +136,13 @@ opHandler callDataCopy, Op.CallDataCopy
|
||||||
opHandler codeSize, Op.CodeSize
|
opHandler codeSize, Op.CodeSize
|
||||||
opHandler codeCopy, Op.CodeCopy
|
opHandler codeCopy, Op.CodeCopy
|
||||||
opHandler gasprice, Op.GasPrice
|
opHandler gasprice, Op.GasPrice
|
||||||
opHandler extCodeSize, Op.ExtCodeSize
|
|
||||||
opHandler extCodeCopy, Op.ExtCodeCopy
|
opHandler extCodeSize, Op.ExtCodeSize, FkFrontier
|
||||||
|
opHandler extCodeSizeEIP2929, Op.ExtCodeSize
|
||||||
|
|
||||||
|
opHandler extCodeCopy, Op.ExtCodeCopy, FkFrontier
|
||||||
|
opHandler extCodeCopyEIP2929, Op.ExtCodeCopy
|
||||||
|
|
||||||
opHandler returnDataSize, Op.ReturnDataSize
|
opHandler returnDataSize, Op.ReturnDataSize
|
||||||
opHandler returnDataCopy, Op.ReturnDataCopy
|
opHandler returnDataCopy, Op.ReturnDataCopy
|
||||||
opHandler blockhash, Op.Blockhash
|
opHandler blockhash, Op.Blockhash
|
||||||
|
@ -146,10 +157,15 @@ opHandler pop, Op.Pop
|
||||||
opHandler mload, Op.Mload
|
opHandler mload, Op.Mload
|
||||||
opHandler mstore, Op.Mstore
|
opHandler mstore, Op.Mstore
|
||||||
opHandler mstore8, Op.Mstore8
|
opHandler mstore8, Op.Mstore8
|
||||||
opHandler sload, Op.Sload
|
|
||||||
|
opHandler sload, Op.Sload, FkFrontier
|
||||||
|
opHandler sloadEIP2929, Op.Sload
|
||||||
|
|
||||||
opHandler sstore, Op.Sstore, FkFrontier
|
opHandler sstore, Op.Sstore, FkFrontier
|
||||||
opHandler sstoreEIP1283, Op.Sstore, FkConstantinople
|
opHandler sstoreEIP1283, Op.Sstore, FkConstantinople
|
||||||
opHandler sstoreEIP2200, Op.Sstore
|
opHandler sstoreEIP2200, Op.Sstore, FkIstanbul
|
||||||
|
opHandler sstoreEIP2929, Op.Sstore
|
||||||
|
|
||||||
opHandler jump, Op.Jump
|
opHandler jump, Op.Jump
|
||||||
opHandler jumpI, Op.JumpI
|
opHandler jumpI, Op.JumpI
|
||||||
opHandler pc, Op.Pc
|
opHandler pc, Op.Pc
|
||||||
|
@ -159,17 +175,75 @@ opHandler jumpDest, Op.JumpDest
|
||||||
opHandler beginSub, Op.BeginSub
|
opHandler beginSub, Op.BeginSub
|
||||||
opHandler returnSub, Op.ReturnSub
|
opHandler returnSub, Op.ReturnSub
|
||||||
opHandler jumpSub, Op.JumpSub
|
opHandler jumpSub, Op.JumpSub
|
||||||
|
opHandler push1, Op.Push1
|
||||||
# ##########################################
|
opHandler push2, Op.Push2
|
||||||
# 60s & 70s: Push Operations.
|
opHandler push3, Op.Push3
|
||||||
# 80s: Duplication Operations
|
opHandler push4, Op.Push4
|
||||||
# 90s: Exchange Operations
|
opHandler push5, Op.Push5
|
||||||
# a0s: Logging Operations
|
opHandler push6, Op.Push6
|
||||||
|
opHandler push7, Op.Push7
|
||||||
genPush()
|
opHandler push8, Op.Push8
|
||||||
genDup()
|
opHandler push9, Op.Push9
|
||||||
genSwap()
|
opHandler push10, Op.Push10
|
||||||
genLog()
|
opHandler push11, Op.Push11
|
||||||
|
opHandler push12, Op.Push12
|
||||||
|
opHandler push13, Op.Push13
|
||||||
|
opHandler push14, Op.Push14
|
||||||
|
opHandler push15, Op.Push15
|
||||||
|
opHandler push16, Op.Push16
|
||||||
|
opHandler push17, Op.Push17
|
||||||
|
opHandler push18, Op.Push18
|
||||||
|
opHandler push19, Op.Push19
|
||||||
|
opHandler push20, Op.Push20
|
||||||
|
opHandler push21, Op.Push21
|
||||||
|
opHandler push22, Op.Push22
|
||||||
|
opHandler push23, Op.Push23
|
||||||
|
opHandler push24, Op.Push24
|
||||||
|
opHandler push25, Op.Push25
|
||||||
|
opHandler push26, Op.Push26
|
||||||
|
opHandler push27, Op.Push27
|
||||||
|
opHandler push28, Op.Push28
|
||||||
|
opHandler push29, Op.Push29
|
||||||
|
opHandler push30, Op.Push30
|
||||||
|
opHandler push31, Op.Push31
|
||||||
|
opHandler push32, Op.Push32
|
||||||
|
opHandler dup1, Op.Dup1
|
||||||
|
opHandler dup2, Op.Dup2
|
||||||
|
opHandler dup3, Op.Dup3
|
||||||
|
opHandler dup4, Op.Dup4
|
||||||
|
opHandler dup5, Op.Dup5
|
||||||
|
opHandler dup6, Op.Dup6
|
||||||
|
opHandler dup7, Op.Dup7
|
||||||
|
opHandler dup8, Op.Dup8
|
||||||
|
opHandler dup9, Op.Dup9
|
||||||
|
opHandler dup10, Op.Dup10
|
||||||
|
opHandler dup11, Op.Dup11
|
||||||
|
opHandler dup12, Op.Dup12
|
||||||
|
opHandler dup13, Op.Dup13
|
||||||
|
opHandler dup14, Op.Dup14
|
||||||
|
opHandler dup15, Op.Dup15
|
||||||
|
opHandler dup16, Op.Dup16
|
||||||
|
opHandler swap1, Op.Swap1
|
||||||
|
opHandler swap2, Op.Swap2
|
||||||
|
opHandler swap3, Op.Swap3
|
||||||
|
opHandler swap4, Op.Swap4
|
||||||
|
opHandler swap5, Op.Swap5
|
||||||
|
opHandler swap6, Op.Swap6
|
||||||
|
opHandler swap7, Op.Swap7
|
||||||
|
opHandler swap8, Op.Swap8
|
||||||
|
opHandler swap9, Op.Swap9
|
||||||
|
opHandler swap10, Op.Swap10
|
||||||
|
opHandler swap11, Op.Swap11
|
||||||
|
opHandler swap12, Op.Swap12
|
||||||
|
opHandler swap13, Op.Swap13
|
||||||
|
opHandler swap14, Op.Swap14
|
||||||
|
opHandler swap15, Op.Swap15
|
||||||
|
opHandler swap16, Op.Swap16
|
||||||
|
opHandler log0, Op.Log0
|
||||||
|
opHandler log1, Op.Log1
|
||||||
|
opHandler log2, Op.Log2
|
||||||
|
opHandler log3, Op.Log3
|
||||||
|
opHandler log4, Op.Log4
|
||||||
|
|
||||||
# ##########################################
|
# ##########################################
|
||||||
# f0s: System operations.
|
# f0s: System operations.
|
||||||
|
@ -471,48 +545,17 @@ op selfDestructEip161, inline = false:
|
||||||
c.selfDestruct(beneficiary)
|
c.selfDestruct(beneficiary)
|
||||||
|
|
||||||
# Constantinople's new opcodes
|
# Constantinople's new opcodes
|
||||||
|
#################################
|
||||||
opHandler shlOp, Op.Shl
|
|
||||||
opHandler shrOp, Op.Shr
|
|
||||||
opHandler sarOp, Op.Sar
|
|
||||||
|
|
||||||
op extCodeHash, inline = true:
|
op extCodeHash, inline = true:
|
||||||
let address = c.stack.popAddress()
|
let address = c.stack.popAddress()
|
||||||
push: c.getCodeHash(address)
|
push: c.getCodeHash(address)
|
||||||
|
|
||||||
op balanceEIP2929, inline = true:
|
|
||||||
## 0x31, Get balance of the given account.
|
|
||||||
let address = c.stack.popAddress()
|
|
||||||
|
|
||||||
c.gasEip2929AccountCheck(address, gasFees[c.fork][GasBalance])
|
|
||||||
push: c.getBalance(address)
|
|
||||||
|
|
||||||
op extCodeHashEIP2929, inline = true:
|
op extCodeHashEIP2929, inline = true:
|
||||||
let address = c.stack.popAddress()
|
let address = c.stack.popAddress()
|
||||||
c.gasEip2929AccountCheck(address, gasFees[c.fork][GasExtCodeHash])
|
c.gasEip2929AccountCheck(address, gasFees[c.fork][GasExtCodeHash])
|
||||||
push: c.getCodeHash(address)
|
push: c.getCodeHash(address)
|
||||||
|
|
||||||
op extCodeSizeEIP2929, inline = true:
|
|
||||||
## 0x3b, Get size of an account's code
|
|
||||||
let address = c.stack.popAddress()
|
|
||||||
c.gasEip2929AccountCheck(address, gasFees[c.fork][GasExtCode])
|
|
||||||
push: c.getCodeSize(address)
|
|
||||||
|
|
||||||
op extCodeCopyEIP2929, inline = true:
|
|
||||||
## 0x3c, Copy an account's code to memory.
|
|
||||||
let address = c.stack.popAddress()
|
|
||||||
let (memStartPos, codeStartPos, size) = c.stack.popInt(3)
|
|
||||||
let (memPos, codePos, len) = (memStartPos.cleanMemRef, codeStartPos.cleanMemRef, size.cleanMemRef)
|
|
||||||
|
|
||||||
c.gasMeter.consumeGas(
|
|
||||||
c.gasCosts[ExtCodeCopy].m_handler(c.memory.len, memPos, len),
|
|
||||||
reason="ExtCodeCopy fee")
|
|
||||||
|
|
||||||
c.gasEip2929AccountCheck(address, gasFees[c.fork][GasExtCode])
|
|
||||||
|
|
||||||
let codeBytes = c.getCode(address)
|
|
||||||
c.memory.writePaddedResult(codeBytes, memPos, codePos, len)
|
|
||||||
|
|
||||||
op selfDestructEIP2929, inline = false:
|
op selfDestructEIP2929, inline = false:
|
||||||
checkInStaticContext(c)
|
checkInStaticContext(c)
|
||||||
|
|
||||||
|
@ -535,7 +578,37 @@ op selfDestructEIP2929, inline = false:
|
||||||
c.gasMeter.consumeGas(gasCost, reason = "SELFDESTRUCT EIP161")
|
c.gasMeter.consumeGas(gasCost, reason = "SELFDESTRUCT EIP161")
|
||||||
c.selfDestruct(beneficiary)
|
c.selfDestruct(beneficiary)
|
||||||
|
|
||||||
op sloadEIP2929, inline = true, slot:
|
# ---------------------------------------------------
|
||||||
|
|
||||||
|
op balanceEIP2929x, inline = true:
|
||||||
|
## 0x31, Get balance of the given account.
|
||||||
|
let address = c.stack.popAddress()
|
||||||
|
|
||||||
|
c.gasEip2929AccountCheck(address, gasFees[c.fork][GasBalance])
|
||||||
|
push: c.getBalance(address)
|
||||||
|
|
||||||
|
op extCodeSizeEIP2929x, inline = true:
|
||||||
|
## 0x3b, Get size of an account's code
|
||||||
|
let address = c.stack.popAddress()
|
||||||
|
c.gasEip2929AccountCheck(address, gasFees[c.fork][GasExtCode])
|
||||||
|
push: c.getCodeSize(address)
|
||||||
|
|
||||||
|
op extCodeCopyEIP2929x, inline = true:
|
||||||
|
## 0x3c, Copy an account's code to memory.
|
||||||
|
let address = c.stack.popAddress()
|
||||||
|
let (memStartPos, codeStartPos, size) = c.stack.popInt(3)
|
||||||
|
let (memPos, codePos, len) = (memStartPos.cleanMemRef, codeStartPos.cleanMemRef, size.cleanMemRef)
|
||||||
|
|
||||||
|
c.gasMeter.consumeGas(
|
||||||
|
c.gasCosts[ExtCodeCopy].m_handler(c.memory.len, memPos, len),
|
||||||
|
reason="ExtCodeCopy fee")
|
||||||
|
|
||||||
|
c.gasEip2929AccountCheck(address, gasFees[c.fork][GasExtCode])
|
||||||
|
|
||||||
|
let codeBytes = c.getCode(address)
|
||||||
|
c.memory.writePaddedResult(codeBytes, memPos, codePos, len)
|
||||||
|
|
||||||
|
op sloadEIP2929x, inline = true, slot:
|
||||||
## 0x54, Load word from storage.
|
## 0x54, Load word from storage.
|
||||||
c.vmState.mutateStateDB:
|
c.vmState.mutateStateDB:
|
||||||
let gasCost = if not db.inAccessList(c.msg.contractAddress, slot):
|
let gasCost = if not db.inAccessList(c.msg.contractAddress, slot):
|
||||||
|
@ -547,7 +620,7 @@ op sloadEIP2929, inline = true, slot:
|
||||||
|
|
||||||
push: c.getStorage(slot)
|
push: c.getStorage(slot)
|
||||||
|
|
||||||
op sstoreEIP2929, inline = false, slot, newValue:
|
op sstoreEIP2929x, inline = false, slot, newValue:
|
||||||
checkInStaticContext(c)
|
checkInStaticContext(c)
|
||||||
const SentryGasEIP2200 = 2300 # Minimum gas required to be present for an SSTORE call, not consumed
|
const SentryGasEIP2200 = 2300 # Minimum gas required to be present for an SSTORE call, not consumed
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue