shift functions from computation.nim => compu_helper.nim

why:
  insulate exec functions in computation.nim
This commit is contained in:
Jordan Hrycaj 2021-04-26 10:07:50 +01:00 committed by zah
parent 73900270db
commit 77518446d9
4 changed files with 224 additions and 190 deletions

View File

@ -11,7 +11,12 @@
import import
../constants, ../constants,
../db/accounts_cache, ../db/accounts_cache,
./interpreter/op_codes, ../utils,
./code_stream,
./interpreter/[forks_list, gas_meter, gas_costs, op_codes],
./memory,
./message,
./stack,
./state, ./state,
./transaction_tracer, ./transaction_tracer,
./types, ./types,
@ -26,35 +31,62 @@ logScope:
when defined(chronicles_log_level): when defined(chronicles_log_level):
import stew/byteutils import stew/byteutils
# ------------------------------------------------------------------------------
# Helpers
# ------------------------------------------------------------------------------
proc generateContractAddress(c: Computation, salt: Uint256): EthAddress =
if c.msg.kind == evmcCreate:
let creationNonce = c.vmState.readOnlyStateDb().getNonce(c.msg.sender)
result = generateAddress(c.msg.sender, creationNonce)
else:
result = generateSafeAddress(c.msg.sender, salt, c.msg.data)
# ------------------------------------------------------------------------------
# Public functions
# ------------------------------------------------------------------------------
template getCoinbase*(c: Computation): EthAddress =
c.vmState.coinbase
template getTimestamp*(c: Computation): int64 =
c.vmState.timestamp.toUnix
template getBlockNumber*(c: Computation): Uint256 =
c.vmState.blockNumber.blockNumberToVmWord
template getDifficulty*(c: Computation): DifficultyInt =
c.vmState.difficulty
template getGasLimit*(c: Computation): GasInt =
c.vmState.gasLimit
template getChainId*(c: Computation): uint =
c.vmState.chaindb.config.chainId.uint
template getOrigin*(c: Computation): EthAddress =
c.vmState.txOrigin
template getGasPrice*(c: Computation): GasInt =
c.vmState.txGasPrice
template getBlockHash*(c: Computation, blockNumber: Uint256): Hash256 =
c.vmState.getAncestorHash(blockNumber.vmWordToBlockNumber)
template accountExists*(c: Computation, address: EthAddress): bool = template accountExists*(c: Computation, address: EthAddress): bool =
if c.fork >= FkSpurious: if c.fork >= FkSpurious:
not c.vmState.readOnlyStateDB.isDeadAccount(address) not c.vmState.readOnlyStateDB.isDeadAccount(address)
else: else:
c.vmState.readOnlyStateDB.accountExists(address) c.vmState.readOnlyStateDB.accountExists(address)
proc addLogEntry*(c: Computation, log: Log) {.inline.} = template getStorage*(c: Computation, slot: Uint256): Uint256 =
c.logEntries.add(log) c.vmState.readOnlyStateDB.getStorage(c.msg.contractAddress, slot)
template fork*(c: Computation): untyped =
c.vmState.fork
template gasCosts*(c: Computation): untyped =
c.vmState.gasCosts
template getBalance*(c: Computation, address: EthAddress): Uint256 = template getBalance*(c: Computation, address: EthAddress): Uint256 =
c.vmState.readOnlyStateDB.getBalance(address) c.vmState.readOnlyStateDB.getBalance(address)
template getBlockHash*(c: Computation, blockNumber: Uint256): Hash256 = template getCodeSize*(c: Computation, address: EthAddress): uint =
c.vmState.getAncestorHash(blockNumber.vmWordToBlockNumber) uint(c.vmState.readOnlyStateDB.getCodeSize(address))
template getBlockNumber*(c: Computation): Uint256 =
c.vmState.blockNumber.blockNumberToVmWord
template getChainId*(c: Computation): uint =
c.vmState.chaindb.config.chainId.uint
template getCode*(c: Computation, address: EthAddress): seq[byte] =
c.vmState.readOnlyStateDB.getCode(address)
template getCodeHash*(c: Computation, address: EthAddress): Hash256 = template getCodeHash*(c: Computation, address: EthAddress): Hash256 =
let let
@ -64,34 +96,109 @@ template getCodeHash*(c: Computation, address: EthAddress): Hash256 =
else: else:
db.getCodeHash(address) db.getCodeHash(address)
template getCodeSize*(c: Computation, address: EthAddress): uint = template selfDestruct*(c: Computation, address: EthAddress) =
uint(c.vmState.readOnlyStateDB.getCodeSize(address)) c.execSelfDestruct(address)
template getCoinbase*(c: Computation): EthAddress = template getCode*(c: Computation, address: EthAddress): seq[byte] =
c.vmState.coinbase c.vmState.readOnlyStateDB.getCode(address)
template getDifficulty*(c: Computation): DifficultyInt = proc newComputation*(vmState: BaseVMState,
c.vmState.difficulty message: Message, salt= 0.u256): Computation =
new result
result.vmState = vmState
result.msg = message
result.memory = Memory()
result.stack = newStack()
result.returnStack = @[]
result.gasMeter.init(message.gas)
result.touchedAccounts = initHashSet[EthAddress]()
result.suicides = initHashSet[EthAddress]()
template getGasLimit*(c: Computation): GasInt = if result.msg.isCreate():
c.vmState.gasLimit result.msg.contractAddress = result.generateContractAddress(salt)
result.code = newCodeStream(message.data)
message.data = @[]
else:
result.code = newCodeStream(
vmState.readOnlyStateDb.getCode(message.codeAddress))
template getGasPrice*(c: Computation): GasInt = template gasCosts*(c: Computation): untyped =
c.vmState.txGasPrice c.vmState.gasCosts
template getOrigin*(c: Computation): EthAddress = template fork*(c: Computation): untyped =
c.vmState.txOrigin c.vmState.fork
template getStorage*(c: Computation, slot: Uint256): Uint256 = proc isOriginComputation*(c: Computation): bool =
c.vmState.readOnlyStateDB.getStorage(c.msg.contractAddress, slot) # Is this computation the computation initiated by a transaction
c.msg.sender == c.vmState.txOrigin
template getTimestamp*(c: Computation): int64 = template isSuccess*(c: Computation): bool =
c.vmState.timestamp.toUnix c.error.isNil
proc prepareTracer*(c: Computation) {.inline.} = template isError*(c: Computation): bool =
c.vmState.tracer.prepare(c.msg.depth) not c.isSuccess
proc selfDestruct*(c: Computation, beneficiary: EthAddress) = func shouldBurnGas*(c: Computation): bool =
c.isError and c.error.burnsGas
proc isSuicided*(c: Computation, address: EthAddress): bool =
result = address in c.suicides
proc snapshot*(c: Computation) =
c.savePoint = c.vmState.accountDb.beginSavePoint()
proc commit*(c: Computation) =
c.vmState.accountDb.commit(c.savePoint)
proc dispose*(c: Computation) {.inline.} =
c.vmState.accountDb.safeDispose(c.savePoint)
c.savePoint = nil
proc rollback*(c: Computation) =
c.vmState.accountDb.rollback(c.savePoint)
proc setError*(c: Computation, msg: string, burnsGas = false) {.inline.} =
c.error = Error(info: msg, burnsGas: burnsGas)
proc writeContract*(c: Computation, fork: Fork): bool {.gcsafe.} =
result = true
let contractCode = c.output
if contractCode.len == 0: return
if fork >= FkSpurious and contractCode.len >= EIP170_CODE_SIZE_LIMIT:
debug "Contract code size exceeds EIP170",
limit = EIP170_CODE_SIZE_LIMIT,
actual = contractCode.len
return false
let storageAddr = c.msg.contractAddress
if c.isSuicided(storageAddr): return
let gasParams = GasParams(kind: Create, cr_memLength: contractCode.len)
let codeCost = c.gasCosts[Create].c_handler(0.u256, gasParams).gasCost
if c.gasMeter.gasRemaining >= codeCost:
c.gasMeter.consumeGas(codeCost, reason = "Write contract code for CREATE")
c.vmState.mutateStateDb:
db.setCode(storageAddr, contractCode)
result = true
else:
if fork < FkHomestead or FkByzantium <= fork:
c.output = @[]
result = false
template chainTo*(c, toChild: Computation, after: untyped) =
c.child = toChild
c.continuation = proc() =
after
proc merge*(c, child: Computation) =
c.logEntries.add child.logEntries
c.gasMeter.refundGas(child.gasMeter.gasRefunded)
c.suicides.incl child.suicides
c.touchedAccounts.incl child.touchedAccounts
proc execSelfDestruct*(c: Computation, beneficiary: EthAddress) =
c.vmState.mutateStateDB: c.vmState.mutateStateDB:
let let
localBalance = c.getBalance(c.msg.contractAddress) localBalance = c.getBalance(c.msg.contractAddress)
@ -114,8 +221,19 @@ proc selfDestruct*(c: Computation, beneficiary: EthAddress) =
# Register the account to be deleted # Register the account to be deleted
c.suicides.incl(c.msg.contractAddress) c.suicides.incl(c.msg.contractAddress)
proc setError*(c: Computation, msg: string, burnsGas = false) {.inline.} = proc addLogEntry*(c: Computation, log: Log) {.inline.} =
c.error = Error(info: msg, burnsGas: burnsGas) c.logEntries.add(log)
proc getGasRefund*(c: Computation): GasInt =
if c.isSuccess:
result = c.gasMeter.gasRefunded
proc refundSelfDestruct*(c: Computation) =
let cost = gasFees[c.fork][RefundSelfDestruct]
c.gasMeter.refundGas(cost * c.suicides.len)
proc tracingEnabled*(c: Computation): bool {.inline.} =
TracerFlags.EnableTracing in c.vmState.tracer.flags
proc traceOpCodeStarted*(c: Computation, op: Op): int {.inline.} = proc traceOpCodeStarted*(c: Computation, op: Op): int {.inline.} =
c.vmState.tracer.traceOpCodeStarted(c, op) c.vmState.tracer.traceOpCodeStarted(c, op)
@ -123,10 +241,12 @@ proc traceOpCodeStarted*(c: Computation, op: Op): int {.inline.} =
proc traceOpCodeEnded*(c: Computation, op: Op, lastIndex: int) {.inline.} = proc traceOpCodeEnded*(c: Computation, op: Op, lastIndex: int) {.inline.} =
c.vmState.tracer.traceOpCodeEnded(c, op, lastIndex) c.vmState.tracer.traceOpCodeEnded(c, op, lastIndex)
proc tracingEnabled*(c: Computation): bool {.inline.} = proc traceError*(c: Computation) {.inline.} =
TracerFlags.EnableTracing in c.vmState.tracer.flags c.vmState.tracer.traceError(c)
proc prepareTracer*(c: Computation) {.inline.} =
c.vmState.tracer.prepare(c.msg.depth)
# deprecated, related to nimvm/evmc implementation # ------------------------------------------------------------------------------
proc execSelfDestruct*(c: Computation, address: EthAddress) {.deprecated.} = # End
c.selfDestruct(address) # ------------------------------------------------------------------------------

