update handler prototype using call-by-reference argument

why:
  this allows for passing back information which can eventually be
  used for reducing use of exceptions

caveat:
  call/create currently needs to un-capture the call-by-reference
  (wrapper) argument using the Computation reference inside
This commit is contained in:
Jordan Hrycaj 2021-04-20 13:07:01 +01:00 committed by zah
parent 06b34a4a56
commit 9b70ab5f8f
16 changed files with 167 additions and 151 deletions

View File

@ -107,7 +107,7 @@ const
rc[fork][op].run = tab[op].exec.run
rc
proc opHandlersRun*(fork: Fork; op: Op; d: Vm2Ctx) {.inline.} =
proc opHandlersRun*(fork: Fork; op: Op; d: var Vm2Ctx) {.inline.} =
## Given a particular `fork` and an `op`-code, run the associated handler
vmOpHandlers[fork][op].run(d)

View File

@ -76,25 +76,25 @@ else:
# ------------------------------------------------------------------------------
const
addOp: Vm2OpFn = proc (k: Vm2Ctx) =
addOp: Vm2OpFn = proc (k: var Vm2Ctx) =
## 0x01, Addition
let (lhs, rhs) = k.cpt.stack.popInt(2)
k.cpt.stack.push:
lhs + rhs
mulOp: Vm2OpFn = proc(k: Vm2Ctx) =
mulOp: Vm2OpFn = proc(k: var Vm2Ctx) =
## 0x02, Multiplication
let (lhs, rhs) = k.cpt.stack.popInt(2)
k.cpt.stack.push:
lhs * rhs
subOp: Vm2OpFn = proc(k: Vm2Ctx) =
subOp: Vm2OpFn = proc(k: var Vm2Ctx) =
## 0x03, Substraction
let (lhs, rhs) = k.cpt.stack.popInt(2)
k.cpt.stack.push:
lhs - rhs
divideOp: Vm2OpFn = proc(k: Vm2Ctx) =
divideOp: Vm2OpFn = proc(k: var Vm2Ctx) =
## 0x04, Division
let (lhs, rhs) = k.cpt.stack.popInt(2)
k.cpt.stack.push:
@ -105,7 +105,7 @@ const
lhs div rhs
sdivOp: Vm2OpFn = proc(k: Vm2Ctx) =
sdivOp: Vm2OpFn = proc(k: var Vm2Ctx) =
## 0x05, Signed division
let (lhs, rhs) = k.cpt.stack.popInt(2)
@ -121,7 +121,7 @@ const
k.cpt.stack.push(r)
moduloOp: Vm2OpFn = proc(k: Vm2Ctx) =
moduloOp: Vm2OpFn = proc(k: var Vm2Ctx) =
## 0x06, Modulo
let (lhs, rhs) = k.cpt.stack.popInt(2)
k.cpt.stack.push:
@ -131,7 +131,7 @@ const
lhs mod rhs
smodOp: Vm2OpFn = proc(k: Vm2Ctx) =
smodOp: Vm2OpFn = proc(k: var Vm2Ctx) =
## 0x07, Signed modulo
let (lhs, rhs) = k.cpt.stack.popInt(2)
@ -147,7 +147,7 @@ const
k.cpt.stack.push(r)
addmodOp: Vm2OpFn = proc(k: Vm2Ctx) =
addmodOp: Vm2OpFn = proc(k: var Vm2Ctx) =
## 0x08, Modulo addition
## Intermediate computations do not roll over at 2^256
let (lhs, rhs, modulus) = k.cpt.stack.popInt(3)
@ -159,7 +159,7 @@ const
addmod(lhs, rhs, modulus)
mulmodOp: Vm2OpFn = proc(k: Vm2Ctx) =
mulmodOp: Vm2OpFn = proc(k: var Vm2Ctx) =
## 0x09, Modulo multiplication
## Intermediate computations do not roll over at 2^256
let (lhs, rhs, modulus) = k.cpt.stack.popInt(3)
@ -171,7 +171,7 @@ const
mulmod(lhs, rhs, modulus)
expOp: Vm2OpFn = proc(k: Vm2Ctx) =
expOp: Vm2OpFn = proc(k: var Vm2Ctx) =
## 0x0A, Exponentiation
let (base, exponent) = k.cpt.stack.popInt(2)
@ -191,7 +191,7 @@ const
zero(UInt256)
signExtendOp: Vm2OpFn = proc(k: Vm2Ctx) =
signExtendOp: Vm2OpFn = proc(k: var Vm2Ctx) =
## 0x0B, Sign extend
## Extend length of twos complement signed integer.
let (bits, value) = k.cpt.stack.popInt(2)
@ -213,67 +213,67 @@ const
res
ltOp: Vm2OpFn = proc(k: Vm2Ctx) =
ltOp: Vm2OpFn = proc(k: var Vm2Ctx) =
## 0x10, Less-than comparison
let (lhs, rhs) = k.cpt.stack.popInt(2)
k.cpt.stack.push:
(lhs < rhs).uint.u256
gtOp: Vm2OpFn = proc(k: Vm2Ctx) =
gtOp: Vm2OpFn = proc(k: var Vm2Ctx) =
## 0x11, Greater-than comparison
let (lhs, rhs) = k.cpt.stack.popInt(2)
k.cpt.stack.push:
(lhs > rhs).uint.u256
sltOp: Vm2OpFn = proc(k: Vm2Ctx) =
sltOp: Vm2OpFn = proc(k: var Vm2Ctx) =
## 0x12, Signed less-than comparison
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) =
sgtOp: Vm2OpFn = proc(k: var Vm2Ctx) =
## 0x14, Signed greater-than comparison
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) =
eqOp: Vm2OpFn = proc(k: var Vm2Ctx) =
## 0x14, Signed greater-than comparison
let (lhs, rhs) = k.cpt.stack.popInt(2)
k.cpt.stack.push:
(lhs == rhs).uint.u256
isZeroOp: Vm2OpFn = proc(k: Vm2Ctx) =
isZeroOp: Vm2OpFn = proc(k: var Vm2Ctx) =
## 0x15, Check if zero
let (value) = k.cpt.stack.popInt(1)
k.cpt.stack.push:
value.isZero.uint.u256
andOp: Vm2OpFn = proc(k: Vm2Ctx) =
andOp: Vm2OpFn = proc(k: var Vm2Ctx) =
## 0x16, Bitwise AND
let (lhs, rhs) = k.cpt.stack.popInt(2)
k.cpt.stack.push:
lhs and rhs
orOp: Vm2OpFn = proc(k: Vm2Ctx) =
orOp: Vm2OpFn = proc(k: var Vm2Ctx) =
## 0x17, Bitwise OR
let (lhs, rhs) = k.cpt.stack.popInt(2)
k.cpt.stack.push:
lhs or rhs
xorOp: Vm2OpFn = proc(k: Vm2Ctx) =
xorOp: Vm2OpFn = proc(k: var Vm2Ctx) =
## 0x18, Bitwise XOR
let (lhs, rhs) = k.cpt.stack.popInt(2)
k.cpt.stack.push:
lhs xor rhs
notOp: Vm2OpFn = proc(k: Vm2Ctx) =
notOp: Vm2OpFn = proc(k: var Vm2Ctx) =
## 0x19, Check if zero
let (value) = k.cpt.stack.popInt(1)
k.cpt.stack.push:
value.not
byteOp: Vm2OpFn = proc(k: Vm2Ctx) =
byteOp: Vm2OpFn = proc(k: var Vm2Ctx) =
## 0x20, Retrieve single byte from word.
let (position, value) = k.cpt.stack.popInt(2)
let pos = position.truncate(int)
@ -288,7 +288,7 @@ const
# Constantinople's new opcodes
shlOp: Vm2OpFn = proc(k: Vm2Ctx) =
shlOp: Vm2OpFn = proc(k: var Vm2Ctx) =
let (shift, num) = k.cpt.stack.popInt(2)
let shiftLen = shift.safeInt
if shiftLen >= 256:
@ -298,7 +298,7 @@ const
k.cpt.stack.push:
num shl shiftLen
shrOp: Vm2OpFn = proc(k: Vm2Ctx) =
shrOp: Vm2OpFn = proc(k: var Vm2Ctx) =
let (shift, num) = k.cpt.stack.popInt(2)
let shiftLen = shift.safeInt
if shiftLen >= 256:
@ -309,7 +309,7 @@ const
k.cpt.stack.push:
num shr shiftLen
sarOp: Vm2OpFn = proc(k: Vm2Ctx) =
sarOp: Vm2OpFn = proc(k: var Vm2Ctx) =
let shiftLen = k.cpt.stack.popInt().safeInt
let num = cast[Int256](k.cpt.stack.popInt())
if shiftLen >= 256:

