From ad51a35021faae55cdc71393eacf8d77699d1718 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C8=98tefan=20Talpalaru?= Date: Wed, 22 Jan 2020 02:00:59 +0100 Subject: [PATCH] Nim wrapper refactoring - no more copies of original EVMC files - automated C API wrapper generation using c2nim, sed and gawk - removed changes to nim_host_create_context() that depended on custom changes to the example C++ host, since the test suite is the same for both --- .appveyor.yml | 39 - bindings/nim/.gitignore | 6 + bindings/nim/README.md | 20 + evmc.nimble => bindings/nim/evmc.nimble | 8 + bindings/nim/evmc/evmc.nim | 127 +++ {evmc => bindings/nim/evmc}/evmc_nim.nim | 17 +- bindings/nim/evmc/generate_wrapper.sh | 57 ++ .../nim/tests}/nim_host.nim | 113 +-- .../nim/tests}/test_host_vm.nim | 50 +- evmc/evmc.nim | 695 ------------- evmc/evmjit.nim | 18 - tests/evmc_c/evmc.h | 941 ------------------ tests/evmc_c/evmc.hpp | 805 --------------- tests/evmc_c/example_host.cpp | 186 ---- tests/evmc_c/example_vm.cpp | 235 ----- tests/evmc_c/helpers.h | 212 ---- 16 files changed, 301 insertions(+), 3228 deletions(-) delete mode 100644 .appveyor.yml create mode 100644 bindings/nim/.gitignore create mode 100644 bindings/nim/README.md rename evmc.nimble => bindings/nim/evmc.nimble (76%) create mode 100644 bindings/nim/evmc/evmc.nim rename {evmc => bindings/nim/evmc}/evmc_nim.nim (86%) create mode 100755 bindings/nim/evmc/generate_wrapper.sh rename {tests/evmc_nim => bindings/nim/tests}/nim_host.nim (61%) rename {tests => bindings/nim/tests}/test_host_vm.nim (77%) delete mode 100644 evmc/evmc.nim delete mode 100644 evmc/evmjit.nim delete mode 100644 tests/evmc_c/evmc.h delete mode 100644 tests/evmc_c/evmc.hpp delete mode 100644 tests/evmc_c/example_host.cpp delete mode 100644 tests/evmc_c/example_vm.cpp delete mode 100644 tests/evmc_c/helpers.h diff --git a/.appveyor.yml b/.appveyor.yml deleted file mode 100644 index 880b8e1..0000000 --- a/.appveyor.yml +++ /dev/null @@ -1,39 +0,0 @@ -version: '{build}' - -image: Visual Studio 2015 - -cache: - - NimBinaries - -matrix: - # We always want 32 and 64-bit compilation - fast_finish: false - -platform: - - x86 - - x64 - -# when multiple CI builds are queued, the tested commit needs to be in the last X commits cloned with "--depth X" -clone_depth: 10 - -install: - # use the newest versions documented here: https://www.appveyor.com/docs/windows-images-software/#mingw-msys-cygwin - - IF "%PLATFORM%" == "x86" SET PATH=C:\mingw-w64\i686-6.3.0-posix-dwarf-rt_v5-rev1\mingw32\bin;%PATH% - - IF "%PLATFORM%" == "x64" SET PATH=C:\mingw-w64\x86_64-8.1.0-posix-seh-rt_v6-rev0\mingw64\bin;%PATH% - - # build nim from our own branch - this to avoid the day-to-day churn and - # regressions of the fast-paced Nim development while maintaining the - # flexibility to apply patches - - curl -O -L -s -S https://raw.githubusercontent.com/status-im/nimbus-build-system/master/scripts/build_nim.sh - - env MAKE="mingw32-make -j2" ARCH_OVERRIDE=%PLATFORM% bash build_nim.sh Nim csources dist/nimble NimBinaries - - SET PATH=%CD%\Nim\bin;%PATH% - -build_script: - - cd C:\projects\%APPVEYOR_PROJECT_SLUG% - - nimble install -y - -test_script: - - nimble test - -deploy: off - diff --git a/bindings/nim/.gitignore b/bindings/nim/.gitignore new file mode 100644 index 0000000..613044e --- /dev/null +++ b/bindings/nim/.gitignore @@ -0,0 +1,6 @@ +# Nim +nimcache/ + +# Executables shall be put in an ignored build/ directory +build/ + diff --git a/bindings/nim/README.md b/bindings/nim/README.md new file mode 100644 index 0000000..5e47f86 --- /dev/null +++ b/bindings/nim/README.md @@ -0,0 +1,20 @@ +# Nim EVMC wrapper + +[![License: Apache](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://opensource.org/licenses/Apache-2.0) + +# Introduction + +This is a Nim wrapper for EVMC, the [Ethereum Client-VM Connector API](https://github.com/ethereum/evmc). + +# Installation + +`nimble install evmc` + +# Testing + +`nimble test` + +# License + +Licensed and distributed under the Apache License, Version 2.0, ([LICENSE](../../LICENSE) or http://www.apache.org/licenses/LICENSE-2.0) + diff --git a/evmc.nimble b/bindings/nim/evmc.nimble similarity index 76% rename from evmc.nimble rename to bindings/nim/evmc.nimble index c8b222a..0cfd822 100644 --- a/evmc.nimble +++ b/bindings/nim/evmc.nimble @@ -1,3 +1,8 @@ +# Copyright (c) 2018-2020 Status Research & Development GmbH +# Licensed under the Apache License, Version 2.0. +# This file may not be copied, modified, or distributed except according to +# those terms. + mode = ScriptMode.Verbose packageName = "evmc" @@ -14,6 +19,9 @@ proc test(name: string, lang: string = "cpp") = if not dirExists "build": mkDir "build" --run + --forceBuild + --verbosity:0 + --hints:off switch("out", ("./build/" & name)) setCommand lang, "tests/" & name & ".nim" diff --git a/bindings/nim/evmc/evmc.nim b/bindings/nim/evmc/evmc.nim new file mode 100644 index 0000000..4408f2e --- /dev/null +++ b/bindings/nim/evmc/evmc.nim @@ -0,0 +1,127 @@ +type + evmc_bytes32* {.importc: "evmc_bytes32", header: "evmc/evmc.h", bycopy.} = object + bytes* {.importc: "bytes".}: array[32, uint8] + evmc_uint256be* = evmc_bytes32 + evmc_address* {.importc: "evmc_address", header: "evmc/evmc.h", bycopy.} = object + bytes* {.importc: "bytes".}: array[20, uint8] + evmc_call_kind* {.size: sizeof(cint).} = enum + EVMC_CALL = 0, EVMC_DELEGATECALL = 1, EVMC_CALLCODE = 2, EVMC_CREATE = 3, + EVMC_CREATE2 = 4 + evmc_flags* {.size: sizeof(cint).} = enum + EVMC_STATIC = 1 + evmc_message* {.importc: "struct evmc_message", header: "evmc/evmc.h", bycopy.} = object + kind* {.importc: "kind".}: evmc_call_kind + flags* {.importc: "flags".}: uint32 + depth* {.importc: "depth".}: int32 + gas* {.importc: "gas".}: int64 + destination* {.importc: "destination".}: evmc_address + sender* {.importc: "sender".}: evmc_address + input_data* {.importc: "input_data".}: ptr uint8 + input_size* {.importc: "input_size".}: uint + value* {.importc: "value".}: evmc_uint256be + create2_salt* {.importc: "create2_salt".}: evmc_bytes32 + evmc_tx_context* {.importc: "struct evmc_tx_context", header: "evmc/evmc.h", bycopy.} = object + tx_gas_price* {.importc: "tx_gas_price".}: evmc_uint256be + tx_origin* {.importc: "tx_origin".}: evmc_address + block_coinbase* {.importc: "block_coinbase".}: evmc_address + block_number* {.importc: "block_number".}: int64 + block_timestamp* {.importc: "block_timestamp".}: int64 + block_gas_limit* {.importc: "block_gas_limit".}: int64 + block_difficulty* {.importc: "block_difficulty".}: evmc_uint256be + chain_id* {.importc: "chain_id".}: evmc_uint256be + evmc_host_context* {.importc: "struct evmc_host_context", header: "evmc/evmc.h", bycopy.} = object + evmc_get_tx_context_fn* = proc (context: ptr evmc_host_context): evmc_tx_context {. + cdecl.} + evmc_get_block_hash_fn* = proc (context: ptr evmc_host_context; number: int64): evmc_bytes32 {. + cdecl.} + evmc_status_code* {.size: sizeof(cint).} = enum + EVMC_OUT_OF_MEMORY = -3, EVMC_REJECTED = -2, EVMC_INTERNAL_ERROR = -1, + EVMC_SUCCESS = 0, EVMC_FAILURE = 1, EVMC_REVERT = 2, EVMC_OUT_OF_GAS = 3, + EVMC_INVALID_INSTRUCTION = 4, EVMC_UNDEFINED_INSTRUCTION = 5, + EVMC_STACK_OVERFLOW = 6, EVMC_STACK_UNDERFLOW = 7, EVMC_BAD_JUMP_DESTINATION = 8, + EVMC_INVALID_MEMORY_ACCESS = 9, EVMC_CALL_DEPTH_EXCEEDED = 10, + EVMC_STATIC_MODE_VIOLATION = 11, EVMC_PRECOMPILE_FAILURE = 12, + EVMC_CONTRACT_VALIDATION_FAILURE = 13, EVMC_ARGUMENT_OUT_OF_RANGE = 14, + EVMC_WASM_UNREACHABLE_INSTRUCTION = 15, EVMC_WASM_TRAP = 16 + evmc_release_result_fn* = proc (result: ptr evmc_result) {.cdecl.} + evmc_result* {.importc: "struct evmc_result", header: "evmc/evmc.h", bycopy.} = object + status_code* {.importc: "status_code".}: evmc_status_code + gas_left* {.importc: "gas_left".}: int64 + output_data* {.importc: "output_data".}: ptr uint8 + output_size* {.importc: "output_size".}: uint + release* {.importc: "release".}: evmc_release_result_fn + create_address* {.importc: "create_address".}: evmc_address + padding* {.importc: "padding".}: array[4, uint8] + evmc_account_exists_fn* = proc (context: ptr evmc_host_context; + address: ptr evmc_address): bool {.cdecl.} + evmc_get_storage_fn* = proc (context: ptr evmc_host_context; + address: ptr evmc_address; key: ptr evmc_bytes32): evmc_bytes32 {. + cdecl.} + evmc_storage_status* {.size: sizeof(cint).} = enum + EVMC_STORAGE_UNCHANGED = 0, EVMC_STORAGE_MODIFIED = 1, + EVMC_STORAGE_MODIFIED_AGAIN = 2, EVMC_STORAGE_ADDED = 3, EVMC_STORAGE_DELETED = 4 + evmc_set_storage_fn* = proc (context: ptr evmc_host_context; + address: ptr evmc_address; key: ptr evmc_bytes32; + value: ptr evmc_bytes32): evmc_storage_status {.cdecl.} + evmc_get_balance_fn* = proc (context: ptr evmc_host_context; + address: ptr evmc_address): evmc_uint256be {.cdecl.} + evmc_get_code_size_fn* = proc (context: ptr evmc_host_context; + address: ptr evmc_address): uint {.cdecl.} + evmc_get_code_hash_fn* = proc (context: ptr evmc_host_context; + address: ptr evmc_address): evmc_bytes32 {.cdecl.} + evmc_copy_code_fn* = proc (context: ptr evmc_host_context; + address: ptr evmc_address; code_offset: uint; + buffer_data: ptr uint8; buffer_size: uint): uint {.cdecl.} + evmc_selfdestruct_fn* = proc (context: ptr evmc_host_context; + address: ptr evmc_address; + beneficiary: ptr evmc_address) {.cdecl.} + evmc_emit_log_fn* = proc (context: ptr evmc_host_context; address: ptr evmc_address; + data: ptr uint8; data_size: uint; + topics: ptr evmc_bytes32; topics_count: uint) {.cdecl.} + evmc_call_fn* = proc (context: ptr evmc_host_context; msg: ptr evmc_message): evmc_result {. + cdecl.} + evmc_host_interface* {.importc: "struct evmc_host_interface", header: "evmc/evmc.h", + bycopy.} = object + account_exists* {.importc: "account_exists".}: evmc_account_exists_fn + get_storage* {.importc: "get_storage".}: evmc_get_storage_fn + set_storage* {.importc: "set_storage".}: evmc_set_storage_fn + get_balance* {.importc: "get_balance".}: evmc_get_balance_fn + get_code_size* {.importc: "get_code_size".}: evmc_get_code_size_fn + get_code_hash* {.importc: "get_code_hash".}: evmc_get_code_hash_fn + copy_code* {.importc: "copy_code".}: evmc_copy_code_fn + selfdestruct* {.importc: "selfdestruct".}: evmc_selfdestruct_fn + call* {.importc: "call".}: evmc_call_fn + get_tx_context* {.importc: "get_tx_context".}: evmc_get_tx_context_fn + get_block_hash* {.importc: "get_block_hash".}: evmc_get_block_hash_fn + emit_log* {.importc: "emit_log".}: evmc_emit_log_fn + evmc_destroy_fn* = proc (vm: ptr evmc_vm) {.cdecl.} + evmc_set_option_result* {.size: sizeof(cint).} = enum + EVMC_SET_OPTION_SUCCESS = 0, EVMC_SET_OPTION_INVALID_NAME = 1, + EVMC_SET_OPTION_INVALID_VALUE = 2 + evmc_set_option_fn* = proc (vm: ptr evmc_vm; name: cstring; value: cstring): evmc_set_option_result {. + cdecl.} + evmc_revision* {.size: sizeof(cint).} = enum + EVMC_FRONTIER = 0, EVMC_HOMESTEAD = 1, EVMC_TANGERINE_WHISTLE = 2, + EVMC_SPURIOUS_DRAGON = 3, EVMC_BYZANTIUM = 4, EVMC_CONSTANTINOPLE = 5, + EVMC_PETERSBURG = 6, EVMC_ISTANBUL = 7, EVMC_BERLIN = 8 + evmc_execute_fn* = proc (vm: ptr evmc_vm; host: ptr evmc_host_interface; + context: ptr evmc_host_context; rev: evmc_revision; + msg: ptr evmc_message; code: ptr uint8; code_size: uint): evmc_result {. + cdecl.} + evmc_capabilities* {.size: sizeof(cint).} = enum + EVMC_CAPABILITY_EVM1 = (1 shl 0), EVMC_CAPABILITY_EWASM = (1 shl 1), + EVMC_CAPABILITY_PRECOMPILES = (1 shl 2) + evmc_capabilities_flagset* = uint32 + evmc_get_capabilities_fn* = proc (vm: ptr evmc_vm): evmc_capabilities_flagset {.cdecl.} + evmc_vm* {.importc: "struct evmc_vm", header: "evmc/evmc.h", bycopy.} = object + abi_version* {.importc: "abi_version".}: cint + name* {.importc: "name".}: cstring + version* {.importc: "version".}: cstring + destroy* {.importc: "destroy".}: evmc_destroy_fn + execute* {.importc: "execute".}: evmc_execute_fn + get_capabilities* {.importc: "get_capabilities".}: evmc_get_capabilities_fn + set_option* {.importc: "set_option".}: evmc_set_option_fn + +const + EVMC_ABI_VERSION* = 7 + EVMC_MAX_REVISION* = EVMC_BERLIN diff --git a/evmc/evmc_nim.nim b/bindings/nim/evmc/evmc_nim.nim similarity index 86% rename from evmc/evmc_nim.nim rename to bindings/nim/evmc/evmc_nim.nim index 22efbbc..9a31cea 100644 --- a/evmc/evmc_nim.nim +++ b/bindings/nim/evmc/evmc_nim.nim @@ -1,19 +1,24 @@ -import evmc +# Copyright (c) 2018-2020 Status Research & Development GmbH +# Licensed under the Apache License, Version 2.0. +# This file may not be copied, modified, or distributed except according to +# those terms. + +import ./evmc type HostContext* = object host: ptr evmc_host_interface - context: evmc_host_context + context: ptr evmc_host_context EvmcVM* = object vm: ptr evmc_vm hc: HostContext -proc init*(x: var HostContext, host: ptr evmc_host_interface, context: evmc_host_context) = +proc init*(x: var HostContext, host: ptr evmc_host_interface, context: ptr evmc_host_context) = x.host = host x.context = context -proc init*(x: typedesc[HostContext], host: ptr evmc_host_interface, context: evmc_host_context): HostContext = +proc init*(x: typedesc[HostContext], host: ptr evmc_host_interface, context: ptr evmc_host_context): HostContext = result.init(host, context) proc getTxContext*(ctx: HostContext): evmc_tx_context = @@ -79,7 +84,7 @@ proc name*(vm: EvmcVM): string = proc version*(vm: EvmcVM): string = $vm.vm.version -proc getCapabilities*(vm: EvmcVM): evmc_capabilities = +proc getCapabilities*(vm: EvmcVM): evmc_capabilities_flagset = vm.vm.get_capabilities(vm.vm) proc setOption*(vm: EvmcVM, name, value: string): evmc_set_option_result = @@ -88,7 +93,7 @@ proc setOption*(vm: EvmcVM, name, value: string): evmc_set_option_result = result = EVMC_SET_OPTION_INVALID_NAME -proc execute*(vm: EvmcVM, rev: evmc_revision, msg: evmc_message, code: openArray[byte]): evmc_result = +proc execute*(vm: EvmcVM, rev: evmc_revision, msg: ptr evmc_message, code: openArray[byte]): evmc_result = vm.vm.execute(vm.vm, vm.hc.host, vm.hc.context, rev, msg, code[0].unsafeAddr, code.len.uint) proc destroy*(vm: EvmcVM) = diff --git a/bindings/nim/evmc/generate_wrapper.sh b/bindings/nim/evmc/generate_wrapper.sh new file mode 100755 index 0000000..4e06799 --- /dev/null +++ b/bindings/nim/evmc/generate_wrapper.sh @@ -0,0 +1,57 @@ +#!/bin/bash + +# Copyright (c) 2020 Status Research & Development GmbH +# Licensed under the Apache License, Version 2.0. +# This file may not be copied, modified, or distributed except according to +# those terms. + +set -e + +cd "$(dirname "${BASH_SOURCE[0]}")" + +sed -e '/^#include/d' \ + -e '/^struct evmc_result;$/d' \ + -e '/^struct evmc_vm;$/d' \ + ../../../include/evmc/evmc.h | cpp | sed '/^#/d' > tmp.h + +c2nim --header:'"evmc/evmc.h"' --cdecl tmp.h + +rm tmp.h + +sed \ + -e 's/uint8_t/uint8/g' \ + -e 's/uint32_t/uint32/g' \ + -e 's/int32_t/int32/g' \ + -e 's/int64_t/int64/g' \ + -e 's/csize/uint/g' \ + -e 's/EVMC_MAX_REVISION/EVMC_MAX_REVISION*/' \ + -e 's/"evmc_message"/"struct evmc_message"/' \ + -e 's/"evmc_tx_context"/"struct evmc_tx_context"/' \ + -e 's/"evmc_host_context"/"struct evmc_host_context"/' \ + -e 's/"evmc_result"/"struct evmc_result"/' \ + -e 's/"evmc_host_interface"/"struct evmc_host_interface"/' \ + -e 's/"evmc_vm"/"struct evmc_vm"/' \ + tmp.nim | gawk ' +/^const$/ { + target = "const" +} +/^type$/ { + target = "type" +} +/^ / { + if(target == "const") + consts[const_index++] = $0 + else if(target == "type") + types[type_index++] = $0 +} +END { + print "type" + for(i in types) + print types[i] + print "\nconst" + for(i in consts) + print consts[i] +} +' > evmc.nim +rm tmp.nim + diff --git a/tests/evmc_nim/nim_host.nim b/bindings/nim/tests/nim_host.nim similarity index 61% rename from tests/evmc_nim/nim_host.nim rename to bindings/nim/tests/nim_host.nim index 1b6752c..8069652 100644 --- a/tests/evmc_nim/nim_host.nim +++ b/bindings/nim/tests/nim_host.nim @@ -1,6 +1,11 @@ -import tables, hashes, strutils -import ../../evmc/evmc -import stew/byteutils +# Copyright (c) 2018-2020 Status Research & Development GmbH +# Licensed under the Apache License, Version 2.0. +# This file may not be copied, modified, or distributed except according to +# those terms. + +import tables, hashes, strutils, + stew/byteutils, + ../evmc/evmc type Account = ref object @@ -12,6 +17,24 @@ type tx_context: evmc_tx_context accounts: Table[evmc_address, Account] +const + EVMC_HOST_NAME = "example_vm" + EVMC_VM_VERSION = "0.0.0" + +# {.nodecl.} only works in the global scope +var globalVM {.importc, nodecl.}: evmc_vm +# Nim doesn't support initialising a struct with const fields, so we do it in C +{.emit: [evmc_vm, " ", globalVM, " = {.abi_version = ", EVMC_ABI_VERSION, ", .name = \"", EVMC_HOST_NAME, "\", .version = \"", EVMC_VM_VERSION, "\"};"].} + +proc incl*(a: var evmc_capabilities_flagset, b: evmc_capabilities) {.inline.} = + a = evmc_capabilities_flagset(a.uint32 or b.uint32) + +proc excl*(a: var evmc_capabilities_flagset, b: evmc_capabilities) {.inline.} = + a = evmc_capabilities_flagset(a.uint32 and (not b.uint32)) + +proc contains*(a: evmc_capabilities_flagset, b: evmc_capabilities): bool {.inline.} = + (a.uint32 and b.uint32) != 0 + proc hash*(x: evmc_bytes32): Hash = result = hash(x.bytes) @@ -24,9 +47,12 @@ proc codeHash(acc: Account): evmc_bytes32 = let idx = v.int mod sizeof(result.bytes) result.bytes[idx] = result.bytes[idx] xor v -proc evmcReleaseResultImpl(result: var evmc_result) {.cdecl.} = +proc evmcReleaseResultImpl(result: ptr evmc_result) {.cdecl.} = discard +converter toEVMCHostContext*(ctx: HostContext): ptr evmc_host_context = + cast[ptr evmc_host_context](ctx) + proc evmcGetTxContextImpl(ctx: HostContext): evmc_tx_context {.cdecl.} = ctx.tx_context @@ -36,7 +62,7 @@ proc evmcGetBlockHashImpl(ctx: HostContext, number: int64): evmc_bytes32 {.cdecl if number < current_block_number and number >= current_block_number - 256: result.bytes = hash -proc evmcAccountExistsImpl(ctx: HostContext, address: var evmc_address): c99bool {.cdecl.} = +proc evmcAccountExistsImpl(ctx: HostContext, address: var evmc_address): bool {.cdecl.} = address in ctx.accounts proc evmcGetStorageImpl(ctx: HostContext, address: var evmc_address, key: var evmc_bytes32): evmc_bytes32 {.cdecl.} = @@ -112,7 +138,7 @@ proc evmcSetOptionImpl(vm: ptr evmc_vm, name, value: cstring): evmc_set_option_r proc evmcExecuteImpl(vm: ptr evmc_vm, host: ptr evmc_host_interface, ctx: HostContext, rev: evmc_revision, - msg: evmc_message, code: ptr byte, code_size: uint): evmc_result {.cdecl.} = + msg: ptr evmc_message, code: ptr byte, code_size: uint): evmc_result {.cdecl.} = var the_code = "\x43\x60\x00\x55\x43\x60\x00\x52\x59\x60\x00\xf3" if (code_size.int == the_code.len) and equalMem(code, the_code[0].addr, code_size): @@ -135,7 +161,7 @@ proc evmcExecuteImpl(vm: ptr evmc_vm, host: ptr evmc_host_interface, result.status_code = EVMC_FAILURE result.gas_left = 0 -proc evmcGetCapabilitiesImpl(vm: ptr evmc_vm): evmc_capabilities {.cdecl.} = +proc evmcGetCapabilitiesImpl(vm: ptr evmc_vm): evmc_capabilities_flagset {.cdecl.} = result.incl(EVMC_CAPABILITY_EVM1) result.incl(EVMC_CAPABILITY_EWASM) @@ -143,67 +169,38 @@ proc evmcDestroyImpl(vm: ptr evmc_vm) {.cdecl.} = dealloc(vm) proc init_host_interface(): evmc_host_interface = - # workaround for nim cpp codegen bug - {.emit: [result.account_exists, " = (", evmc_account_exists_fn, ")", evmcAccountExistsImpl, ";" ].} - {.emit: [result.get_storage, " = (", evmc_get_storage_fn, ")", evmcGetStorageImpl, ";" ].} - {.emit: [result.set_storage, " = (", evmc_set_storage_fn, ")", evmcSetStorageImpl, ";" ].} - {.emit: [result.get_balance, " = (", evmc_get_balance_fn, ")", evmcGetBalanceImpl, ";" ].} - {.emit: [result.get_code_size, " = (", evmc_get_code_size_fn, ")", evmcGetCodeSizeImpl, ";" ].} - {.emit: [result.get_code_hash, " = (", evmc_get_code_hash_fn, ")", evmcGetCodeHashImpl, ";" ].} - {.emit: [result.copy_code, " = (", evmc_copy_code_fn, ")", evmcCopyCodeImpl, ";" ].} - {.emit: [result.selfdestruct, " = (", evmc_selfdestruct_fn, ")", evmcSelfdestructImpl, ";" ].} - {.emit: [result.call, " = (", evmc_call_fn, ")", evmcCallImpl, ";" ].} - {.emit: [result.get_tx_context, " = (", evmc_get_tx_context_fn, ")", evmcGetTxContextImpl, ";" ].} - {.emit: [result.get_block_hash, " = (", evmc_get_block_hash_fn, ")", evmcGetBlockHashImpl, ";" ].} - {.emit: [result.emit_log, " = (", evmc_emit_log_fn, ")", evmcEmitLogImpl, ";" ].} + result.account_exists = cast[evmc_account_exists_fn](evmcAccountExistsImpl) + result.get_storage = cast[evmc_get_storage_fn](evmcGetStorageImpl) + result.set_storage = cast[evmc_set_storage_fn](evmcSetStorageImpl) + result.get_balance = cast[evmc_get_balance_fn](evmcGetBalanceImpl) + result.get_code_size = cast[evmc_get_code_size_fn](evmcGetCodeSizeImpl) + result.get_code_hash = cast[evmc_get_code_hash_fn](evmcGetCodeHashImpl) + result.copy_code = cast[evmc_copy_code_fn](evmcCopyCodeImpl) + result.selfdestruct = cast[evmc_selfdestruct_fn](evmcSelfdestructImpl) + result.call = cast[evmc_call_fn](evmcCallImpl) + result.get_tx_context = cast[evmc_get_tx_context_fn](evmcGetTxContextImpl) + result.get_block_hash = cast[evmc_get_block_hash_fn](evmcGetBlockHashImpl) + result.emit_log = cast[evmc_emit_log_fn](evmcEmitLogImpl) - #result.account_exists = cast[evmc_account_exists_fn](evmcAccountExistsImpl) - #result.get_storage = cast[evmc_get_storage_fn](evmcGetStorageImpl) - #result.set_storage = cast[evmc_set_storage_fn](evmcSetStorageImpl) - #result.get_balance = cast[evmc_get_balance_fn](evmcGetBalanceImpl) - #result.get_code_size = cast[evmc_get_code_size_fn](evmcGetCodeSizeImpl) - #result.get_code_hash = cast[evmc_get_code_hash_fn](evmcGetCodeHashImpl) - #result.copy_code = cast[evmc_copy_code_fn](evmcCopyCodeImpl) - #result.selfdestruct = cast[evmc_selfdestruct_fn](evmcSelfdestructImpl) - #result.call = cast[evmc_call_fn](evmcCallImpl) - #result.get_tx_context = cast[evmc_get_tx_context_fn](evmcGetTxContextImpl) - #result.get_block_hash = cast[evmc_get_block_hash_fn](evmcGetBlockHashImpl) - #result.emit_log = cast[evmc_emit_log_fn](evmcEmitLogImpl) - -const - EVMC_HOST_NAME = "example_vm" - EVMC_VM_VERSION = "0.0.0" - -proc init(vm: var evmc_vm) {.exportc, cdecl.} = - vm.abi_version = EVMC_ABI_VERSION - vm.name = EVMC_HOST_NAME - vm.version = EVMC_VM_VERSION +proc init(vm: ptr evmc_vm) {.exportc, cdecl.} = vm.destroy = evmcDestroyImpl - - {.emit: [vm.execute, " = (", evmc_execute_fn, ")", evmcExecuteImpl, ";" ].} - #vm.execute = cast[evmc_execute_fn](evmcExecuteImpl) - + vm.execute = cast[evmc_execute_fn](evmcExecuteImpl) vm.get_capabilities = evmcGetCapabilitiesImpl vm.set_option = evmcSetOptionImpl let gHost = init_host_interface() -proc nim_host_get_interface(): ptr evmc_host_interface {.exportc, cdecl.} = +proc nim_host_get_interface*(): ptr evmc_host_interface {.exportc, cdecl.} = result = gHost.unsafeAddr -proc nim_host_create_context(tx_context: evmc_tx_context): HostContext {.exportc, cdecl.} = - const address = evmc_address(bytes: hexToByteArray[20]("0x0001020000000000000000000000000000000000")) - var acc = Account( - balance: evmc_uint256be(bytes: hexToByteArray[32]("0x0100000000000000000000000000000000000000000000000000000000000000")), - code: @[10.byte, 11, 12, 13, 14, 15] - ) - +proc nim_host_create_context*(tx_context: evmc_tx_context): HostContext {.exportc, cdecl.} = result = HostContext(tx_context: tx_context) - result.accounts[address] = acc GC_ref(result) -proc nim_host_destroy_context(ctx: HostContext) {.exportc, cdecl.} = +proc nim_host_destroy_context*(ctx: HostContext) {.exportc, cdecl.} = GC_unref(ctx) -proc nim_create_example_vm(): ptr evmc_vm {.exportc, cdecl.} = - result = create(evmc_vm) - init(result[]) +proc nim_create_example_vm*(): ptr evmc_vm {.exportc, cdecl.} = + result = cast[ptr evmc_vm](new(evmc_vm)) + copyMem(result, globalVM.addr, sizeof(globalVM)) + init(result) + diff --git a/tests/test_host_vm.nim b/bindings/nim/tests/test_host_vm.nim similarity index 77% rename from tests/test_host_vm.nim rename to bindings/nim/tests/test_host_vm.nim index 28f86a5..14fe440 100644 --- a/tests/test_host_vm.nim +++ b/bindings/nim/tests/test_host_vm.nim @@ -1,24 +1,24 @@ -import ../evmc/[evmc, evmc_nim], unittest -import evmc_nim/nim_host -import stew/byteutils +# Copyright (c) 2018-2020 Status Research & Development GmbH +# Licensed under the Apache License, Version 2.0. +# This file may not be copied, modified, or distributed except according to +# those terms. -{.compile: "evmc_c/example_host.cpp".} -{.compile: "evmc_c/example_vm.cpp".} -{.passL: "-lstdc++"} +import os, unittest, + stew/byteutils, + ../evmc/evmc, ../evmc/evmc_nim, ./nim_host +{.compile: "../../../examples/example_host.cpp".} +{.compile: "../../../examples/example_vm/example_vm.c".} + +{.passC: "-I" & currentSourcePath.parentDir().parentDir().parentDir().parentDir() / "include".} when defined(posix): {.passC: "-std=c++11".} proc example_host_get_interface(): ptr evmc_host_interface {.importc, cdecl.} -proc example_host_create_context(tx_context: var evmc_tx_context): evmc_host_context {.importc, cdecl.} -proc example_host_destroy_context(context: evmc_host_context) {.importc, cdecl.} +proc example_host_create_context(tx_context: evmc_tx_context): ptr evmc_host_context {.importc, cdecl.} +proc example_host_destroy_context(context: ptr evmc_host_context) {.importc, cdecl.} proc evmc_create_example_vm(): ptr evmc_vm {.importc, cdecl.} -proc nim_host_get_interface(): ptr evmc_host_interface {.importc, cdecl.} -proc nim_host_create_context(tx_context: var evmc_tx_context): evmc_host_context {.importc, cdecl.} -proc nim_host_destroy_context(context: evmc_host_context) {.importc, cdecl.} -proc nim_create_example_vm(): ptr evmc_vm {.importc, cdecl.} - template runTest(testName: string, create_vm, get_host_interface, create_host_context, destroy_host_context: untyped) = var vm = create_vm() var host = get_host_interface() @@ -83,22 +83,6 @@ template runTest(testName: string, create_vm, get_host_interface, create_host_co test "accountExists": check hc.accountExists(address) == true - test "getBalance": - let bal = hc.getBalance(address) - check bal == balance - - test "getCodeSize": - check hc.getCodeSize(address) == 6 - - test "getCodeHash": - let hash = hc.getCodeHash(address) - check hash == ahash - - test "copyCode": - let acode = @[11.byte, 12, 13, 14, 15] - let bcode = hc.copyCode(address, 1) - check acode == bcode - test "selfdestruct": hc.selfdestruct(address, address) @@ -137,11 +121,11 @@ template runTest(testName: string, create_vm, get_host_interface, create_host_co test "execute and destroy": var bn = $tx_context.block_number - var res = nvm.execute(EVMC_HOMESTEAD, msg, code) + var res = nvm.execute(EVMC_HOMESTEAD, msg.addr, code) check res.status_code == EVMC_SUCCESS check res.gas_left == 100000 check equalMem(bn[0].addr, res.output_data, bn.len) - res.release(res) + res.release(res.addr) var empty_key: evmc_bytes32 let val = hc.getStorage(address, empty_key) @@ -151,14 +135,14 @@ template runTest(testName: string, create_vm, get_host_interface, create_host_co destroy_host_context(ctx) proc main() = - runTest("EVMC Nim to C API", + runTest("Nim EVMC wrapper: C++ host, C VM", evmc_create_example_vm, example_host_get_interface, example_host_create_context, example_host_destroy_context ) - runTest("EVMC Nim to Nim API", + runTest("Nim EVMC wrapper: Nim host, Nim VM", nim_create_example_vm, nim_host_get_interface, nim_host_create_context, diff --git a/evmc/evmc.nim b/evmc/evmc.nim deleted file mode 100644 index b72a6dd..0000000 --- a/evmc/evmc.nim +++ /dev/null @@ -1,695 +0,0 @@ -# Nimbus -# Copyright (c) 2019 Status Research & Development GmbH -# Licensed under either of -# * Apache License, version 2.0, ([LICENSE-APACHE](LICENSE-APACHE)) -# * MIT license ([LICENSE-MIT](LICENSE-MIT)) -# at your option. -# This file may not be copied, modified, or distributed except according to -# those terms. - - -# The EVMC ABI version number of the interface declared in this file. -# -# The EVMC ABI version always equals the major version number of the EVMC project. -# The Host SHOULD check if the ABI versions match when dynamically loading VMs. -const - EVMC_ABI_VERSION* = 7.cint - -type - # SPECIAL NOTE - # EVMC adopt C99 standard, and one of it's interface using - # C99 'bool' as return type. Nowhere in the C documentation - # mentions about it's size. - # chfast@ethereum/evmc told me about this "https://godbolt.org/z/marD9R" - # lucky for us, in practice C compilers agree to use one byte long for C99 bool. - # Nim sizeof(bool) also == 1. - # but still we need to be careful about this though. - c99bool* = bool - - # The fixed size array of 32 bytes. - # 32 bytes of data capable of storing e.g. 256-bit hashes. - evmc_bytes32* = object - bytes*: array[32, byte] - - # The alias for evmc_bytes32 to represent a big-endian 256-bit integer. - evmc_uint256be* = evmc_bytes32 - - # Big-endian 160-bit hash suitable for keeping an Ethereum address. - evmc_address* = object - bytes*: array[20, byte] - - # The kind of call-like instruction. - evmc_call_kind* {.size: sizeof(cint).} = enum - EVMC_CALL = 0 # Request CALL. - EVMC_DELEGATECALL = 1 # Request DELEGATECALL. Valid since Homestead. - # The value param ignored. - EVMC_CALLCODE = 2 # Request CALLCODE. - EVMC_CREATE = 3 # Request CREATE. - EVMC_CREATE2 = 4 # Request CREATE2. Valid since Constantinople. - - # The flags for ::evmc_message. - evmc_flags* {.size: sizeof(cint).} = enum - EVMC_STATIC = 1 # Static call mode. - - # The message describing an EVM call, - # including a zero-depth calls from a transaction origin. - evmc_message* = object - # The kind of the call. For zero-depth calls ::EVMC_CALL SHOULD be used. - kind*: evmc_call_kind - - # Additional flags modifying the call execution behavior. - # In the current version the only valid values are ::EVMC_STATIC or 0. - flags*: uint32 - - # The call depth. - depth*: int32 - - # The amount of gas for message execution. - gas*: int64 - - # The destination of the message. - destination*: evmc_address - - # The sender of the message. - sender*: evmc_address - - # The message input data. - # This MAY be NULL. - input_data*: ptr byte - - # The size of the message input data. - # If input_data is NULL this MUST be 0. - # actually it's a size_t - input_size*: uint - - # The amount of Ether transferred with the message. - value*: evmc_uint256be - - # The optional value used in new contract address construction. - # Ignored unless kind is EVMC_CREATE2. - create2_salt*: evmc_bytes32 - - # The transaction and block data for execution. - evmc_tx_context* = object - tx_gas_price* : evmc_uint256be # The transaction gas price. - tx_origin* : evmc_address # The transaction origin account. - block_coinbase* : evmc_address # 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. - - # @struct evmc_host_context - # The opaque data type representing the Host execution context. - # @see evmc_execute_fn(). - evmc_host_context* = distinct pointer - - # Get transaction context callback function. - # - # This callback function is used by an EVM to retrieve the transaction and - # block context. - # - # @param context The pointer to the Host execution context. - # @return The transaction context. - evmc_get_tx_context_fn* = proc(context: evmc_host_context): evmc_tx_context {.cdecl.} - - # Get block hash callback function. - # - # This callback function is used by a VM to query the hash of the header of the given block. - # If the information about the requested block is not available, then this is signalled by - # returning null bytes. - # - # @param context The pointer to the Host execution context. - # @param number The block number. - # @return The block hash or null bytes - # if the information about the block is not available. - evmc_get_block_hash_fn* = proc(context: evmc_host_context, number: int64): evmc_bytes32 {.cdecl.} - - # The execution status code. - # - # Successful execution is represented by ::EVMC_SUCCESS having value 0. - # - # Positive values represent failures defined by VM specifications with generic - # ::EVMC_FAILURE code of value 1. - # - # Status codes with negative values represent VM internal errors - # not provided by EVM specifications. These errors MUST not be passed back - # to the caller. They MAY be handled by the Client in predefined manner - # (see e.g. ::EVMC_REJECTED), otherwise internal errors are not recoverable. - # The generic representant of errors is ::EVMC_INTERNAL_ERROR but - # an EVM implementation MAY return negative status codes that are not defined - # in the EVMC documentation. - # - # @note - # In case new status codes are needed, please create an issue or pull request - # in the EVMC repository (https://github.com/ethereum/evmc). - evmc_status_code* = distinct cint - # EVMC_SUCCESS - # EVMC_FAILURE - # EVMC_REVERT - # EVMC_OUT_OF_GAS - # EVMC_INVALID_INSTRUCTION - # EVMC_UNDEFINED_INSTRUCTION - # EVMC_STACK_OVERFLOW - # EVMC_STACK_UNDERFLOW - # EVMC_BAD_JUMP_DESTINATION - # EVMC_INVALID_MEMORY_ACCESS - # EVMC_CALL_DEPTH_EXCEEDED - # EVMC_STATIC_MODE_VIOLATION - # EVMC_PRECOMPILE_FAILURE - # EVMC_CONTRACT_VALIDATION_FAILURE - # EVMC_ARGUMENT_OUT_OF_RANGE - # EVMC_WASM_UNREACHABLE_INSTRUCTION - # EVMC_WASM_TRAP - # EVMC_INTERNAL_ERROR - # EVMC_REJECTED - # EVMC_OUT_OF_MEMORY - - # Releases resources assigned to an execution result. - # - # This function releases memory (and other resources, if any) assigned to the - # specified execution result making the result object invalid. - # - # @param result The execution result which resources are to be released. The - # result itself it not modified by this function, but becomes - # invalid and user MUST discard it as well. - # This MUST NOT be NULL. - # - # @note - # The result is passed by pointer to avoid (shallow) copy of the ::evmc_result - # struct. Think of this as the best possible C language approximation to - # passing objects by reference. - evmc_release_result_fn* = proc(result: var evmc_result) {.cdecl.} - - # The EVM code execution result. - evmc_result* = object - # The execution status code. - status_code*: evmc_status_code - - #The amount of gas left after the execution. - # If evmc_result::code is not ::EVMC_SUCCESS nor ::EVMC_REVERT - # the value MUST be 0. - gas_left*: int64 - - # The reference to output data. - # - # The output contains data coming from RETURN opcode (iff evmc_result::code - # field is ::EVMC_SUCCESS) or from REVERT opcode. - # - # The memory containing the output data is owned by EVM and has to be - # freed with evmc_result::release(). - # - # This MAY be NULL. - output_data*: ptr byte - - # The size of the output data. - # If output_data is NULL this MUST be 0. - output_size*: uint - - # The method releasing all resources associated with the result object. - # - # This method (function pointer) is optional (MAY be NULL) and MAY be set - # by the VM implementation. If set it MUST be called by the user once to - # release memory and other resources associated with the result object. - # Once the resources are released the result object MUST NOT be used again. - # - # The suggested code pattern for releasing execution results: - # @code - # struct evmc_result result = ...; - # if (result.release) - # result.release(&result); - # @endcode - # - # @note - # It works similarly to C++ virtual destructor. Attaching the release - # function to the result itself allows VM composition. - release*: evmc_release_result_fn - - # The address of the contract created by create instructions. - # - # This field has valid value only if: - # - it is a result of the Host method evmc_host_interface::call - # - and the result describes successful contract creation - # (evmc_result::status_code is ::EVMC_SUCCESS). - # In all other cases the address MUST be null bytes. - # - create_address*: evmc_address - - # Reserved data that MAY be used by a evmc_result object creator. - # - # This reserved 4 bytes together with 20 bytes from create_address form - # 24 bytes of memory called "optional data" within evmc_result struct - # to be optionally used by the evmc_result object creator. - # - # @see evmc_result_optional_data, evmc_get_optional_data(). - # - # Also extends the size of the evmc_result to 64 bytes (full cache line). - padding*: array[4, byte] - - # Check account existence callback function. - # - # This callback function is used by the VM to check if - # there exists an account at given address. - # @param context The pointer to the Host execution context. - # @param address The address of the account the query is about. - # @return true if exists, false otherwise. - evmc_account_exists_fn* = proc(context: evmc_host_context, address: ptr evmc_address): c99bool {.cdecl.} - - # Get storage callback function. - # - # This callback function is used by a VM to query the given account storage entry. - # - # @param context The Host execution context. - # @param address The address of the account. - # @param key The index of the account's storage entry. - # @return The storage value at the given storage key or null bytes - # if the account does not exist. - evmc_get_storage_fn* = proc(context: evmc_host_context, address: ptr evmc_address, key: ptr evmc_bytes32): evmc_bytes32 {.cdecl.} - - # The effect of an attempt to modify a contract storage item. - # - # For the purpose of explaining the meaning of each element, the following - # notation is used: - # - 0 is zero value, - # - X != 0 (X is any value other than 0), - # - Y != X, Y != 0 (Y is any value other than X and 0), - # - Z != Y (Z is any value other than Y), - # - the "->" means the change from one value to another. - evmc_storage_status* {.size: sizeof(cint).} = enum - # The value of a storage item has been left unchanged: 0 -> 0 and X -> X. - EVMC_STORAGE_UNCHANGED = 0 - - # The value of a storage item has been modified: X -> Y. - EVMC_STORAGE_MODIFIED = 1 - - # A storage item has been modified after being modified before: X -> Y -> Z. - EVMC_STORAGE_MODIFIED_AGAIN = 2 - - # A new storage item has been added: 0 -> X. - EVMC_STORAGE_ADDED = 3 - - # A storage item has been deleted: X -> 0. - EVMC_STORAGE_DELETED = 4 - - # Set storage callback function. - # - # This callback function is used by a VM to update the given account storage entry. - # The VM MUST make sure that the account exists. This requirement is only a formality because - # VM implementations only modify storage of the account of the current execution context - # (i.e. referenced by evmc_message::destination). - # - # @param context The pointer to the Host execution context. - # @param address The address of the account. - # @param key The index of the storage entry. - # @param value The value to be stored. - # @return The effect on the storage item. - evmc_set_storage_fn* = proc(context: evmc_host_context, address: ptr evmc_address, - key, value: ptr evmc_bytes32): evmc_storage_status {.cdecl.} - - # Get balance callback function. - # - # This callback function is used by a VM to query the balance of the given account. - # - # @param context The pointer to the Host execution context. - # @param address The address of the account. - # @return The balance of the given account or 0 if the account does not exist. - evmc_get_balance_fn* = proc(context: evmc_host_context, address: ptr evmc_address): evmc_uint256be {.cdecl.} - - # Get code size callback function. - # - # This callback function is used by a VM to get the size of the code stored - # in the account at the given address. - # - # @param context The pointer to the Host execution context. - # @param address The address of the account. - # @return The size of the code in the account or 0 if the account does not exist. - evmc_get_code_size_fn* = proc(context: evmc_host_context, address: ptr evmc_address): uint {.cdecl.} - - # Get code hash callback function. - # - # This callback function is used by a VM to get the keccak256 hash of the code stored - # in the account at the given address. For existing accounts not having a code, this - # function returns keccak256 hash of empty data. - # - # @param context The pointer to the Host execution context. - # @param address The address of the account. - # @return The hash of the code in the account or null bytes if the account does not exist. - evmc_get_code_hash_fn* = proc(context: evmc_host_context, address: ptr evmc_address): evmc_bytes32 {.cdecl.} - - # Copy code callback function. - # - # This callback function is used by an EVM to request a copy of the code - # of the given account to the memory buffer provided by the EVM. - # The Client MUST copy the requested code, starting with the given offset, - # to the provided memory buffer up to the size of the buffer or the size of - # the code, whichever is smaller. - # - # @param context The pointer to the Host execution context. See ::evmc_host_context. - # @param address The address of the account. - # @param code_offset The offset of the code to copy. - # @param buffer_data The pointer to the memory buffer allocated by the EVM - # to store a copy of the requested code. - # @param buffer_size The size of the memory buffer. - # @return The number of bytes copied to the buffer by the Client. - evmc_copy_code_fn* = proc(context: evmc_host_context, address: ptr evmc_address, - code_offset: uint, buffer_data: ptr byte, - buffer_size: uint): uint {.cdecl.} - - # Selfdestruct callback function. - # - # This callback function is used by an EVM to SELFDESTRUCT given contract. - # The execution of the contract will not be stopped, that is up to the EVM. - # - # @param context The pointer to the Host execution context. See ::evmc_host_context. - # @param address The address of the contract to be selfdestructed. - # @param beneficiary The address where the remaining ETH is going to be transferred. - evmc_selfdestruct_fn* = proc(context: evmc_host_context, address, beneficiary: ptr evmc_address) {.cdecl.} - - # Log callback function. - # - # This callback function is used by an EVM to inform about a LOG that happened - # during an EVM bytecode execution. - # - # @param context The pointer to the Host execution context. See ::evmc_host_context. - # @param address The address of the contract that generated the log. - # @param data The pointer to unindexed data attached to the log. - # @param data_size The length of the data. - # @param topics The pointer to the array of topics attached to the log. - # @param topics_count The number of the topics. Valid values are between 0 and 4 inclusively. - evmc_emit_log_fn* = proc(context: evmc_host_context, address: ptr evmc_address, - data: ptr byte, data_size: uint, - topics: ptr evmc_bytes32, topics_count: uint) {.cdecl.} - - # Pointer to the callback function supporting EVM calls. - # - # @param context The pointer to the Host execution context. - # @param msg The call parameters. - # @return The result of the call. - evmc_call_fn* = proc(context: evmc_host_context, msg: ptr evmc_message): evmc_result {.cdecl.} - - # The Host interface. - # - # The set of all callback functions expected by VM instances. This is C - # realisation of vtable for OOP interface (only virtual methods, no data). - # Host implementations SHOULD create constant singletons of this (similarly - # to vtables) to lower the maintenance and memory management cost. - evmc_host_interface* = object - # Check account existence callback function. - account_exists*: evmc_account_exists_fn - - # Get storage callback function. - get_storage*: evmc_get_storage_fn - - # Set storage callback function. - set_storage*: evmc_set_storage_fn - - # Get balance callback function. - get_balance*: evmc_get_balance_fn - - # Get code size callback function. - get_code_size*: evmc_get_code_size_fn - - # Get code hash callback function. - get_code_hash*: evmc_get_code_hash_fn - - # Copy code callback function. - copy_code*: evmc_copy_code_fn - - # Selfdestruct callback function. - selfdestruct*: evmc_selfdestruct_fn - - # Call callback function. - call*: evmc_call_fn - - # Get transaction context callback function. - get_tx_context*: evmc_get_tx_context_fn - - # Get block hash callback function. - get_block_hash*: evmc_get_block_hash_fn - - # Emit log callback function. - emit_log*: evmc_emit_log_fn - - # Destroys the VM instance. - # - # @param vm The VM instance to be destroyed. - evmc_destroy_fn* = proc(vm: ptr evmc_vm) {.cdecl.} - - # Possible outcomes of evmc_set_option. - evmc_set_option_result* {.size: sizeof(cint).} = enum - EVMC_SET_OPTION_SUCCESS = 0 - EVMC_SET_OPTION_INVALID_NAME = 1 - EVMC_SET_OPTION_INVALID_VALUE = 2 - - # Configures the VM instance. - # - # Allows modifying options of the VM instance. - # Options: - # - code cache behavior: on, off, read-only, ... - # - optimizations, - # - # @param vm The VM instance to be configured. - # @param name The option name. NULL-terminated string. Cannot be NULL. - # @param value The new option value. NULL-terminated string. Cannot be NULL. - # @return The outcome of the operation. - evmc_set_option_fn* = proc(vm: ptr evmc_vm, name, value: cstring): evmc_set_option_result {.cdecl.} - - # EVM revision. - # - # The revision of the EVM specification based on the Ethereum - # upgrade / hard fork codenames. - evmc_revision* {.size: sizeof(cint).} = enum - # The Frontier revision. - # The one Ethereum launched with. - EVMC_FRONTIER = 0 - - # The Homestead revision. - # https://eips.ethereum.org/EIPS/eip-606 - EVMC_HOMESTEAD = 1 - - # The Tangerine Whistle revision. - # https://eips.ethereum.org/EIPS/eip-608 - EVMC_TANGERINE_WHISTLE = 2 - - # The Spurious Dragon revision. - # https://eips.ethereum.org/EIPS/eip-607 - EVMC_SPURIOUS_DRAGON = 3 - - # The Byzantium revision. - # https://eips.ethereum.org/EIPS/eip-609 - EVMC_BYZANTIUM = 4 - - # The Constantinople revision. - # https://eips.ethereum.org/EIPS/eip-1013 - EVMC_CONSTANTINOPLE = 5 - - # The Petersburg revision. - # Other names: Constantinople2, ConstantinopleFix. - # https://eips.ethereum.org/EIPS/eip-1716 - EVMC_PETERSBURG = 6 - - # The Istanbul revision. - # The spec draft: https://eips.ethereum.org/EIPS/eip-1679. - EVMC_ISTANBUL = 7 - - # The Berlin revision. - # The spec draft: https://eips.ethereum.org/EIPS/eip-2070. - EVMC_BERLIN = 8 - - # Executes the given code using the input from the message. - # - # This function MAY be invoked multiple times for a single VM instance. - # - # @param vm The VM instance. This argument MUST NOT be NULL. - # @param host The Host interface. This argument MUST NOT be NULL unless - # the @p vm has the ::EVMC_CAPABILITY_PRECOMPILES capability. - # @param context The opaque pointer to the Host execution context. - # This argument MAY be NULL. The VM MUST pass the same - # pointer to the methods of the @p host interface. - # The VM MUST NOT dereference the pointer. - # @param rev The requested EVM specification revision. - # @param msg The call parameters. See ::evmc_message. This argument MUST NOT be NULL. - # @param code The reference to the code to be executed. This argument MAY be NULL. - # @param code_size The length of the code. If @p code is NULL this argument MUST be 0. - # @return The execution result. - evmc_execute_fn* = proc(vm: ptr evmc_vm, host: ptr evmc_host_interface, - context: evmc_host_context, rev: evmc_revision, - msg: evmc_message, code: ptr byte, code_size: uint): evmc_result {.cdecl.} - - # Possible capabilities of a VM. - evmc_capabilities* = distinct uint32 - # EVMC_CAPABILITY_EVM1 - # EVMC_CAPABILITY_EWASM - # EVMC_CAPABILITY_PRECOMPILES - - # Return the supported capabilities of the VM instance. - # - # This function MAY be invoked multiple times for a single VM instance, - # and its value MAY be influenced by calls to evmc_vm::set_option. - # - # @param vm The VM instance. - # @return The supported capabilities of the VM. @see evmc_capabilities. - evmc_get_capabilities_fn* = proc(vm: ptr evmc_vm): evmc_capabilities {.cdecl.} - - # The VM instance. - # - # Defines the base struct of the VM implementation. - evmc_vm* = object - # EVMC ABI version implemented by the VM instance. - # - # Can be used to detect ABI incompatibilities. - # The EVMC ABI version represented by this file is in ::EVMC_ABI_VERSION. - abi_version*: cint - - # The name of the EVMC VM implementation. - # - # It MUST be a NULL-terminated not empty string. - # The content MUST be UTF-8 encoded (this implies ASCII encoding is also allowed). - name*: cstring - - # The version of the EVMC VM implementation, e.g. "1.2.3b4". - # - # It MUST be a NULL-terminated not empty string. - # The content MUST be UTF-8 encoded (this implies ASCII encoding is also allowed). - version*: cstring - - # Pointer to function destroying the VM instance. - # - # This is a mandatory method and MUST NOT be set to NULL. - destroy*: evmc_destroy_fn - - # Pointer to function executing a code by the VM instance. - # - # This is a mandatory method and MUST NOT be set to NULL. - execute*: evmc_execute_fn - - # A method returning capabilities supported by the VM instance. - # - # The value returned MAY change when different options are set via the set_option() method. - # - # A Client SHOULD only rely on the value returned if it has queried it after - # it has called the set_option(). - # - # This is a mandatory method and MUST NOT be set to NULL. - get_capabilities*: evmc_get_capabilities_fn - - # Optional pointer to function modifying VM's options. - # - # If the VM does not support this feature the pointer can be NULL. - set_option*: evmc_set_option_fn - -const - # The VM is capable of executing EVM1 bytecode. - EVMC_CAPABILITY_EVM1* = 1.evmc_capabilities - - # The VM is capable of executing ewasm bytecode. - EVMC_CAPABILITY_EWASM* = 2.evmc_capabilities - - # The VM is capable of executing the precompiled contracts - # defined for the range of destination addresses. - # - # The EIP-1352 (https://eips.ethereum.org/EIPS/eip-1352) specifies - # the range 0x000...0000 - 0x000...ffff of addresses - # reserved for precompiled and system contracts. - # - # This capability is **experimental** and MAY be removed without notice. - EVMC_CAPABILITY_PRECOMPILES* = 4.evmc_capabilities - - # Execution finished with success. - EVMC_SUCCESS* = 0.evmc_status_code - - # Generic execution failure. - EVMC_FAILURE* = 1.evmc_status_code - - # Execution terminated with REVERT opcode. - # - # In this case the amount of gas left MAY be non-zero and additional output - # data MAY be provided in ::evmc_result. - EVMC_REVERT* = 2.evmc_status_code - - # The execution has run out of gas. - EVMC_OUT_OF_GAS* = 3.evmc_status_code - - # The designated INVALID instruction has been hit during execution. - # - # The EIP-141 (https://github.com/ethereum/EIPs/blob/master/EIPS/eip-141.md) - # defines the instruction 0xfe as INVALID instruction to indicate execution - # abortion coming from high-level languages. This status code is reported - # in case this INVALID instruction has been encountered. - EVMC_INVALID_INSTRUCTION* = 4.evmc_status_code - - # An undefined instruction has been encountered. - EVMC_UNDEFINED_INSTRUCTION* = 5.evmc_status_code - - # The execution has attempted to put more items on the EVM stack - # than the specified limit. - EVMC_STACK_OVERFLOW* = 6.evmc_status_code - - # Execution of an opcode has required more items on the EVM stack. - EVMC_STACK_UNDERFLOW* = 7.evmc_status_code - - # Execution has violated the jump destination restrictions. - EVMC_BAD_JUMP_DESTINATION* = 8.evmc_status_code - - # Tried to read outside memory bounds. - # - # An example is RETURNDATACOPY reading past the available buffer. - EVMC_INVALID_MEMORY_ACCESS* = 9.evmc_status_code - - # Call depth has exceeded the limit (if any) - EVMC_CALL_DEPTH_EXCEEDED* = 10.evmc_status_code - - # Tried to execute an operation which is restricted in static mode. - EVMC_STATIC_MODE_VIOLATION* = 11.evmc_status_code - - # A call to a precompiled or system contract has ended with a failure. - # - # An example: elliptic curve functions handed invalid EC points. - EVMC_PRECOMPILE_FAILURE* = 12.evmc_status_code - - # Contract validation has failed (e.g. due to EVM 1.5 jump validity, - # Casper's purity checker or ewasm contract rules). - EVMC_CONTRACT_VALIDATION_FAILURE* = 13.evmc_status_code - - # An argument to a state accessing method has a value outside of the - # accepted range of values. - EVMC_ARGUMENT_OUT_OF_RANGE* = 14.evmc_status_code - - # A WebAssembly `unreachable` instruction has been hit during execution. - EVMC_WASM_UNREACHABLE_INSTRUCTION* = 15.evmc_status_code - - # A WebAssembly trap has been hit during execution. This can be for many - # reasons, including division by zero, validation errors, etc. - EVMC_WASM_TRAP* = 16.evmc_status_code - - # EVM implementation generic internal error. - EVMC_INTERNAL_ERROR* = evmc_status_code(-1) - - # The execution of the given code and/or message has been rejected - # by the EVM implementation. - # - # This error SHOULD be used to signal that the EVM is not able to or - # willing to execute the given code type or message. - # If an EVM returns the ::EVMC_REJECTED status code, - # the Client MAY try to execute it in other EVM implementation. - # For example, the Client tries running a code in the EVM 1.5. If the - # code is not supported there, the execution falls back to the EVM 1.0. - EVMC_REJECTED* = evmc_status_code(-2) - - # The VM failed to allocate the amount of memory needed for execution. - EVMC_OUT_OF_MEMORY* = evmc_status_code(-3) - - # The maximum EVM revision supported. - EVMC_MAX_REVISION* = EVMC_BERLIN - -proc incl*(a: var evmc_capabilities, b: evmc_capabilities) {.inline.} = - a = evmc_capabilities(a.uint32 or b.uint32) - -proc excl*(a: var evmc_capabilities, b: evmc_capabilities) {.inline.} = - a = evmc_capabilities(a.uint32 and (not b.uint32)) - -proc contains*(a, b: evmc_capabilities): bool {.inline.} = - (a.uint32 and b.uint32) != 0 - -proc `==`*(a, b: evmc_status_code): bool {.borrow.} diff --git a/evmc/evmjit.nim b/evmc/evmjit.nim deleted file mode 100644 index e24c0a9..0000000 --- a/evmc/evmjit.nim +++ /dev/null @@ -1,18 +0,0 @@ -{.deadCodeElim: on.} -when defined(windows): - const - libevmjit* = "libevmjit.dll" -elif defined(macosx): - const - libevmjit* = "libevmjit.dylib" -else: - const - libevmjit* = "libevmjit.so" - -import evmc -export evmc - -proc evmjit_create*(): ptr evmc_vm {.cdecl, importc: "evmjit_create", dynlib: libevmjit.} - ## Create EVMJIT instance. - ## - ## @return The EVMJIT instance. diff --git a/tests/evmc_c/evmc.h b/tests/evmc_c/evmc.h deleted file mode 100644 index 3fc3ca6..0000000 --- a/tests/evmc_c/evmc.h +++ /dev/null @@ -1,941 +0,0 @@ -/** - * EVMC: Ethereum Client-VM Connector API - * - * @copyright - * Copyright 2016-2019 The EVMC Authors. - * Licensed under the Apache License, Version 2.0. - * - * @defgroup EVMC EVMC - * @{ - */ -#ifndef EVMC_H -#define EVMC_H - -#if defined(__clang__) || (defined(__GNUC__) && __GNUC__ >= 6) -/** - * Portable declaration of "deprecated" attribute. - * - * Available for clang and GCC 6+ compilers. The older GCC compilers know - * this attribute, but it cannot be applied to enum elements. - */ -#define EVMC_DEPRECATED __attribute__((deprecated)) -#else -#define EVMC_DEPRECATED -#endif - - -#include /* Definition of bool, true and false. */ -#include /* Definition of size_t. */ -#include /* Definition of int64_t, uint64_t. */ - -#if __cplusplus -extern "C" { -#endif - -/* BEGIN Python CFFI declarations */ - -enum -{ - /** - * The EVMC ABI version number of the interface declared in this file. - * - * The EVMC ABI version always equals the major version number of the EVMC project. - * The Host SHOULD check if the ABI versions match when dynamically loading VMs. - * - * @see @ref versioning - */ - EVMC_ABI_VERSION = 7 -}; - - -/** - * The fixed size array of 32 bytes. - * - * 32 bytes of data capable of storing e.g. 256-bit hashes. - */ -typedef struct evmc_bytes32 -{ - /** The 32 bytes. */ - uint8_t bytes[32]; -} evmc_bytes32; - -/** - * The alias for evmc_bytes32 to represent a big-endian 256-bit integer. - */ -typedef struct evmc_bytes32 evmc_uint256be; - -/** Big-endian 160-bit hash suitable for keeping an Ethereum address. */ -typedef struct evmc_address -{ - /** The 20 bytes of the hash. */ - uint8_t bytes[20]; -} evmc_address; - -/** The kind of call-like instruction. */ -enum evmc_call_kind -{ - EVMC_CALL = 0, /**< Request CALL. */ - EVMC_DELEGATECALL = 1, /**< Request DELEGATECALL. Valid since Homestead. - The value param ignored. */ - EVMC_CALLCODE = 2, /**< Request CALLCODE. */ - EVMC_CREATE = 3, /**< Request CREATE. */ - EVMC_CREATE2 = 4 /**< Request CREATE2. Valid since Constantinople.*/ -}; - -/** The flags for ::evmc_message. */ -enum evmc_flags -{ - EVMC_STATIC = 1 /**< Static call mode. */ -}; - -/** - * The message describing an EVM call, - * including a zero-depth calls from a transaction origin. - */ -struct evmc_message -{ - /** The kind of the call. For zero-depth calls ::EVMC_CALL SHOULD be used. */ - enum evmc_call_kind kind; - - /** - * Additional flags modifying the call execution behavior. - * In the current version the only valid values are ::EVMC_STATIC or 0. - */ - uint32_t flags; - - /** The call depth. */ - int32_t depth; - - /** The amount of gas for message execution. */ - int64_t gas; - - /** The destination of the message. */ - evmc_address destination; - - /** The sender of the message. */ - evmc_address sender; - - /** - * The message input data. - * - * This MAY be NULL. - */ - const uint8_t* input_data; - - /** - * The size of the message input data. - * - * If input_data is NULL this MUST be 0. - */ - size_t input_size; - - /** - * The amount of Ether transferred with the message. - */ - evmc_uint256be value; - - /** - * The optional value used in new contract address construction. - * - * Ignored unless kind is EVMC_CREATE2. - */ - evmc_bytes32 create2_salt; -}; - - -/** The transaction and block data for execution. */ -struct evmc_tx_context -{ - evmc_uint256be tx_gas_price; /**< The transaction gas price. */ - evmc_address tx_origin; /**< The transaction origin account. */ - evmc_address block_coinbase; /**< The miner of the block. */ - int64_t block_number; /**< The block number. */ - int64_t block_timestamp; /**< The block timestamp. */ - int64_t block_gas_limit; /**< The block gas limit. */ - evmc_uint256be block_difficulty; /**< The block difficulty. */ - evmc_uint256be chain_id; /**< The blockchain's ChainID. */ -}; - -/** - * @struct evmc_host_context - * The opaque data type representing the Host execution context. - * @see evmc_execute_fn(). - */ -struct evmc_host_context; - -/** - * Get transaction context callback function. - * - * This callback function is used by an EVM to retrieve the transaction and - * block context. - * - * @param context The pointer to the Host execution context. - * @return The transaction context. - */ -typedef struct evmc_tx_context (*evmc_get_tx_context_fn)(struct evmc_host_context* context); - -/** - * Get block hash callback function. - * - * This callback function is used by a VM to query the hash of the header of the given block. - * If the information about the requested block is not available, then this is signalled by - * returning null bytes. - * - * @param context The pointer to the Host execution context. - * @param number The block number. - * @return The block hash or null bytes - * if the information about the block is not available. - */ -typedef evmc_bytes32 (*evmc_get_block_hash_fn)(struct evmc_host_context* context, int64_t number); - -/** - * The execution status code. - * - * Successful execution is represented by ::EVMC_SUCCESS having value 0. - * - * Positive values represent failures defined by VM specifications with generic - * ::EVMC_FAILURE code of value 1. - * - * Status codes with negative values represent VM internal errors - * not provided by EVM specifications. These errors MUST not be passed back - * to the caller. They MAY be handled by the Client in predefined manner - * (see e.g. ::EVMC_REJECTED), otherwise internal errors are not recoverable. - * The generic representant of errors is ::EVMC_INTERNAL_ERROR but - * an EVM implementation MAY return negative status codes that are not defined - * in the EVMC documentation. - * - * @note - * In case new status codes are needed, please create an issue or pull request - * in the EVMC repository (https://github.com/ethereum/evmc). - */ -enum evmc_status_code -{ - /** Execution finished with success. */ - EVMC_SUCCESS = 0, - - /** Generic execution failure. */ - EVMC_FAILURE = 1, - - /** - * Execution terminated with REVERT opcode. - * - * In this case the amount of gas left MAY be non-zero and additional output - * data MAY be provided in ::evmc_result. - */ - EVMC_REVERT = 2, - - /** The execution has run out of gas. */ - EVMC_OUT_OF_GAS = 3, - - /** - * The designated INVALID instruction has been hit during execution. - * - * The EIP-141 (https://github.com/ethereum/EIPs/blob/master/EIPS/eip-141.md) - * defines the instruction 0xfe as INVALID instruction to indicate execution - * abortion coming from high-level languages. This status code is reported - * in case this INVALID instruction has been encountered. - */ - EVMC_INVALID_INSTRUCTION = 4, - - /** An undefined instruction has been encountered. */ - EVMC_UNDEFINED_INSTRUCTION = 5, - - /** - * The execution has attempted to put more items on the EVM stack - * than the specified limit. - */ - EVMC_STACK_OVERFLOW = 6, - - /** Execution of an opcode has required more items on the EVM stack. */ - EVMC_STACK_UNDERFLOW = 7, - - /** Execution has violated the jump destination restrictions. */ - EVMC_BAD_JUMP_DESTINATION = 8, - - /** - * Tried to read outside memory bounds. - * - * An example is RETURNDATACOPY reading past the available buffer. - */ - EVMC_INVALID_MEMORY_ACCESS = 9, - - /** Call depth has exceeded the limit (if any) */ - EVMC_CALL_DEPTH_EXCEEDED = 10, - - /** Tried to execute an operation which is restricted in static mode. */ - EVMC_STATIC_MODE_VIOLATION = 11, - - /** - * A call to a precompiled or system contract has ended with a failure. - * - * An example: elliptic curve functions handed invalid EC points. - */ - EVMC_PRECOMPILE_FAILURE = 12, - - /** - * Contract validation has failed (e.g. due to EVM 1.5 jump validity, - * Casper's purity checker or ewasm contract rules). - */ - EVMC_CONTRACT_VALIDATION_FAILURE = 13, - - /** - * An argument to a state accessing method has a value outside of the - * accepted range of values. - */ - EVMC_ARGUMENT_OUT_OF_RANGE = 14, - - /** - * A WebAssembly `unreachable` instruction has been hit during execution. - */ - EVMC_WASM_UNREACHABLE_INSTRUCTION = 15, - - /** - * A WebAssembly trap has been hit during execution. This can be for many - * reasons, including division by zero, validation errors, etc. - */ - EVMC_WASM_TRAP = 16, - - /** EVM implementation generic internal error. */ - EVMC_INTERNAL_ERROR = -1, - - /** - * The execution of the given code and/or message has been rejected - * by the EVM implementation. - * - * This error SHOULD be used to signal that the EVM is not able to or - * willing to execute the given code type or message. - * If an EVM returns the ::EVMC_REJECTED status code, - * the Client MAY try to execute it in other EVM implementation. - * For example, the Client tries running a code in the EVM 1.5. If the - * code is not supported there, the execution falls back to the EVM 1.0. - */ - EVMC_REJECTED = -2, - - /** The VM failed to allocate the amount of memory needed for execution. */ - EVMC_OUT_OF_MEMORY = -3 -}; - -/* Forward declaration. */ -struct evmc_result; - -/** - * Releases resources assigned to an execution result. - * - * This function releases memory (and other resources, if any) assigned to the - * specified execution result making the result object invalid. - * - * @param result The execution result which resources are to be released. The - * result itself it not modified by this function, but becomes - * invalid and user MUST discard it as well. - * This MUST NOT be NULL. - * - * @note - * The result is passed by pointer to avoid (shallow) copy of the ::evmc_result - * struct. Think of this as the best possible C language approximation to - * passing objects by reference. - */ -typedef void (*evmc_release_result_fn)(const struct evmc_result* result); - -/** The EVM code execution result. */ -struct evmc_result -{ - /** The execution status code. */ - enum evmc_status_code status_code; - - /** - * The amount of gas left after the execution. - * - * If evmc_result::code is not ::EVMC_SUCCESS nor ::EVMC_REVERT - * the value MUST be 0. - */ - int64_t gas_left; - - /** - * The reference to output data. - * - * The output contains data coming from RETURN opcode (iff evmc_result::code - * field is ::EVMC_SUCCESS) or from REVERT opcode. - * - * The memory containing the output data is owned by EVM and has to be - * freed with evmc_result::release(). - * - * This MAY be NULL. - */ - const uint8_t* output_data; - - /** - * The size of the output data. - * - * If output_data is NULL this MUST be 0. - */ - size_t output_size; - - /** - * The method releasing all resources associated with the result object. - * - * This method (function pointer) is optional (MAY be NULL) and MAY be set - * by the VM implementation. If set it MUST be called by the user once to - * release memory and other resources associated with the result object. - * Once the resources are released the result object MUST NOT be used again. - * - * The suggested code pattern for releasing execution results: - * @code - * struct evmc_result result = ...; - * if (result.release) - * result.release(&result); - * @endcode - * - * @note - * It works similarly to C++ virtual destructor. Attaching the release - * function to the result itself allows VM composition. - */ - evmc_release_result_fn release; - - /** - * The address of the contract created by create instructions. - * - * This field has valid value only if: - * - it is a result of the Host method evmc_host_interface::call - * - and the result describes successful contract creation - * (evmc_result::status_code is ::EVMC_SUCCESS). - * In all other cases the address MUST be null bytes. - */ - evmc_address create_address; - - /** - * Reserved data that MAY be used by a evmc_result object creator. - * - * This reserved 4 bytes together with 20 bytes from create_address form - * 24 bytes of memory called "optional data" within evmc_result struct - * to be optionally used by the evmc_result object creator. - * - * @see evmc_result_optional_data, evmc_get_optional_data(). - * - * Also extends the size of the evmc_result to 64 bytes (full cache line). - */ - uint8_t padding[4]; -}; - - -/** - * Check account existence callback function. - * - * This callback function is used by the VM to check if - * there exists an account at given address. - * @param context The pointer to the Host execution context. - * @param address The address of the account the query is about. - * @return true if exists, false otherwise. - */ -typedef bool (*evmc_account_exists_fn)(struct evmc_host_context* context, - const evmc_address* address); - -/** - * Get storage callback function. - * - * This callback function is used by a VM to query the given account storage entry. - * - * @param context The Host execution context. - * @param address The address of the account. - * @param key The index of the account's storage entry. - * @return The storage value at the given storage key or null bytes - * if the account does not exist. - */ -typedef evmc_bytes32 (*evmc_get_storage_fn)(struct evmc_host_context* context, - const evmc_address* address, - const evmc_bytes32* key); - - -/** - * The effect of an attempt to modify a contract storage item. - * - * For the purpose of explaining the meaning of each element, the following - * notation is used: - * - 0 is zero value, - * - X != 0 (X is any value other than 0), - * - Y != X, Y != 0 (Y is any value other than X and 0), - * - Z != Y (Z is any value other than Y), - * - the "->" means the change from one value to another. - */ -enum evmc_storage_status -{ - /** - * The value of a storage item has been left unchanged: 0 -> 0 and X -> X. - */ - EVMC_STORAGE_UNCHANGED = 0, - - /** - * The value of a storage item has been modified: X -> Y. - */ - EVMC_STORAGE_MODIFIED = 1, - - /** - * A storage item has been modified after being modified before: X -> Y -> Z. - */ - EVMC_STORAGE_MODIFIED_AGAIN = 2, - - /** - * A new storage item has been added: 0 -> X. - */ - EVMC_STORAGE_ADDED = 3, - - /** - * A storage item has been deleted: X -> 0. - */ - EVMC_STORAGE_DELETED = 4 -}; - - -/** - * Set storage callback function. - * - * This callback function is used by a VM to update the given account storage entry. - * The VM MUST make sure that the account exists. This requirement is only a formality because - * VM implementations only modify storage of the account of the current execution context - * (i.e. referenced by evmc_message::destination). - * - * @param context The pointer to the Host execution context. - * @param address The address of the account. - * @param key The index of the storage entry. - * @param value The value to be stored. - * @return The effect on the storage item. - */ -typedef enum evmc_storage_status (*evmc_set_storage_fn)(struct evmc_host_context* context, - const evmc_address* address, - const evmc_bytes32* key, - const evmc_bytes32* value); - -/** - * Get balance callback function. - * - * This callback function is used by a VM to query the balance of the given account. - * - * @param context The pointer to the Host execution context. - * @param address The address of the account. - * @return The balance of the given account or 0 if the account does not exist. - */ -typedef evmc_uint256be (*evmc_get_balance_fn)(struct evmc_host_context* context, - const evmc_address* address); - -/** - * Get code size callback function. - * - * This callback function is used by a VM to get the size of the code stored - * in the account at the given address. - * - * @param context The pointer to the Host execution context. - * @param address The address of the account. - * @return The size of the code in the account or 0 if the account does not exist. - */ -typedef size_t (*evmc_get_code_size_fn)(struct evmc_host_context* context, - const evmc_address* address); - -/** - * Get code hash callback function. - * - * This callback function is used by a VM to get the keccak256 hash of the code stored - * in the account at the given address. For existing accounts not having a code, this - * function returns keccak256 hash of empty data. - * - * @param context The pointer to the Host execution context. - * @param address The address of the account. - * @return The hash of the code in the account or null bytes if the account does not exist. - */ -typedef evmc_bytes32 (*evmc_get_code_hash_fn)(struct evmc_host_context* context, - const evmc_address* address); - -/** - * Copy code callback function. - * - * This callback function is used by an EVM to request a copy of the code - * of the given account to the memory buffer provided by the EVM. - * The Client MUST copy the requested code, starting with the given offset, - * to the provided memory buffer up to the size of the buffer or the size of - * the code, whichever is smaller. - * - * @param context The pointer to the Host execution context. See ::evmc_host_context. - * @param address The address of the account. - * @param code_offset The offset of the code to copy. - * @param buffer_data The pointer to the memory buffer allocated by the EVM - * to store a copy of the requested code. - * @param buffer_size The size of the memory buffer. - * @return The number of bytes copied to the buffer by the Client. - */ -typedef size_t (*evmc_copy_code_fn)(struct evmc_host_context* context, - const evmc_address* address, - size_t code_offset, - uint8_t* buffer_data, - size_t buffer_size); - -/** - * Selfdestruct callback function. - * - * This callback function is used by an EVM to SELFDESTRUCT given contract. - * The execution of the contract will not be stopped, that is up to the EVM. - * - * @param context The pointer to the Host execution context. See ::evmc_host_context. - * @param address The address of the contract to be selfdestructed. - * @param beneficiary The address where the remaining ETH is going to be transferred. - */ -typedef void (*evmc_selfdestruct_fn)(struct evmc_host_context* context, - const evmc_address* address, - const evmc_address* beneficiary); - -/** - * Log callback function. - * - * This callback function is used by an EVM to inform about a LOG that happened - * during an EVM bytecode execution. - * - * @param context The pointer to the Host execution context. See ::evmc_host_context. - * @param address The address of the contract that generated the log. - * @param data The pointer to unindexed data attached to the log. - * @param data_size The length of the data. - * @param topics The pointer to the array of topics attached to the log. - * @param topics_count The number of the topics. Valid values are between 0 and 4 inclusively. - */ -typedef void (*evmc_emit_log_fn)(struct evmc_host_context* context, - const evmc_address* address, - const uint8_t* data, - size_t data_size, - const evmc_bytes32 topics[], - size_t topics_count); - -/** - * Pointer to the callback function supporting EVM calls. - * - * @param context The pointer to the Host execution context. - * @param msg The call parameters. - * @return The result of the call. - */ -typedef struct evmc_result (*evmc_call_fn)(struct evmc_host_context* context, - const struct evmc_message* msg); - -/** - * The Host interface. - * - * The set of all callback functions expected by VM instances. This is C - * realisation of vtable for OOP interface (only virtual methods, no data). - * Host implementations SHOULD create constant singletons of this (similarly - * to vtables) to lower the maintenance and memory management cost. - */ -struct evmc_host_interface -{ - /** Check account existence callback function. */ - evmc_account_exists_fn account_exists; - - /** Get storage callback function. */ - evmc_get_storage_fn get_storage; - - /** Set storage callback function. */ - evmc_set_storage_fn set_storage; - - /** Get balance callback function. */ - evmc_get_balance_fn get_balance; - - /** Get code size callback function. */ - evmc_get_code_size_fn get_code_size; - - /** Get code hash callback function. */ - evmc_get_code_hash_fn get_code_hash; - - /** Copy code callback function. */ - evmc_copy_code_fn copy_code; - - /** Selfdestruct callback function. */ - evmc_selfdestruct_fn selfdestruct; - - /** Call callback function. */ - evmc_call_fn call; - - /** Get transaction context callback function. */ - evmc_get_tx_context_fn get_tx_context; - - /** Get block hash callback function. */ - evmc_get_block_hash_fn get_block_hash; - - /** Emit log callback function. */ - evmc_emit_log_fn emit_log; -}; - - -/* Forward declaration. */ -struct evmc_vm; - -/** - * Destroys the VM instance. - * - * @param vm The VM instance to be destroyed. - */ -typedef void (*evmc_destroy_fn)(struct evmc_vm* vm); - -/** - * Possible outcomes of evmc_set_option. - */ -enum evmc_set_option_result -{ - EVMC_SET_OPTION_SUCCESS = 0, - EVMC_SET_OPTION_INVALID_NAME = 1, - EVMC_SET_OPTION_INVALID_VALUE = 2 -}; - -/** - * Configures the VM instance. - * - * Allows modifying options of the VM instance. - * Options: - * - code cache behavior: on, off, read-only, ... - * - optimizations, - * - * @param vm The VM instance to be configured. - * @param name The option name. NULL-terminated string. Cannot be NULL. - * @param value The new option value. NULL-terminated string. Cannot be NULL. - * @return The outcome of the operation. - */ -typedef enum evmc_set_option_result (*evmc_set_option_fn)(struct evmc_vm* vm, - char const* name, - char const* value); - - -/** - * EVM revision. - * - * The revision of the EVM specification based on the Ethereum - * upgrade / hard fork codenames. - */ -enum evmc_revision -{ - /** - * The Frontier revision. - * - * The one Ethereum launched with. - */ - EVMC_FRONTIER = 0, - - /** - * The Homestead revision. - * - * https://eips.ethereum.org/EIPS/eip-606 - */ - EVMC_HOMESTEAD = 1, - - /** - * The Tangerine Whistle revision. - * - * https://eips.ethereum.org/EIPS/eip-608 - */ - EVMC_TANGERINE_WHISTLE = 2, - - /** - * The Spurious Dragon revision. - * - * https://eips.ethereum.org/EIPS/eip-607 - */ - EVMC_SPURIOUS_DRAGON = 3, - - /** - * The Byzantium revision. - * - * https://eips.ethereum.org/EIPS/eip-609 - */ - EVMC_BYZANTIUM = 4, - - /** - * The Constantinople revision. - * - * https://eips.ethereum.org/EIPS/eip-1013 - */ - EVMC_CONSTANTINOPLE = 5, - - /** - * The Petersburg revision. - * - * Other names: Constantinople2, ConstantinopleFix. - * - * https://eips.ethereum.org/EIPS/eip-1716 - */ - EVMC_PETERSBURG = 6, - - /** - * The Istanbul revision. - * - * The spec draft: https://eips.ethereum.org/EIPS/eip-1679. - */ - EVMC_ISTANBUL = 7, - - /** - * The Berlin revision. - * - * The spec draft: https://eips.ethereum.org/EIPS/eip-2070. - */ - EVMC_BERLIN = 8, - - /** The maximum EVM revision supported. */ - EVMC_MAX_REVISION = EVMC_BERLIN -}; - - -/** - * Executes the given code using the input from the message. - * - * This function MAY be invoked multiple times for a single VM instance. - * - * @param vm The VM instance. This argument MUST NOT be NULL. - * @param host The Host interface. This argument MUST NOT be NULL unless - * the @p vm has the ::EVMC_CAPABILITY_PRECOMPILES capability. - * @param context The opaque pointer to the Host execution context. - * This argument MAY be NULL. The VM MUST pass the same - * pointer to the methods of the @p host interface. - * The VM MUST NOT dereference the pointer. - * @param rev The requested EVM specification revision. - * @param msg The call parameters. See ::evmc_message. This argument MUST NOT be NULL. - * @param code The reference to the code to be executed. This argument MAY be NULL. - * @param code_size The length of the code. If @p code is NULL this argument MUST be 0. - * @return The execution result. - */ -typedef struct evmc_result (*evmc_execute_fn)(struct evmc_vm* vm, - const struct evmc_host_interface* host, - struct evmc_host_context* context, - enum evmc_revision rev, - const struct evmc_message* msg, - uint8_t const* code, - size_t code_size); - -/** - * Possible capabilities of a VM. - */ -enum evmc_capabilities -{ - /** - * The VM is capable of executing EVM1 bytecode. - */ - EVMC_CAPABILITY_EVM1 = (1u << 0), - - /** - * The VM is capable of executing ewasm bytecode. - */ - EVMC_CAPABILITY_EWASM = (1u << 1), - - /** - * The VM is capable of executing the precompiled contracts - * defined for the range of destination addresses. - * - * The EIP-1352 (https://eips.ethereum.org/EIPS/eip-1352) specifies - * the range 0x000...0000 - 0x000...ffff of addresses - * reserved for precompiled and system contracts. - * - * This capability is **experimental** and MAY be removed without notice. - */ - EVMC_CAPABILITY_PRECOMPILES = (1u << 2) -}; - -/** - * Alias for unsigned integer representing a set of bit flags of EVMC capabilities. - * - * @see evmc_capabilities - */ -typedef uint32_t evmc_capabilities_flagset; - -/** - * Return the supported capabilities of the VM instance. - * - * This function MAY be invoked multiple times for a single VM instance, - * and its value MAY be influenced by calls to evmc_vm::set_option. - * - * @param vm The VM instance. - * @return The supported capabilities of the VM. @see evmc_capabilities. - */ -typedef evmc_capabilities_flagset (*evmc_get_capabilities_fn)(struct evmc_vm* vm); - - -/** - * The VM instance. - * - * Defines the base struct of the VM implementation. - */ -struct evmc_vm -{ - /** - * EVMC ABI version implemented by the VM instance. - * - * Can be used to detect ABI incompatibilities. - * The EVMC ABI version represented by this file is in ::EVMC_ABI_VERSION. - */ - const int abi_version; - - /** - * The name of the EVMC VM implementation. - * - * It MUST be a NULL-terminated not empty string. - * The content MUST be UTF-8 encoded (this implies ASCII encoding is also allowed). - */ - const char* name; - - /** - * The version of the EVMC VM implementation, e.g. "1.2.3b4". - * - * It MUST be a NULL-terminated not empty string. - * The content MUST be UTF-8 encoded (this implies ASCII encoding is also allowed). - */ - const char* version; - - /** - * Pointer to function destroying the VM instance. - * - * This is a mandatory method and MUST NOT be set to NULL. - */ - evmc_destroy_fn destroy; - - /** - * Pointer to function executing a code by the VM instance. - * - * This is a mandatory method and MUST NOT be set to NULL. - */ - evmc_execute_fn execute; - - /** - * A method returning capabilities supported by the VM instance. - * - * The value returned MAY change when different options are set via the set_option() method. - * - * A Client SHOULD only rely on the value returned if it has queried it after - * it has called the set_option(). - * - * This is a mandatory method and MUST NOT be set to NULL. - */ - evmc_get_capabilities_fn get_capabilities; - - /** - * Optional pointer to function modifying VM's options. - * - * If the VM does not support this feature the pointer can be NULL. - */ - evmc_set_option_fn set_option; -}; - -/* END Python CFFI declarations */ - -#if EVMC_DOCUMENTATION -/** - * Example of a function creating an instance of an example EVM implementation. - * - * Each EVM implementation MUST provide a function returning an EVM instance. - * The function SHOULD be named `evmc_create_(void)`. If the VM name contains hyphens - * replaces them with underscores in the function names. - * - * @par Binaries naming convention - * For VMs distributed as shared libraries, the name of the library SHOULD match the VM name. - * The convetional library filename prefixes and extensions SHOULD be ignored by the Client. - * For example, the shared library with the "beta-interpreter" implementation may be named - * `libbeta-interpreter.so`. - * - * @return The VM instance or NULL indicating instance creation failure. - */ -struct evmc_vm* evmc_create_example_vm(void); -#endif - -#if __cplusplus -} -#endif - -#endif -/** @} */ diff --git a/tests/evmc_c/evmc.hpp b/tests/evmc_c/evmc.hpp deleted file mode 100644 index b9c4151..0000000 --- a/tests/evmc_c/evmc.hpp +++ /dev/null @@ -1,805 +0,0 @@ -/* EVMC: Ethereum Client-VM Connector API. - * Copyright 2018-2019 The EVMC Authors. - * Licensed under the Apache License, Version 2.0. - */ -#pragma once - -#include "evmc.h" -#include "helpers.h" - -#include -#include -#include - -/// EVMC C++ API - wrappers and bindings for C++ -/// @ingroup cpp -namespace evmc -{ -/// The big-endian 160-bit hash suitable for keeping an Ethereum address. -/// -/// This type wraps C ::evmc_address to make sure objects of this type are always initialized. -struct address : evmc_address -{ - /// Default and converting constructor. - /// - /// Initializes bytes to zeros if not other @p init value provided. - constexpr address(evmc_address init = {}) noexcept : evmc_address{init} {} - - /// Explicit operator converting to bool. - constexpr inline explicit operator bool() const noexcept; -}; - -/// The fixed size array of 32 bytes for storing 256-bit EVM values. -/// -/// This type wraps C ::evmc_bytes32 to make sure objects of this type are always initialized. -struct bytes32 : evmc_bytes32 -{ - /// Default and converting constructor. - /// - /// Initializes bytes to zeros if not other @p init value provided. - constexpr bytes32(evmc_bytes32 init = {}) noexcept : evmc_bytes32{init} {} - - /// Explicit operator converting to bool. - constexpr inline explicit operator bool() const noexcept; -}; - -/// The alias for evmc::bytes32 to represent a big-endian 256-bit integer. -using uint256be = bytes32; - - -/// Loads 64 bits / 8 bytes of data from the given @p bytes array in big-endian order. -constexpr inline uint64_t load64be(const uint8_t* bytes) noexcept -{ - return (uint64_t{bytes[0]} << 56) | (uint64_t{bytes[1]} << 48) | (uint64_t{bytes[2]} << 40) | - (uint64_t{bytes[3]} << 32) | (uint64_t{bytes[4]} << 24) | (uint64_t{bytes[5]} << 16) | - (uint64_t{bytes[6]} << 8) | uint64_t{bytes[7]}; -} - -/// Loads 32 bits / 4 bytes of data from the given @p bytes array in big-endian order. -constexpr inline uint32_t load32be(const uint8_t* bytes) noexcept -{ - return (uint32_t{bytes[0]} << 24) | (uint32_t{bytes[1]} << 16) | (uint32_t{bytes[2]} << 8) | - uint32_t{bytes[3]}; -} - -namespace fnv -{ -constexpr auto prime = 0x100000001b3; ///< The 64-bit FNV prime number. -constexpr auto offset_basis = 0xcbf29ce484222325; ///< The 64-bit FNV offset basis. - -/// The hashing transformation for 64-bit inputs based on the FNV-1a formula. -constexpr inline uint64_t fnv1a_by64(uint64_t h, uint64_t x) noexcept -{ - return (h ^ x) * prime; -} -} // namespace fnv - - -/// The "equal to" comparison operator for the evmc::address type. -constexpr bool operator==(const address& a, const address& b) noexcept -{ - // TODO: Report bug in clang keeping unnecessary bswap. - return load64be(&a.bytes[0]) == load64be(&b.bytes[0]) && - load64be(&a.bytes[8]) == load64be(&b.bytes[8]) && - load32be(&a.bytes[16]) == load32be(&b.bytes[16]); -} - -/// The "not equal to" comparison operator for the evmc::address type. -constexpr bool operator!=(const address& a, const address& b) noexcept -{ - return !(a == b); -} - -/// The "less than" comparison operator for the evmc::address type. -constexpr bool operator<(const address& a, const address& b) noexcept -{ - return load64be(&a.bytes[0]) < load64be(&b.bytes[0]) || - (load64be(&a.bytes[0]) == load64be(&b.bytes[0]) && - load64be(&a.bytes[8]) < load64be(&b.bytes[8])) || - (load64be(&a.bytes[8]) == load64be(&b.bytes[8]) && - load32be(&a.bytes[16]) < load32be(&b.bytes[16])); -} - -/// The "greater than" comparison operator for the evmc::address type. -constexpr bool operator>(const address& a, const address& b) noexcept -{ - return b < a; -} - -/// The "less than or equal to" comparison operator for the evmc::address type. -constexpr bool operator<=(const address& a, const address& b) noexcept -{ - return !(b < a); -} - -/// The "greater than or equal to" comparison operator for the evmc::address type. -constexpr bool operator>=(const address& a, const address& b) noexcept -{ - return !(a < b); -} - -/// The "equal to" comparison operator for the evmc::bytes32 type. -constexpr bool operator==(const bytes32& a, const bytes32& b) noexcept -{ - return load64be(&a.bytes[0]) == load64be(&b.bytes[0]) && - load64be(&a.bytes[8]) == load64be(&b.bytes[8]) && - load64be(&a.bytes[16]) == load64be(&b.bytes[16]) && - load64be(&a.bytes[24]) == load64be(&b.bytes[24]); -} - -/// The "not equal to" comparison operator for the evmc::bytes32 type. -constexpr bool operator!=(const bytes32& a, const bytes32& b) noexcept -{ - return !(a == b); -} - -/// The "less than" comparison operator for the evmc::bytes32 type. -constexpr bool operator<(const bytes32& a, const bytes32& b) noexcept -{ - return load64be(&a.bytes[0]) < load64be(&b.bytes[0]) || - (load64be(&a.bytes[0]) == load64be(&b.bytes[0]) && - load64be(&a.bytes[8]) < load64be(&b.bytes[8])) || - (load64be(&a.bytes[8]) == load64be(&b.bytes[8]) && - load64be(&a.bytes[16]) < load64be(&b.bytes[16])) || - (load64be(&a.bytes[16]) == load64be(&b.bytes[16]) && - load64be(&a.bytes[24]) < load64be(&b.bytes[24])); -} - -/// The "greater than" comparison operator for the evmc::bytes32 type. -constexpr bool operator>(const bytes32& a, const bytes32& b) noexcept -{ - return b < a; -} - -/// The "less than or equal to" comparison operator for the evmc::bytes32 type. -constexpr bool operator<=(const bytes32& a, const bytes32& b) noexcept -{ - return !(b < a); -} - -/// The "greater than or equal to" comparison operator for the evmc::bytes32 type. -constexpr bool operator>=(const bytes32& a, const bytes32& b) noexcept -{ - return !(a < b); -} - -/// Checks if the given address is the zero address. -constexpr inline bool is_zero(const address& a) noexcept -{ - return a == address{}; -} - -constexpr address::operator bool() const noexcept -{ - return !is_zero(*this); -} - -/// Checks if the given bytes32 object has all zero bytes. -constexpr inline bool is_zero(const bytes32& a) noexcept -{ - return a == bytes32{}; -} - -constexpr bytes32::operator bool() const noexcept -{ - return !is_zero(*this); -} - -namespace literals -{ -namespace internal -{ -template -struct integer_sequence -{ -}; - -template -using byte_sequence = integer_sequence; - -template -using char_sequence = integer_sequence; - - -template -struct concatenate; - -template -struct concatenate, byte_sequence> -{ - using type = byte_sequence; -}; - -template -constexpr uint8_t parse_hex_digit() noexcept -{ - static_assert((D >= '0' && D <= '9') || (D >= 'a' && D <= 'f') || (D >= 'A' && D <= 'F'), - "literal must be hexadecimal integer"); - return static_cast( - (D >= '0' && D <= '9') ? D - '0' : (D >= 'a' && D <= 'f') ? D - 'a' + 10 : D - 'A' + 10); -} - - -template -struct parse_digits; - -template -struct parse_digits> -{ - using type = byte_sequence(parse_hex_digit() << 4) | - parse_hex_digit()>; -}; - -template -struct parse_digits> -{ - using type = typename concatenate>::type, - typename parse_digits>::type>::type; -}; - - -template -struct parse_literal; - -template -struct parse_literal> -{ - static_assert(Prefix1 == '0' && Prefix2 == 'x', "literal must be in hexadecimal notation"); - static_assert(sizeof...(Literal) == sizeof(T) * 2, "literal must match the result type size"); - - template - static constexpr T create_from(byte_sequence) noexcept - { - return T{{{Bytes...}}}; - } - - static constexpr T get() noexcept - { - return create_from(typename parse_digits>::type{}); - } -}; - -template -struct parse_literal> -{ - static_assert(Digit == '0', "only 0 is allowed as a single digit literal"); - static constexpr T get() noexcept { return {}; } -}; - -template -constexpr T parse() noexcept -{ - return parse_literal>::get(); -} -} // namespace internal - -/// Literal for evmc::address. -template -constexpr address operator"" _address() noexcept -{ - return internal::parse(); -} - -/// Literal for evmc::bytes32. -template -constexpr bytes32 operator"" _bytes32() noexcept -{ - return internal::parse(); -} -} // namespace literals - -using namespace literals; - - -/// Alias for evmc_make_result(). -constexpr auto make_result = evmc_make_result; - -/// @copydoc evmc_result -/// -/// This is a RAII wrapper for evmc_result and objects of this type -/// automatically release attached resources. -class result : private evmc_result -{ -public: - using evmc_result::create_address; - using evmc_result::gas_left; - using evmc_result::output_data; - using evmc_result::output_size; - using evmc_result::status_code; - - /// Creates the result from the provided arguments. - /// - /// The provided output is copied to memory allocated with malloc() - /// and the evmc_result::release function is set to one invoking free(). - /// - /// @param _status_code The status code. - /// @param _gas_left The amount of gas left. - /// @param _output_data The pointer to the output. - /// @param _output_size The output size. - result(evmc_status_code _status_code, - int64_t _gas_left, - const uint8_t* _output_data, - size_t _output_size) noexcept - : evmc_result{make_result(_status_code, _gas_left, _output_data, _output_size)} - {} - - /// Converting constructor from raw evmc_result. - explicit result(evmc_result const& res) noexcept : evmc_result{res} {} - - /// Destructor responsible for automatically releasing attached resources. - ~result() noexcept - { - if (release != nullptr) - release(this); - } - - /// Move constructor. - result(result&& other) noexcept : evmc_result{other} - { - other.release = nullptr; // Disable releasing of the rvalue object. - } - - /// Move assignment operator. - /// - /// The self-assigment MUST never happen. - /// - /// @param other The other result object. - /// @return The reference to the left-hand side object. - result& operator=(result&& other) noexcept - { - this->~result(); // Release this object. - static_cast(*this) = other; // Copy data. - other.release = nullptr; // Disable releasing of the rvalue object. - return *this; - } - - /// Releases the ownership and returns the raw copy of evmc_result. - /// - /// This method drops the ownership of the result - /// (result's resources are not going to be released when this object is destructed). - /// It is the caller's responsibility having the returned copy of the result to release it. - /// This object MUST NOT be used after this method is invoked. - /// - /// @return The copy of this object converted to raw evmc_result. - evmc_result release_raw() noexcept - { - const auto out = evmc_result{*this}; // Copy data. - this->release = nullptr; // Disable releasing of this object. - return out; - } -}; - - -/// The EVMC Host interface -class HostInterface -{ -public: - virtual ~HostInterface() noexcept = default; - - /// @copydoc evmc_host_interface::account_exists - virtual bool account_exists(const address& addr) const noexcept = 0; - - /// @copydoc evmc_host_interface::get_storage - virtual bytes32 get_storage(const address& addr, const bytes32& key) const noexcept = 0; - - /// @copydoc evmc_host_interface::set_storage - virtual evmc_storage_status set_storage(const address& addr, - const bytes32& key, - const bytes32& value) noexcept = 0; - - /// @copydoc evmc_host_interface::get_balance - virtual uint256be get_balance(const address& addr) const noexcept = 0; - - /// @copydoc evmc_host_interface::get_code_size - virtual size_t get_code_size(const address& addr) const noexcept = 0; - - /// @copydoc evmc_host_interface::get_code_hash - virtual bytes32 get_code_hash(const address& addr) const noexcept = 0; - - /// @copydoc evmc_host_interface::copy_code - virtual size_t copy_code(const address& addr, - size_t code_offset, - uint8_t* buffer_data, - size_t buffer_size) const noexcept = 0; - - /// @copydoc evmc_host_interface::selfdestruct - virtual void selfdestruct(const address& addr, const address& beneficiary) noexcept = 0; - - /// @copydoc evmc_host_interface::call - virtual result call(const evmc_message& msg) noexcept = 0; - - /// @copydoc evmc_host_interface::get_tx_context - virtual evmc_tx_context get_tx_context() const noexcept = 0; - - /// @copydoc evmc_host_interface::get_block_hash - virtual bytes32 get_block_hash(int64_t block_number) const noexcept = 0; - - /// @copydoc evmc_host_interface::emit_log - virtual void emit_log(const address& addr, - const uint8_t* data, - size_t data_size, - const bytes32 topics[], - size_t num_topics) noexcept = 0; -}; - - -/// Wrapper around EVMC host context / host interface. -/// -/// To be used by VM implementations as better alternative to using ::evmc_host_context directly. -class HostContext : public HostInterface -{ - const evmc_host_interface* host = nullptr; - evmc_host_context* context = nullptr; - mutable evmc_tx_context tx_context = {}; - -public: - /// Default constructor for null Host context. - HostContext() = default; - - /// Constructor from the EVMC Host primitives. - /// @param interface The reference to the Host interface. - /// @param ctx The pointer to the Host context object. This parameter MAY be null. - HostContext(const evmc_host_interface& interface, evmc_host_context* ctx) noexcept - : host{&interface}, context{ctx} - {} - - bool account_exists(const address& address) const noexcept final - { - return host->account_exists(context, &address); - } - - bytes32 get_storage(const address& address, const bytes32& key) const noexcept final - { - return host->get_storage(context, &address, &key); - } - - evmc_storage_status set_storage(const address& address, - const bytes32& key, - const bytes32& value) noexcept final - { - return host->set_storage(context, &address, &key, &value); - } - - uint256be get_balance(const address& address) const noexcept final - { - return host->get_balance(context, &address); - } - - size_t get_code_size(const address& address) const noexcept final - { - return host->get_code_size(context, &address); - } - - bytes32 get_code_hash(const address& address) const noexcept final - { - return host->get_code_hash(context, &address); - } - - size_t copy_code(const address& address, - size_t code_offset, - uint8_t* buffer_data, - size_t buffer_size) const noexcept final - { - return host->copy_code(context, &address, code_offset, buffer_data, buffer_size); - } - - void selfdestruct(const address& addr, const address& beneficiary) noexcept final - { - host->selfdestruct(context, &addr, &beneficiary); - } - - result call(const evmc_message& message) noexcept final - { - return result{host->call(context, &message)}; - } - - /// @copydoc HostInterface::get_tx_context() - /// - /// The implementation caches the received transaction context - /// by assuming that the block timestamp should never be zero. - /// - /// @return The cached transaction context. - evmc_tx_context get_tx_context() const noexcept final - { - if (tx_context.block_timestamp == 0) - tx_context = host->get_tx_context(context); - return tx_context; - } - - bytes32 get_block_hash(int64_t number) const noexcept final - { - return host->get_block_hash(context, number); - } - - void emit_log(const address& addr, - const uint8_t* data, - size_t data_size, - const bytes32 topics[], - size_t topics_count) noexcept final - { - host->emit_log(context, &addr, data, data_size, topics, topics_count); - } -}; - - -/// Abstract class to be used by Host implementations. -/// -/// When implementing EVMC Host, you can directly inherit from the evmc::Host class. -/// This way your implementation will be simpler by avoiding manual handling -/// of the ::evmc_host_context and the ::evmc_host_interface. -class Host : public HostInterface -{ -public: - /// Provides access to the global host interface. - /// @returns Reference to the host interface object. - static const evmc_host_interface& get_interface() noexcept; - - /// Converts the Host object to the opaque host context pointer. - /// @returns Pointer to evmc_host_context. - evmc_host_context* to_context() noexcept { return reinterpret_cast(this); } - - /// Converts the opaque host context pointer back to the original Host object. - /// @tparam DerivedClass The class derived from the Host class. - /// @param context The opaque host context pointer. - /// @returns The pointer to DerivedClass. - template - static DerivedClass* from_context(evmc_host_context* context) noexcept - { - // Get pointer of the Host base class. - auto* h = reinterpret_cast(context); - - // Additional downcast, only possible if DerivedClass inherits from Host. - return static_cast(h); - } -}; - - -/// @copybrief evmc_vm -/// -/// This is a RAII wrapper for evmc_vm, and object of this type -/// automatically destroys the VM instance. -class VM -{ -public: - VM() noexcept = default; - - /// Converting constructor from evmc_vm. - explicit VM(evmc_vm* vm) noexcept : m_instance{vm} {} - - /// Destructor responsible for automatically destroying the VM instance. - ~VM() noexcept - { - if (m_instance != nullptr) - m_instance->destroy(m_instance); - } - - VM(const VM&) = delete; - VM& operator=(const VM&) = delete; - - /// Move constructor. - VM(VM&& other) noexcept : m_instance{other.m_instance} { other.m_instance = nullptr; } - - /// Move assignment operator. - VM& operator=(VM&& other) noexcept - { - this->~VM(); - m_instance = other.m_instance; - other.m_instance = nullptr; - return *this; - } - - /// The constructor that captures a VM instance and configures the instance - /// with the provided list of options. - inline VM(evmc_vm* vm, - std::initializer_list> options) noexcept; - - /// Checks if contains a valid pointer to the VM instance. - explicit operator bool() const noexcept { return m_instance != nullptr; } - - /// Checks whenever the VM instance is ABI compatible with the current EVMC API. - bool is_abi_compatible() const noexcept { return m_instance->abi_version == EVMC_ABI_VERSION; } - - /// @copydoc evmc_vm::name - char const* name() const noexcept { return m_instance->name; } - - /// @copydoc evmc_vm::version - char const* version() const noexcept { return m_instance->version; } - - /// Checks if the VM has the given capability. - bool has_capability(evmc_capabilities capability) const noexcept - { - return (get_capabilities() & static_cast(capability)) != 0; - } - - /// @copydoc evmc::vm::get_capabilities - evmc_capabilities_flagset get_capabilities() const noexcept - { - return m_instance->get_capabilities(m_instance); - } - - /// @copydoc evmc_set_option() - evmc_set_option_result set_option(const char name[], const char value[]) noexcept - { - return evmc_set_option(m_instance, name, value); - } - - /// @copydoc evmc_execute() - result execute(const evmc_host_interface& host, - evmc_host_context* ctx, - evmc_revision rev, - const evmc_message& msg, - const uint8_t* code, - size_t code_size) noexcept - { - return result{m_instance->execute(m_instance, &host, ctx, rev, &msg, code, code_size)}; - } - - /// Convenient variant of the VM::execute() that takes reference to evmc::Host class. - result execute(Host& host, - evmc_revision rev, - const evmc_message& msg, - const uint8_t* code, - size_t code_size) noexcept - { - return execute(Host::get_interface(), host.to_context(), rev, msg, code, code_size); - } - - /// Executes code without the Host context. - /// - /// The same as - /// execute(const evmc_host_interface&, evmc_host_context*, evmc_revision, - /// const evmc_message&, const uint8_t*, size_t), - /// but without providing the Host context and interface. - /// This method is for experimental precompiles support where execution is - /// guaranteed not to require any Host access. - result execute(evmc_revision rev, - const evmc_message& msg, - const uint8_t* code, - size_t code_size) noexcept - { - return result{ - m_instance->execute(m_instance, nullptr, nullptr, rev, &msg, code, code_size)}; - } - -private: - evmc_vm* m_instance = nullptr; -}; - -inline VM::VM(evmc_vm* vm, - std::initializer_list> options) noexcept - : m_instance{vm} -{ - // This constructor is implemented outside of the class definition to workaround a doxygen bug. - for (const auto& option : options) - set_option(option.first, option.second); -} - - -namespace internal -{ -inline bool account_exists(evmc_host_context* h, const evmc_address* addr) noexcept -{ - return Host::from_context(h)->account_exists(*addr); -} - -inline evmc_bytes32 get_storage(evmc_host_context* h, - const evmc_address* addr, - const evmc_bytes32* key) noexcept -{ - return Host::from_context(h)->get_storage(*addr, *key); -} - -inline evmc_storage_status set_storage(evmc_host_context* h, - const evmc_address* addr, - const evmc_bytes32* key, - const evmc_bytes32* value) noexcept -{ - return Host::from_context(h)->set_storage(*addr, *key, *value); -} - -inline evmc_uint256be get_balance(evmc_host_context* h, const evmc_address* addr) noexcept -{ - return Host::from_context(h)->get_balance(*addr); -} - -inline size_t get_code_size(evmc_host_context* h, const evmc_address* addr) noexcept -{ - return Host::from_context(h)->get_code_size(*addr); -} - -inline evmc_bytes32 get_code_hash(evmc_host_context* h, const evmc_address* addr) noexcept -{ - return Host::from_context(h)->get_code_hash(*addr); -} - -inline size_t copy_code(evmc_host_context* h, - const evmc_address* addr, - size_t code_offset, - uint8_t* buffer_data, - size_t buffer_size) noexcept -{ - return Host::from_context(h)->copy_code(*addr, code_offset, buffer_data, buffer_size); -} - -inline void selfdestruct(evmc_host_context* h, - const evmc_address* addr, - const evmc_address* beneficiary) noexcept -{ - Host::from_context(h)->selfdestruct(*addr, *beneficiary); -} - -inline evmc_result call(evmc_host_context* h, const evmc_message* msg) noexcept -{ - return Host::from_context(h)->call(*msg).release_raw(); -} - -inline evmc_tx_context get_tx_context(evmc_host_context* h) noexcept -{ - return Host::from_context(h)->get_tx_context(); -} - -inline evmc_bytes32 get_block_hash(evmc_host_context* h, int64_t block_number) noexcept -{ - return Host::from_context(h)->get_block_hash(block_number); -} - -inline void emit_log(evmc_host_context* h, - const evmc_address* addr, - const uint8_t* data, - size_t data_size, - const evmc_bytes32 topics[], - size_t num_topics) noexcept -{ - Host::from_context(h)->emit_log(*addr, data, data_size, static_cast(topics), - num_topics); -} -} // namespace internal - -inline const evmc_host_interface& Host::get_interface() noexcept -{ - static constexpr evmc_host_interface interface{ - ::evmc::internal::account_exists, ::evmc::internal::get_storage, - ::evmc::internal::set_storage, ::evmc::internal::get_balance, - ::evmc::internal::get_code_size, ::evmc::internal::get_code_hash, - ::evmc::internal::copy_code, ::evmc::internal::selfdestruct, - ::evmc::internal::call, ::evmc::internal::get_tx_context, - ::evmc::internal::get_block_hash, ::evmc::internal::emit_log}; - return interface; -} -} // namespace evmc - - -namespace std -{ -/// Hash operator template specialization for evmc::address. Needed for unordered containers. -template <> -struct hash -{ - /// Hash operator using FNV1a-based folding. - constexpr size_t operator()(const evmc::address& s) const noexcept - { - using namespace evmc; - using namespace fnv; - return static_cast(fnv1a_by64( - fnv1a_by64(fnv1a_by64(fnv::offset_basis, load64be(&s.bytes[0])), load64be(&s.bytes[8])), - load32be(&s.bytes[16]))); - } -}; - -/// Hash operator template specialization for evmc::bytes32. Needed for unordered containers. -template <> -struct hash -{ - /// Hash operator using FNV1a-based folding. - constexpr size_t operator()(const evmc::bytes32& s) const noexcept - { - using namespace evmc; - using namespace fnv; - return static_cast( - fnv1a_by64(fnv1a_by64(fnv1a_by64(fnv1a_by64(fnv::offset_basis, load64be(&s.bytes[0])), - load64be(&s.bytes[8])), - load64be(&s.bytes[16])), - load64be(&s.bytes[24]))); - } -}; -} // namespace std diff --git a/tests/evmc_c/example_host.cpp b/tests/evmc_c/example_host.cpp deleted file mode 100644 index ac30aff..0000000 --- a/tests/evmc_c/example_host.cpp +++ /dev/null @@ -1,186 +0,0 @@ -/* EVMC: Ethereum Client-VM Connector API. - * Copyright 2016-2019 The EVMC Authors. - * Licensed under the Apache License, Version 2.0. - */ - -/// @file -/// Example implementation of an EVMC Host. -#include "evmc.hpp" - -#include -#include -#include - -using namespace evmc::literals; - -namespace evmc -{ -struct account -{ - evmc::uint256be balance = {}; - std::vector code; - std::map storage; - - virtual evmc::bytes32 code_hash() const - { - // Extremely dumb "hash" function. - evmc::bytes32 ret{}; - for (std::vector::size_type i = 0; i != code.size(); i++) - { - auto v = code[i]; - ret.bytes[v % sizeof(ret.bytes)] ^= v; - } - return ret; - } -}; - -using accounts = std::map; - -} // namespace evmc - -class ExampleHost : public evmc::Host -{ - evmc::accounts accounts; - evmc_tx_context tx_context{}; - -public: - ExampleHost() = default; - explicit ExampleHost(evmc_tx_context& _tx_context) noexcept : tx_context{_tx_context} {}; - ExampleHost(evmc_tx_context& _tx_context, evmc::accounts& _accounts) noexcept - : accounts{_accounts}, tx_context{_tx_context} {}; - - bool account_exists(const evmc::address& addr) const noexcept final - { - return accounts.find(addr) != accounts.end(); - } - - evmc::bytes32 get_storage(const evmc::address& addr, const evmc::bytes32& key) const - noexcept final - { - const auto account_iter = accounts.find(addr); - if (account_iter == accounts.end()) - return {}; - - const auto storage_iter = account_iter->second.storage.find(key); - if (storage_iter != account_iter->second.storage.end()) - return storage_iter->second; - return {}; - } - - evmc_storage_status set_storage(const evmc::address& addr, - const evmc::bytes32& key, - const evmc::bytes32& value) noexcept final - { - auto& account = accounts[addr]; - auto prev_value = account.storage[key]; - account.storage[key] = value; - - return (prev_value == value) ? EVMC_STORAGE_UNCHANGED : EVMC_STORAGE_MODIFIED; - } - - evmc::uint256be get_balance(const evmc::address& addr) const noexcept final - { - auto it = accounts.find(addr); - if (it != accounts.end()) - return it->second.balance; - return {}; - } - - size_t get_code_size(const evmc::address& addr) const noexcept final - { - auto it = accounts.find(addr); - if (it != accounts.end()) - return it->second.code.size(); - return 0; - } - - evmc::bytes32 get_code_hash(const evmc::address& addr) const noexcept final - { - auto it = accounts.find(addr); - if (it != accounts.end()) - return it->second.code_hash(); - return {}; - } - - size_t copy_code(const evmc::address& addr, - size_t code_offset, - uint8_t* buffer_data, - size_t buffer_size) const noexcept final - { - const auto it = accounts.find(addr); - if (it == accounts.end()) - return 0; - - const auto& code = it->second.code; - - if (code_offset >= code.size()) - return 0; - - const auto n = std::min(buffer_size, code.size() - code_offset); - - if (n > 0) - std::copy_n(&code[code_offset], n, buffer_data); - return n; - } - - void selfdestruct(const evmc::address& addr, const evmc::address& beneficiary) noexcept final - { - (void)addr; - (void)beneficiary; - } - - evmc::result call(const evmc_message& msg) noexcept final - { - return {EVMC_REVERT, msg.gas, msg.input_data, msg.input_size}; - } - - evmc_tx_context get_tx_context() const noexcept final { return tx_context; } - - evmc::bytes32 get_block_hash(int64_t number) const noexcept final - { - const int64_t current_block_number = get_tx_context().block_number; - - return (number < current_block_number && number >= current_block_number - 256) ? - 0xb10c8a5fb10c8a5fb10c8a5fb10c8a5fb10c8a5fb10c8a5fb10c8a5fb10c8a5f_bytes32 : - 0_bytes32; - } - - void emit_log(const evmc::address& addr, - const uint8_t* data, - size_t data_size, - const evmc::bytes32 topics[], - size_t topics_count) noexcept final - { - (void)addr; - (void)data; - (void)data_size; - (void)topics; - (void)topics_count; - } -}; - -extern "C" { - -const evmc_host_interface* example_host_get_interface() -{ - return &evmc::Host::get_interface(); -} - -evmc_host_context* example_host_create_context(evmc_tx_context &tx_context) -{ - evmc::accounts accounts; - evmc::account acc; - evmc_address addr = {{0, 1, 2}}; - acc.balance = {{1, 0}}; - acc.code = {10, 11, 12, 13, 14, 15}; - accounts[addr] = acc; - - auto host = new ExampleHost{tx_context, accounts}; - return host->to_context(); -} - -void example_host_destroy_context(evmc_host_context* context) -{ - delete evmc::Host::from_context(context); -} -} diff --git a/tests/evmc_c/example_vm.cpp b/tests/evmc_c/example_vm.cpp deleted file mode 100644 index cc250bd..0000000 --- a/tests/evmc_c/example_vm.cpp +++ /dev/null @@ -1,235 +0,0 @@ -/* EVMC: Ethereum Client-VM Connector API. - * Copyright 2016-2019 The EVMC Authors. - * Licensed under the Apache License, Version 2.0. - */ - -/// @file -/// Example implementation of the EVMC VM interface. -/// -/// This VM does not do anything useful except for showing -/// how EVMC VM API should be implemented. -/// The implementation is done in C only, but could be done in C++ in very -/// similar way. - -#include "evmc.h" -#include -#include -#include -#include - -extern "C" { - -/// The example VM instance struct extending the evmc_vm. -struct example_vm -{ - struct evmc_vm instance; ///< The base struct. - int verbose; ///< The verbosity level. -}; - -/// The implementation of the evmc_vm::destroy() method. -static void destroy(struct evmc_vm* vm) -{ - free(vm); -} - -/// The example implementation of the evmc_vm::get_capabilities() method. -static evmc_capabilities_flagset get_capabilities(struct evmc_vm* vm) -{ - (void)vm; - return EVMC_CAPABILITY_EVM1 | EVMC_CAPABILITY_EWASM; -} - -/// Example VM options. -/// -/// The implementation of the evmc_vm::set_option() method. -/// VMs are allowed to omit this method implementation. -static enum evmc_set_option_result set_option(struct evmc_vm* instance, - const char* name, - const char* value) -{ - struct example_vm* vm = (struct example_vm*)instance; - if (strcmp(name, "verbose") == 0) - { - if (!value) - return EVMC_SET_OPTION_INVALID_VALUE; - - char* end = NULL; - long int v = strtol(value, &end, 0); - if (end == value) // Parsing the value failed. - return EVMC_SET_OPTION_INVALID_VALUE; - if (v > 9 || v < -1) // Not in the valid range. - return EVMC_SET_OPTION_INVALID_VALUE; - vm->verbose = (int)v; - return EVMC_SET_OPTION_SUCCESS; - } - - return EVMC_SET_OPTION_INVALID_NAME; -} - -/// The implementation of the evmc_result::release() method that frees -/// the output buffer attached to the result object. -static void free_result_output_data(const struct evmc_result* result) -{ - free((uint8_t*)result->output_data); -} - -/// The example implementation of the evmc_vm::execute() method. -static struct evmc_result execute(struct evmc_vm* instance, - const struct evmc_host_interface* host, - struct evmc_host_context* context, - enum evmc_revision rev, - const struct evmc_message* msg, - const uint8_t* code, - size_t code_size) -{ - struct evmc_result ret = {.status_code = EVMC_INTERNAL_ERROR}; - if (code_size == 0) - { - // In case of empty code return a fancy error message. - const char* error = rev == EVMC_BYZANTIUM ? "Welcome to Byzantium!" : "Hello Ethereum!"; - ret.output_data = (const uint8_t*)error; - ret.output_size = strlen(error); - ret.status_code = EVMC_FAILURE; - ret.gas_left = msg->gas / 10; - ret.release = NULL; // We don't need to release the constant messages. - return ret; - } - - struct example_vm* vm = (struct example_vm*)instance; - - // Simulate executing by checking for some code patterns. - // Solidity inline assembly is used in the examples instead of EVM bytecode. - - // Assembly: `{ mstore(0, address()) return(0, msize()) }`. - const char return_address[] = "\x30\x60\x00\x52\x59\x60\x00\xf3"; - - // Assembly: `{ sstore(0, add(sload(0), 1)) }` - const char counter[] = "\x60\x01\x60\x00\x54\x01\x60\x00\x55"; - - // Assembly: `{ mstore(0, number()) return(0, msize()) }` - const char return_block_number[] = "\x43\x60\x00\x52\x59\x60\x00\xf3"; - - // Assembly: `{ sstore(0, number()) mstore(0, number()) return(0, msize()) }` - const char save_return_block_number[] = "\x43\x60\x00\x55\x43\x60\x00\x52\x59\x60\x00\xf3"; - - // Assembly: PUSH(0) 6x DUP1 CALL - const char make_a_call[] = "\x60\x00\x80\x80\x80\x80\x80\x80\xf1"; - - if (msg->kind == EVMC_CREATE) - { - ret.status_code = EVMC_SUCCESS; - ret.gas_left = msg->gas / 10; - return ret; - } - else if (code_size == (sizeof(return_address) - 1) && - strncmp((const char*)code, return_address, code_size) == 0) - { - static const size_t address_size = sizeof(msg->destination); - uint8_t* output_data = (uint8_t*)malloc(address_size); - if (!output_data) - { - // malloc failed, report internal error. - ret.status_code = EVMC_INTERNAL_ERROR; - return ret; - } - memcpy(output_data, &msg->destination, address_size); - ret.status_code = EVMC_SUCCESS; - ret.output_data = output_data; - ret.output_size = address_size; - ret.release = &free_result_output_data; - return ret; - } - else if (code_size == (sizeof(counter) - 1) && - strncmp((const char*)code, counter, code_size) == 0) - { - const evmc_bytes32 key = {{0}}; - evmc_bytes32 value = host->get_storage(context, &msg->destination, &key); - value.bytes[31]++; - host->set_storage(context, &msg->destination, &key, &value); - ret.status_code = EVMC_SUCCESS; - return ret; - } - else if (code_size == (sizeof(return_block_number) - 1) && - strncmp((const char*)code, return_block_number, code_size) == 0) - { - const struct evmc_tx_context tx_context = host->get_tx_context(context); - const size_t output_size = 20; - - uint8_t* output_data = (uint8_t*)calloc(1, output_size); - snprintf((char*)output_data, output_size, "%u", (unsigned)tx_context.block_number); - ret.status_code = EVMC_SUCCESS; - ret.gas_left = msg->gas / 2; - ret.output_data = output_data; - ret.output_size = output_size; - ret.release = &free_result_output_data; - return ret; - } - else if (code_size == (sizeof(save_return_block_number) - 1) && - strncmp((const char*)code, save_return_block_number, code_size) == 0) - { - const struct evmc_tx_context tx_context = host->get_tx_context(context); - const size_t output_size = 20; - - // Store block number. - const evmc_bytes32 key = {{0}}; - evmc_bytes32 value = {{0}}; - // NOTE: assume block number is <= 255 - value.bytes[31] = (uint8_t)tx_context.block_number; - host->set_storage(context, &msg->destination, &key, &value); - - // Return block number. - uint8_t* output_data = (uint8_t*)calloc(1, output_size); - snprintf((char*)output_data, output_size, "%u", (unsigned)tx_context.block_number); - ret.status_code = EVMC_SUCCESS; - ret.gas_left = msg->gas / 2; - ret.output_data = output_data; - ret.output_size = output_size; - ret.release = &free_result_output_data; - return ret; - } - else if (code_size == (sizeof(make_a_call) - 1) && - strncmp((const char*)code, make_a_call, code_size) == 0) - { - struct evmc_message call_msg; - memset(&call_msg, 0, sizeof(call_msg)); - call_msg.kind = EVMC_CALL; - call_msg.depth = msg->depth + 1; - call_msg.gas = msg->gas - (msg->gas / 64); - call_msg.sender = msg->destination; - return host->call(context, &call_msg); - } - - ret.status_code = EVMC_FAILURE; - ret.gas_left = 0; - - if (vm->verbose) - printf("Execution done.\n"); - - return ret; -} - -/// @cond internal -#if !defined(PROJECT_VERSION) -/// The dummy project version if not provided by the build system. -#define PROJECT_VERSION "0.0.0" -#endif -/// @endcond - -struct evmc_vm* evmc_create_example_vm() -{ - struct evmc_vm init = { - .abi_version = EVMC_ABI_VERSION, - .name = "example_vm", - .version = PROJECT_VERSION, - .destroy = destroy, - .execute = execute, - .get_capabilities = get_capabilities, - .set_option = set_option, - }; - struct example_vm* vm = (example_vm*)calloc(1, sizeof(struct example_vm)); - struct evmc_vm* interface = &vm->instance; - memcpy(interface, &init, sizeof(init)); - return interface; -} - -} \ No newline at end of file diff --git a/tests/evmc_c/helpers.h b/tests/evmc_c/helpers.h deleted file mode 100644 index 345e351..0000000 --- a/tests/evmc_c/helpers.h +++ /dev/null @@ -1,212 +0,0 @@ -/* EVMC: Ethereum Client-VM Connector API. - * Copyright 2018-2019 The EVMC Authors. - * Licensed under the Apache License, Version 2.0. - */ - -/** - * EVMC Helpers - * - * A collection of C helper functions for invoking a VM instance methods. - * These are convenient for languages where invoking function pointers - * is "ugly" or impossible (such as Go). - * - * It also contains helpers (overloaded operators) for using EVMC types effectively in C++. - * - * @defgroup helpers EVMC Helpers - * @{ - */ -#pragma once - -#include "evmc.h" -#include -#include - -/** - * Returns true if the VM has a compatible ABI version. - */ -static inline bool evmc_is_abi_compatible(struct evmc_vm* vm) -{ - return vm->abi_version == EVMC_ABI_VERSION; -} - -/** - * Returns the name of the VM. - */ -static inline const char* evmc_vm_name(struct evmc_vm* vm) -{ - return vm->name; -} - -/** - * Returns the version of the VM. - */ -static inline const char* evmc_vm_version(struct evmc_vm* vm) -{ - return vm->version; -} - -/** - * Checks if the VM has the given capability. - * - * @see evmc_get_capabilities_fn - */ -static inline bool evmc_vm_has_capability(struct evmc_vm* vm, enum evmc_capabilities capability) -{ - return (vm->get_capabilities(vm) & (evmc_capabilities_flagset)capability) != 0; -} - -/** - * Destroys the VM instance. - * - * @see evmc_destroy_fn - */ -static inline void evmc_destroy(struct evmc_vm* vm) -{ - vm->destroy(vm); -} - -/** - * Sets the option for the VM, if the feature is supported by the VM. - * - * @see evmc_set_option_fn - */ -static inline enum evmc_set_option_result evmc_set_option(struct evmc_vm* vm, - char const* name, - char const* value) -{ - if (vm->set_option) - return vm->set_option(vm, name, value); - return EVMC_SET_OPTION_INVALID_NAME; -} - -/** - * Executes code in the VM instance. - * - * @see evmc_execute_fn. - */ -static inline struct evmc_result evmc_execute(struct evmc_vm* vm, - const struct evmc_host_interface* host, - struct evmc_host_context* context, - enum evmc_revision rev, - const struct evmc_message* msg, - uint8_t const* code, - size_t code_size) -{ - return vm->execute(vm, host, context, rev, msg, code, code_size); -} - -/// The evmc_result release function using free() for releasing the memory. -/// -/// This function is used in the evmc_make_result(), -/// but may be also used in other case if convenient. -/// -/// @param result The result object. -static void evmc_free_result_memory(const struct evmc_result* result) -{ - free((uint8_t*)result->output_data); -} - -/// Creates the result from the provided arguments. -/// -/// The provided output is copied to memory allocated with malloc() -/// and the evmc_result::release function is set to one invoking free(). -/// -/// In case of memory allocation failure, the result has all fields zeroed -/// and only evmc_result::status_code is set to ::EVMC_OUT_OF_MEMORY internal error. -/// -/// @param status_code The status code. -/// @param gas_left The amount of gas left. -/// @param output_data The pointer to the output. -/// @param output_size The output size. -static inline struct evmc_result evmc_make_result(enum evmc_status_code status_code, - int64_t gas_left, - const uint8_t* output_data, - size_t output_size) -{ - struct evmc_result result; - memset(&result, 0, sizeof(result)); - - if (output_size != 0) - { - uint8_t* buffer = (uint8_t*)malloc(output_size); - - if (!buffer) - { - result.status_code = EVMC_OUT_OF_MEMORY; - return result; - } - - memcpy(buffer, output_data, output_size); - result.output_data = buffer; - result.output_size = output_size; - result.release = evmc_free_result_memory; - } - - result.status_code = status_code; - result.gas_left = gas_left; - return result; -} - -/** - * Releases the resources allocated to the execution result. - * - * @param result The result object to be released. MUST NOT be NULL. - * - * @see evmc_result::release() evmc_release_result_fn - */ -static inline void evmc_release_result(struct evmc_result* result) -{ - if (result->release) - result->release(result); -} - - -/** - * Helpers for optional storage of evmc_result. - * - * In some contexts (i.e. evmc_result::create_address is unused) objects of - * type evmc_result contains a memory storage that MAY be used by the object - * owner. This group defines helper types and functions for accessing - * the optional storage. - * - * @defgroup result_optional_storage Result Optional Storage - * @{ - */ - -/** - * The union representing evmc_result "optional storage". - * - * The evmc_result struct contains 24 bytes of optional storage that can be - * reused by the object creator if the object does not contain - * evmc_result::create_address. - * - * A VM implementation MAY use this memory to keep additional data - * when returning result from evmc_execute_fn(). - * The host application MAY use this memory to keep additional data - * when returning result of performed calls from evmc_call_fn(). - * - * @see evmc_get_optional_storage(), evmc_get_const_optional_storage(). - */ -union evmc_result_optional_storage -{ - uint8_t bytes[24]; /**< 24 bytes of optional storage. */ - void* pointer; /**< Optional pointer. */ -}; - -/** Provides read-write access to evmc_result "optional storage". */ -static inline union evmc_result_optional_storage* evmc_get_optional_storage( - struct evmc_result* result) -{ - return (union evmc_result_optional_storage*)&result->create_address; -} - -/** Provides read-only access to evmc_result "optional storage". */ -static inline const union evmc_result_optional_storage* evmc_get_const_optional_storage( - const struct evmc_result* result) -{ - return (const union evmc_result_optional_storage*)&result->create_address; -} - -/** @} */ - -/** @} */