View File

@ -13,94 +13,14 @@ import
sets, eth/[common, keys], sets, eth/[common, keys],
../constants, ../constants,
./compu_helper, ./compu_helper,
./interpreter/[op_codes, gas_meter, gas_costs, forks_list], ./interpreter/forks_list,
./code_stream, ./memory, ./message, ./stack, ./types, ./state, ./message, ./types, ./state,
../db/accounts_cache, ../db/accounts_cache,
./precompiles, ./precompiles
./transaction_tracer, ../utils
logScope: logScope:
topics = "vm computation" topics = "vm computation"
proc generateContractAddress(c: Computation, salt: Uint256): EthAddress =
if c.msg.kind == evmcCreate:
let creationNonce = c.vmState.readOnlyStateDb().getNonce(c.msg.sender)
result = generateAddress(c.msg.sender, creationNonce)
else:
result = generateSafeAddress(c.msg.sender, salt, c.msg.data)
proc newComputation*(vmState: BaseVMState, message: Message, salt= 0.u256): Computation =
new result
result.vmState = vmState
result.msg = message
result.memory = Memory()
result.stack = newStack()
result.returnStack = @[]
result.gasMeter.init(message.gas)
result.touchedAccounts = initHashSet[EthAddress]()
result.suicides = initHashSet[EthAddress]()
if result.msg.isCreate():
result.msg.contractAddress = result.generateContractAddress(salt)
result.code = newCodeStream(message.data)
message.data = @[]
else:
result.code = newCodeStream(vmState.readOnlyStateDb.getCode(message.codeAddress))
proc isOriginComputation*(c: Computation): bool =
# Is this computation the computation initiated by a transaction
c.msg.sender == c.vmState.txOrigin
template isSuccess*(c: Computation): bool =
c.error.isNil
template isError*(c: Computation): bool =
not c.isSuccess
func shouldBurnGas*(c: Computation): bool =
c.isError and c.error.burnsGas
proc isSuicided*(c: Computation, address: EthAddress): bool =
result = address in c.suicides
proc snapshot*(c: Computation) =
c.savePoint = c.vmState.accountDb.beginSavePoint()
proc commit*(c: Computation) =
c.vmState.accountDb.commit(c.savePoint)
proc dispose*(c: Computation) {.inline.} =
c.vmState.accountDb.safeDispose(c.savePoint)
c.savePoint = nil
proc rollback*(c: Computation) =
c.vmState.accountDb.rollback(c.savePoint)
proc writeContract*(c: Computation, fork: Fork): bool {.gcsafe.} =
result = true
let contractCode = c.output
if contractCode.len == 0: return
if fork >= FkSpurious and contractCode.len >= EIP170_CODE_SIZE_LIMIT:
debug "Contract code size exceeds EIP170", limit=EIP170_CODE_SIZE_LIMIT, actual=contractCode.len
return false
let storageAddr = c.msg.contractAddress
if c.isSuicided(storageAddr): return
let gasParams = GasParams(kind: Create, cr_memLength: contractCode.len)
let codeCost = c.gasCosts[Create].c_handler(0.u256, gasParams).gasCost
if c.gasMeter.gasRemaining >= codeCost:
c.gasMeter.consumeGas(codeCost, reason = "Write contract code for CREATE")
c.vmState.mutateStateDb:
db.setCode(storageAddr, contractCode)
result = true
else:
if fork < FkHomestead or fork >= FkByzantium: c.output = @[]
result = false
proc initAddress(x: int): EthAddress {.compileTime.} = result[19] = x.byte proc initAddress(x: int): EthAddress {.compileTime.} = result[19] = x.byte
const ripemdAddr = initAddress(3) const ripemdAddr = initAddress(3)
proc executeOpcodes*(c: Computation) {.gcsafe.} proc executeOpcodes*(c: Computation) {.gcsafe.}
@ -180,11 +100,6 @@ proc afterExec(c: Computation) =
else: else:
c.afterExecCreate() c.afterExecCreate()
template chainTo*(c, toChild: Computation, after: untyped) =
c.child = toChild
c.continuation = proc() =
after
proc execCallOrCreate*(cParam: Computation) = proc execCallOrCreate*(cParam: Computation) =
var (c, before) = (cParam, true) var (c, before) = (cParam, true)
defer: defer:
@ -208,24 +123,6 @@ proc execCallOrCreate*(cParam: Computation) =
(before, c.parent, c) = (false, nil.Computation, c.parent) (before, c.parent, c) = (false, nil.Computation, c.parent)
(c.continuation)() (c.continuation)()
proc merge*(c, child: Computation) =
c.logEntries.add child.logEntries
c.gasMeter.refundGas(child.gasMeter.gasRefunded)
c.suicides.incl child.suicides
c.touchedAccounts.incl child.touchedAccounts
proc getGasRefund*(c: Computation): GasInt =
if c.isSuccess:
result = c.gasMeter.gasRefunded
proc refundSelfDestruct*(c: Computation) =
let cost = gasFees[c.fork][RefundSelfDestruct]
c.gasMeter.refundGas(cost * c.suicides.len)
proc traceError*(c: Computation) {.inline.} =
c.vmState.tracer.traceError(c)
import interpreter_dispatch import interpreter_dispatch