View File

@ -65,43 +65,43 @@ else:
# ------------------------------------------------------------------------------
const
blockhashOp: Vm2OpFn = proc (k: Vm2Ctx) =
blockhashOp: Vm2OpFn = proc (k: var Vm2Ctx) =
## 0x40, Get the hash of one of the 256 most recent complete blocks.
let (blockNumber) = k.cpt.stack.popInt(1)
k.cpt.stack.push:
k.cpt.getBlockHash(blockNumber)
coinBaseOp: Vm2OpFn = proc (k: Vm2Ctx) =
coinBaseOp: Vm2OpFn = proc (k: var Vm2Ctx) =
## 0x41, Get the block's beneficiary address.
k.cpt.stack.push:
k.cpt.getCoinbase
timestampOp: Vm2OpFn = proc (k: Vm2Ctx) =
timestampOp: Vm2OpFn = proc (k: var Vm2Ctx) =
## 0x42, Get the block's timestamp.
k.cpt.stack.push:
k.cpt.getTimestamp
blocknumberOp: Vm2OpFn = proc (k: Vm2Ctx) =
blocknumberOp: Vm2OpFn = proc (k: var Vm2Ctx) =
## 0x43, Get the block's number.
k.cpt.stack.push:
k.cpt.getBlockNumber
difficultyOp: Vm2OpFn = proc (k: Vm2Ctx) =
difficultyOp: Vm2OpFn = proc (k: var Vm2Ctx) =
## 0x44, Get the block's difficulty
k.cpt.stack.push:
k.cpt.getDifficulty
gasLimitOp: Vm2OpFn = proc (k: Vm2Ctx) =
gasLimitOp: Vm2OpFn = proc (k: var Vm2Ctx) =
## 0x45, Get the block's gas limit
k.cpt.stack.push:
k.cpt.getGasLimit
chainIdOp: Vm2OpFn = proc (k: Vm2Ctx) =
chainIdOp: Vm2OpFn = proc (k: var Vm2Ctx) =
## 0x46, Get current chains EIP-155 unique identifier.
k.cpt.stack.push:
k.cpt.getChainId
selfBalanceOp: Vm2OpFn = proc (k: Vm2Ctx) =
selfBalanceOp: Vm2OpFn = proc (k: var Vm2Ctx) =
## 0x47, Get current contract's balance.
k.cpt.stack.push:
k.cpt.getBalance(k.cpt.msg.contractAddress)

