nimbus-eth1/nimbus/transaction/evmc_vm_glue.nim
Jordan Hrycaj df1217b7ca
Silence compiler gossip after nim upgrade cont3 (#1466)
* Removed some Windows specific unit test annoyances

details:
+ Short put()/get() cycles on persistent database have a race condition
  with vendor rocksdb. On a specific (and slow) qemu/win7 a 50ms `sleep()`
  in between will mostly do the job (i.e. unless heavy CPU load.) This
  issue was not observed on github/ci.
+ Removed annoyances when qemu/Win7 keeps the rocksdb database files
  locked even after closing the db. The problem is solved by strictly
  using fresh names for each test. No assumption made to be able to
  properly clean up. This issue was not observed on github/ci.

* Silence some compiler gossip -- part 7, misc/non(sync or graphql)

details:
  Adding some missing exception annotation
2023-02-14 20:27:17 +00:00

108 lines
4.7 KiB
Nim

# Nimbus - Binary compatibility on the VM side of the EVMC API interface
#
# Copyright (c) 2019-2021 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.
{.push raises: [].}
import
./host_types, evmc/evmc, stew/ranges/ptr_arith,
".."/[vm_types, vm_computation, vm_state_transactions]
proc evmcReleaseResult(result: var evmc_result) {.cdecl.} =
dealloc(result.output_data)
proc evmcExecute(vm: ptr evmc_vm, hostInterface: ptr evmc_host_interface,
hostContext: evmc_host_context, rev: evmc_revision,
msg: var evmc_message, code: ptr byte,
code_size: csize_t): evmc_result
{.cdecl, raises: [CatchableError].} =
# TODO: Obviously we are cheating here at the moment, knowing the caller type.
# TODO: This lets the host read extra results needed for tests, but it
# means the Nimbus EVM cannot be used by a non-Nimbus host, yet.
let host = cast[TransactionHost](hostContext)
var c = host.computation
# Allocate `Computation` on demand, and leave it in `host` for that to
# extract additional results.
#if c.isNil:
# let cMsg = hostToComputationMessage(host.msg)
# # TODO: Can we avoid `seq[byte]` so we don't have to copy the code?
# let codeSeq = if code_size <= 0: @[]
# else: @(makeOpenArray(code, code_size.int))
# c = newComputation(host.vmState, cMsg, codeSeq)
# c.host.init(cast[ptr nimbus_host_interface](hostInterface), hostContext)
# host.computation = c
c.host.init(cast[ptr nimbus_host_interface](hostInterface), hostContext)
execComputation(c)
# When output size is zero, output data pointer may be null.
var output_data: ptr byte
var output_size: int
if c.output.len > 0:
# TODO: Don't use a copy, share the underlying data and use `GC_ref`.
# Return a copy, because reference counting is complicated across the
# shared library boundary. We could use a refcount but we don't have a
# `ref seq[byte]` to start with, so need to check `GC_ref` on a non-ref
# `seq` does what we want first.
output_size = c.output.len
# The `alloc` here matches `dealloc` in `evmcReleaseResult`.
output_data = cast[ptr byte](alloc(output_size))
copyMem(output_data, c.output[0].addr, output_size)
return evmc_result(
# Standard EVMC result, if a bit generic.
status_code: if c.isSuccess: EVMC_SUCCESS
elif not c.error.burnsGas: EVMC_REVERT
else: EVMC_FAILURE,
# Gas left is required to be zero when not `EVMC_SUCCESS` or `EVMC_REVERT`.
gas_left: if result.status_code notin {EVMC_SUCCESS, EVMC_REVERT}: 0'i64
else: c.gasMeter.gasRemaining.int64,
gas_refund: if result.status_code == EVMC_SUCCESS: c.gasMeter.gasRefunded.int64
else: 0'i64,
output_data: output_data,
output_size: output_size.csize_t,
release: if output_data.isNil: nil
else: evmcReleaseResult
# Nim defaults are fine for `create_address` and `padding`, zero bytes.
)
const evmcName = "Nimbus EVM (vm2)"
const evmcVersion = "0.0.1"
proc evmcGetCapabilities(vm: ptr evmc_vm): evmc_capabilities {.cdecl.} =
{EVMC_CAPABILITY_EVM1, EVMC_CAPABILITY_PRECOMPILES}
proc evmcSetOption(vm: ptr evmc_vm, name, value: cstring): evmc_set_option_result {.cdecl.} =
return EVMC_SET_OPTION_INVALID_NAME
proc evmcDestroy(vm: ptr evmc_vm) {.cdecl.} =
GC_unref(cast[ref evmc_vm](vm))
proc evmc_create_nimbus_evm(): ptr evmc_vm {.cdecl, exportc.} =
## Entry point to the Nimbus EVM, using an EVMC compatible interface.
## This is an exported C function. EVMC specifies the function must
## have this name format when exported from a shared library.
let vm = (ref evmc_vm)(
abi_version: EVMC_ABI_VERSION,
name: evmcName,
version: evmcVersion,
destroy: evmcDestroy,
execute: evmcExecute,
get_capabilities: evmcGetCapabilities,
set_option: evmcSetOption
)
# Keep an extra reference on this, until `evmcDestroy` is called.
GC_ref(vm)
return cast[ptr evmc_vm](vm)
# This code assumes fields, methods and types of ABI version 10, and must be
# checked for compatibility if the `import evmc/evmc` major version is updated.
when EVMC_ABI_VERSION != 10:
{.error: ("This code assumes EVMC_ABI_VERSION 10;" &
" update the code to use EVMC_ABI_VERSION " & $EVMC_ABI_VERSION).}