parent
b7bf84a71f
commit
cf2d771c4d
|
@ -23,100 +23,66 @@ import
|
||||||
when defined(chronicles_log_level):
|
when defined(chronicles_log_level):
|
||||||
import stew/byteutils
|
import stew/byteutils
|
||||||
|
|
||||||
when defined(evmc_enabled):
|
|
||||||
import evmc/evmc, evmc_helpers, evmc_api, stew/ranges/ptr_arith
|
|
||||||
|
|
||||||
logScope:
|
logScope:
|
||||||
topics = "vm computation"
|
topics = "vm computation"
|
||||||
|
|
||||||
const
|
|
||||||
evmc_enabled* = defined(evmc_enabled)
|
|
||||||
|
|
||||||
template getCoinbase*(c: Computation): EthAddress =
|
template getCoinbase*(c: Computation): EthAddress =
|
||||||
when evmc_enabled:
|
block:
|
||||||
c.host.getTxContext().block_coinbase
|
|
||||||
else:
|
|
||||||
c.vmState.coinbase
|
c.vmState.coinbase
|
||||||
|
|
||||||
template getTimestamp*(c: Computation): int64 =
|
template getTimestamp*(c: Computation): int64 =
|
||||||
when evmc_enabled:
|
block:
|
||||||
c.host.getTxContext().block_timestamp
|
|
||||||
else:
|
|
||||||
c.vmState.timestamp.toUnix
|
c.vmState.timestamp.toUnix
|
||||||
|
|
||||||
template getBlockNumber*(c: Computation): Uint256 =
|
template getBlockNumber*(c: Computation): Uint256 =
|
||||||
when evmc_enabled:
|
block:
|
||||||
c.host.getTxContext().block_number.u256
|
|
||||||
else:
|
|
||||||
c.vmState.blockNumber.blockNumberToVmWord
|
c.vmState.blockNumber.blockNumberToVmWord
|
||||||
|
|
||||||
template getDifficulty*(c: Computation): DifficultyInt =
|
template getDifficulty*(c: Computation): DifficultyInt =
|
||||||
when evmc_enabled:
|
block:
|
||||||
Uint256.fromEvmc c.host.getTxContext().block_difficulty
|
|
||||||
else:
|
|
||||||
c.vmState.difficulty
|
c.vmState.difficulty
|
||||||
|
|
||||||
template getGasLimit*(c: Computation): GasInt =
|
template getGasLimit*(c: Computation): GasInt =
|
||||||
when evmc_enabled:
|
block:
|
||||||
c.host.getTxContext().block_gas_limit.GasInt
|
|
||||||
else:
|
|
||||||
c.vmState.gasLimit
|
c.vmState.gasLimit
|
||||||
|
|
||||||
template getChainId*(c: Computation): uint =
|
template getChainId*(c: Computation): uint =
|
||||||
when evmc_enabled:
|
block:
|
||||||
Uint256.fromEvmc(c.host.getTxContext().chain_id).truncate(uint)
|
|
||||||
else:
|
|
||||||
c.vmState.chaindb.config.chainId.uint
|
c.vmState.chaindb.config.chainId.uint
|
||||||
|
|
||||||
template getOrigin*(c: Computation): EthAddress =
|
template getOrigin*(c: Computation): EthAddress =
|
||||||
when evmc_enabled:
|
block:
|
||||||
c.host.getTxContext().tx_origin
|
|
||||||
else:
|
|
||||||
c.vmState.txOrigin
|
c.vmState.txOrigin
|
||||||
|
|
||||||
template getGasPrice*(c: Computation): GasInt =
|
template getGasPrice*(c: Computation): GasInt =
|
||||||
when evmc_enabled:
|
block:
|
||||||
Uint256.fromEvmc(c.host.getTxContext().tx_gas_price).truncate(GasInt)
|
|
||||||
else:
|
|
||||||
c.vmState.txGasPrice
|
c.vmState.txGasPrice
|
||||||
|
|
||||||
template getBlockHash*(c: Computation, blockNumber: Uint256): Hash256 =
|
template getBlockHash*(c: Computation, blockNumber: Uint256): Hash256 =
|
||||||
when evmc_enabled:
|
block:
|
||||||
c.host.getBlockHash(blockNumber)
|
|
||||||
else:
|
|
||||||
c.vmState.getAncestorHash(blockNumber.vmWordToBlockNumber)
|
c.vmState.getAncestorHash(blockNumber.vmWordToBlockNumber)
|
||||||
|
|
||||||
template accountExists*(c: Computation, address: EthAddress): bool =
|
template accountExists*(c: Computation, address: EthAddress): bool =
|
||||||
when evmc_enabled:
|
block:
|
||||||
c.host.accountExists(address)
|
|
||||||
else:
|
|
||||||
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)
|
||||||
|
|
||||||
template getStorage*(c: Computation, slot: Uint256): Uint256 =
|
template getStorage*(c: Computation, slot: Uint256): Uint256 =
|
||||||
when evmc_enabled:
|
block:
|
||||||
c.host.getStorage(c.msg.contractAddress, slot)
|
|
||||||
else:
|
|
||||||
c.vmState.readOnlyStateDB.getStorage(c.msg.contractAddress, slot)
|
c.vmState.readOnlyStateDB.getStorage(c.msg.contractAddress, slot)
|
||||||
|
|
||||||
template getBalance*(c: Computation, address: EthAddress): Uint256 =
|
template getBalance*(c: Computation, address: EthAddress): Uint256 =
|
||||||
when evmc_enabled:
|
block:
|
||||||
c.host.getBalance(address)
|
|
||||||
else:
|
|
||||||
c.vmState.readOnlyStateDB.getBalance(address)
|
c.vmState.readOnlyStateDB.getBalance(address)
|
||||||
|
|
||||||
template getCodeSize*(c: Computation, address: EthAddress): uint =
|
template getCodeSize*(c: Computation, address: EthAddress): uint =
|
||||||
when evmc_enabled:
|
block:
|
||||||
c.host.getCodeSize(address)
|
|
||||||
else:
|
|
||||||
uint(c.vmState.readOnlyStateDB.getCodeSize(address))
|
uint(c.vmState.readOnlyStateDB.getCodeSize(address))
|
||||||
|
|
||||||
template getCodeHash*(c: Computation, address: EthAddress): Hash256 =
|
template getCodeHash*(c: Computation, address: EthAddress): Hash256 =
|
||||||
when evmc_enabled:
|
block:
|
||||||
c.host.getCodeHash(address)
|
|
||||||
else:
|
|
||||||
let db = c.vmState.readOnlyStateDB
|
let db = c.vmState.readOnlyStateDB
|
||||||
if not db.accountExists(address) or db.isEmptyAccount(address):
|
if not db.accountExists(address) or db.isEmptyAccount(address):
|
||||||
default(Hash256)
|
default(Hash256)
|
||||||
|
@ -124,15 +90,11 @@ template getCodeHash*(c: Computation, address: EthAddress): Hash256 =
|
||||||
db.getCodeHash(address)
|
db.getCodeHash(address)
|
||||||
|
|
||||||
template selfDestruct*(c: Computation, address: EthAddress) =
|
template selfDestruct*(c: Computation, address: EthAddress) =
|
||||||
when evmc_enabled:
|
block:
|
||||||
c.host.selfDestruct(c.msg.contractAddress, address)
|
|
||||||
else:
|
|
||||||
c.execSelfDestruct(address)
|
c.execSelfDestruct(address)
|
||||||
|
|
||||||
template getCode*(c: Computation, address: EthAddress): seq[byte] =
|
template getCode*(c: Computation, address: EthAddress): seq[byte] =
|
||||||
when evmc_enabled:
|
block:
|
||||||
c.host.copyCode(address)
|
|
||||||
else:
|
|
||||||
c.vmState.readOnlyStateDB.getCode(address)
|
c.vmState.readOnlyStateDB.getCode(address)
|
||||||
|
|
||||||
proc generateContractAddress(c: Computation, salt: Uint256): EthAddress =
|
proc generateContractAddress(c: Computation, salt: Uint256): EthAddress =
|
||||||
|
@ -162,11 +124,6 @@ proc newComputation*(vmState: BaseVMState, message: Message, salt= 0.u256): Comp
|
||||||
else:
|
else:
|
||||||
result.code = newCodeStream(vmState.readOnlyStateDb.getCode(message.codeAddress))
|
result.code = newCodeStream(vmState.readOnlyStateDb.getCode(message.codeAddress))
|
||||||
|
|
||||||
when evmc_enabled:
|
|
||||||
result.host.init(
|
|
||||||
nim_host_get_interface(),
|
|
||||||
cast[evmc_host_context](result)
|
|
||||||
)
|
|
||||||
|
|
||||||
template gasCosts*(c: Computation): untyped =
|
template gasCosts*(c: Computation): untyped =
|
||||||
c.vmState.gasCosts
|
c.vmState.gasCosts
|
||||||
|
@ -401,6 +358,3 @@ proc prepareTracer*(c: Computation) {.inline.} =
|
||||||
c.vmState.tracer.prepare(c.msg.depth)
|
c.vmState.tracer.prepare(c.msg.depth)
|
||||||
|
|
||||||
include interpreter_dispatch
|
include interpreter_dispatch
|
||||||
|
|
||||||
when defined(evmc_enabled):
|
|
||||||
include evmc_host
|
|
||||||
|
|
|
@ -1,147 +0,0 @@
|
||||||
# Nimbus
|
|
||||||
# Copyright (c) 2019 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.
|
|
||||||
|
|
||||||
import evmc/evmc, ./evmc_helpers, eth/common, ../constants
|
|
||||||
|
|
||||||
type
|
|
||||||
# we are not using EVMC original signature here
|
|
||||||
# because we want to trick the compiler
|
|
||||||
# and reduce unnecessary conversion/typecast
|
|
||||||
# TODO: move this type definition to nim-evmc
|
|
||||||
# after we have implemented ABI compatibility test
|
|
||||||
# TODO: investigate the possibility to use Big Endian VMWord
|
|
||||||
# directly if it's not involving stint computation
|
|
||||||
# and we can reduce unecessary conversion further
|
|
||||||
nimbus_tx_context* = object
|
|
||||||
tx_gas_price* : evmc_uint256be # The transaction gas price.
|
|
||||||
tx_origin* : EthAddress # The transaction origin account.
|
|
||||||
block_coinbase* : EthAddress # The miner of the block.
|
|
||||||
block_number* : int64 # The block number.
|
|
||||||
block_timestamp* : int64 # The block timestamp.
|
|
||||||
block_gas_limit* : int64 # The block gas limit.
|
|
||||||
block_difficulty*: evmc_uint256be # The block difficulty.
|
|
||||||
chain_id* : evmc_uint256be # The blockchain's ChainID.
|
|
||||||
|
|
||||||
nimbus_message* = object
|
|
||||||
kind*: evmc_call_kind
|
|
||||||
flags*: uint32
|
|
||||||
depth*: int32
|
|
||||||
gas*: int64
|
|
||||||
destination*: EthAddress
|
|
||||||
sender*: EthAddress
|
|
||||||
input_data*: ptr byte
|
|
||||||
input_size*: uint
|
|
||||||
value*: evmc_uint256be
|
|
||||||
create2_salt*: evmc_bytes32
|
|
||||||
|
|
||||||
nimbus_result* = object
|
|
||||||
status_code*: evmc_status_code
|
|
||||||
gas_left*: int64
|
|
||||||
output_data*: ptr byte
|
|
||||||
output_size*: uint
|
|
||||||
release*: proc(result: var nimbus_result) {.cdecl, gcsafe.}
|
|
||||||
create_address*: EthAddress
|
|
||||||
padding*: array[4, byte]
|
|
||||||
|
|
||||||
nimbus_host_interface* = object
|
|
||||||
account_exists*: proc(context: evmc_host_context, address: EthAddress): bool {.cdecl, gcsafe.}
|
|
||||||
get_storage*: proc(context: evmc_host_context, address: EthAddress, key: ptr evmc_uint256be): evmc_uint256be {.cdecl, gcsafe.}
|
|
||||||
set_storage*: proc(context: evmc_host_context, address: EthAddress,
|
|
||||||
key, value: ptr evmc_uint256be): evmc_storage_status {.cdecl, gcsafe.}
|
|
||||||
get_balance*: proc(context: evmc_host_context, address: EthAddress): evmc_uint256be {.cdecl, gcsafe.}
|
|
||||||
get_code_size*: proc(context: evmc_host_context, address: EthAddress): uint {.cdecl, gcsafe.}
|
|
||||||
get_code_hash*: proc(context: evmc_host_context, address: EthAddress): Hash256 {.cdecl, gcsafe.}
|
|
||||||
copy_code*: proc(context: evmc_host_context, address: EthAddress,
|
|
||||||
code_offset: int, buffer_data: ptr byte,
|
|
||||||
buffer_size: int): int {.cdecl, gcsafe.}
|
|
||||||
selfdestruct*: proc(context: evmc_host_context, address, beneficiary: EthAddress) {.cdecl, gcsafe.}
|
|
||||||
call*: proc(context: evmc_host_context, msg: ptr nimbus_message): nimbus_result {.cdecl, gcsafe.}
|
|
||||||
get_tx_context*: proc(context: evmc_host_context): nimbus_tx_context {.cdecl, gcsafe.}
|
|
||||||
get_block_hash*: proc(context: evmc_host_context, number: int64): Hash256 {.cdecl, gcsafe.}
|
|
||||||
emit_log*: proc(context: evmc_host_context, address: EthAddress,
|
|
||||||
data: ptr byte, data_size: uint,
|
|
||||||
topics: ptr evmc_bytes32, topics_count: uint) {.cdecl, gcsafe.}
|
|
||||||
|
|
||||||
proc nim_host_get_interface*(): ptr nimbus_host_interface {.importc, cdecl.}
|
|
||||||
proc nim_host_create_context*(vmstate: pointer, msg: ptr evmc_message): evmc_host_context {.importc, cdecl.}
|
|
||||||
proc nim_host_destroy_context*(ctx: evmc_host_context) {.importc, cdecl.}
|
|
||||||
proc nim_create_nimbus_vm*(): ptr evmc_vm {.importc, cdecl.}
|
|
||||||
|
|
||||||
type
|
|
||||||
HostContext* = object
|
|
||||||
host*: ptr nimbus_host_interface
|
|
||||||
context*: evmc_host_context
|
|
||||||
|
|
||||||
proc init*(x: var HostContext, host: ptr nimbus_host_interface, context: evmc_host_context) =
|
|
||||||
x.host = host
|
|
||||||
x.context = context
|
|
||||||
|
|
||||||
proc init*(x: typedesc[HostContext], host: ptr nimbus_host_interface, context: evmc_host_context): HostContext =
|
|
||||||
result.init(host, context)
|
|
||||||
|
|
||||||
proc getTxContext*(ctx: HostContext): nimbus_tx_context {.inline.} =
|
|
||||||
ctx.host.get_tx_context(ctx.context)
|
|
||||||
|
|
||||||
proc getBlockHash*(ctx: HostContext, number: Uint256): Hash256 =
|
|
||||||
let
|
|
||||||
blockNumber = ctx.getTxContext().block_number.u256
|
|
||||||
ancestorDepth = blockNumber - number - 1
|
|
||||||
if ancestorDepth >= constants.MAX_PREV_HEADER_DEPTH:
|
|
||||||
return
|
|
||||||
if number >= blockNumber:
|
|
||||||
return
|
|
||||||
ctx.host.get_block_hash(ctx.context, number.truncate(int64))
|
|
||||||
|
|
||||||
proc accountExists*(ctx: HostContext, address: EthAddress): bool {.inline.} =
|
|
||||||
ctx.host.account_exists(ctx.context, address)
|
|
||||||
|
|
||||||
proc getStorage*(ctx: HostContext, address: EthAddress, key: Uint256): Uint256 =
|
|
||||||
var key = toEvmc(key)
|
|
||||||
Uint256.fromEvmc ctx.host.get_storage(ctx.context, address, key.addr)
|
|
||||||
|
|
||||||
proc setStorage*(ctx: HostContext, address: EthAddress,
|
|
||||||
key, value: Uint256): evmc_storage_status {.inline.} =
|
|
||||||
var
|
|
||||||
key = toEvmc(key)
|
|
||||||
value = toEvmc(value)
|
|
||||||
ctx.host.set_storage(ctx.context, address, key.addr, value.addr)
|
|
||||||
|
|
||||||
proc getBalance*(ctx: HostContext, address: EthAddress): Uint256 {.inline.} =
|
|
||||||
Uint256.fromEvmc ctx.host.get_balance(ctx.context, address)
|
|
||||||
|
|
||||||
proc getCodeSize*(ctx: HostContext, address: EthAddress): uint {.inline.} =
|
|
||||||
ctx.host.get_code_size(ctx.context, address)
|
|
||||||
|
|
||||||
proc getCodeHash*(ctx: HostContext, address: EthAddress): Hash256 {.inline.} =
|
|
||||||
ctx.host.get_code_hash(ctx.context, address)
|
|
||||||
|
|
||||||
proc copyCode*(ctx: HostContext, address: EthAddress, codeOffset: int = 0): seq[byte] =
|
|
||||||
let size = ctx.getCodeSize(address).int
|
|
||||||
if size - codeOffset > 0:
|
|
||||||
result = newSeq[byte](size - codeOffset)
|
|
||||||
let read = ctx.host.copy_code(ctx.context, address,
|
|
||||||
codeOffset, result[0].addr, result.len)
|
|
||||||
doAssert(read == result.len)
|
|
||||||
|
|
||||||
proc selfdestruct*(ctx: HostContext, address, beneficiary: EthAddress) {.inline.} =
|
|
||||||
ctx.host.selfdestruct(ctx.context, address, beneficiary)
|
|
||||||
|
|
||||||
proc emitLog*(ctx: HostContext, address: EthAddress, data: openArray[byte],
|
|
||||||
topics: ptr evmc_bytes32, topicsCount: int) {.inline.} =
|
|
||||||
ctx.host.emit_log(ctx.context, address, if data.len > 0: data[0].unsafeAddr else: nil,
|
|
||||||
data.len.uint, topics, topicsCount.uint)
|
|
||||||
|
|
||||||
proc call*(ctx: HostContext, msg: nimbus_message): nimbus_result {.inline.} =
|
|
||||||
ctx.host.call(ctx.context, msg.unsafeAddr)
|
|
||||||
|
|
||||||
#proc vmHost*(vmState: BaseVMState, gasPrice: GasInt, origin: EthAddress): HostContext =
|
|
||||||
# let host = nim_host_get_interface()
|
|
||||||
# let context = nim_host_create_context(cast[pointer](vmState), gasPrice, toEvmc(origin))
|
|
||||||
# result.init(host, context)
|
|
||||||
#
|
|
||||||
#proc destroy*(hc: HostContext) =
|
|
||||||
# nim_host_destroy_context(hc.context)
|
|
|
@ -1,43 +0,0 @@
|
||||||
import eth/common, stint, evmc/evmc
|
|
||||||
|
|
||||||
const
|
|
||||||
evmc_native* {.booldefine.} = false
|
|
||||||
|
|
||||||
func toEvmc*(a: EthAddress): evmc_address {.inline.} =
|
|
||||||
cast[evmc_address](a)
|
|
||||||
|
|
||||||
func toEvmc*(h: Hash256): evmc_bytes32 {.inline.} =
|
|
||||||
cast[evmc_bytes32](h)
|
|
||||||
|
|
||||||
func toEvmc*(n: Uint256): evmc_uint256be {.inline.} =
|
|
||||||
when evmc_native:
|
|
||||||
cast[evmc_uint256be](n)
|
|
||||||
else:
|
|
||||||
cast[evmc_uint256be](n.toByteArrayBE)
|
|
||||||
|
|
||||||
func fromEvmc*(T: type, n: evmc_bytes32): T {.inline.} =
|
|
||||||
when T is Hash256:
|
|
||||||
cast[Hash256](n)
|
|
||||||
elif T is Uint256:
|
|
||||||
when evmc_native:
|
|
||||||
cast[Uint256](n)
|
|
||||||
else:
|
|
||||||
Uint256.fromBytesBE(n.bytes)
|
|
||||||
else:
|
|
||||||
{.error: "cannot convert unsupported evmc type".}
|
|
||||||
|
|
||||||
func fromEvmc*(a: evmc_address): EthAddress {.inline.} =
|
|
||||||
cast[EthAddress](a)
|
|
||||||
|
|
||||||
when isMainModule:
|
|
||||||
import constants
|
|
||||||
var a: evmc_address
|
|
||||||
a.bytes[19] = 3.byte
|
|
||||||
var na = fromEvmc(a)
|
|
||||||
assert(a == toEvmc(na))
|
|
||||||
var b = stuint(10, 256)
|
|
||||||
var eb = b.toEvmc
|
|
||||||
assert(b == fromEvmc(Uint256, eb))
|
|
||||||
var h = EMPTY_SHA3
|
|
||||||
var eh = toEvmc(h)
|
|
||||||
assert(h == fromEvmc(Hash256, eh))
|
|
|
@ -1,252 +0,0 @@
|
||||||
# Nimbus
|
|
||||||
# Copyright (c) 2019 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.
|
|
||||||
|
|
||||||
proc hostReleaseResultImpl(res: var nimbus_result) {.cdecl, gcsafe.} =
|
|
||||||
dealloc(res.output_data)
|
|
||||||
|
|
||||||
proc hostGetTxContextImpl(ctx: Computation): nimbus_tx_context {.cdecl.} =
|
|
||||||
let vmstate = ctx.vmState
|
|
||||||
result.tx_gas_price = toEvmc(vmstate.txGasPrice.u256)
|
|
||||||
result.tx_origin = vmstate.txOrigin
|
|
||||||
result.block_coinbase = vmstate.coinbase
|
|
||||||
result.block_number = vmstate.blockNumber.truncate(int64)
|
|
||||||
result.block_timestamp = vmstate.timestamp.toUnix()
|
|
||||||
result.block_gas_limit = int64(vmstate.blockHeader.gasLimit)
|
|
||||||
result.block_difficulty = toEvmc(vmstate.difficulty)
|
|
||||||
result.chain_id = toEvmc(vmstate.chaindb.config.chainId.uint.u256)
|
|
||||||
|
|
||||||
proc hostGetBlockHashImpl(ctx: Computation, number: int64): Hash256 {.cdecl.} =
|
|
||||||
ctx.vmState.getAncestorHash(number.u256)
|
|
||||||
|
|
||||||
proc hostAccountExistsImpl(ctx: Computation, address: EthAddress): bool {.cdecl.} =
|
|
||||||
let db = ctx.vmState.readOnlyStateDB
|
|
||||||
if ctx.fork >= FkSpurious:
|
|
||||||
not db.isDeadAccount(address)
|
|
||||||
else:
|
|
||||||
db.accountExists(address)
|
|
||||||
|
|
||||||
proc hostGetStorageImpl(ctx: Computation, address: EthAddress, key: var evmc_bytes32): evmc_bytes32 {.cdecl.} =
|
|
||||||
ctx.vmState.accountDB.getStorage(address, Uint256.fromEvmc(key)).toEvmc()
|
|
||||||
|
|
||||||
proc sstoreNetGasMetering(ctx: Computation): bool {.inline.} =
|
|
||||||
ctx.fork in {FkConstantinople, FkIstanbul, FkBerlin}
|
|
||||||
|
|
||||||
proc hostSetStorageImpl(ctx: Computation, address: EthAddress,
|
|
||||||
key, value: var evmc_bytes32): evmc_storage_status {.cdecl.} =
|
|
||||||
let
|
|
||||||
slot = Uint256.fromEvmc(key)
|
|
||||||
newValue = Uint256.fromEvmc(value)
|
|
||||||
statedb = ctx.vmState.readOnlyStateDb
|
|
||||||
currValue = statedb.getStorage(address, slot)
|
|
||||||
|
|
||||||
assert address == ctx.msg.contractAddress
|
|
||||||
|
|
||||||
var
|
|
||||||
status = EVMC_STORAGE_MODIFIED
|
|
||||||
gasRefund = 0.GasInt
|
|
||||||
origValue = 0.u256
|
|
||||||
|
|
||||||
if newValue == currValue:
|
|
||||||
status = EVMC_STORAGE_UNCHANGED
|
|
||||||
else:
|
|
||||||
origValue = statedb.getCommittedStorage(address, slot)
|
|
||||||
if origValue == currValue or not ctx.sstoreNetGasMetering():
|
|
||||||
if currValue == 0:
|
|
||||||
status = EVMC_STORAGE_ADDED
|
|
||||||
elif newValue == 0:
|
|
||||||
status = EVMC_STORAGE_DELETED
|
|
||||||
else:
|
|
||||||
status = EVMC_STORAGE_MODIFIED_AGAIN
|
|
||||||
ctx.vmState.mutateStateDB:
|
|
||||||
db.setStorage(address, slot, newValue)
|
|
||||||
|
|
||||||
let gasParam = GasParams(kind: Op.Sstore,
|
|
||||||
s_status: status,
|
|
||||||
s_currentValue: currValue,
|
|
||||||
s_originalValue: origValue
|
|
||||||
)
|
|
||||||
gasRefund = ctx.gasCosts[Sstore].c_handler(newValue, gasParam)[1]
|
|
||||||
|
|
||||||
if gasRefund != 0:
|
|
||||||
ctx.gasMeter.refundGas(gasRefund)
|
|
||||||
|
|
||||||
result = status
|
|
||||||
|
|
||||||
proc hostGetBalanceImpl(ctx: Computation, address: EthAddress): evmc_bytes32 {.cdecl.} =
|
|
||||||
ctx.vmState.readOnlyStateDB.getBalance(address).toEvmc()
|
|
||||||
|
|
||||||
proc hostGetCodeSizeImpl(ctx: Computation, address: EthAddress): uint {.cdecl.} =
|
|
||||||
ctx.vmState.readOnlyStateDB.getCode(address).len.uint
|
|
||||||
|
|
||||||
proc hostGetCodeHashImpl(ctx: Computation, address: EthAddress): Hash256 {.cdecl.} =
|
|
||||||
let db = ctx.vmstate.readOnlyStateDB
|
|
||||||
if not db.accountExists(address):
|
|
||||||
return
|
|
||||||
if db.isEmptyAccount(address):
|
|
||||||
return
|
|
||||||
db.getCodeHash(address)
|
|
||||||
|
|
||||||
proc hostCopyCodeImpl(ctx: Computation, address: EthAddress,
|
|
||||||
codeOffset: int, bufferData: ptr byte,
|
|
||||||
bufferSize: int): int {.cdecl.} =
|
|
||||||
|
|
||||||
var code = ctx.vmState.readOnlyStateDB.getCode(address)
|
|
||||||
|
|
||||||
# Handle "big offset" edge case.
|
|
||||||
if codeOffset > code.len:
|
|
||||||
return 0
|
|
||||||
|
|
||||||
let maxToCopy = code.len - codeOffset
|
|
||||||
let numToCopy = min(maxToCopy, bufferSize)
|
|
||||||
if numToCopy > 0:
|
|
||||||
copyMem(bufferData, code[codeOffset].addr, numToCopy)
|
|
||||||
result = numToCopy
|
|
||||||
|
|
||||||
proc hostSelfdestructImpl(ctx: Computation, address, beneficiary: EthAddress) {.cdecl.} =
|
|
||||||
assert address == ctx.msg.contractAddress
|
|
||||||
ctx.execSelfDestruct(beneficiary)
|
|
||||||
|
|
||||||
proc hostEmitLogImpl(ctx: Computation, address: EthAddress,
|
|
||||||
data: ptr byte, dataSize: int,
|
|
||||||
topics: UncheckedArray[evmc_bytes32], topicsCount: int) {.cdecl.} =
|
|
||||||
var log: Log
|
|
||||||
if topicsCount > 0:
|
|
||||||
log.topics = newSeq[Topic](topicsCount)
|
|
||||||
for i in 0 ..< topicsCount:
|
|
||||||
log.topics[i] = topics[i].bytes
|
|
||||||
|
|
||||||
log.data = @(makeOpenArray(data, dataSize))
|
|
||||||
log.address = address
|
|
||||||
ctx.addLogEntry(log)
|
|
||||||
|
|
||||||
template createImpl(c: Computation, m: nimbus_message, res: nimbus_result) =
|
|
||||||
# TODO: use evmc_message to evoid copy
|
|
||||||
let childMsg = Message(
|
|
||||||
kind: CallKind(m.kind),
|
|
||||||
depth: m.depth,
|
|
||||||
gas: m.gas,
|
|
||||||
sender: m.sender,
|
|
||||||
value: Uint256.fromEvmc(m.value),
|
|
||||||
data: @(makeOpenArray(m.inputData, m.inputSize.int))
|
|
||||||
)
|
|
||||||
|
|
||||||
let child = newComputation(c.vmState, childMsg, Uint256.fromEvmc(m.create2_salt))
|
|
||||||
child.execCallOrCreate()
|
|
||||||
|
|
||||||
if not child.shouldBurnGas:
|
|
||||||
res.gas_left = child.gasMeter.gasRemaining
|
|
||||||
|
|
||||||
if child.isSuccess:
|
|
||||||
c.merge(child)
|
|
||||||
res.status_code = EVMC_SUCCESS
|
|
||||||
res.create_address = child.msg.contractAddress
|
|
||||||
else:
|
|
||||||
res.status_code = if child.shouldBurnGas: EVMC_FAILURE else: EVMC_REVERT
|
|
||||||
if child.output.len > 0:
|
|
||||||
# TODO: can we move the ownership of seq to raw pointer?
|
|
||||||
res.output_size = child.output.len.uint
|
|
||||||
res.output_data = cast[ptr byte](alloc(child.output.len))
|
|
||||||
copyMem(res.output_data, child.output[0].addr, child.output.len)
|
|
||||||
res.release = hostReleaseResultImpl
|
|
||||||
|
|
||||||
template callImpl(c: Computation, m: nimbus_message, res: nimbus_result) =
|
|
||||||
let childMsg = Message(
|
|
||||||
kind: CallKind(m.kind),
|
|
||||||
depth: m.depth,
|
|
||||||
gas: m.gas,
|
|
||||||
sender: m.sender,
|
|
||||||
codeAddress: m.destination,
|
|
||||||
contractAddress: if m.kind == EVMC_CALL: m.destination else: c.msg.contractAddress,
|
|
||||||
value: Uint256.fromEvmc(m.value),
|
|
||||||
data: @(makeOpenArray(m.inputData, m.inputSize.int)),
|
|
||||||
flags: MsgFlags(m.flags)
|
|
||||||
)
|
|
||||||
|
|
||||||
let child = newComputation(c.vmState, childMsg)
|
|
||||||
child.execCallOrCreate()
|
|
||||||
|
|
||||||
if not child.shouldBurnGas:
|
|
||||||
res.gas_left = child.gasMeter.gasRemaining
|
|
||||||
|
|
||||||
if child.isSuccess:
|
|
||||||
c.merge(child)
|
|
||||||
res.status_code = EVMC_SUCCESS
|
|
||||||
else:
|
|
||||||
res.status_code = if child.shouldBurnGas: EVMC_FAILURE else: EVMC_REVERT
|
|
||||||
|
|
||||||
if child.output.len > 0:
|
|
||||||
# TODO: can we move the ownership of seq to raw pointer?
|
|
||||||
res.output_size = child.output.len.uint
|
|
||||||
res.output_data = cast[ptr byte](alloc(child.output.len))
|
|
||||||
copyMem(res.output_data, child.output[0].addr, child.output.len)
|
|
||||||
res.release = hostReleaseResultImpl
|
|
||||||
|
|
||||||
proc hostCallImpl(ctx: Computation, msg: var nimbus_message): nimbus_result {.cdecl.} =
|
|
||||||
if msg.kind == EVMC_CREATE or msg.kind == EVMC_CREATE2:
|
|
||||||
createImpl(ctx, msg, result)
|
|
||||||
else:
|
|
||||||
callImpl(ctx, msg, result)
|
|
||||||
|
|
||||||
proc initHostInterface(): evmc_host_interface =
|
|
||||||
result.account_exists = cast[evmc_account_exists_fn](hostAccountExistsImpl)
|
|
||||||
result.get_storage = cast[evmc_get_storage_fn](hostGetStorageImpl)
|
|
||||||
result.set_storage = cast[evmc_set_storage_fn](hostSetStorageImpl)
|
|
||||||
result.get_balance = cast[evmc_get_balance_fn](hostGetBalanceImpl)
|
|
||||||
result.get_code_size = cast[evmc_get_code_size_fn](hostGetCodeSizeImpl)
|
|
||||||
result.get_code_hash = cast[evmc_get_code_hash_fn](hostGetCodeHashImpl)
|
|
||||||
result.copy_code = cast[evmc_copy_code_fn](hostCopyCodeImpl)
|
|
||||||
result.selfdestruct = cast[evmc_selfdestruct_fn](hostSelfdestructImpl)
|
|
||||||
result.call = cast[evmc_call_fn](hostCallImpl)
|
|
||||||
result.get_tx_context = cast[evmc_get_tx_context_fn](hostGetTxContextImpl)
|
|
||||||
result.get_block_hash = cast[evmc_get_block_hash_fn](hostGetBlockHashImpl)
|
|
||||||
result.emit_log = cast[evmc_emit_log_fn](hostEmitLogImpl)
|
|
||||||
|
|
||||||
proc vmSetOptionImpl(vm: ptr evmc_vm, name, value: cstring): evmc_set_option_result {.cdecl.} =
|
|
||||||
return EVMC_SET_OPTION_INVALID_NAME
|
|
||||||
|
|
||||||
proc vmExecuteImpl(vm: ptr evmc_vm, host: ptr evmc_host_interface,
|
|
||||||
ctx: Computation, rev: evmc_revision,
|
|
||||||
msg: evmc_message, code: ptr byte, code_size: uint): evmc_result {.cdecl.} =
|
|
||||||
discard
|
|
||||||
|
|
||||||
proc vmGetCapabilitiesImpl(vm: ptr evmc_vm): evmc_capabilities {.cdecl.} =
|
|
||||||
result.incl(EVMC_CAPABILITY_EVM1)
|
|
||||||
|
|
||||||
proc vmDestroyImpl(vm: ptr evmc_vm) {.cdecl.} =
|
|
||||||
dealloc(vm)
|
|
||||||
|
|
||||||
const
|
|
||||||
EVMC_HOST_NAME = "nimbus_vm"
|
|
||||||
EVMC_VM_VERSION = "0.0.1"
|
|
||||||
|
|
||||||
proc init(vm: var evmc_vm) =
|
|
||||||
vm.abi_version = EVMC_ABI_VERSION
|
|
||||||
vm.name = EVMC_HOST_NAME
|
|
||||||
vm.version = EVMC_VM_VERSION
|
|
||||||
vm.destroy = vmDestroyImpl
|
|
||||||
vm.execute = cast[evmc_execute_fn](vmExecuteImpl)
|
|
||||||
vm.get_capabilities = vmGetCapabilitiesImpl
|
|
||||||
vm.set_option = vmSetOptionImpl
|
|
||||||
|
|
||||||
let gHost = initHostInterface()
|
|
||||||
proc nim_host_get_interface(): ptr nimbus_host_interface {.exportc, cdecl.} =
|
|
||||||
result = cast[ptr nimbus_host_interface](gHost.unsafeAddr)
|
|
||||||
|
|
||||||
proc nim_host_create_context(vmstate: BaseVmState, msg: ptr evmc_message): Computation {.exportc, cdecl.} =
|
|
||||||
#result = HostContext(
|
|
||||||
# vmState: vmstate,
|
|
||||||
# gasPrice: GasInt(gasPrice),
|
|
||||||
# origin: fromEvmc(origin)
|
|
||||||
#)
|
|
||||||
GC_ref(result)
|
|
||||||
|
|
||||||
proc nim_host_destroy_context(ctx: Computation) {.exportc, cdecl.} =
|
|
||||||
GC_unref(ctx)
|
|
||||||
|
|
||||||
proc nim_create_nimbus_vm(): ptr evmc_vm {.exportc, cdecl.} =
|
|
||||||
result = create(evmc_vm)
|
|
||||||
init(result[])
|
|
|
@ -15,9 +15,6 @@ import
|
||||||
./utils/[macros_gen_opcodes, utils_numeric],
|
./utils/[macros_gen_opcodes, utils_numeric],
|
||||||
./opcode_values, ./vm_forks, ../../errors
|
./opcode_values, ./vm_forks, ../../errors
|
||||||
|
|
||||||
when defined(evmc_enabled):
|
|
||||||
import evmc/evmc
|
|
||||||
|
|
||||||
# Gas Fee Schedule
|
# Gas Fee Schedule
|
||||||
# Yellow Paper Appendix G - https://ethereum.github.io/yellowpaper/paper.pdf
|
# Yellow Paper Appendix G - https://ethereum.github.io/yellowpaper/paper.pdf
|
||||||
type
|
type
|
||||||
|
@ -72,8 +69,6 @@ type
|
||||||
|
|
||||||
case kind*: Op
|
case kind*: Op
|
||||||
of Sstore:
|
of Sstore:
|
||||||
when defined(evmc_enabled):
|
|
||||||
s_status*: evmc_storage_status
|
|
||||||
s_currentValue*: Uint256
|
s_currentValue*: Uint256
|
||||||
s_originalValue*: Uint256
|
s_originalValue*: Uint256
|
||||||
of Call, CallCode, DelegateCall, StaticCall:
|
of Call, CallCode, DelegateCall, StaticCall:
|
||||||
|
@ -244,32 +239,7 @@ template gasCosts(fork: Fork, prefix, ResultGasCostsName: untyped) =
|
||||||
CleanRefund = SSTORE_RESET_GAS - SLOAD_GAS # resetting to the original non-zero value
|
CleanRefund = SSTORE_RESET_GAS - SLOAD_GAS # resetting to the original non-zero value
|
||||||
ClearRefund = FeeSchedule[RefundsClear]# clearing an originally existing storage slot
|
ClearRefund = FeeSchedule[RefundsClear]# clearing an originally existing storage slot
|
||||||
|
|
||||||
when defined(evmc_enabled):
|
block:
|
||||||
const
|
|
||||||
sstoreDirty = when fork < FkConstantinople or fork == FkPetersburg: CleanGas
|
|
||||||
else: DirtyGas
|
|
||||||
|
|
||||||
case gasParams.s_status
|
|
||||||
of EVMC_STORAGE_ADDED: result.gasCost = InitGas
|
|
||||||
of EVMC_STORAGE_MODIFIED: result.gasCost = CleanGas
|
|
||||||
of EVMC_STORAGE_DELETED:
|
|
||||||
result.gasCost = CleanGas
|
|
||||||
result.gasRefund += ClearRefund
|
|
||||||
of EVMC_STORAGE_UNCHANGED: result.gasCost = sstoreDirty
|
|
||||||
of EVMC_STORAGE_MODIFIED_AGAIN:
|
|
||||||
result.gasCost = sstoreDirty
|
|
||||||
if not gasParams.s_originalValue.isZero:
|
|
||||||
if gasParams.s_currentValue.isZero:
|
|
||||||
result.gasRefund -= ClearRefund
|
|
||||||
if value.isZero:
|
|
||||||
result.gasRefund += ClearRefund
|
|
||||||
|
|
||||||
if gasParams.s_originalValue == value:
|
|
||||||
if gasParams.s_originalValue.isZero:
|
|
||||||
result.gasRefund += InitRefund
|
|
||||||
else:
|
|
||||||
result.gasRefund += CleanRefund
|
|
||||||
else:
|
|
||||||
when fork < FkConstantinople or fork == FkPetersburg:
|
when fork < FkConstantinople or fork == FkPetersburg:
|
||||||
let isStorageEmpty = gasParams.s_currentValue.isZero
|
let isStorageEmpty = gasParams.s_currentValue.isZero
|
||||||
|
|
||||||
|
|
|
@ -14,9 +14,6 @@ import
|
||||||
../../errors, ../../constants,
|
../../errors, ../../constants,
|
||||||
../../db/[db_chain, accounts_cache]
|
../../db/[db_chain, accounts_cache]
|
||||||
|
|
||||||
when defined(evmc_enabled):
|
|
||||||
import ../evmc_api, ../evmc_helpers, evmc/evmc
|
|
||||||
|
|
||||||
logScope:
|
logScope:
|
||||||
topics = "opcode impl"
|
topics = "opcode impl"
|
||||||
|
|
||||||
|
@ -439,8 +436,7 @@ op sload, inline = true, slot:
|
||||||
## 0x54, Load word from storage.
|
## 0x54, Load word from storage.
|
||||||
push: c.getStorage(slot)
|
push: c.getStorage(slot)
|
||||||
|
|
||||||
when not evmc_enabled:
|
template sstoreImpl(c: Computation, slot, newValue: Uint256) =
|
||||||
template sstoreImpl(c: Computation, slot, newValue: Uint256) =
|
|
||||||
let currentValue {.inject.} = c.getStorage(slot)
|
let currentValue {.inject.} = c.getStorage(slot)
|
||||||
|
|
||||||
let
|
let
|
||||||
|
@ -455,27 +451,13 @@ when not evmc_enabled:
|
||||||
c.vmState.mutateStateDB:
|
c.vmState.mutateStateDB:
|
||||||
db.setStorage(c.msg.contractAddress, slot, newValue)
|
db.setStorage(c.msg.contractAddress, slot, newValue)
|
||||||
|
|
||||||
when evmc_enabled:
|
|
||||||
template sstoreEvmc(c: Computation, slot, newValue: Uint256) =
|
|
||||||
let
|
|
||||||
currentValue {.inject.} = c.getStorage(slot)
|
|
||||||
status = c.host.setStorage(c.msg.contractAddress, slot, newValue)
|
|
||||||
gasParam = GasParams(kind: Op.Sstore, s_status: status)
|
|
||||||
gasCost = c.gasCosts[Sstore].c_handler(newValue, gasParam)[0]
|
|
||||||
|
|
||||||
c.gasMeter.consumeGas(gasCost, &"SSTORE: {c.msg.contractAddress}[{slot}] -> {newValue} ({currentValue})")
|
|
||||||
|
|
||||||
op sstore, inline = false, slot, newValue:
|
op sstore, inline = false, slot, newValue:
|
||||||
## 0x55, Save word to storage.
|
## 0x55, Save word to storage.
|
||||||
checkInStaticContext(c)
|
checkInStaticContext(c)
|
||||||
|
block:
|
||||||
when evmc_enabled:
|
|
||||||
sstoreEvmc(c, slot, newValue)
|
|
||||||
else:
|
|
||||||
sstoreImpl(c, slot, newValue)
|
sstoreImpl(c, slot, newValue)
|
||||||
|
|
||||||
when not evmc_enabled:
|
template sstoreNetGasMeteringImpl(c: Computation, slot, newValue: Uint256) =
|
||||||
template sstoreNetGasMeteringImpl(c: Computation, slot, newValue: Uint256) =
|
|
||||||
let stateDB = c.vmState.readOnlyStateDB
|
let stateDB = c.vmState.readOnlyStateDB
|
||||||
let currentValue {.inject.} = c.getStorage(slot)
|
let currentValue {.inject.} = c.getStorage(slot)
|
||||||
|
|
||||||
|
@ -500,18 +482,12 @@ op sstoreEIP2200, inline = false, slot, newValue:
|
||||||
|
|
||||||
if c.gasMeter.gasRemaining <= SentryGasEIP2200:
|
if c.gasMeter.gasRemaining <= SentryGasEIP2200:
|
||||||
raise newException(OutOfGas, "Gas not enough to perform EIP2200 SSTORE")
|
raise newException(OutOfGas, "Gas not enough to perform EIP2200 SSTORE")
|
||||||
|
block:
|
||||||
when evmc_enabled:
|
|
||||||
sstoreEvmc(c, slot, newValue)
|
|
||||||
else:
|
|
||||||
sstoreNetGasMeteringImpl(c, slot, newValue)
|
sstoreNetGasMeteringImpl(c, slot, newValue)
|
||||||
|
|
||||||
op sstoreEIP1283, inline = false, slot, newValue:
|
op sstoreEIP1283, inline = false, slot, newValue:
|
||||||
checkInStaticContext(c)
|
checkInStaticContext(c)
|
||||||
|
block:
|
||||||
when evmc_enabled:
|
|
||||||
sstoreEvmc(c, slot, newValue)
|
|
||||||
else:
|
|
||||||
sstoreNetGasMeteringImpl(c, slot, newValue)
|
sstoreNetGasMeteringImpl(c, slot, newValue)
|
||||||
|
|
||||||
proc jumpImpl(c: Computation, jumpTarget: UInt256) =
|
proc jumpImpl(c: Computation, jumpTarget: UInt256) =
|
||||||
|
@ -645,29 +621,7 @@ template genCreate(callName: untyped, opCode: Op): untyped =
|
||||||
createMsgGas -= createMsgGas div 64
|
createMsgGas -= createMsgGas div 64
|
||||||
c.gasMeter.consumeGas(createMsgGas, reason="CREATE")
|
c.gasMeter.consumeGas(createMsgGas, reason="CREATE")
|
||||||
|
|
||||||
when evmc_enabled:
|
block:
|
||||||
let msg = nimbus_message(
|
|
||||||
kind: callKind.evmc_call_kind,
|
|
||||||
depth: (c.msg.depth + 1).int32,
|
|
||||||
gas: createMsgGas,
|
|
||||||
sender: c.msg.contractAddress,
|
|
||||||
input_data: c.memory.readPtr(memPos),
|
|
||||||
input_size: memLen.uint,
|
|
||||||
value: toEvmc(endowment),
|
|
||||||
create2_salt: toEvmc(salt)
|
|
||||||
)
|
|
||||||
|
|
||||||
var res = c.host.call(msg)
|
|
||||||
c.returnData = @(makeOpenArray(res.outputData, res.outputSize.int))
|
|
||||||
c.gasMeter.returnGas(res.gas_left)
|
|
||||||
|
|
||||||
if res.status_code == EVMC_SUCCESS:
|
|
||||||
c.stack.top(res.create_address)
|
|
||||||
|
|
||||||
# TODO: a good candidate for destructor
|
|
||||||
if not res.release.isNil:
|
|
||||||
res.release(res)
|
|
||||||
else:
|
|
||||||
let childMsg = Message(
|
let childMsg = Message(
|
||||||
kind: callKind,
|
kind: callKind,
|
||||||
depth: c.msg.depth + 1,
|
depth: c.msg.depth + 1,
|
||||||
|
@ -828,36 +782,7 @@ template genCall(callName: untyped, opCode: Op): untyped =
|
||||||
c.gasMeter.returnGas(childGasLimit)
|
c.gasMeter.returnGas(childGasLimit)
|
||||||
return
|
return
|
||||||
|
|
||||||
when evmc_enabled:
|
block:
|
||||||
let msg = nimbus_message(
|
|
||||||
kind: callKind.evmc_call_kind,
|
|
||||||
depth: (c.msg.depth + 1).int32,
|
|
||||||
gas: childGasLimit,
|
|
||||||
sender: sender,
|
|
||||||
destination: destination,
|
|
||||||
input_data: c.memory.readPtr(memInPos),
|
|
||||||
input_size: memInLen.uint,
|
|
||||||
value: toEvmc(value),
|
|
||||||
flags: flags.uint32
|
|
||||||
)
|
|
||||||
|
|
||||||
var res = c.host.call(msg)
|
|
||||||
c.returnData = @(makeOpenArray(res.outputData, res.outputSize.int))
|
|
||||||
|
|
||||||
let actualOutputSize = min(memOutLen, c.returnData.len)
|
|
||||||
if actualOutputSize > 0:
|
|
||||||
c.memory.write(memOutPos,
|
|
||||||
c.returnData.toOpenArray(0, actualOutputSize - 1))
|
|
||||||
|
|
||||||
c.gasMeter.returnGas(res.gas_left)
|
|
||||||
|
|
||||||
if res.status_code == EVMC_SUCCESS:
|
|
||||||
c.stack.top(1)
|
|
||||||
|
|
||||||
# TODO: a good candidate for destructor
|
|
||||||
if not res.release.isNil:
|
|
||||||
res.release(res)
|
|
||||||
else:
|
|
||||||
let msg = Message(
|
let msg = Message(
|
||||||
kind: callKind,
|
kind: callKind,
|
||||||
depth: c.msg.depth + 1,
|
depth: c.msg.depth + 1,
|
||||||
|
@ -1058,7 +983,5 @@ op sstoreEIP2929, inline = false, slot, newValue:
|
||||||
db.accessList(c.msg.contractAddress, slot)
|
db.accessList(c.msg.contractAddress, slot)
|
||||||
c.gasMeter.consumeGas(ColdSloadCost, reason = "sstoreEIP2929")
|
c.gasMeter.consumeGas(ColdSloadCost, reason = "sstoreEIP2929")
|
||||||
|
|
||||||
when evmc_enabled:
|
block:
|
||||||
sstoreEvmc(c, slot, newValue)
|
|
||||||
else:
|
|
||||||
sstoreNetGasMeteringImpl(c, slot, newValue)
|
sstoreNetGasMeteringImpl(c, slot, newValue)
|
||||||
|
|
|
@ -14,9 +14,6 @@ import
|
||||||
../../types, ../../../errors, ../gas_meter, ../opcode_values,
|
../../types, ../../../errors, ../gas_meter, ../opcode_values,
|
||||||
./utils_numeric
|
./utils_numeric
|
||||||
|
|
||||||
when defined(evmc_enabled):
|
|
||||||
import ../../evmc_api, evmc/evmc
|
|
||||||
|
|
||||||
proc pop(tree: var NimNode): NimNode =
|
proc pop(tree: var NimNode): NimNode =
|
||||||
## Returns the last value of a NimNode and remove it
|
## Returns the last value of a NimNode and remove it
|
||||||
result = tree[tree.len-1]
|
result = tree[tree.len-1]
|
||||||
|
@ -122,15 +119,7 @@ proc logImpl(c: Computation, opcode: Op, topicCount: int) =
|
||||||
reason="Memory expansion, Log topic and data gas cost")
|
reason="Memory expansion, Log topic and data gas cost")
|
||||||
c.memory.extend(memPos, len)
|
c.memory.extend(memPos, len)
|
||||||
|
|
||||||
when evmc_enabled:
|
block:
|
||||||
var topics: array[4, evmc_bytes32]
|
|
||||||
for i in 0 ..< topicCount:
|
|
||||||
topics[i].bytes = c.stack.popTopic()
|
|
||||||
|
|
||||||
c.host.emitLog(c.msg.contractAddress,
|
|
||||||
c.memory.read(memPos, len),
|
|
||||||
topics[0].addr, topicCount)
|
|
||||||
else:
|
|
||||||
var log: Log
|
var log: Log
|
||||||
log.topics = newSeqOfCap[Topic](topicCount)
|
log.topics = newSeqOfCap[Topic](topicCount)
|
||||||
for i in 0 ..< topicCount:
|
for i in 0 ..< topicCount:
|
||||||
|
|
|
@ -47,11 +47,6 @@ proc read*(memory: var Memory, startPos: Natural, size: Natural): seq[byte] =
|
||||||
# TODO: use an openarray[byte]
|
# TODO: use an openarray[byte]
|
||||||
result = memory.bytes[startPos ..< (startPos + size)]
|
result = memory.bytes[startPos ..< (startPos + size)]
|
||||||
|
|
||||||
when defined(evmc_enabled):
|
|
||||||
proc readPtr*(memory: var Memory, startPos: Natural): ptr byte =
|
|
||||||
if memory.bytes.len == 0 or startPos >= memory.bytes.len: return
|
|
||||||
result = memory.bytes[startPos].addr
|
|
||||||
|
|
||||||
proc write*(memory: var Memory, startPos: Natural, value: openarray[byte]) =
|
proc write*(memory: var Memory, startPos: Natural, value: openarray[byte]) =
|
||||||
let size = value.len
|
let size = value.len
|
||||||
if size == 0:
|
if size == 0:
|
||||||
|
|
|
@ -21,10 +21,6 @@ import
|
||||||
# TODO - will be hidden at a lower layer
|
# TODO - will be hidden at a lower layer
|
||||||
../db/[db_chain, accounts_cache]
|
../db/[db_chain, accounts_cache]
|
||||||
|
|
||||||
when defined(evmc_enabled):
|
|
||||||
import
|
|
||||||
./evmc_api
|
|
||||||
|
|
||||||
type
|
type
|
||||||
VMFlag* = enum
|
VMFlag* = enum
|
||||||
ExecutionOK
|
ExecutionOK
|
||||||
|
@ -73,8 +69,6 @@ type
|
||||||
Computation* = ref object
|
Computation* = ref object
|
||||||
# The execution computation
|
# The execution computation
|
||||||
vmState*: BaseVMState
|
vmState*: BaseVMState
|
||||||
when defined(evmc_enabled):
|
|
||||||
host*: HostContext
|
|
||||||
msg*: Message
|
msg*: Message
|
||||||
memory*: Memory
|
memory*: Memory
|
||||||
stack*: Stack
|
stack*: Stack
|
||||||
|
|
Loading…
Reference in New Issue