View File

@ -35,6 +35,9 @@ import
export export
xmc.accountExists, xmc.accountExists,
xmc.addLogEntry, xmc.addLogEntry,
xmc.chainTo,
xmc.commit,
xmc.dispose,
xmc.fork, xmc.fork,
xmc.getBalance, xmc.getBalance,
xmc.getBlockHash, xmc.getBlockHash,
@ -47,37 +50,35 @@ export
xmc.getDifficulty, xmc.getDifficulty,
xmc.getGasLimit, xmc.getGasLimit,
xmc.getGasPrice, xmc.getGasPrice,
xmc.getGasRefund,
xmc.getOrigin, xmc.getOrigin,
xmc.getStorage, xmc.getStorage,
xmc.getTimestamp, xmc.getTimestamp,
xmc.isError,
xmc.isOriginComputation,
xmc.isSuccess,
xmc.isSuicided,
xmc.merge,
xmc.newComputation,
xmc.prepareTracer, xmc.prepareTracer,
xmc.refundSelfDestruct,
xmc.rollback,
xmc.selfDestruct, xmc.selfDestruct,
xmc.setError, xmc.setError,
xmc.shouldBurnGas,
xmc.snapshot,
xmc.traceError,
xmc.traceOpCodeEnded, xmc.traceOpCodeEnded,
xmc.traceOpCodeStarted, xmc.traceOpCodeStarted,
xmc.tracingEnabled xmc.tracingEnabled,
xmc.writeContract
import import
./computation as vmc ./computation as vmc
export export
vmc.commit,
vmc.dispose,
vmc.execCallOrCreate, vmc.execCallOrCreate,
vmc.chainTo, vmc.executeOpcodes
vmc.executeOpcodes,
vmc.getGasRefund,
vmc.isError,
vmc.isOriginComputation,
vmc.isSuccess,
vmc.isSuicided,
vmc.merge,
vmc.newComputation,
vmc.refundSelfDestruct,
vmc.rollback,
vmc.shouldBurnGas,
vmc.snapshot,
vmc.traceError,
vmc.writeContract
import import