View File

@ -225,7 +225,7 @@ proc staticCallParams(c: Computation): LocalParams =
# ------------------------------------------------------------------------------
const
callOp: Vm2OpFn = proc(k: Vm2Ctx) =
callOp: Vm2OpFn = proc(k: var Vm2Ctx) =
## 0xf1, Message-Call into an account
if emvcStatic == k.cpt.msg.flags and k.cpt.stack[^3, UInt256] > 0.u256:
@ -288,24 +288,27 @@ const
data: k.cpt.memory.read(p.memInPos, p.memInLen),
flags: p.flags)
var child = newComputation(k.cpt.vmState, msg)
k.cpt.chainTo(child):
# call -- need to un-capture k
var
c = k.cpt
child = newComputation(c.vmState, msg)
c.chainTo(child):
if not child.shouldBurnGas:
k.cpt.gasMeter.returnGas(child.gasMeter.gasRemaining)
c.gasMeter.returnGas(child.gasMeter.gasRemaining)
if child.isSuccess:
k.cpt.merge(child)
k.cpt.stack.top(1)
c.merge(child)
c.stack.top(1)
k.cpt.returnData = child.output
c.returnData = child.output
let actualOutputSize = min(p.memOutLen, child.output.len)
if actualOutputSize > 0:
k.cpt.memory.write(p.memOutPos,
child.output.toOpenArray(0, actualOutputSize - 1))
c.memory.write(p.memOutPos,
child.output.toOpenArray(0, actualOutputSize - 1))
# ---------------------
callCodeOp: Vm2OpFn = proc(k: Vm2Ctx) =
callCodeOp: Vm2OpFn = proc(k: var Vm2Ctx) =
## 0xf2, Message-call into this account with an alternative account's code.
let
p = k.cpt.callCodeParams
@ -366,24 +369,27 @@ const
data: k.cpt.memory.read(p.memInPos, p.memInLen),
flags: p.flags)
var child = newComputation(k.cpt.vmState, msg)
k.cpt.chainTo(child):
# call -- need to un-capture k
var
c = k.cpt
child = newComputation(c.vmState, msg)
c.chainTo(child):
if not child.shouldBurnGas:
k.cpt.gasMeter.returnGas(child.gasMeter.gasRemaining)
c.gasMeter.returnGas(child.gasMeter.gasRemaining)
if child.isSuccess:
k.cpt.merge(child)
k.cpt.stack.top(1)
c.merge(child)
c.stack.top(1)
k.cpt.returnData = child.output
c.returnData = child.output
let actualOutputSize = min(p.memOutLen, child.output.len)
if actualOutputSize > 0:
k.cpt.memory.write(p.memOutPos,
child.output.toOpenArray(0, actualOutputSize - 1))
c.memory.write(p.memOutPos,
child.output.toOpenArray(0, actualOutputSize - 1))
# ---------------------
delegateCallOp: Vm2OpFn = proc(k: Vm2Ctx) =
delegateCallOp: Vm2OpFn = proc(k: var Vm2Ctx) =
## 0xf4, Message-call into this account with an alternative account's
## code, but persisting the current values for sender and value.
let
@ -433,24 +439,27 @@ const
data: k.cpt.memory.read(p.memInPos, p.memInLen),
flags: p.flags)
var child = newComputation(k.cpt.vmState, msg)
k.cpt.chainTo(child):
# call -- need to un-capture k
var
c = k.cpt
child = newComputation(c.vmState, msg)
c.chainTo(child):
if not child.shouldBurnGas:
k.cpt.gasMeter.returnGas(child.gasMeter.gasRemaining)
c.gasMeter.returnGas(child.gasMeter.gasRemaining)
if child.isSuccess:
k.cpt.merge(child)
k.cpt.stack.top(1)
c.merge(child)
c.stack.top(1)
k.cpt.returnData = child.output
c.returnData = child.output
let actualOutputSize = min(p.memOutLen, child.output.len)
if actualOutputSize > 0:
k.cpt.memory.write(p.memOutPos,
child.output.toOpenArray(0, actualOutputSize - 1))
c.memory.write(p.memOutPos,
child.output.toOpenArray(0, actualOutputSize - 1))
# ---------------------
staticCallOp: Vm2OpFn = proc(k: Vm2Ctx) =
staticCallOp: Vm2OpFn = proc(k: var Vm2Ctx) =
## 0xfa, Static message-call into an account.
let
@ -505,20 +514,23 @@ const
data: k.cpt.memory.read(p.memInPos, p.memInLen),
flags: p.flags)
var child = newComputation(k.cpt.vmState, msg)
k.cpt.chainTo(child):
# call -- need to un-capture k
var
c = k.cpt
child = newComputation(c.vmState, msg)
c.chainTo(child):
if not child.shouldBurnGas:
k.cpt.gasMeter.returnGas(child.gasMeter.gasRemaining)
c.gasMeter.returnGas(child.gasMeter.gasRemaining)
if child.isSuccess:
k.cpt.merge(child)
k.cpt.stack.top(1)
c.merge(child)
c.stack.top(1)
k.cpt.returnData = child.output
c.returnData = child.output
let actualOutputSize = min(p.memOutLen, child.output.len)
if actualOutputSize > 0:
k.cpt.memory.write(p.memOutPos,
child.output.toOpenArray(0, actualOutputSize - 1))
c.memory.write(p.memOutPos,
child.output.toOpenArray(0, actualOutputSize - 1))
# ------------------------------------------------------------------------------
# Public, op exec table entries

