vendor: Upgrade EVMC to version 6.0.0

This commit is contained in:
Paweł Bylica 2018-10-18 18:32:19 +02:00
parent d7fefbbc78
commit a54ce7f361
No known key found for this signature in database
GPG key ID: 7A0C037434FE77EF
8 changed files with 401 additions and 248 deletions

View file

@ -15,9 +15,9 @@ package evmc
#include <stdlib.h>
#include <string.h>
static inline int set_option(struct evmc_instance* instance, char* name, char* value)
static inline enum evmc_set_option_result set_option(struct evmc_instance* instance, char* name, char* value)
{
int ret = evmc_set_option(instance, name, value);
enum evmc_set_option_result ret = evmc_set_option(instance, name, value);
free(name);
free(value);
return ret;
@ -29,29 +29,29 @@ struct extended_context
int64_t index;
};
extern const struct evmc_context_fn_table evmc_go_fn_table;
extern const struct evmc_host_interface evmc_go_host;
static struct evmc_result execute_wrapper(struct evmc_instance* instance, int64_t context_index, enum evmc_revision rev,
const struct evmc_address* destination, const struct evmc_address* sender, const struct evmc_uint256be* value,
const uint8_t* input_data, size_t input_size, const struct evmc_uint256be* code_hash, int64_t gas,
int32_t depth, enum evmc_call_kind kind, uint32_t flags, const uint8_t* code, size_t code_size)
static struct evmc_result execute_wrapper(struct evmc_instance* instance,
int64_t context_index, enum evmc_revision rev,
enum evmc_call_kind kind, uint32_t flags, int32_t depth, int64_t gas,
const evmc_address* destination, const evmc_address* sender,
const uint8_t* input_data, size_t input_size, const evmc_uint256be* value,
const uint8_t* code, size_t code_size, const evmc_bytes32* create2_salt)
{
struct evmc_uint256be create2_salt = {};
struct evmc_message msg = {
*destination,
*sender,
*value,
input_data,
input_size,
*code_hash,
create2_salt,
gas,
depth,
kind,
flags,
depth,
gas,
*destination,
*sender,
input_data,
input_size,
*value,
*create2_salt,
};
struct extended_context ctx = {{&evmc_go_fn_table}, context_index};
struct extended_context ctx = {{&evmc_go_host}, context_index};
return evmc_execute(instance, &ctx.context, rev, &msg, code, code_size);
}
*/
@ -68,10 +68,10 @@ import (
// Static asserts.
const (
_ = uint(common.HashLength - C.sizeof_struct_evmc_uint256be) // The size of evmc_uint256be equals the size of Hash.
_ = uint(C.sizeof_struct_evmc_uint256be - common.HashLength)
_ = uint(common.AddressLength - C.sizeof_struct_evmc_address) // The size of evmc_address equals the size of Address.
_ = uint(C.sizeof_struct_evmc_address - common.AddressLength)
_ = uint(common.HashLength - C.sizeof_evmc_bytes32) // The size of evmc_bytes32 equals the size of Hash.
_ = uint(C.sizeof_evmc_bytes32 - common.HashLength)
_ = uint(common.AddressLength - C.sizeof_evmc_address) // The size of evmc_address equals the size of Address.
_ = uint(C.sizeof_evmc_address - common.AddressLength)
)
type Error int32
@ -185,18 +185,34 @@ func (instance *Instance) Version() string {
return C.GoString(instance.handle.version)
}
type Capability uint32
const (
CapabilityEVM1 Capability = C.EVMC_CAPABILITY_EVM1
CapabilityEWASM Capability = C.EVMC_CAPABILITY_EWASM
)
func (instance *Instance) HasCapability(capability Capability) bool {
return bool(C.evmc_vm_has_capability(instance.handle, uint32(capability)))
}
func (instance *Instance) SetOption(name string, value string) (err error) {
r := C.set_option(instance.handle, C.CString(name), C.CString(value))
if r != 1 {
switch r {
case C.EVMC_SET_OPTION_INVALID_NAME:
err = fmt.Errorf("evmc: option '%s' not accepted", name)
case C.EVMC_SET_OPTION_INVALID_VALUE:
err = fmt.Errorf("evmc: option '%s' has invalid value", name)
case C.EVMC_SET_OPTION_SUCCESS:
}
return err
}
func (instance *Instance) Execute(ctx HostContext, rev Revision,
destination common.Address, sender common.Address, value common.Hash, input []byte, codeHash common.Hash, gas int64,
depth int, kind CallKind, static bool, code []byte) (output []byte, gasLeft int64, err error) {
kind CallKind, static bool, depth int, gas int64,
destination common.Address, sender common.Address, input []byte, value common.Hash,
code []byte, create2Salt common.Hash) (output []byte, gasLeft int64, err error) {
flags := C.uint32_t(0)
if static {
@ -207,11 +223,12 @@ func (instance *Instance) Execute(ctx HostContext, rev Revision,
// FIXME: Clarify passing by pointer vs passing by value.
evmcDestination := evmcAddress(destination)
evmcSender := evmcAddress(sender)
evmcValue := evmcUint256be(value)
evmcCodeHash := evmcUint256be(codeHash)
result := C.execute_wrapper(instance.handle, C.int64_t(ctxId), uint32(rev), &evmcDestination, &evmcSender, &evmcValue,
bytesPtr(input), C.size_t(len(input)), &evmcCodeHash, C.int64_t(gas), C.int32_t(depth), C.enum_evmc_call_kind(kind),
flags, bytesPtr(code), C.size_t(len(code)))
evmcValue := evmcBytes32(value)
evmcCreate2Salt := evmcBytes32(create2Salt)
result := C.execute_wrapper(instance.handle, C.int64_t(ctxId), uint32(rev),
C.enum_evmc_call_kind(kind), flags, C.int32_t(depth), C.int64_t(gas),
&evmcDestination, &evmcSender, bytesPtr(input), C.size_t(len(input)), &evmcValue,
bytesPtr(code), C.size_t(len(code)), &evmcCreate2Salt)
removeHostContext(ctxId)
output = C.GoBytes(unsafe.Pointer(result.output_data), C.int(result.output_size))
@ -255,16 +272,16 @@ func getHostContext(idx int) HostContext {
return ctx
}
func evmcUint256be(in common.Hash) C.struct_evmc_uint256be {
out := C.struct_evmc_uint256be{}
func evmcBytes32(in common.Hash) C.evmc_bytes32 {
out := C.evmc_bytes32{}
for i := 0; i < len(in); i++ {
out.bytes[i] = C.uint8_t(in[i])
}
return out
}
func evmcAddress(address common.Address) C.struct_evmc_address {
r := C.struct_evmc_address{}
func evmcAddress(address common.Address) C.evmc_address {
r := C.evmc_address{}
for i := 0; i < len(address); i++ {
r.bytes[i] = C.uint8_t(address[i])
}

View file

@ -11,8 +11,9 @@
#ifndef EVMC_H
#define EVMC_H
#include <stddef.h> /* Definition of size_t. */
#include <stdint.h> /* Definition of int64_t, uint64_t. */
#include <stdbool.h> /* Definition of bool, true and false. */
#include <stddef.h> /* Definition of size_t. */
#include <stdint.h> /* Definition of int64_t, uint64_t. */
#if __cplusplus
extern "C" {
@ -22,30 +23,40 @@ extern "C" {
enum
{
/** The EVMC ABI version number of the interface declared in this file. */
EVMC_ABI_VERSION = 5
/**
* 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 = 6
};
/**
* Big-endian 256-bit integer.
* The fixed size array of 32 bytes.
*
* 32 bytes of data representing big-endian 256-bit integer. I.e. bytes[0] is
* the most significant byte, bytes[31] is the least significant byte.
* This type is used to transfer to/from the VM values interpreted by the user
* as both 256-bit integers and 256-bit hashes.
* 32 bytes of data capable of storing e.g. 256-bit hashes.
*/
struct evmc_uint256be
typedef struct evmc_bytes32
{
/** The 32 bytes of the big-endian integer or hash. */
/** 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. */
struct evmc_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
@ -70,71 +81,65 @@ enum evmc_flags
*/
struct evmc_message
{
/** The destination of the message. */
struct evmc_address destination;
/** The sender of the message. */
struct evmc_address sender;
/** The kind of the call. For zero-depth calls ::EVMC_CALL SHOULD be used. */
enum evmc_call_kind kind;
/**
* The amount of Ether transferred with the message.
* Additional flags modifying the call execution behavior.
* In the current version the only valid values are ::EVMC_STATIC or 0.
*/
struct evmc_uint256be value;
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.
* 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.
* If input_data is NULL this MUST be 0.
*/
size_t input_size;
/**
* The optional hash of the code of the destination account.
* The null hash MUST be used when not specified.
* The amount of Ether transferred with the message.
*/
struct evmc_uint256be code_hash;
evmc_uint256be value;
/**
* The optional value used in new contract address construction.
*
* Ignored unless kind is EVMC_CREATE2.
* Ignored unless kind is EVMC_CREATE2.
*/
struct evmc_uint256be create2_salt;
/** The amount of gas for message execution. */
int64_t gas;
/** The call depth. */
int32_t depth;
/** 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;
evmc_bytes32 create2_salt;
};
/** The transaction and block data for execution. */
struct evmc_tx_context
{
struct evmc_uint256be tx_gas_price; /**< The transaction gas price. */
struct evmc_address tx_origin; /**< The transaction origin account. */
struct 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. */
struct evmc_uint256be block_difficulty; /**< The block difficulty. */
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. */
};
struct evmc_context;
@ -145,28 +150,24 @@ struct evmc_context;
* This callback function is used by an EVM to retrieve the transaction and
* block context.
*
* @param[out] result The returned transaction context.
* @see ::evmc_tx_context.
* @param context The pointer to the Host execution context.
* @see ::evmc_context.
* @return The transaction context.
*/
typedef void (*evmc_get_tx_context_fn)(struct evmc_tx_context* result,
struct evmc_context* context);
typedef struct evmc_tx_context (*evmc_get_tx_context_fn)(struct evmc_context* context);
/**
* Get block hash callback function.
*
* This callback function is used by an EVM to query the block hash of
* a given block.
* 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[out] result The returned block hash value.
* @param context The pointer to the Host execution context.
* @param number The block number. Must be a value between
* (and including) 0 and 255.
* @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 void (*evmc_get_block_hash_fn)(struct evmc_uint256be* result,
struct evmc_context* context,
int64_t number);
typedef evmc_bytes32 (*evmc_get_block_hash_fn)(struct evmc_context* context, int64_t number);
/**
* The execution status code.
@ -265,7 +266,7 @@ enum evmc_status_code
EVMC_ARGUMENT_OUT_OF_RANGE = 14,
/**
* A WebAssembly `unreachable` instruction has been hit during exection.
* A WebAssembly `unreachable` instruction has been hit during execution.
*/
EVMC_WASM_UNREACHABLE_INSTRUCTION = 15,
@ -376,7 +377,7 @@ struct evmc_result
* This field has valid value only if the result describes successful
* CREATE (evmc_result::status_code is ::EVMC_SUCCESS).
*/
struct evmc_address create_address;
evmc_address create_address;
/**
* Reserved data that MAY be used by a evmc_result object creator.
@ -394,33 +395,30 @@ struct evmc_result
/**
* Check account existence callback function
* Check account existence callback function.
*
* This callback function is used by the EVM to check if
* there exists an account at given address.
* @param context The pointer to the Host execution context.
* @see ::evmc_context.
* @param address The address of the account the query is about.
* @return 1 if exists, 0 otherwise.
* 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 int (*evmc_account_exists_fn)(struct evmc_context* context,
const struct evmc_address* address);
typedef bool (*evmc_account_exists_fn)(struct evmc_context* context, const evmc_address* address);
/**
* Get storage callback function.
*
* This callback function is used by an EVM to query the given contract
* storage entry.
* @param[out] result The returned storage value.
* @param context The pointer to the Host execution context.
* @see ::evmc_context.
* @param address The address of the contract.
* @param key The index of the storage entry.
* 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 void (*evmc_get_storage_fn)(struct evmc_uint256be* result,
struct evmc_context* context,
const struct evmc_address* address,
const struct evmc_uint256be* key);
typedef evmc_bytes32 (*evmc_get_storage_fn)(struct evmc_context* context,
const evmc_address* address,
const evmc_bytes32* key);
/**
@ -431,6 +429,7 @@ typedef void (*evmc_get_storage_fn)(struct evmc_uint256be* result,
* - 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
@ -445,70 +444,79 @@ enum evmc_storage_status
*/
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 = 2,
EVMC_STORAGE_ADDED = 3,
/**
* A storage item has been deleted: X -> 0.
*/
EVMC_STORAGE_DELETED = 3
EVMC_STORAGE_DELETED = 4
};
/**
* Set storage callback function.
*
* This callback function is used by an EVM to update the given contract
* storage entry.
* 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.
* @see ::evmc_context.
* @param address The address of the contract.
* @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, @see ::evmc_storage_status.
* @return The effect on the storage item.
*/
typedef enum evmc_storage_status (*evmc_set_storage_fn)(struct evmc_context* context,
const struct evmc_address* address,
const struct evmc_uint256be* key,
const struct evmc_uint256be* value);
const evmc_address* address,
const evmc_bytes32* key,
const evmc_bytes32* value);
/**
* Get balance callback function.
*
* This callback function is used by an EVM to query the balance of the given
* address.
* @param[out] result The returned balance value.
* @param context The pointer to the Host execution context.
* @see ::evmc_context.
* @param address The address.
* 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 void (*evmc_get_balance_fn)(struct evmc_uint256be* result,
struct evmc_context* context,
const struct evmc_address* address);
typedef evmc_uint256be (*evmc_get_balance_fn)(struct evmc_context* context,
const evmc_address* address);
/**
* Get code size callback function.
*
* This callback function is used by an EVM to get the size of the code stored
* in the account at the given address. For accounts not having a code, this
* function returns 0.
* 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_context* context,
const struct evmc_address* address);
typedef size_t (*evmc_get_code_size_fn)(struct evmc_context* context, const evmc_address* address);
/**
* Get code size callback function.
*
* This callback function is used by an EVM to get the keccak256 hash of the code stored
* in the account at the given address. For accounts not having a code, this
* function returns keccak256 hash of empty data. For accounts not existing in the state,
* this function returns 0.
* 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 void (*evmc_get_code_hash_fn)(struct evmc_uint256be* result,
struct evmc_context* context,
const struct evmc_address* address);
typedef evmc_bytes32 (*evmc_get_code_hash_fn)(struct evmc_context* context,
const evmc_address* address);
/**
* Copy code callback function.
@ -529,7 +537,7 @@ typedef void (*evmc_get_code_hash_fn)(struct evmc_uint256be* result,
* @return The number of bytes copied to the buffer by the Client.
*/
typedef size_t (*evmc_copy_code_fn)(struct evmc_context* context,
const struct evmc_address* address,
const evmc_address* address,
size_t code_offset,
uint8_t* buffer_data,
size_t buffer_size);
@ -547,8 +555,8 @@ typedef size_t (*evmc_copy_code_fn)(struct evmc_context* context,
* transferred.
*/
typedef void (*evmc_selfdestruct_fn)(struct evmc_context* context,
const struct evmc_address* address,
const struct evmc_address* beneficiary);
const evmc_address* address,
const evmc_address* beneficiary);
/**
* Log callback function.
@ -565,35 +573,31 @@ typedef void (*evmc_selfdestruct_fn)(struct evmc_context* context,
* 0 and 4 inclusively.
*/
typedef void (*evmc_emit_log_fn)(struct evmc_context* context,
const struct evmc_address* address,
const evmc_address* address,
const uint8_t* data,
size_t data_size,
const struct evmc_uint256be topics[],
const evmc_bytes32 topics[],
size_t topics_count);
/**
* Pointer to the callback function supporting EVM calls.
*
* @param[out] result The result of the call. The result object is not
* initialized by the EVM, the Client MUST correctly
* initialize all expected fields of the structure.
* @param context The pointer to the Host execution context.
* @see ::evmc_context.
* @param msg Call parameters. @see ::evmc_message.
* @param context The pointer to the Host execution context.
* @param msg The call parameters.
* @return The result of the call.
*/
typedef void (*evmc_call_fn)(struct evmc_result* result,
struct evmc_context* context,
const struct evmc_message* msg);
typedef struct evmc_result (*evmc_call_fn)(struct evmc_context* context,
const struct evmc_message* msg);
/**
* The context interface.
* The Host interface.
*
* The set of all callback functions expected by EVM 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.
* 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_context_fn_table
struct evmc_host_interface
{
/** Check account existence callback function. */
evmc_account_exists_fn account_exists;
@ -645,8 +649,8 @@ struct evmc_context_fn_table
*/
struct evmc_context
{
/** Function table defining the context interface (vtable). */
const struct evmc_context_fn_table* fn_table;
/** The Host interface. */
const struct evmc_host_interface* host;
};
@ -660,6 +664,15 @@ struct evmc_instance;
*/
typedef void (*evmc_destroy_fn)(struct evmc_instance* evm);
/**
* 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 EVM instance.
@ -672,9 +685,11 @@ typedef void (*evmc_destroy_fn)(struct evmc_instance* evm);
* @param evm The EVM 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 1 if the option set successfully, 0 otherwise.
* @return The outcome of the operation.
*/
typedef int (*evmc_set_option_fn)(struct evmc_instance* evm, char const* name, char const* value);
typedef enum evmc_set_option_result (*evmc_set_option_fn)(struct evmc_instance* evm,
char const* name,
char const* value);
/**
@ -717,6 +732,32 @@ typedef struct evmc_result (*evmc_execute_fn)(struct evmc_instance* instance,
uint8_t const* code,
size_t code_size);
/**
* Possible capabilities of a VM.
*/
enum evmc_capabilities
{
EVMC_CAPABILITY_EVM1 = (1u << 0), /**< The VM is capable of executing EVM1 bytecode. */
EVMC_CAPABILITY_EWASM = (1u << 1) /**< The VM is capable of execution ewasm bytecode. */
};
/**
* 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_instance::set_option.
*
* @param instance The EVM instance.
* @return The supported capabilities of the VM. @see evmc_capabilities.
*/
typedef evmc_capabilities_flagset (*evmc_get_capabilities_fn)(struct evmc_instance* instance);
/** The opaque type representing a Client-side tracer object. */
struct evmc_tracer_context;
@ -762,7 +803,7 @@ typedef void (*evmc_trace_callback)(struct evmc_tracer_context* context,
enum evmc_status_code status_code,
int64_t gas_left,
size_t stack_num_items,
const struct evmc_uint256be* pushed_stack_item,
const evmc_uint256be* pushed_stack_item,
size_t memory_size,
size_t changed_memory_offset,
size_t changed_memory_size,
@ -824,6 +865,16 @@ struct evmc_instance
/** Pointer to function executing a code by the EVM instance. */
evmc_execute_fn execute;
/**
* Pointer to function returning capabilities supported by the VM instance.
*
* The value returned might change when different options are requested via set_option.
*
* A Client SHOULD only rely on the value returned here if it has queried it after
* it has called set_option.
*/
evmc_get_capabilities_fn get_capabilities;
/**
* Optional pointer to function setting the EVM instruction tracer.
*
@ -857,7 +908,7 @@ struct evmc_instance
*
* @return EVM instance or NULL indicating instance creation failure.
*/
struct evmc_instance* evmc_create_examplevm(void);
struct evmc_instance* evmc_create_example_vm(void);
#endif
#if __cplusplus

View file

@ -10,6 +10,8 @@
* 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
* @{
*/
@ -41,6 +43,17 @@ static inline const char* evmc_vm_version(struct evmc_instance* instance)
return instance->version;
}
/**
* Checks if the VM instance has the given capability.
*
* @see evmc_get_capabilities_fn
*/
static inline bool evmc_vm_has_capability(struct evmc_instance* vm,
enum evmc_capabilities capability)
{
return (vm->get_capabilities(vm) & (evmc_capabilities_flagset)capability) != 0;
}
/**
* Destroys the VM instance.
*
@ -56,13 +69,13 @@ static inline void evmc_destroy(struct evmc_instance* instance)
*
* @see evmc_set_option_fn
*/
static inline int evmc_set_option(struct evmc_instance* instance,
char const* name,
char const* value)
static inline enum evmc_set_option_result evmc_set_option(struct evmc_instance* instance,
char const* name,
char const* value)
{
if (instance->set_option)
return instance->set_option(instance, name, value);
return 0;
return EVMC_SET_OPTION_INVALID_NAME;
}
/**

View file

@ -7,7 +7,20 @@
#include <stdlib.h>
const struct evmc_context_fn_table evmc_go_fn_table = {
void evmc_go_free_result_output(const struct evmc_result* result)
{
free((void*)result->output_data);
}
/* Go does not support exporting functions with parameters with const modifiers,
* so we have to cast function pointers to the function types defined in EVMC.
* This disables any type checking of exported Go functions. To mitigate this
* problem the go_exported_functions_type_checks() function simulates usage
* of Go exported functions with expected types to check them during compilation.
*/
const struct evmc_host_interface evmc_go_host = {
(evmc_account_exists_fn)accountExists,
(evmc_get_storage_fn)getStorage,
(evmc_set_storage_fn)setStorage,
@ -22,7 +35,74 @@ const struct evmc_context_fn_table evmc_go_fn_table = {
(evmc_emit_log_fn)emitLog,
};
void evmc_go_free_result_output(const struct evmc_result* result)
#pragma GCC diagnostic error "-Wconversion"
static inline void go_exported_functions_type_checks()
{
free((void*)result->output_data);
struct evmc_context* context = NULL;
evmc_address* address = NULL;
evmc_bytes32 bytes32;
uint8_t* data = NULL;
size_t size = 0;
int64_t number = 0;
struct evmc_message* message = NULL;
evmc_uint256be uint256be;
(void)uint256be;
struct evmc_tx_context tx_context;
(void)tx_context;
struct evmc_result result;
(void)result;
enum evmc_storage_status storage_status;
(void)storage_status;
bool bool_flag;
(void)bool_flag;
evmc_account_exists_fn account_exists_fn = NULL;
bool_flag = account_exists_fn(context, address);
bool_flag = accountExists(context, address);
evmc_get_storage_fn get_storage_fn = NULL;
bytes32 = get_storage_fn(context, address, &bytes32);
bytes32 = getStorage(context, address, &bytes32);
evmc_set_storage_fn set_storage_fn = NULL;
storage_status = set_storage_fn(context, address, &bytes32, &bytes32);
storage_status = setStorage(context, address, &bytes32, &bytes32);
evmc_get_balance_fn get_balance_fn = NULL;
uint256be = get_balance_fn(context, address);
uint256be = getBalance(context, address);
evmc_get_code_size_fn get_code_size_fn = NULL;
size = get_code_size_fn(context, address);
size = getCodeSize(context, address);
evmc_get_code_hash_fn get_code_hash_fn = NULL;
bytes32 = get_code_hash_fn(context, address);
bytes32 = getCodeHash(context, address);
evmc_copy_code_fn copy_code_fn = NULL;
size = copy_code_fn(context, address, size, data, size);
size = copyCode(context, address, size, data, size);
evmc_selfdestruct_fn selfdestruct_fn = NULL;
selfdestruct_fn(context, address, address);
selfdestruct(context, address, address);
evmc_call_fn call_fn = NULL;
result = call_fn(context, message);
result = call(context, message);
evmc_get_tx_context_fn get_tx_context_fn = NULL;
tx_context = get_tx_context_fn(context);
tx_context = getTxContext(context);
evmc_get_block_hash_fn get_block_hash_fn = NULL;
bytes32 = get_block_hash_fn(context, number);
bytes32 = getBlockHash(context, number);
evmc_emit_log_fn emit_log_fn = NULL;
emit_log_fn(context, address, data, size, &bytes32, size);
emitLog(context, address, data, size, &bytes32, size);
}

View file

@ -39,13 +39,14 @@ const (
type StorageStatus int
const (
StorageUnchanged StorageStatus = C.EVMC_STORAGE_UNCHANGED
StorageModified StorageStatus = C.EVMC_STORAGE_MODIFIED
StorageAdded StorageStatus = C.EVMC_STORAGE_ADDED
StorageDeleted StorageStatus = C.EVMC_STORAGE_DELETED
StorageUnchanged StorageStatus = C.EVMC_STORAGE_UNCHANGED
StorageModified StorageStatus = C.EVMC_STORAGE_MODIFIED
StorageModifiedAgain StorageStatus = C.EVMC_STORAGE_MODIFIED_AGAIN
StorageAdded StorageStatus = C.EVMC_STORAGE_ADDED
StorageDeleted StorageStatus = C.EVMC_STORAGE_DELETED
)
func goAddress(in C.struct_evmc_address) common.Address {
func goAddress(in C.evmc_address) common.Address {
out := common.Address{}
for i := 0; i < len(out); i++ {
out[i] = byte(in.bytes[i])
@ -53,7 +54,7 @@ func goAddress(in C.struct_evmc_address) common.Address {
return out
}
func goHash(in C.struct_evmc_uint256be) common.Hash {
func goHash(in C.evmc_bytes32) common.Hash {
out := common.Hash{}
for i := 0; i < len(out); i++ {
out[i] = byte(in.bytes[i])
@ -87,56 +88,49 @@ type HostContext interface {
}
//export accountExists
func accountExists(pCtx unsafe.Pointer, pAddr *C.struct_evmc_address) C.int {
func accountExists(pCtx unsafe.Pointer, pAddr *C.evmc_address) C.bool {
idx := int((*C.struct_extended_context)(pCtx).index)
ctx := getHostContext(idx)
exists := ctx.AccountExists(goAddress(*pAddr))
r := C.int(0)
if exists {
r = 1
}
return r
return C.bool(ctx.AccountExists(goAddress(*pAddr)))
}
//export getStorage
func getStorage(pResult *C.struct_evmc_uint256be, pCtx unsafe.Pointer, pAddr *C.struct_evmc_address, pKey *C.struct_evmc_uint256be) {
func getStorage(pCtx unsafe.Pointer, pAddr *C.struct_evmc_address, pKey *C.evmc_bytes32) C.evmc_bytes32 {
idx := int((*C.struct_extended_context)(pCtx).index)
ctx := getHostContext(idx)
value := ctx.GetStorage(goAddress(*pAddr), goHash(*pKey))
*pResult = evmcUint256be(value)
return evmcBytes32(ctx.GetStorage(goAddress(*pAddr), goHash(*pKey)))
}
//export setStorage
func setStorage(pCtx unsafe.Pointer, pAddr *C.struct_evmc_address, pKey *C.struct_evmc_uint256be, pVal *C.struct_evmc_uint256be) C.enum_evmc_storage_status {
func setStorage(pCtx unsafe.Pointer, pAddr *C.evmc_address, pKey *C.evmc_bytes32, pVal *C.evmc_bytes32) C.enum_evmc_storage_status {
idx := int((*C.struct_extended_context)(pCtx).index)
ctx := getHostContext(idx)
return C.enum_evmc_storage_status(ctx.SetStorage(goAddress(*pAddr), goHash(*pKey), goHash(*pVal)))
}
//export getBalance
func getBalance(pResult *C.struct_evmc_uint256be, pCtx unsafe.Pointer, pAddr *C.struct_evmc_address) {
func getBalance(pCtx unsafe.Pointer, pAddr *C.evmc_address) C.evmc_uint256be {
idx := int((*C.struct_extended_context)(pCtx).index)
ctx := getHostContext(idx)
balance := ctx.GetBalance(goAddress(*pAddr))
*pResult = evmcUint256be(balance)
return evmcBytes32(ctx.GetBalance(goAddress(*pAddr)))
}
//export getCodeSize
func getCodeSize(pCtx unsafe.Pointer, pAddr *C.struct_evmc_address) C.size_t {
func getCodeSize(pCtx unsafe.Pointer, pAddr *C.evmc_address) C.size_t {
idx := int((*C.struct_extended_context)(pCtx).index)
ctx := getHostContext(idx)
return C.size_t(ctx.GetCodeSize(goAddress(*pAddr)))
}
//export getCodeHash
func getCodeHash(pResult *C.struct_evmc_uint256be, pCtx unsafe.Pointer, pAddr *C.struct_evmc_address) {
func getCodeHash(pCtx unsafe.Pointer, pAddr *C.evmc_address) C.evmc_bytes32 {
idx := int((*C.struct_extended_context)(pCtx).index)
ctx := getHostContext(idx)
*pResult = evmcUint256be(ctx.GetCodeHash(goAddress(*pAddr)))
return evmcBytes32(ctx.GetCodeHash(goAddress(*pAddr)))
}
//export copyCode
func copyCode(pCtx unsafe.Pointer, pAddr *C.struct_evmc_address, offset C.size_t, p *C.uint8_t, size C.size_t) C.size_t {
func copyCode(pCtx unsafe.Pointer, pAddr *C.evmc_address, offset C.size_t, p *C.uint8_t, size C.size_t) C.size_t {
idx := int((*C.struct_extended_context)(pCtx).index)
ctx := getHostContext(idx)
code := ctx.GetCode(goAddress(*pAddr))
@ -157,40 +151,39 @@ func copyCode(pCtx unsafe.Pointer, pAddr *C.struct_evmc_address, offset C.size_t
}
//export selfdestruct
func selfdestruct(pCtx unsafe.Pointer, pAddr *C.struct_evmc_address, pBeneficiary *C.struct_evmc_address) {
func selfdestruct(pCtx unsafe.Pointer, pAddr *C.evmc_address, pBeneficiary *C.evmc_address) {
idx := int((*C.struct_extended_context)(pCtx).index)
ctx := getHostContext(idx)
ctx.Selfdestruct(goAddress(*pAddr), goAddress(*pBeneficiary))
}
//export getTxContext
func getTxContext(pResult unsafe.Pointer, pCtx unsafe.Pointer) {
func getTxContext(pCtx unsafe.Pointer) C.struct_evmc_tx_context {
idx := int((*C.struct_extended_context)(pCtx).index)
ctx := getHostContext(idx)
gasPrice, origin, coinbase, number, timestamp, gasLimit, difficulty := ctx.GetTxContext()
*(*C.struct_evmc_tx_context)(pResult) = C.struct_evmc_tx_context{
evmcUint256be(gasPrice),
return C.struct_evmc_tx_context{
evmcBytes32(gasPrice),
evmcAddress(origin),
evmcAddress(coinbase),
C.int64_t(number),
C.int64_t(timestamp),
C.int64_t(gasLimit),
evmcUint256be(difficulty),
evmcBytes32(difficulty),
}
}
//export getBlockHash
func getBlockHash(pResult *C.struct_evmc_uint256be, pCtx unsafe.Pointer, number int64) {
func getBlockHash(pCtx unsafe.Pointer, number int64) C.evmc_bytes32 {
idx := int((*C.struct_extended_context)(pCtx).index)
ctx := getHostContext(idx)
*pResult = evmcUint256be(ctx.GetBlockHash(number))
return evmcBytes32(ctx.GetBlockHash(number))
}
//export emitLog
func emitLog(pCtx unsafe.Pointer, pAddr *C.struct_evmc_address, pData unsafe.Pointer, dataSize C.size_t, pTopics unsafe.Pointer, topicsCount C.size_t) {
func emitLog(pCtx unsafe.Pointer, pAddr *C.evmc_address, pData unsafe.Pointer, dataSize C.size_t, pTopics unsafe.Pointer, topicsCount C.size_t) {
idx := int((*C.struct_extended_context)(pCtx).index)
ctx := getHostContext(idx)
@ -208,7 +201,7 @@ func emitLog(pCtx unsafe.Pointer, pAddr *C.struct_evmc_address, pData unsafe.Poi
}
//export call
func call(pResult *C.struct_evmc_result, pCtx unsafe.Pointer, msg *C.struct_evmc_message) {
func call(pCtx unsafe.Pointer, msg *C.struct_evmc_message) C.struct_evmc_result {
idx := int((*C.struct_extended_context)(pCtx).index)
ctx := getHostContext(idx)
@ -234,5 +227,5 @@ func call(pResult *C.struct_evmc_result, pCtx unsafe.Pointer, msg *C.struct_evmc
result.release = (C.evmc_release_result_fn)(C.evmc_go_free_result_output)
}
*pResult = result
return result
}

View file

@ -16,7 +16,7 @@
#define DLL_HANDLE HMODULE
#define DLL_OPEN(filename) LoadLibrary(filename)
#define DLL_CLOSE(handle) FreeLibrary(handle)
#define DLL_GET_CREATE_FN(handle, name) (evmc_create_fn) GetProcAddress(handle, name)
#define DLL_GET_CREATE_FN(handle, name) (evmc_create_fn)(uintptr_t) GetProcAddress(handle, name)
#define HAVE_STRCPY_S 1
#else
#include <dlfcn.h>
@ -69,8 +69,8 @@ evmc_create_fn evmc_load(const char* filename, enum evmc_loader_error_code* erro
// Create name buffer with the prefix.
const char prefix[] = "evmc_create_";
const size_t prefix_length = strlen(prefix);
char name[sizeof(prefix) + PATH_MAX_LENGTH];
strcpy_s(name, sizeof(name), prefix);
char prefixed_name[sizeof(prefix) + PATH_MAX_LENGTH];
strcpy_s(prefixed_name, sizeof(prefixed_name), prefix);
// Find filename in the path.
const char* sep_pos = strrchr(filename, '/');
@ -87,30 +87,28 @@ evmc_create_fn evmc_load(const char* filename, enum evmc_loader_error_code* erro
if (strncmp(name_pos, lib_prefix, lib_prefix_length) == 0)
name_pos += lib_prefix_length;
strcpy_s(name + prefix_length, PATH_MAX_LENGTH, name_pos);
char* base_name = prefixed_name + prefix_length;
strcpy_s(base_name, PATH_MAX_LENGTH, name_pos);
// Trim the file extension.
char* ext_pos = strrchr(name, '.');
char* ext_pos = strrchr(prefixed_name, '.');
if (ext_pos)
*ext_pos = 0;
// Replace all "-" with "_".
char* dash_pos = name;
char* dash_pos = base_name;
while ((dash_pos = strchr(dash_pos, '-')) != NULL)
*dash_pos++ = '_';
// Search for the "full name" based function name.
create_fn = DLL_GET_CREATE_FN(handle, name);
if (!create_fn)
// Search for the built function name.
while ((create_fn = DLL_GET_CREATE_FN(handle, prefixed_name)) == NULL)
{
// Try the "short name" based function name.
const char* short_name_pos = strrchr(name, '_');
if (short_name_pos)
{
short_name_pos += 1;
memmove(name + prefix_length, short_name_pos, strlen(short_name_pos) + 1);
create_fn = DLL_GET_CREATE_FN(handle, name);
}
// Shorten the base name by skipping the `word_` segment.
const char* shorter_name_pos = strchr(base_name, '_');
if (!shorter_name_pos)
break;
memmove(base_name, shorter_name_pos + 1, strlen(shorter_name_pos) + 1);
}
if (!create_fn)

View file

@ -60,15 +60,16 @@ enum evmc_loader_error_code
* "libexample-interpreter.so",
* - the "lib" prefix and file extension are stripped from the name:
* "example-interpreter"
* - all "-" are replaced with "_" to construct _full name_:
* - all "-" are replaced with "_" to construct _base name_:
* "example_interpreter",
* - the _full name_ is split by "_" char and the last item is taken to form the _short name_:
* "interpreter",
* - the name "evmc_create_" + _full name_ is checked in the library:
* - the function name "evmc_create_" + _base name_ is searched in the library:
* "evmc_create_example_interpreter",
* - then, the name "evmc_create_" + _short name_ is checked in the library:
* "evmc_create_interpreter".
* - lastly, the name "evmc_create" is checked in the library
* - if function not found, the _base name_ is shorten by skipping the first word separated by "_":
* "interpreter",
* - then, the function of the shorter name "evmc_create_" + _base name_ is searched in the library:
* "evmc_create_interpreter",
* - the name shortening continues until a function is found or the name cannot be shorten more,
* - lastly, when no function found, the function name "evmc_create" is searched in the library.
*
* If the create function is found in the library, the pointer to the function is returned.
* Otherwise, the ::EVMC_LOADER_SYMBOL_NOT_FOUND error code is signaled and NULL is returned.

10
vendor/vendor.json vendored
View file

@ -105,12 +105,12 @@
"revisionTime": "2018-01-22T22:25:45Z"
},
{
"checksumSHA1": "gvcZHEaRD0J5Y6QrFTo0GrR2TkE=",
"checksumSHA1": "HxlAMyHDmEEDsOIlULQD2HPoN40=",
"path": "github.com/ethereum/evmc/bindings/go/evmc",
"revision": "224080ef8c8d99f5cfe59067a3bd995be23349bf",
"revisionTime": "2018-08-28T21:11:56Z",
"version": "=v5.2.0",
"versionExact": "v5.2.0"
"revision": "3b3aab4f7720f80ba0b989da88b60907c2a8f733",
"revisionTime": "2018-10-18T15:29:18Z",
"version": "v6",
"versionExact": "v6"
},
{
"checksumSHA1": "7oFpbmDfGobwKsFLIf6wMUvVoKw=",