re-integrated 0x3# op handlers
This commit is contained in:
parent
fda676062f
commit
fb94aa8a35
|
@ -20,7 +20,7 @@ import
|
|||
strformat,
|
||||
./op_codes,
|
||||
./op_handlers/[oph_defs,
|
||||
oph_arithmetic, oph_hash,
|
||||
oph_arithmetic, oph_hash, oph_envinfo,
|
||||
oph_sysops]
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
|
@ -50,6 +50,11 @@ const
|
|||
doAssert rc[w.opCode].info == ""
|
||||
rc[w.opCode] = w
|
||||
|
||||
for w in vm2OpExecEnvInfo:
|
||||
if w.complain("EnvInfo"):
|
||||
doAssert rc[w.opCode].info == ""
|
||||
rc[w.opCode] = w
|
||||
|
||||
for w in vm2OpExecSysOP:
|
||||
if w.complain("SysOp"):
|
||||
doAssert rc[w.opCode].info == ""
|
||||
|
|
|
@ -8,8 +8,8 @@
|
|||
# at your option. This file may not be copied, modified, or distributed except
|
||||
# according to those terms.
|
||||
|
||||
## EVM Opcodes, Definitons
|
||||
## =======================
|
||||
## EVM Opcodes, Definitions
|
||||
## ========================
|
||||
##
|
||||
|
||||
const
|
||||
|
@ -36,17 +36,32 @@ else:
|
|||
{.fatal: "Flag \"vm2_enabled\" must be unset "&
|
||||
"while circular dependency breaker kludge is activated".}
|
||||
type
|
||||
GasMeter* = object
|
||||
whatever: int
|
||||
|
||||
CodeStream* = ref object
|
||||
bytes*: seq[byte]
|
||||
|
||||
Message* = ref object
|
||||
contractAddress*: UInt256
|
||||
sender*: UInt256
|
||||
value*: UInt256
|
||||
data*: seq[byte]
|
||||
|
||||
Computation* = ref object
|
||||
gasMeter*: GasMeter
|
||||
stack*: Stack
|
||||
memory*: Memory
|
||||
code: int
|
||||
msg*: Message
|
||||
code*: CodeStream
|
||||
returnData*: seq[byte]
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# Kludge END
|
||||
# ------------------------------------------------------------------------------
|
||||
|
||||
export
|
||||
Op, Fork, Computation, Memory, Stack, UInt256
|
||||
Op, Fork, Computation, Memory, Stack, UInt256, Message
|
||||
|
||||
type
|
||||
Vm2Ctx* = object of RootObj
|
||||
|
|
|
@ -0,0 +1,370 @@
|
|||
# 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: Environmental Information
|
||||
## ==============================================
|
||||
##
|
||||
|
||||
const
|
||||
kludge {.intdefine.}: int = 0
|
||||
breakCircularDependency {.used.} = kludge > 0
|
||||
|
||||
import
|
||||
../../../errors,
|
||||
./oph_defs,
|
||||
sequtils,
|
||||
strformat,
|
||||
stint
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# Kludge BEGIN
|
||||
# ------------------------------------------------------------------------------
|
||||
|
||||
when not breakCircularDependency:
|
||||
import
|
||||
../../code_stream,
|
||||
../../stack,
|
||||
../../v2computation,
|
||||
../../v2memory,
|
||||
../../v2state,
|
||||
../gas_meter,
|
||||
../utils/v2utils_numeric,
|
||||
eth/common
|
||||
|
||||
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 popAddress(x: var Stack): UInt256 = 0.u256
|
||||
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 getBalance[T](c: Computation, address: T): Uint256 = 0.u256
|
||||
proc getOrigin(c: Computation): Uint256 = 0.u256
|
||||
proc getGasPrice(c: Computation): Uint256 = 0.u256
|
||||
proc getCodeSize[T](c: Computation, address: T): uint = 0
|
||||
proc getCode[T](c: Computation, address: T): seq[byte] = @[]
|
||||
|
||||
# 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 write(mem: var Memory, startPos: Natural, val: openarray[byte]) = discard
|
||||
|
||||
# function stubs from code_stream.nim
|
||||
proc len(c: CodeStream): int = len(c.bytes)
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# Kludge END
|
||||
# ------------------------------------------------------------------------------
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# Private helpers
|
||||
# ------------------------------------------------------------------------------
|
||||
|
||||
proc writePaddedResult(mem: var Memory,
|
||||
data: openarray[byte],
|
||||
memPos, dataPos, len: Natural,
|
||||
paddingValue = 0.byte) =
|
||||
|
||||
mem.extend(memPos, len)
|
||||
let dataEndPosition = dataPos.int64 + len - 1
|
||||
let sourceBytes =
|
||||
data[min(dataPos, data.len) .. min(data.len - 1, dataEndPosition)]
|
||||
|
||||
mem.write(memPos, sourceBytes)
|
||||
|
||||
# Don't duplicate zero-padding of mem.extend
|
||||
let paddingOffset = min(memPos + sourceBytes.len, mem.len)
|
||||
let numPaddingBytes = min(mem.len - paddingOffset, len - sourceBytes.len)
|
||||
if numPaddingBytes > 0:
|
||||
# TODO: avoid unnecessary memory allocation
|
||||
mem.write(paddingOffset, repeat(paddingValue, numPaddingBytes))
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# Private, op handlers implementation
|
||||
# ------------------------------------------------------------------------------
|
||||
|
||||
const
|
||||
addressOp: Vm2OpFn = proc (k: Vm2Ctx) =
|
||||
## 0x30, Get address of currently executing account.
|
||||
k.cpt.stack.push:
|
||||
k.cpt.msg.contractAddress
|
||||
|
||||
balanceOp: Vm2OpFn = proc (k: Vm2Ctx) =
|
||||
## 0x31, Get balance of the given account.
|
||||
let address = k.cpt.stack.popAddress
|
||||
k.cpt.stack.push:
|
||||
k.cpt.getBalance(address)
|
||||
|
||||
originOp: Vm2OpFn = proc (k: Vm2Ctx) =
|
||||
## 0x32, Get execution origination address.
|
||||
k.cpt.stack.push:
|
||||
k.cpt.getOrigin()
|
||||
|
||||
callerOp: Vm2OpFn = proc (k: Vm2Ctx) =
|
||||
## 0x33, Get caller address.
|
||||
k.cpt.stack.push:
|
||||
k.cpt.msg.sender
|
||||
|
||||
callValueOp: Vm2OpFn = proc (k: Vm2Ctx) =
|
||||
## 0x34, Get deposited value by the instruction/transaction
|
||||
## responsible for this execution
|
||||
k.cpt.stack.push:
|
||||
k.cpt.msg.value
|
||||
|
||||
callDataLoadOp: Vm2OpFn = proc (k: Vm2Ctx) =
|
||||
## 0x35, Get input data of current environment
|
||||
let (startPos) = k.cpt.stack.popInt(1)
|
||||
let start = startPos.cleanMemRef
|
||||
if start >= k.cpt.msg.data.len:
|
||||
k.cpt.stack.push:
|
||||
0
|
||||
return
|
||||
|
||||
# If the data does not take 32 bytes, pad with zeros
|
||||
let endRange = min(k.cpt.msg.data.len - 1, start + 31)
|
||||
let presentBytes = endRange - start
|
||||
|
||||
# We rely on value being initialized with 0 by default
|
||||
var value: array[32, byte]
|
||||
value[0 .. presentBytes] = k.cpt.msg.data.toOpenArray(start, endRange)
|
||||
k.cpt.stack.push:
|
||||
value
|
||||
|
||||
|
||||
callDataSizeOp: Vm2OpFn = proc (k: Vm2Ctx) =
|
||||
## 0x36, Get size of input data in current environment.
|
||||
k.cpt.stack.push:
|
||||
k.cpt.msg.data.len.u256
|
||||
|
||||
|
||||
callDataCopyOp: Vm2OpFn = proc (k: Vm2Ctx) =
|
||||
## 0x37, Copy input data in current environment to memory.
|
||||
let (memStartPos, copyStartPos, size) = k.cpt.stack.popInt(3)
|
||||
|
||||
# TODO tests: https://github.com/status-im/nimbus/issues/67
|
||||
let (memPos, copyPos, len) =
|
||||
(memStartPos.cleanMemRef, copyStartPos.cleanMemRef, size.cleanMemRef)
|
||||
|
||||
when not breakCircularDependency:
|
||||
k.cpt.gasMeter.consumeGas(
|
||||
k.cpt.gasCosts[CallDataCopy].m_handler(k.cpt.memory.len, memPos, len),
|
||||
reason = "CallDataCopy fee")
|
||||
|
||||
k.cpt.memory.writePaddedResult(k.cpt.msg.data, memPos, copyPos, len)
|
||||
|
||||
|
||||
codeSizeOp: Vm2OpFn = proc (k: Vm2Ctx) =
|
||||
## 0x38, Get size of code running in current environment.
|
||||
k.cpt.stack.push:
|
||||
k.cpt.code.len
|
||||
|
||||
|
||||
codeCopyOp: Vm2OpFn = proc (k: Vm2Ctx) =
|
||||
## 0x39, Copy code running in current environment to memory.
|
||||
let (memStartPos, copyStartPos, size) = k.cpt.stack.popInt(3)
|
||||
|
||||
# TODO tests: https://github.com/status-im/nimbus/issues/67
|
||||
let (memPos, copyPos, len) =
|
||||
(memStartPos.cleanMemRef, copyStartPos.cleanMemRef, size.cleanMemRef)
|
||||
|
||||
when not breakCircularDependency:
|
||||
k.cpt.gasMeter.consumeGas(
|
||||
k.cpt.gasCosts[CodeCopy].m_handler(k.cpt.memory.len, memPos, len),
|
||||
reason = "CodeCopy fee")
|
||||
|
||||
k.cpt.memory.writePaddedResult(k.cpt.code.bytes, memPos, copyPos, len)
|
||||
|
||||
|
||||
gasPriceOp: Vm2OpFn = proc (k: Vm2Ctx) =
|
||||
## 0x3A, Get price of gas in current environment.
|
||||
k.cpt.stack.push:
|
||||
k.cpt.getGasPrice
|
||||
|
||||
extCodeSizeOp: Vm2OpFn = proc (k: Vm2Ctx) =
|
||||
## 0x3b, Get size of an account's code
|
||||
let address = k.cpt.stack.popAddress()
|
||||
k.cpt.stack.push:
|
||||
k.cpt.getCodeSize(address)
|
||||
|
||||
|
||||
extCodeCopyOp: Vm2OpFn = proc (k: Vm2Ctx) =
|
||||
## 0x3c, Copy an account's code to memory.
|
||||
let address = k.cpt.stack.popAddress()
|
||||
|
||||
let (memStartPos, codeStartPos, size) = k.cpt.stack.popInt(3)
|
||||
let (memPos, codePos, len) =
|
||||
(memStartPos.cleanMemRef, codeStartPos.cleanMemRef, size.cleanMemRef)
|
||||
|
||||
when not breakCircularDependency:
|
||||
k.cpt.gasMeter.consumeGas(
|
||||
k.cpt.gasCosts[ExtCodeCopy].m_handler(k.cpt.memory.len, memPos, len),
|
||||
reason = "ExtCodeCopy fee")
|
||||
|
||||
let codeBytes = k.cpt.getCode(address)
|
||||
k.cpt.memory.writePaddedResult(codeBytes, memPos, codePos, len)
|
||||
|
||||
|
||||
returnDataSizeOp: Vm2OpFn = proc (k: Vm2Ctx) =
|
||||
## 0x3d, Get size of output data from the previous call from the
|
||||
## current environment.
|
||||
k.cpt.stack.push:
|
||||
k.cpt.returnData.len
|
||||
|
||||
|
||||
returnDataCopyOp: Vm2OpFn = proc (k: Vm2Ctx) =
|
||||
## 0x3e, Copy output data from the previous call to memory.
|
||||
let (memStartPos, copyStartPos, size) = k.cpt.stack.popInt(3)
|
||||
|
||||
let (memPos, copyPos, len) =
|
||||
(memStartPos.cleanMemRef, copyStartPos.cleanMemRef, size.cleanMemRef)
|
||||
|
||||
when not breakCircularDependency:
|
||||
let gasCost = k.cpt.gasCosts[ReturnDataCopy].m_handler(
|
||||
k.cpt.memory.len, memPos, len)
|
||||
k.cpt.gasMeter.consumeGas(gasCost, reason = "returnDataCopy fee")
|
||||
|
||||
if copyPos + len > k.cpt.returnData.len:
|
||||
raise newException(
|
||||
OutOfBoundsRead,
|
||||
"Return data length is not sufficient to satisfy request. Asked\n"&
|
||||
&"for data from index {copyStartPos} to {copyStartPos + size}. "&
|
||||
&"Return data is {k.cpt.returnData.len} in \n" &
|
||||
"length")
|
||||
k.cpt.memory.writePaddedResult(k.cpt.returnData, memPos, copyPos, len)
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# Public, op exec table entries
|
||||
# ------------------------------------------------------------------------------
|
||||
|
||||
const
|
||||
vm2OpExecEnvInfo*: seq[Vm2OpExec] = @[
|
||||
|
||||
(opCode: Address, ## 0x20, Address
|
||||
forks: Vm2OpAllForks,
|
||||
info: "Get address of currently executing account",
|
||||
exec: (prep: vm2OpIgnore,
|
||||
run: addressOp,
|
||||
post: vm2OpIgnore)),
|
||||
|
||||
(opCode: Balance, ## 0x31, Balance
|
||||
forks: Vm2OpAllForks,
|
||||
info: "Get balance of the given account",
|
||||
exec: (prep: vm2OpIgnore,
|
||||
run: balanceOp,
|
||||
post: vm2OpIgnore)),
|
||||
|
||||
(opCode: Origin, ## 0x32, Origination address
|
||||
forks: Vm2OpAllForks,
|
||||
info: "Get execution origination address",
|
||||
exec: (prep: vm2OpIgnore,
|
||||
run: originOp,
|
||||
post: vm2OpIgnore)),
|
||||
|
||||
(opCode: Caller, ## 0x33, Caller address
|
||||
forks: Vm2OpAllForks,
|
||||
info: "Get caller address",
|
||||
exec: (prep: vm2OpIgnore,
|
||||
run: callerOp,
|
||||
post: vm2OpIgnore)),
|
||||
|
||||
(opCode: CallValue, ## 0x34, Execution deposited value
|
||||
forks: Vm2OpAllForks,
|
||||
info: "Get deposited value by the instruction/transaction " &
|
||||
"responsible for this execution",
|
||||
exec: (prep: vm2OpIgnore,
|
||||
run: callValueOp,
|
||||
post: vm2OpIgnore)),
|
||||
|
||||
(opCode: CallDataLoad, ## 0x35, Input data
|
||||
forks: Vm2OpAllForks,
|
||||
info: "Get input data of current environment",
|
||||
exec: (prep: vm2OpIgnore,
|
||||
run: callDataLoadOp,
|
||||
post: vm2OpIgnore)),
|
||||
|
||||
(opCode: CallDataSize, ## 0x36, Size of input data
|
||||
forks: Vm2OpAllForks,
|
||||
info: "Get size of input data in current environment",
|
||||
exec: (prep: vm2OpIgnore,
|
||||
run: callDataSizeOp,
|
||||
post: vm2OpIgnore)),
|
||||
|
||||
(opCode: CallDataCopy, ## 0x37, Copy input data to memory.
|
||||
forks: Vm2OpAllForks,
|
||||
info: "Copy input data in current environment to memory",
|
||||
exec: (prep: vm2OpIgnore,
|
||||
run: callDataCopyOp,
|
||||
post: vm2OpIgnore)),
|
||||
|
||||
(opCode: CodeSize, ## 0x38, Size of code
|
||||
forks: Vm2OpAllForks,
|
||||
info: "Get size of code running in current environment",
|
||||
exec: (prep: vm2OpIgnore,
|
||||
run: codeSizeOp,
|
||||
post: vm2OpIgnore)),
|
||||
|
||||
(opCode: CodeCopy, ## 0x39, Copy code to memory.
|
||||
forks: Vm2OpAllForks,
|
||||
info: "Copy code running in current environment to memory",
|
||||
exec: (prep: vm2OpIgnore,
|
||||
run: codeCopyOp,
|
||||
post: vm2OpIgnore)),
|
||||
|
||||
(opCode: GasPrice, ## 0x3a, Gas price
|
||||
forks: Vm2OpAllForks,
|
||||
info: "Get price of gas in current environment",
|
||||
exec: (prep: vm2OpIgnore,
|
||||
run: gasPriceOp,
|
||||
post: vm2OpIgnore)),
|
||||
|
||||
(opCode: ExtCodeSize, ## 0x3b, Account code size
|
||||
forks: Vm2OpAllForks,
|
||||
info: "Get size of an account's code",
|
||||
exec: (prep: vm2OpIgnore,
|
||||
run: extCodeSizeOp,
|
||||
post: vm2OpIgnore)),
|
||||
|
||||
(opCode: ExtCodeCopy, ## 0x3c, Account code copy to memory.
|
||||
forks: Vm2OpAllForks,
|
||||
info: "Copy an account's code to memory",
|
||||
exec: (prep: vm2OpIgnore,
|
||||
run: extCodeCopyOp,
|
||||
post: vm2OpIgnore)),
|
||||
|
||||
(opCode: ReturnDataSize, ## 0x3d, Previous call output data size
|
||||
forks: Vm2OpAllForks,
|
||||
info: "Get size of output data from the previous call " &
|
||||
"from the current environment",
|
||||
exec: (prep: vm2OpIgnore,
|
||||
run: returnDataSizeOp,
|
||||
post: vm2OpIgnore)),
|
||||
|
||||
(opCode: ReturnDataCopy, ## 0x3e, Previous call output data copy to memory
|
||||
forks: Vm2OpAllForks,
|
||||
info: "Copy output data from the previous call to memory",
|
||||
exec: (prep: vm2OpIgnore,
|
||||
run: returnDataCopyOp,
|
||||
post: vm2OpIgnore))]
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# End
|
||||
# ------------------------------------------------------------------------------
|
|
@ -38,6 +38,26 @@ template push(x: typed) {.dirty.} =
|
|||
## Push an expression on the computation stack
|
||||
c.stack.push x
|
||||
|
||||
proc writePaddedResult(mem: var Memory,
|
||||
data: openarray[byte],
|
||||
memPos, dataPos, len: Natural,
|
||||
paddingValue = 0.byte) =
|
||||
|
||||
mem.extend(memPos, len)
|
||||
let dataEndPosition = dataPos.int64 + len - 1
|
||||
let sourceBytes = data[min(dataPos, data.len) .. min(data.len - 1, dataEndPosition)]
|
||||
mem.write(memPos, sourceBytes)
|
||||
|
||||
# Don't duplicate zero-padding of mem.extend
|
||||
let paddingOffset = min(memPos + sourceBytes.len, mem.len)
|
||||
let numPaddingBytes = min(mem.len - paddingOffset, len - sourceBytes.len)
|
||||
if numPaddingBytes > 0:
|
||||
# TODO: avoid unnecessary memory allocation
|
||||
mem.write(paddingOffset, repeat(paddingValue, numPaddingBytes))
|
||||
|
||||
# ##################################
|
||||
# re-implemented OP handlers
|
||||
|
||||
var gdbBPHook_counter = 0
|
||||
proc gdbBPHook*() =
|
||||
gdbBPHook_counter.inc
|
||||
|
@ -57,175 +77,44 @@ template opHandler(callName: untyped; opCode: Op) =
|
|||
desc.cpt = c
|
||||
vm2OpTabBerlin[opCode].exec.run(desc)
|
||||
|
||||
# ##################################
|
||||
# 0s: Stop and Arithmetic Operations
|
||||
|
||||
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
|
||||
|
||||
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
|
||||
|
||||
opHandler sha3, Op.Sha3
|
||||
|
||||
# ##########################################
|
||||
# 30s: Environmental Information
|
||||
|
||||
proc writePaddedResult(mem: var Memory,
|
||||
data: openarray[byte],
|
||||
memPos, dataPos, len: Natural,
|
||||
paddingValue = 0.byte) =
|
||||
|
||||
mem.extend(memPos, len)
|
||||
let dataEndPosition = dataPos.int64 + len - 1
|
||||
let sourceBytes = data[min(dataPos, data.len) .. min(data.len - 1, dataEndPosition)]
|
||||
mem.write(memPos, sourceBytes)
|
||||
|
||||
# Don't duplicate zero-padding of mem.extend
|
||||
let paddingOffset = min(memPos + sourceBytes.len, mem.len)
|
||||
let numPaddingBytes = min(mem.len - paddingOffset, len - sourceBytes.len)
|
||||
if numPaddingBytes > 0:
|
||||
# TODO: avoid unnecessary memory allocation
|
||||
mem.write(paddingOffset, repeat(paddingValue, numPaddingBytes))
|
||||
|
||||
op address, inline = true:
|
||||
## 0x30, Get address of currently executing account.
|
||||
push: c.msg.contractAddress
|
||||
|
||||
op balance, inline = true:
|
||||
## 0x31, Get balance of the given account.
|
||||
let address = c.stack.popAddress()
|
||||
push: c.getBalance(address)
|
||||
|
||||
op origin, inline = true:
|
||||
## 0x32, Get execution origination address.
|
||||
push: c.getOrigin()
|
||||
|
||||
op caller, inline = true:
|
||||
## 0x33, Get caller address.
|
||||
push: c.msg.sender
|
||||
|
||||
op callValue, inline = true:
|
||||
## 0x34, Get deposited value by the instruction/transaction
|
||||
## responsible for this execution
|
||||
push: c.msg.value
|
||||
|
||||
op callDataLoad, inline = false, startPos:
|
||||
## 0x35, Get input data of current environment
|
||||
let start = startPos.cleanMemRef
|
||||
if start >= c.msg.data.len:
|
||||
push: 0
|
||||
return
|
||||
|
||||
# If the data does not take 32 bytes, pad with zeros
|
||||
let endRange = min(c.msg.data.len - 1, start + 31)
|
||||
let presentBytes = endRange - start
|
||||
# We rely on value being initialized with 0 by default
|
||||
var value: array[32, byte]
|
||||
value[0 .. presentBytes] = c.msg.data.toOpenArray(start, endRange)
|
||||
|
||||
push: value
|
||||
|
||||
op callDataSize, inline = true:
|
||||
## 0x36, Get size of input data in current environment.
|
||||
push: c.msg.data.len.u256
|
||||
|
||||
op callDataCopy, inline = false, memStartPos, copyStartPos, size:
|
||||
## 0x37, Copy input data in current environment to memory.
|
||||
# TODO tests: https://github.com/status-im/nimbus/issues/67
|
||||
|
||||
let (memPos, copyPos, len) = (memStartPos.cleanMemRef, copyStartPos.cleanMemRef, size.cleanMemRef)
|
||||
|
||||
c.gasMeter.consumeGas(
|
||||
c.gasCosts[CallDataCopy].m_handler(c.memory.len, memPos, len),
|
||||
reason="CallDataCopy fee")
|
||||
|
||||
c.memory.writePaddedResult(c.msg.data, memPos, copyPos, len)
|
||||
|
||||
op codeSize, inline = true:
|
||||
## 0x38, Get size of code running in current environment.
|
||||
push: c.code.len
|
||||
|
||||
op codeCopy, inline = false, memStartPos, copyStartPos, size:
|
||||
## 0x39, Copy code running in current environment to memory.
|
||||
# TODO tests: https://github.com/status-im/nimbus/issues/67
|
||||
|
||||
let (memPos, copyPos, len) = (memStartPos.cleanMemRef, copyStartPos.cleanMemRef, size.cleanMemRef)
|
||||
|
||||
c.gasMeter.consumeGas(
|
||||
c.gasCosts[CodeCopy].m_handler(c.memory.len, memPos, len),
|
||||
reason="CodeCopy fee")
|
||||
|
||||
c.memory.writePaddedResult(c.code.bytes, memPos, copyPos, len)
|
||||
|
||||
op gasprice, inline = true:
|
||||
## 0x3A, Get price of gas in current environment.
|
||||
push: c.getGasPrice()
|
||||
|
||||
op extCodeSize, inline = true:
|
||||
## 0x3b, Get size of an account's code
|
||||
let address = c.stack.popAddress()
|
||||
push: c.getCodeSize(address)
|
||||
|
||||
op extCodeCopy, 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")
|
||||
|
||||
let codeBytes = c.getCode(address)
|
||||
c.memory.writePaddedResult(codeBytes, memPos, codePos, len)
|
||||
|
||||
op returnDataSize, inline = true:
|
||||
## 0x3d, Get size of output data from the previous call from the current environment.
|
||||
push: c.returnData.len
|
||||
|
||||
op returnDataCopy, inline = false, memStartPos, copyStartPos, size:
|
||||
## 0x3e, Copy output data from the previous call to memory.
|
||||
let (memPos, copyPos, len) = (memStartPos.cleanMemRef, copyStartPos.cleanMemRef, size.cleanMemRef)
|
||||
let gasCost = c.gasCosts[ReturnDataCopy].m_handler(c.memory.len, memPos, len)
|
||||
c.gasMeter.consumeGas(
|
||||
gasCost,
|
||||
reason="returnDataCopy fee")
|
||||
|
||||
if copyPos + len > c.returnData.len:
|
||||
# TODO Geth additionally checks copyPos + len < 64
|
||||
# Parity uses a saturating addition
|
||||
# Yellow paper mentions μs[1] + i are not subject to the 2^256 modulo.
|
||||
raise newException(OutOfBoundsRead,
|
||||
"Return data length is not sufficient to satisfy request. Asked \n" &
|
||||
&"for data from index {copyStartPos} to {copyStartPos + size}. Return data is {c.returnData.len} in \n" &
|
||||
"length")
|
||||
|
||||
c.memory.writePaddedResult(c.returnData, memPos, copyPos, len)
|
||||
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
|
||||
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
|
||||
opHandler sha3, Op.Sha3
|
||||
opHandler address, Op.Address
|
||||
opHandler balance, Op.Balance
|
||||
opHandler origin, Op.Origin
|
||||
opHandler caller, Op.Caller
|
||||
opHandler callValue, Op.CallValue
|
||||
opHandler callDataLoad, Op.CallDataLoad
|
||||
opHandler callDataSize, Op.CallDataSize
|
||||
opHandler callDataCopy, Op.CallDataCopy
|
||||
opHandler codeSize, Op.CodeSize
|
||||
opHandler codeCopy, Op.CodeCopy
|
||||
opHandler gasprice, Op.GasPrice
|
||||
opHandler extCodeSize, Op.ExtCodeSize
|
||||
opHandler extCodeCopy, Op.ExtCodeCopy
|
||||
opHandler returnDataSize, Op.ReturnDataSize
|
||||
opHandler returnDataCopy, Op.ReturnDataCopy
|
||||
|
||||
# ##########################################
|
||||
# 40s: Block Information
|
||||
|
|
Loading…
Reference in New Issue