View File

@ -97,7 +97,7 @@ else:
# ------------------------------------------------------------------------------
const
createOp: Vm2OpFn = proc(k: Vm2Ctx) =
createOp: Vm2OpFn = proc(k: var Vm2Ctx) =
## 0xf0, Create a new account with associated code
checkInStaticContext(k.cpt)
@ -150,20 +150,23 @@ const
value: endowment,
data: k.cpt.memory.read(memPos, memLen))
var child = newComputation(k.cpt.vmState, childMsg, salt)
k.cpt.chainTo(child):
# call -- need to un-capture k
var
c = k.cpt
child = newComputation(c.vmState, childMsg, salt)
c.chainTo(child):
if not child.shouldBurnGas:
k.cpt.gasMeter.returnGas(child.gasMeter.gasRemaining)
c.gasMeter.returnGas(child.gasMeter.gasRemaining)
if child.isSuccess:
k.cpt.merge(child)
k.cpt.stack.top child.msg.contractAddress
c.merge(child)
c.stack.top child.msg.contractAddress
else:
k.cpt.returnData = child.output
c.returnData = child.output
# ---------------------
create2Op: Vm2OpFn = proc(k: Vm2Ctx) =
create2Op: Vm2OpFn = proc(k: var Vm2Ctx) =
## 0xf5, Behaves identically to CREATE, except using keccak256
checkInStaticContext(k.cpt)
@ -218,16 +221,19 @@ const
value: endowment,
data: k.cpt.memory.read(memPos, memLen))
var child = newComputation(k.cpt.vmState, childMsg, salt)
k.cpt.chainTo(child):
# call -- need to un-capture k
var
c = k.cpt
child = newComputation(c.vmState, childMsg, salt)
c.chainTo(child):
if not child.shouldBurnGas:
k.cpt.gasMeter.returnGas(child.gasMeter.gasRemaining)
c.gasMeter.returnGas(child.gasMeter.gasRemaining)
if child.isSuccess:
k.cpt.merge(child)
k.cpt.stack.top child.msg.contractAddress
c.merge(child)
c.stack.top child.msg.contractAddress
else:
k.cpt.returnData = child.output
c.returnData = child.output
# ------------------------------------------------------------------------------
# Public, op exec table entries

View File

@ -85,13 +85,13 @@ export
Op, Fork, Computation, Memory, Stack, UInt256, Message, EthAddress
type
Vm2Ctx* = object of RootObj
cpt*: Computation ## computation text
rc*: int ## return code from op handler
Vm2Ctx* = tuple
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.}
proc(k: var Vm2Ctx) {.gcsafe.}
Vm2OpHanders* = tuple ## three step op code execution, typically
@ -114,7 +114,7 @@ type
const
vm2OpIgnore*: Vm2OpFn = ## No operation, placeholder function
proc(k: Vm2Ctx) = discard
proc(k: var Vm2Ctx) = discard
# similar to: toSeq(Fork).mapIt({it}).foldl(a+b)
Vm2OpAllForks* =

