merged contents of computations.nim int interpreter_dispatch.nim
why: only two public functions left: executeOpcodes() and execCallOrCreate() where the former one was originally in interpreter_dispatch.nim and the latter one calls this one. improves maintainability
This commit is contained in:
parent
49afac46b7
commit
a86308c079
|
@ -5,144 +5,8 @@
|
|||
# * 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.
|
||||
|
||||
when defined(evmc_enabled):
|
||||
{.fatal: "Flags \"evmc_enabled\" and \"vm2_enabled\" are mutually exclusive"}
|
||||
|
||||
import
|
||||
chronicles, strformat, macros, options,
|
||||
sets, eth/[common, keys],
|
||||
../constants,
|
||||
./compu_helper,
|
||||
./interpreter/forks_list,
|
||||
./interpreter_dispatch,
|
||||
./message, ./types, ./state,
|
||||
../db/accounts_cache,
|
||||
./precompiles
|
||||
./interpreter_dispatch
|
||||
|
||||
logScope:
|
||||
topics = "vm computation"
|
||||
|
||||
const
|
||||
ripemdAddr = block:
|
||||
proc initAddress(x: int): EthAddress {.compileTime.} =
|
||||
result[19] = x.byte
|
||||
initAddress(3)
|
||||
|
||||
|
||||
proc beforeExecCall(c: Computation) =
|
||||
c.snapshot()
|
||||
if c.msg.kind == evmcCall:
|
||||
c.vmState.mutateStateDb:
|
||||
db.subBalance(c.msg.sender, c.msg.value)
|
||||
db.addBalance(c.msg.contractAddress, c.msg.value)
|
||||
|
||||
proc afterExecCall(c: Computation) =
|
||||
## Collect all of the accounts that *may* need to be deleted based on EIP161
|
||||
## https://github.com/ethereum/EIPs/blob/master/EIPS/eip-161.md
|
||||
## also see: https://github.com/ethereum/EIPs/issues/716
|
||||
|
||||
if c.isError or c.fork >= FKByzantium:
|
||||
if c.msg.contractAddress == ripemdAddr:
|
||||
# Special case to account for geth+parity bug
|
||||
c.vmState.touchedAccounts.incl c.msg.contractAddress
|
||||
|
||||
if c.isSuccess:
|
||||
c.commit()
|
||||
c.touchedAccounts.incl c.msg.contractAddress
|
||||
else:
|
||||
c.rollback()
|
||||
|
||||
proc beforeExecCreate(c: Computation): bool =
|
||||
c.vmState.mutateStateDB:
|
||||
db.incNonce(c.msg.sender)
|
||||
|
||||
# We add this to the access list _before_ taking a snapshot.
|
||||
# Even if the creation fails, the access-list change should not be rolled back
|
||||
# EIP2929
|
||||
if c.fork >= FkBerlin:
|
||||
db.accessList(c.msg.contractAddress)
|
||||
|
||||
c.snapshot()
|
||||
|
||||
if c.vmState.readOnlyStateDb().hasCodeOrNonce(c.msg.contractAddress):
|
||||
c.setError("Address collision when creating contract address={c.msg.contractAddress.toHex}", true)
|
||||
c.rollback()
|
||||
return true
|
||||
|
||||
c.vmState.mutateStateDb:
|
||||
db.subBalance(c.msg.sender, c.msg.value)
|
||||
db.addBalance(c.msg.contractAddress, c.msg.value)
|
||||
db.clearStorage(c.msg.contractAddress)
|
||||
if c.fork >= FkSpurious:
|
||||
# EIP161 nonce incrementation
|
||||
db.incNonce(c.msg.contractAddress)
|
||||
|
||||
return false
|
||||
|
||||
proc afterExecCreate(c: Computation) =
|
||||
if c.isSuccess:
|
||||
let fork = c.fork
|
||||
let contractFailed = not c.writeContract(fork)
|
||||
if contractFailed and fork >= FkHomestead:
|
||||
c.setError(&"writeContract failed, depth={c.msg.depth}", true)
|
||||
|
||||
if c.isSuccess:
|
||||
c.commit()
|
||||
else:
|
||||
c.rollback()
|
||||
|
||||
proc beforeExec(c: Computation): bool =
|
||||
if not c.msg.isCreate:
|
||||
c.beforeExecCall()
|
||||
false
|
||||
else:
|
||||
c.beforeExecCreate()
|
||||
|
||||
proc afterExec(c: Computation) =
|
||||
if not c.msg.isCreate:
|
||||
c.afterExecCall()
|
||||
else:
|
||||
c.afterExecCreate()
|
||||
|
||||
proc executeOpcodes*(c: Computation) =
|
||||
let fork = c.fork
|
||||
|
||||
block:
|
||||
if not c.continuation.isNil:
|
||||
c.continuation = nil
|
||||
elif c.execPrecompiles(fork):
|
||||
break
|
||||
|
||||
try:
|
||||
c.selectVM(fork)
|
||||
except CatchableError as e:
|
||||
c.setError(
|
||||
&"Opcode Dispatch Error msg={e.msg}, depth={c.msg.depth}", true)
|
||||
|
||||
if c.isError() and c.continuation.isNil:
|
||||
if c.tracingEnabled: c.traceError()
|
||||
debug "executeOpcodes error", msg=c.error.info
|
||||
|
||||
|
||||
proc execCallOrCreate*(cParam: Computation) =
|
||||
var (c, before) = (cParam, true)
|
||||
defer:
|
||||
while not c.isNil:
|
||||
c.dispose()
|
||||
c = c.parent
|
||||
|
||||
# No actual recursion, but simulate recursion including before/after/dispose.
|
||||
while true:
|
||||
while true:
|
||||
if before and c.beforeExec():
|
||||
break
|
||||
c.executeOpcodes()
|
||||
if c.continuation.isNil:
|
||||
c.afterExec()
|
||||
break
|
||||
(before, c.child, c, c.parent) = (true, nil.Computation, c.child, c)
|
||||
if c.parent.isNil:
|
||||
break
|
||||
c.dispose()
|
||||
(before, c.parent, c) = (false, nil.Computation, c.parent)
|
||||
(c.continuation)()
|
||||
export
|
||||
interpreter_dispatch
|
||||
|
|
|
@ -9,25 +9,42 @@
|
|||
# according to those terms.
|
||||
|
||||
const
|
||||
# help with low memory when compiling
|
||||
# help with low memory when compiling selectVM() function
|
||||
lowmem {.intdefine.}: int = 0
|
||||
lowMemoryCompileTime {.used.} = lowmem > 0
|
||||
|
||||
import
|
||||
../constants,
|
||||
../db/accounts_cache,
|
||||
./code_stream,
|
||||
./compu_helper,
|
||||
./interpreter/op_dispatcher,
|
||||
./message,
|
||||
./precompiles,
|
||||
./state,
|
||||
./types,
|
||||
chronicles
|
||||
chronicles,
|
||||
eth/[common, keys],
|
||||
macros,
|
||||
options,
|
||||
sets,
|
||||
stew/byteutils,
|
||||
strformat
|
||||
|
||||
logScope:
|
||||
topics = "vm opcode"
|
||||
|
||||
const
|
||||
ripemdAddr = block:
|
||||
proc initAddress(x: int): EthAddress {.compileTime.} =
|
||||
result[19] = x.byte
|
||||
initAddress(3)
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# Public functions
|
||||
# Private functions
|
||||
# ------------------------------------------------------------------------------
|
||||
|
||||
proc selectVM*(c: Computation, fork: Fork) {.gcsafe.} =
|
||||
proc selectVM(c: Computation, fork: Fork) {.gcsafe.} =
|
||||
## Op code execution handler main loop.
|
||||
var desc: Vm2Ctx
|
||||
desc.cpt = c
|
||||
|
@ -87,6 +104,132 @@ proc selectVM*(c: Computation, fork: Fork) {.gcsafe.} =
|
|||
|
||||
genLowMemDispatcher(fork, c.instr, desc)
|
||||
|
||||
|
||||
proc beforeExecCall(c: Computation) =
|
||||
c.snapshot()
|
||||
if c.msg.kind == evmcCall:
|
||||
c.vmState.mutateStateDb:
|
||||
db.subBalance(c.msg.sender, c.msg.value)
|
||||
db.addBalance(c.msg.contractAddress, c.msg.value)
|
||||
|
||||
proc afterExecCall(c: Computation) =
|
||||
## Collect all of the accounts that *may* need to be deleted based on EIP161
|
||||
## https://github.com/ethereum/EIPs/blob/master/EIPS/eip-161.md
|
||||
## also see: https://github.com/ethereum/EIPs/issues/716
|
||||
|
||||
if c.isError or c.fork >= FKByzantium:
|
||||
if c.msg.contractAddress == ripemdAddr:
|
||||
# Special case to account for geth+parity bug
|
||||
c.vmState.touchedAccounts.incl c.msg.contractAddress
|
||||
|
||||
if c.isSuccess:
|
||||
c.commit()
|
||||
c.touchedAccounts.incl c.msg.contractAddress
|
||||
else:
|
||||
c.rollback()
|
||||
|
||||
|
||||
proc beforeExecCreate(c: Computation): bool =
|
||||
c.vmState.mutateStateDB:
|
||||
db.incNonce(c.msg.sender)
|
||||
|
||||
# We add this to the access list _before_ taking a snapshot.
|
||||
# Even if the creation fails, the access-list change should not be rolled
|
||||
# back EIP2929
|
||||
if c.fork >= FkBerlin:
|
||||
db.accessList(c.msg.contractAddress)
|
||||
|
||||
c.snapshot()
|
||||
|
||||
if c.vmState.readOnlyStateDb().hasCodeOrNonce(c.msg.contractAddress):
|
||||
var blurb =c.msg.contractAddress.toHex
|
||||
c.setError("Address collision when creating contract address={blurb}", true)
|
||||
c.rollback()
|
||||
return true
|
||||
|
||||
c.vmState.mutateStateDb:
|
||||
db.subBalance(c.msg.sender, c.msg.value)
|
||||
db.addBalance(c.msg.contractAddress, c.msg.value)
|
||||
db.clearStorage(c.msg.contractAddress)
|
||||
if c.fork >= FkSpurious:
|
||||
# EIP161 nonce incrementation
|
||||
db.incNonce(c.msg.contractAddress)
|
||||
|
||||
return false
|
||||
|
||||
proc afterExecCreate(c: Computation) =
|
||||
if c.isSuccess:
|
||||
let fork = c.fork
|
||||
let contractFailed = not c.writeContract(fork)
|
||||
if contractFailed and fork >= FkHomestead:
|
||||
c.setError(&"writeContract failed, depth={c.msg.depth}", true)
|
||||
|
||||
if c.isSuccess:
|
||||
c.commit()
|
||||
else:
|
||||
c.rollback()
|
||||
|
||||
|
||||
proc beforeExec(c: Computation): bool =
|
||||
if not c.msg.isCreate:
|
||||
c.beforeExecCall()
|
||||
false
|
||||
else:
|
||||
c.beforeExecCreate()
|
||||
|
||||
proc afterExec(c: Computation) =
|
||||
if not c.msg.isCreate:
|
||||
c.afterExecCall()
|
||||
else:
|
||||
c.afterExecCreate()
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# Public functions
|
||||
# ------------------------------------------------------------------------------
|
||||
|
||||
proc executeOpcodes*(c: Computation) =
|
||||
let fork = c.fork
|
||||
|
||||
block:
|
||||
if not c.continuation.isNil:
|
||||
c.continuation = nil
|
||||
elif c.execPrecompiles(fork):
|
||||
break
|
||||
|
||||
try:
|
||||
c.selectVM(fork)
|
||||
except CatchableError as e:
|
||||
c.setError(
|
||||
&"Opcode Dispatch Error msg={e.msg}, depth={c.msg.depth}", true)
|
||||
|
||||
if c.isError() and c.continuation.isNil:
|
||||
if c.tracingEnabled: c.traceError()
|
||||
debug "executeOpcodes error", msg=c.error.info
|
||||
|
||||
|
||||
proc execCallOrCreate*(cParam: Computation) =
|
||||
var (c, before) = (cParam, true)
|
||||
defer:
|
||||
while not c.isNil:
|
||||
c.dispose()
|
||||
c = c.parent
|
||||
|
||||
# No actual recursion, but simulate recursion including before/after/dispose.
|
||||
while true:
|
||||
while true:
|
||||
if before and c.beforeExec():
|
||||
break
|
||||
c.executeOpcodes()
|
||||
if c.continuation.isNil:
|
||||
c.afterExec()
|
||||
break
|
||||
(before, c.child, c, c.parent) = (true, nil.Computation, c.child, c)
|
||||
if c.parent.isNil:
|
||||
break
|
||||
c.dispose()
|
||||
(before, c.parent, c) = (false, nil.Computation, c.parent)
|
||||
(c.continuation)()
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# End
|
||||
# ------------------------------------------------------------------------------
|
||||
|
|
Loading…
Reference in New Issue