View File

@ -18,6 +18,9 @@ when defined(evmc_enabled) or not defined(vm2_enabled):
export export
vmc.accountExists, vmc.accountExists,
vmc.addLogEntry, vmc.addLogEntry,
vmc.chainTo,
vmc.commit,
vmc.dispose,
vmc.execSelfDestruct, vmc.execSelfDestruct,
vmc.fork, vmc.fork,
vmc.getBalance, vmc.getBalance,
@ -31,15 +34,28 @@ when defined(evmc_enabled) or not defined(vm2_enabled):
vmc.getDifficulty, vmc.getDifficulty,
vmc.getGasLimit, vmc.getGasLimit,
vmc.getGasPrice, vmc.getGasPrice,
vmc.getGasRefund,
vmc.getOrigin, vmc.getOrigin,
vmc.getStorage, vmc.getStorage,
vmc.getTimestamp, vmc.getTimestamp,
vmc.isError,
vmc.isOriginComputation,
vmc.isSuccess,
vmc.isSuicided,
vmc.merge,
vmc.newComputation,
vmc.prepareTracer,
vmc.refundSelfDestruct,
vmc.rollback,
vmc.selfDestruct, vmc.selfDestruct,
vmc.setError, vmc.setError,
vmc.prepareTracer, vmc.shouldBurnGas,
vmc.snapshot,
vmc.traceError,
vmc.traceOpCodeEnded, vmc.traceOpCodeEnded,
vmc.traceOpCodeStarted, vmc.traceOpCodeStarted,
vmc.tracingEnabled vmc.tracingEnabled,
vmc.writeContract
else: else:
import import
@ -49,6 +65,9 @@ else:
export export
xmc.accountExists, xmc.accountExists,
xmc.addLogEntry, xmc.addLogEntry,
xmc.chainTo,
xmc.commit,
xmc.dispose,
xmc.execSelfDestruct, xmc.execSelfDestruct,
xmc.fork, xmc.fork,
xmc.getBalance, xmc.getBalance,
@ -62,34 +81,31 @@ else:
xmc.getDifficulty, xmc.getDifficulty,
xmc.getGasLimit, xmc.getGasLimit,
xmc.getGasPrice, xmc.getGasPrice,
xmc.getGasRefund,
xmc.getOrigin, xmc.getOrigin,
xmc.getStorage, xmc.getStorage,
xmc.getTimestamp, xmc.getTimestamp,
xmc.isError,
xmc.isOriginComputation,
xmc.isSuccess,
xmc.isSuicided,
xmc.merge,
xmc.newComputation,
xmc.prepareTracer, xmc.prepareTracer,
xmc.refundSelfDestruct,
xmc.rollback,
xmc.selfDestruct, xmc.selfDestruct,
xmc.setError, xmc.setError,
xmc.shouldBurnGas,
xmc.snapshot,
xmc.traceError,
xmc.traceOpCodeEnded, xmc.traceOpCodeEnded,
xmc.traceOpCodeStarted, xmc.traceOpCodeStarted,
xmc.tracingEnabled xmc.tracingEnabled,
xmc.writeContract
export export
vmc.commit,
vmc.dispose,
vmc.execCallOrCreate, vmc.execCallOrCreate,
vmc.chainTo, vmc.executeOpcodes
vmc.executeOpcodes,
vmc.getGasRefund,
vmc.isError,
vmc.isOriginComputation,
vmc.isSuccess,
vmc.isSuicided,
vmc.merge,
vmc.newComputation,
vmc.refundSelfDestruct,
vmc.rollback,
vmc.shouldBurnGas,
vmc.snapshot,
vmc.traceError,
vmc.writeContract
# End # End