View File

@ -59,7 +59,7 @@ proc fnInfo(n: int): string {.compileTime.} =
&"Duplicate {blurb} item in the stack"
proc dupImpl(k: Vm2Ctx; n: int) =
proc dupImpl(k: var Vm2Ctx; n: int) =
k.cpt.stack.dup(n)
const

View File

@ -121,20 +121,20 @@ proc writePaddedResult(mem: var Memory,
# ------------------------------------------------------------------------------
const
addressOp: Vm2OpFn = proc (k: Vm2Ctx) =
addressOp: Vm2OpFn = proc (k: var Vm2Ctx) =
## 0x30, Get address of currently executing account.
k.cpt.stack.push:
k.cpt.msg.contractAddress
# ------------------
balanceOp: Vm2OpFn = proc (k: Vm2Ctx) =
balanceOp: Vm2OpFn = proc (k: var Vm2Ctx) =
## 0x31, Get balance of the given account.
let address = k.cpt.stack.popAddress
k.cpt.stack.push:
k.cpt.getBalance(address)
balanceEIP2929Op: Vm2OpFn = proc (k: Vm2Ctx) =
balanceEIP2929Op: Vm2OpFn = proc (k: var Vm2Ctx) =
## 0x31, EIP292: Get balance of the given account for Berlin and later
let address = k.cpt.stack.popAddress()
@ -145,23 +145,23 @@ const
# ------------------
originOp: Vm2OpFn = proc (k: Vm2Ctx) =
originOp: Vm2OpFn = proc (k: var Vm2Ctx) =
## 0x32, Get execution origination address.
k.cpt.stack.push:
k.cpt.getOrigin()
callerOp: Vm2OpFn = proc (k: Vm2Ctx) =
callerOp: Vm2OpFn = proc (k: var Vm2Ctx) =
## 0x33, Get caller address.
k.cpt.stack.push:
k.cpt.msg.sender
callValueOp: Vm2OpFn = proc (k: Vm2Ctx) =
callValueOp: Vm2OpFn = proc (k: var 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) =
callDataLoadOp: Vm2OpFn = proc (k: var Vm2Ctx) =
## 0x35, Get input data of current environment
let (startPos) = k.cpt.stack.popInt(1)
let start = startPos.cleanMemRef
@ -181,13 +181,13 @@ const
value
callDataSizeOp: Vm2OpFn = proc (k: Vm2Ctx) =
callDataSizeOp: Vm2OpFn = proc (k: var 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) =
callDataCopyOp: Vm2OpFn = proc (k: var Vm2Ctx) =
## 0x37, Copy input data in current environment to memory.
let (memStartPos, copyStartPos, size) = k.cpt.stack.popInt(3)
@ -202,13 +202,13 @@ const
k.cpt.memory.writePaddedResult(k.cpt.msg.data, memPos, copyPos, len)
codeSizeOp: Vm2OpFn = proc (k: Vm2Ctx) =
codeSizeOp: Vm2OpFn = proc (k: var Vm2Ctx) =
## 0x38, Get size of code running in current environment.
k.cpt.stack.push:
k.cpt.code.len
codeCopyOp: Vm2OpFn = proc (k: Vm2Ctx) =
codeCopyOp: Vm2OpFn = proc (k: var Vm2Ctx) =
## 0x39, Copy code running in current environment to memory.
let (memStartPos, copyStartPos, size) = k.cpt.stack.popInt(3)
@ -223,20 +223,20 @@ const
k.cpt.memory.writePaddedResult(k.cpt.code.bytes, memPos, copyPos, len)
gasPriceOp: Vm2OpFn = proc (k: Vm2Ctx) =
gasPriceOp: Vm2OpFn = proc (k: var Vm2Ctx) =
## 0x3A, Get price of gas in current environment.
k.cpt.stack.push:
k.cpt.getGasPrice()
# -----------
extCodeSizeOp: Vm2OpFn = proc (k: Vm2Ctx) =
extCodeSizeOp: Vm2OpFn = proc (k: var Vm2Ctx) =
## 0x3b, Get size of an account's code
let address = k.cpt.stack.popAddress()
k.cpt.stack.push:
k.cpt.getCodeSize(address)
extCodeSizeEIP2929Op: Vm2OpFn = proc (k: Vm2Ctx) =
extCodeSizeEIP2929Op: Vm2OpFn = proc (k: var Vm2Ctx) =
## 0x3b, Get size of an account's code
let address = k.cpt.stack.popAddress()
@ -247,7 +247,7 @@ const
# -----------
extCodeCopyOp: Vm2OpFn = proc (k: Vm2Ctx) =
extCodeCopyOp: Vm2OpFn = proc (k: var Vm2Ctx) =
## 0x3c, Copy an account's code to memory.
let address = k.cpt.stack.popAddress()
@ -263,7 +263,7 @@ const
k.cpt.memory.writePaddedResult(codeBytes, memPos, codePos, len)
extCodeCopyEIP2929Op: Vm2OpFn = proc (k: Vm2Ctx) =
extCodeCopyEIP2929Op: Vm2OpFn = proc (k: var Vm2Ctx) =
## 0x3c, Copy an account's code to memory.
let address = k.cpt.stack.popAddress()
@ -282,14 +282,14 @@ const
# -----------
returnDataSizeOp: Vm2OpFn = proc (k: Vm2Ctx) =
returnDataSizeOp: Vm2OpFn = proc (k: var 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) =
returnDataCopyOp: Vm2OpFn = proc (k: var Vm2Ctx) =
## 0x3e, Copy output data from the previous call to memory.
let (memStartPos, copyStartPos, size) = k.cpt.stack.popInt(3)
@ -311,13 +311,13 @@ const
# ---------------
extCodeHashOp: Vm2OpFn = proc (k: Vm2Ctx) =
extCodeHashOp: Vm2OpFn = proc (k: var Vm2Ctx) =
## 0x3f, Returns the keccak256 hash of a contracts code
let address = k.cpt.stack.popAddress()
k.cpt.stack.push:
k.cpt.getCodeHash(address)
extCodeHashEIP2929Op: Vm2OpFn = proc (k: Vm2Ctx) =
extCodeHashEIP2929Op: Vm2OpFn = proc (k: var Vm2Ctx) =
## 0x3f, EIP2929: Returns the keccak256 hash of a contracts code
let address = k.cpt.stack.popAddress()

View File

@ -85,7 +85,7 @@ else:
# ------------------------------------------------------------------------------
const
sha3Op: Vm2OpFn = proc (k: Vm2Ctx) =
sha3Op: Vm2OpFn = proc (k: var Vm2Ctx) =
## 0x20, Compute Keccak-256 hash.
let (startPos, length) = k.cpt.stack.popInt(2)

View File

@ -25,7 +25,7 @@ import
type
OphNumToTextFn* = proc(n: int): string
OpHanldlerImplFn* = proc(k: Vm2Ctx; n: int)
OpHanldlerImplFn* = proc(k: var Vm2Ctx; n: int)
const
recForkSet = "Vm2OpAllForks"
@ -114,7 +114,7 @@ macro genOphHandlers*(runHandler: static[OphNumToTextFn];
body: static[OpHanldlerImplFn]): untyped =
## Generate the equivalent of
## ::
## const <runHandler>: Vm2OpFn = proc (k: Vm2Ctx) =
## const <runHandler>: Vm2OpFn = proc (k: var Vm2Ctx) =
## ## <itemInfo(n)>,
## <body(k,n)>
##
@ -127,9 +127,9 @@ macro genOphHandlers*(runHandler: static[OphNumToTextFn];
fnName = ident(n.runHandler)
comment = newCommentStmtNode(n.itemInfo)
# => push##Op: Vm2OpFn = proc (k: Vm2Ctx) = ...
# => push##Op: Vm2OpFn = proc (k: var Vm2Ctx) = ...
result.add quote do:
const `fnName`: Vm2OpFn = proc(k: Vm2Ctx) =
const `fnName`: Vm2OpFn = proc(k: var Vm2Ctx) =
`comment`
`body`(k,`n`)
# echo ">>>", result.repr

View File

@ -134,7 +134,7 @@ const
# Private, op handlers implementation
# ------------------------------------------------------------------------------
proc wrapperFn(k: Vm2Ctx; n: int) =
proc wrapperFn(k: var Vm2Ctx; n: int) =
logImpl(k.cpt, logOpArg[n], n)
genOphHandlers fnName, fnInfo, inxRange, wrapperFn

View File

@ -163,11 +163,11 @@ proc jumpImpl(c: Computation; jumpTarget: UInt256) =
# ------------------------------------------------------------------------------
const
popOp: Vm2OpFn = proc (k: Vm2Ctx) =
popOp: Vm2OpFn = proc (k: var Vm2Ctx) =
## 0x50, Remove item from stack.
discard k.cpt.stack.popInt
mloadOp: Vm2OpFn = proc (k: Vm2Ctx) =
mloadOp: Vm2OpFn = proc (k: var Vm2Ctx) =
## 0x51, Load word from memory
let (memStartPos) = k.cpt.stack.popInt(1)
@ -181,7 +181,7 @@ const
k.cpt.memory.read(memPos, 32)
mstoreOp: Vm2OpFn = proc (k: Vm2Ctx) =
mstoreOp: Vm2OpFn = proc (k: var Vm2Ctx) =
## 0x52, Save word to memory
let (memStartPos, value) = k.cpt.stack.popInt(2)
@ -194,7 +194,7 @@ const
k.cpt.memory.write(memPos, value.toByteArrayBE)
mstore8Op: Vm2OpFn = proc (k: Vm2Ctx) =
mstore8Op: Vm2OpFn = proc (k: var Vm2Ctx) =
## 0x53, Save byte to memory
let (memStartPos, value) = k.cpt.stack.popInt(2)
@ -208,13 +208,13 @@ const
# -------
sloadOp: Vm2OpFn = proc (k: Vm2Ctx) =
sloadOp: Vm2OpFn = proc (k: var Vm2Ctx) =
## 0x54, Load word from storage.
let (slot) = k.cpt.stack.popInt(1)
k.cpt.stack.push:
k.cpt.getStorage(slot)
sloadEIP2929Op: Vm2OpFn = proc (k: Vm2Ctx) =
sloadEIP2929Op: Vm2OpFn = proc (k: var Vm2Ctx) =
## 0x54, EIP2929: Load word from storage for Berlin and later
let (slot) = k.cpt.stack.popInt(1)
@ -230,7 +230,7 @@ const
# -------
sstoreOp: Vm2OpFn = proc (k: Vm2Ctx) =
sstoreOp: Vm2OpFn = proc (k: var Vm2Ctx) =
## 0x55, Save word to storage.
let (slot, newValue) = k.cpt.stack.popInt(2)
@ -256,7 +256,7 @@ const
db.setStorage(k.cpt.msg.contractAddress, slot, newValue)
sstoreEIP1283Op: Vm2OpFn = proc (k: Vm2Ctx) =
sstoreEIP1283Op: Vm2OpFn = proc (k: var Vm2Ctx) =
## 0x55, EIP1283: sstore for Constantinople and later
let (slot, newValue) = k.cpt.stack.popInt(2)
@ -264,7 +264,7 @@ const
sstoreNetGasMeteringImpl(k.cpt, slot, newValue)
sstoreEIP2200Op: Vm2OpFn = proc (k: Vm2Ctx) =
sstoreEIP2200Op: Vm2OpFn = proc (k: var Vm2Ctx) =
## 0x55, EIP2200: sstore for Istanbul and later
let (slot, newValue) = k.cpt.stack.popInt(2)
@ -279,7 +279,7 @@ const
sstoreNetGasMeteringImpl(k.cpt, slot, newValue)
sstoreEIP2929Op: Vm2OpFn = proc (k: Vm2Ctx) =
sstoreEIP2929Op: Vm2OpFn = proc (k: var Vm2Ctx) =
## 0x55, EIP2929: sstore for Berlin and later
let (slot, newValue) = k.cpt.stack.popInt(2)
checkInStaticContext(k.cpt)
@ -299,47 +299,47 @@ const
# -------
jumpOp: Vm2OpFn = proc (k: Vm2Ctx) =
jumpOp: Vm2OpFn = proc (k: var Vm2Ctx) =
## 0x56, Alter the program counter
let (jumpTarget) = k.cpt.stack.popInt(1)
jumpImpl(k.cpt, jumpTarget)
jumpIOp: Vm2OpFn = proc (k: Vm2Ctx) =
jumpIOp: Vm2OpFn = proc (k: var Vm2Ctx) =
## 0x57, Conditionally alter the program counter.
let (jumpTarget, testedValue) = k.cpt.stack.popInt(2)
if testedValue != 0:
jumpImpl(k.cpt, jumpTarget)
pcOp: Vm2OpFn = proc (k: Vm2Ctx) =
pcOp: Vm2OpFn = proc (k: var Vm2Ctx) =
## 0x58, Get the value of the program counter prior to the increment
## corresponding to this instruction.
k.cpt.stack.push:
max(k.cpt.code.pc - 1, 0)
msizeOp: Vm2OpFn = proc (k: Vm2Ctx) =
msizeOp: Vm2OpFn = proc (k: var Vm2Ctx) =
## 0x59, Get the size of active memory in bytes.
k.cpt.stack.push:
k.cpt.memory.len
gasOp: Vm2OpFn = proc (k: Vm2Ctx) =
gasOp: Vm2OpFn = proc (k: var Vm2Ctx) =
## 0x5a, Get the amount of available gas, including the corresponding
## reduction for the cost of this instruction.
k.cpt.stack.push:
k.cpt.gasMeter.gasRemaining
jumpDestOp: Vm2OpFn = proc (k: Vm2Ctx) =
jumpDestOp: Vm2OpFn = proc (k: var Vm2Ctx) =
## 0x5b, Mark a valid destination for jumps. This operation has no effect
## on machine state during execution.
discard
beginSubOp: Vm2OpFn = proc (k: Vm2Ctx) =
beginSubOp: Vm2OpFn = proc (k: var Vm2Ctx) =
## 0x5c, Marks the entry point to a subroutine
raise newException(
OutOfGas,
"Abort: Attempt to execute BeginSub opcode")
returnSubOp: Vm2OpFn = proc (k: Vm2Ctx) =
returnSubOp: Vm2OpFn = proc (k: var Vm2Ctx) =
## 0x5d, Returns control to the caller of a subroutine.
if k.cpt.returnStack.len == 0:
raise newException(
@ -348,7 +348,7 @@ const
k.cpt.code.pc = k.cpt.returnStack.pop()
jumpSubOp: Vm2OpFn = proc (k: Vm2Ctx) =
jumpSubOp: Vm2OpFn = proc (k: var Vm2Ctx) =
## 0x5e, Transfers control to a subroutine.
let (jumpTarget) = k.cpt.stack.popInt(1)

View File

@ -61,7 +61,7 @@ proc fnInfo(n: int): string {.compileTime.} =
&"Push {blurb} on the stack"
proc pushImpl(k: Vm2Ctx; n: int) =
proc pushImpl(k: var Vm2Ctx; n: int) =
k.cpt.stack.push:
k.cpt.code.readVmWord(n)

View File

@ -58,7 +58,7 @@ proc fnInfo(n: int): string {.compileTime.} =
&"Exchange first and {blurb} stack items"
proc swapImpl(k: Vm2Ctx; n: int) =
proc swapImpl(k: var Vm2Ctx; n: int) =
k.cpt.stack.swap(n)
const

View File

@ -105,7 +105,7 @@ else:
# ------------------------------------------------------------------------------
const
returnOp: Vm2OpFn = proc(k: Vm2Ctx) =
returnOp: Vm2OpFn = proc(k: var Vm2Ctx) =
## 0xf3, Halt execution returning output data.
let (startPos, size) = k.cpt.stack.popInt(2)
@ -117,7 +117,7 @@ const
k.cpt.output = k.cpt.memory.read(pos, len)
revertOp: Vm2OpFn = proc(k: Vm2Ctx) =
revertOp: Vm2OpFn = proc(k: var Vm2Ctx) =
## 0xfd, Halt execution reverting state changes but returning data
## and remaining gas.
let (startPos, size) = k.cpt.stack.popInt(2)
@ -133,20 +133,20 @@ const
k.cpt.setError("REVERT opcode executed", false)
invalidOp: Vm2OpFn = proc(k: Vm2Ctx) =
invalidOp: Vm2OpFn = proc(k: var Vm2Ctx) =
raise newException(InvalidInstruction,
"Invalid instruction, received an opcode " &
"not implemented in the current fork.")
# -----------
selfDestructOp: Vm2OpFn = proc(k: Vm2Ctx) =
selfDestructOp: Vm2OpFn = proc(k: var Vm2Ctx) =
## 0xff, Halt execution and register account for later deletion.
let beneficiary = k.cpt.stack.popAddress()
k.cpt.selfDestruct(beneficiary)
selfDestructEIP150Op: Vm2OpFn = proc(k: Vm2Ctx) =
selfDestructEIP150Op: Vm2OpFn = proc(k: var Vm2Ctx) =
## selfDestructEip150 (auto generated comment)
let beneficiary = k.cpt.stack.popAddress()
@ -161,7 +161,7 @@ const
k.cpt.selfDestruct(beneficiary)
selfDestructEip161Op: Vm2OpFn = proc(k: Vm2Ctx) =
selfDestructEip161Op: Vm2OpFn = proc(k: var Vm2Ctx) =
## selfDestructEip161 (auto generated comment)
checkInStaticContext(k.cpt)
@ -181,7 +181,7 @@ const
k.cpt.selfDestruct(beneficiary)
selfDestructEIP2929Op: Vm2OpFn = proc(k: Vm2Ctx) =
selfDestructEIP2929Op: Vm2OpFn = proc(k: var Vm2Ctx) =
## selfDestructEIP2929 (auto generated comment)
checkInStaticContext(k.cpt)

View File

@ -15,17 +15,14 @@ logScope:
proc selectVM(c: Computation, fork: Fork) {.gcsafe.} =
var desc: Vm2Ctx
if c.tracingEnabled:
c.prepareTracer()
while true:
c.instr = c.code.next()
var
op = c.instr
desc: Vm2Ctx
desc.cpt = c
var op = c.instr
if op == Stop:
trace "op: Stop"
@ -39,6 +36,7 @@ proc selectVM(c: Computation, fork: Fork) {.gcsafe.} =
if BaseGasCosts[op].kind == GckFixed:
c.gasMeter.consumeGas(c.gasCosts[op].cost, reason = $op)
desc.cpt = c
opHandlersRun(fork, op, desc)
if c.tracingEnabled:
@ -47,7 +45,7 @@ proc selectVM(c: Computation, fork: Fork) {.gcsafe.} =
case op
of Create, Create2, Call, CallCode, DelegateCall, StaticCall:
if not c.continuation.isNil:
return
break
of Return, Revert, SelfDestruct:
break
else: