Update EVMC to 7

This commit is contained in:
Alex Beregszaszi 2019-11-07 12:13:29 +00:00
parent cf13339ad8
commit 92745c7bfc
5 changed files with 308 additions and 360 deletions

View File

@ -44,7 +44,7 @@ enum
* *
* @see @ref versioning * @see @ref versioning
*/ */
EVMC_ABI_VERSION = 6 EVMC_ABI_VERSION = 7
}; };
@ -153,9 +153,15 @@ struct evmc_tx_context
int64_t block_timestamp; /**< The block timestamp. */ int64_t block_timestamp; /**< The block timestamp. */
int64_t block_gas_limit; /**< The block gas limit. */ int64_t block_gas_limit; /**< The block gas limit. */
evmc_uint256be block_difficulty; /**< The block difficulty. */ evmc_uint256be block_difficulty; /**< The block difficulty. */
evmc_uint256be chain_id; /**< The blockchain's ChainID. */
}; };
struct evmc_context; /**
* @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. * Get transaction context callback function.
@ -166,7 +172,7 @@ struct evmc_context;
* @param context The pointer to the Host execution context. * @param context The pointer to the Host execution context.
* @return The transaction context. * @return The transaction context.
*/ */
typedef struct evmc_tx_context (*evmc_get_tx_context_fn)(struct evmc_context* context); typedef struct evmc_tx_context (*evmc_get_tx_context_fn)(struct evmc_host_context* context);
/** /**
* Get block hash callback function. * Get block hash callback function.
@ -180,7 +186,7 @@ typedef struct evmc_tx_context (*evmc_get_tx_context_fn)(struct evmc_context* co
* @return The block hash or null bytes * @return The block hash or null bytes
* if the information about the block is not available. * if the information about the block is not available.
*/ */
typedef evmc_bytes32 (*evmc_get_block_hash_fn)(struct evmc_context* context, int64_t number); typedef evmc_bytes32 (*evmc_get_block_hash_fn)(struct evmc_host_context* context, int64_t number);
/** /**
* The execution status code. * The execution status code.
@ -420,7 +426,8 @@ struct evmc_result
* @param address The address of the account the query is about. * @param address The address of the account the query is about.
* @return true if exists, false otherwise. * @return true if exists, false otherwise.
*/ */
typedef bool (*evmc_account_exists_fn)(struct evmc_context* context, const evmc_address* address); typedef bool (*evmc_account_exists_fn)(struct evmc_host_context* context,
const evmc_address* address);
/** /**
* Get storage callback function. * Get storage callback function.
@ -433,7 +440,7 @@ typedef bool (*evmc_account_exists_fn)(struct evmc_context* context, const evmc_
* @return The storage value at the given storage key or null bytes * @return The storage value at the given storage key or null bytes
* if the account does not exist. * if the account does not exist.
*/ */
typedef evmc_bytes32 (*evmc_get_storage_fn)(struct evmc_context* context, typedef evmc_bytes32 (*evmc_get_storage_fn)(struct evmc_host_context* context,
const evmc_address* address, const evmc_address* address,
const evmc_bytes32* key); const evmc_bytes32* key);
@ -492,7 +499,7 @@ enum evmc_storage_status
* @param value The value to be stored. * @param value The value to be stored.
* @return The effect on the storage item. * @return The effect on the storage item.
*/ */
typedef enum evmc_storage_status (*evmc_set_storage_fn)(struct evmc_context* context, typedef enum evmc_storage_status (*evmc_set_storage_fn)(struct evmc_host_context* context,
const evmc_address* address, const evmc_address* address,
const evmc_bytes32* key, const evmc_bytes32* key,
const evmc_bytes32* value); const evmc_bytes32* value);
@ -506,7 +513,7 @@ typedef enum evmc_storage_status (*evmc_set_storage_fn)(struct evmc_context* con
* @param address The address of the account. * @param address The address of the account.
* @return The balance of the given account or 0 if the account does not exist. * @return The balance of the given account or 0 if the account does not exist.
*/ */
typedef evmc_uint256be (*evmc_get_balance_fn)(struct evmc_context* context, typedef evmc_uint256be (*evmc_get_balance_fn)(struct evmc_host_context* context,
const evmc_address* address); const evmc_address* address);
/** /**
@ -519,7 +526,8 @@ typedef evmc_uint256be (*evmc_get_balance_fn)(struct evmc_context* context,
* @param address The address of the account. * @param address The address of the account.
* @return The size of the code in the account or 0 if the account does not exist. * @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 evmc_address* address); typedef size_t (*evmc_get_code_size_fn)(struct evmc_host_context* context,
const evmc_address* address);
/** /**
* Get code size callback function. * Get code size callback function.
@ -532,28 +540,27 @@ typedef size_t (*evmc_get_code_size_fn)(struct evmc_context* context, const evmc
* @param address The address of the account. * @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. * @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_context* context, typedef evmc_bytes32 (*evmc_get_code_hash_fn)(struct evmc_host_context* context,
const evmc_address* address); const evmc_address* address);
/** /**
* Copy code callback function. * Copy code callback function.
* *
* This callback function is used by an EVM to request a copy of the code * 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. * of the given account to the memory buffer provided by the EVM.
* The Client MUST copy the requested code, starting with the given offset, * 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 * to the provided memory buffer up to the size of the buffer or the size of
* the code, whichever is smaller. * the code, whichever is smaller.
* *
* @param context The pointer to the Client execution context. * @param context The pointer to the Host execution context. See ::evmc_host_context.
* @see ::evmc_context. * @param address The address of the account.
* @param address The address of the account. * @param code_offset The offset of the code to copy.
* @param code_offset The offset of the code to copy. * @param buffer_data The pointer to the memory buffer allocated by the EVM
* @param buffer_data The pointer to the memory buffer allocated by the EVM * to store a copy of the requested code.
* to store a copy of the requested code. * @param buffer_size The size of the memory buffer.
* @param buffer_size The size of the memory buffer. * @return The number of bytes copied to the buffer by the Client.
* @return The number of bytes copied to the buffer by the Client.
*/ */
typedef size_t (*evmc_copy_code_fn)(struct evmc_context* context, typedef size_t (*evmc_copy_code_fn)(struct evmc_host_context* context,
const evmc_address* address, const evmc_address* address,
size_t code_offset, size_t code_offset,
uint8_t* buffer_data, uint8_t* buffer_data,
@ -562,34 +569,31 @@ typedef size_t (*evmc_copy_code_fn)(struct evmc_context* context,
/** /**
* Selfdestruct callback function. * Selfdestruct callback function.
* *
* This callback function is used by an EVM to SELFDESTRUCT given contract. * 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. * The execution of the contract will not be stopped, that is up to the EVM.
* *
* @param context The pointer to the Host execution context. * @param context The pointer to the Host execution context. See ::evmc_host_context.
* @see ::evmc_context. * @param address The address of the contract to be selfdestructed.
* @param address The address of the contract to be selfdestructed. * @param beneficiary The address where the remaining ETH is going to be transferred.
* @param beneficiary The address where the remaining ETH is going to be
* transferred.
*/ */
typedef void (*evmc_selfdestruct_fn)(struct evmc_context* context, typedef void (*evmc_selfdestruct_fn)(struct evmc_host_context* context,
const evmc_address* address, const evmc_address* address,
const evmc_address* beneficiary); const evmc_address* beneficiary);
/** /**
* Log callback function. * Log callback function.
* *
* This callback function is used by an EVM to inform about a LOG that happened * This callback function is used by an EVM to inform about a LOG that happened
* during an EVM bytecode execution. * during an EVM bytecode execution.
* @param context The pointer to the Host execution context. *
* @see ::evmc_context. * @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 address The address of the contract that generated the log.
* @param data The pointer to unindexed data attached to the log. * @param data The pointer to unindexed data attached to the log.
* @param data_size The length of the data. * @param data_size The length of the data.
* @param topics The pointer to the array of topics attached to the log. * @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 * @param topics_count The number of the topics. Valid values are between 0 and 4 inclusively.
* 0 and 4 inclusively.
*/ */
typedef void (*evmc_emit_log_fn)(struct evmc_context* context, typedef void (*evmc_emit_log_fn)(struct evmc_host_context* context,
const evmc_address* address, const evmc_address* address,
const uint8_t* data, const uint8_t* data,
size_t data_size, size_t data_size,
@ -599,11 +603,11 @@ typedef void (*evmc_emit_log_fn)(struct evmc_context* context,
/** /**
* Pointer to the callback function supporting EVM calls. * Pointer to the callback function supporting EVM calls.
* *
* @param context The pointer to the Host execution context. * @param context The pointer to the Host execution context.
* @param msg The call parameters. * @param msg The call parameters.
* @return The result of the call. * @return The result of the call.
*/ */
typedef struct evmc_result (*evmc_call_fn)(struct evmc_context* context, typedef struct evmc_result (*evmc_call_fn)(struct evmc_host_context* context,
const struct evmc_message* msg); const struct evmc_message* msg);
/** /**
@ -654,31 +658,15 @@ struct evmc_host_interface
}; };
/**
* Execution context managed by the Host.
*
* The Host MUST pass the pointer to the execution context to ::evmc_execute_fn.
* The VM MUST pass the same pointer back to the Host in every callback function.
* The context MUST contain at least the function table defining
* the context callback interface.
* Optionally, the Host MAY include in the context additional data.
*/
struct evmc_context
{
/** The Host interface. */
const struct evmc_host_interface* host;
};
/* Forward declaration. */ /* Forward declaration. */
struct evmc_instance; struct evmc_vm;
/** /**
* Destroys the EVM instance. * Destroys the VM instance.
* *
* @param evm The EVM instance to be destroyed. * @param vm The VM instance to be destroyed.
*/ */
typedef void (*evmc_destroy_fn)(struct evmc_instance* evm); typedef void (*evmc_destroy_fn)(struct evmc_vm* vm);
/** /**
* Possible outcomes of evmc_set_option. * Possible outcomes of evmc_set_option.
@ -691,19 +679,19 @@ enum evmc_set_option_result
}; };
/** /**
* Configures the EVM instance. * Configures the VM instance.
* *
* Allows modifying options of the EVM instance. * Allows modifying options of the VM instance.
* Options: * Options:
* - code cache behavior: on, off, read-only, ... * - code cache behavior: on, off, read-only, ...
* - optimizations, * - optimizations,
* *
* @param evm The EVM instance to be configured. * @param vm The VM instance to be configured.
* @param name The option name. NULL-terminated string. Cannot be NULL. * @param name The option name. NULL-terminated string. Cannot be NULL.
* @param value The new option value. NULL-terminated string. Cannot be NULL. * @param value The new option value. NULL-terminated string. Cannot be NULL.
* @return The outcome of the operation. * @return The outcome of the operation.
*/ */
typedef enum evmc_set_option_result (*evmc_set_option_fn)(struct evmc_instance* evm, typedef enum evmc_set_option_result (*evmc_set_option_fn)(struct evmc_vm* vm,
char const* name, char const* name,
char const* value); char const* value);
@ -762,6 +750,7 @@ enum evmc_revision
* The Petersburg revision. * The Petersburg revision.
* *
* Other names: Constantinople2, ConstantinopleFix. * Other names: Constantinople2, ConstantinopleFix.
*
* https://eips.ethereum.org/EIPS/eip-1716 * https://eips.ethereum.org/EIPS/eip-1716
*/ */
EVMC_PETERSBURG = 6, EVMC_PETERSBURG = 6,
@ -773,23 +762,15 @@ enum evmc_revision
*/ */
EVMC_ISTANBUL = 7, EVMC_ISTANBUL = 7,
/**
* The Berlin revision.
*
* The spec draft: https://eips.ethereum.org/EIPS/eip-2070.
*/
EVMC_BERLIN = 8,
/** The maximum EVM revision supported. */ /** The maximum EVM revision supported. */
EVMC_MAX_REVISION = EVMC_ISTANBUL, EVMC_MAX_REVISION = EVMC_BERLIN
/**
* Reserved for the post-Constantinople upgrade.
*
* @deprecated Replaced with ::EVMC_PETERSBURG.
*/
EVMC_CONSTANTINOPLE2 EVMC_DEPRECATED = EVMC_PETERSBURG,
/**
* The latests EVM revision supported.
*
* @deprecated Replaced with ::EVMC_MAX_REVISION.
*/
EVMC_LATEST_REVISION EVMC_DEPRECATED = EVMC_MAX_REVISION
}; };
@ -798,19 +779,22 @@ enum evmc_revision
* *
* This function MAY be invoked multiple times for a single VM instance. * This function MAY be invoked multiple times for a single VM instance.
* *
* @param instance The VM instance. This argument MUST NOT be NULL. * @param vm The VM instance. This argument MUST NOT be NULL.
* @param context The pointer to the Host execution context to be passed * @param host The Host interface. This argument MUST NOT be NULL unless
* to the Host interface methods (::evmc_host_interface). * the @p vm has the ::EVMC_CAPABILITY_PRECOMPILES capability.
* This argument MUST NOT be NULL unless * @param context The opaque pointer to the Host execution context.
* the @p instance has the ::EVMC_CAPABILITY_PRECOMPILES capability. * 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 rev The requested EVM specification revision.
* @param msg The call parameters. See ::evmc_message. This argument MUST NOT be NULL. * @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 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. * @param code_size The length of the code. If @p code is NULL this argument MUST be 0.
* @return The execution result. * @return The execution result.
*/ */
typedef struct evmc_result (*evmc_execute_fn)(struct evmc_instance* instance, typedef struct evmc_result (*evmc_execute_fn)(struct evmc_vm* vm,
struct evmc_context* context, const struct evmc_host_interface* host,
struct evmc_host_context* context,
enum evmc_revision rev, enum evmc_revision rev,
const struct evmc_message* msg, const struct evmc_message* msg,
uint8_t const* code, uint8_t const* code,
@ -855,98 +839,20 @@ typedef uint32_t evmc_capabilities_flagset;
* Return the supported capabilities of the VM instance. * Return the supported capabilities of the VM instance.
* *
* This function MAY be invoked multiple times for a single 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. * and its value MAY be influenced by calls to evmc_vm::set_option.
* *
* @param instance The EVM instance. * @param vm The VM instance.
* @return The supported capabilities of the VM. @see evmc_capabilities. * @return The supported capabilities of the VM. @see evmc_capabilities.
*/ */
typedef evmc_capabilities_flagset (*evmc_get_capabilities_fn)(struct evmc_instance* instance); typedef evmc_capabilities_flagset (*evmc_get_capabilities_fn)(struct evmc_vm* vm);
/**
* The opaque type representing a Client-side tracer object.
*
* @deprecated Deprecated since EVMC 6.3, see evmc_instance::set_tracer().
*/
struct evmc_tracer_context;
/**
* The callback to trace instructions execution in an EVM.
*
* This function informs the Client what instruction has been executed in the EVM implementation
* and what are the results of executing this particular instruction.
* The message level information (like call depth, destination address, etc.) are not provided here.
* This piece of information can be acquired by inspecting messages being sent to the EVM in
* ::evmc_execute_fn and the results of the messages execution.
*
* @deprecated Deprecated since EVMC 6.3, see evmc_instance::set_tracer().
*
* @param context The pointer to the Client-side tracing context. This allows to
* implement the tracer in OOP manner.
* @param code_offset The current instruction position in the code.
* @param status_code The status code of the instruction execution.
* @param gas_left The amount of the gas left after the instruction execution.
* @param stack_num_items The current EVM stack height after the instruction execution.
* @param pushed_stack_item The top EVM stack item pushed as the result of the instruction
* execution. This value is null when the instruction does not push
* anything to the stack.
* @param memory_size The size of the EVM memory after the instruction execution.
* @param changed_memory_offset The offset in number of bytes of the beginning of the memory area
* modified as the result of the instruction execution.
* The Client MAY use this information together with
* @p changed_memory_size and @p changed_memory to incrementally
* update the copy of the full VM's memory.
* @param changed_memory_size The size of the memory area modified as the result of
* the instruction execution.
* @param changed_memory The pointer to the memory area modified as the result of
* the instruction execution.
* The Client MAY access the pointed memory area
* (limited by the @p changed_memory_size) only during the current
* execution of the evmc_trace_callback().
* The pointer MUST NOT be stored by the Client.
* The Client MUST NOT assume that
* `changed_memory - changed_memory_offset` is a valid base pointer
* of the VM memory.
*/
typedef void (*evmc_trace_callback)(struct evmc_tracer_context* context,
size_t code_offset,
enum evmc_status_code status_code,
int64_t gas_left,
size_t stack_num_items,
const evmc_uint256be* pushed_stack_item,
size_t memory_size,
size_t changed_memory_offset,
size_t changed_memory_size,
const uint8_t* changed_memory);
/**
* Sets the EVM instruction tracer.
*
* When the tracer is set in the EVM instance, the EVM SHOULD call back the tracer with information
* about instructions execution in the EVM.
* @see ::evmc_trace_callback.
*
* This will overwrite the previous settings (the callback and the context).
*
* @deprecated Deprecated since EVMC 6.3, see evmc_instance::set_tracer().
*
* @param instance The EVM instance.
* @param callback The tracer callback function. This argument MAY be NULL to disable previously
* set tracer.
* @param context The Client-side tracer context. This argument MAY be NULL in case the tracer
* does not require any context. This argument MUST be NULL if the callback
* argument is NULL.
*/
typedef void (*evmc_set_tracer_fn)(struct evmc_instance* instance,
evmc_trace_callback callback,
struct evmc_tracer_context* context);
/** /**
* The EVM instance. * The VM instance.
* *
* Defines the base struct of the VM implementation. * Defines the base struct of the VM implementation.
*/ */
struct evmc_instance struct evmc_vm
{ {
/** /**
* EVMC ABI version implemented by the VM instance. * EVMC ABI version implemented by the VM instance.
@ -973,14 +879,14 @@ struct evmc_instance
const char* version; const char* version;
/** /**
* Pointer to function destroying the EVM instance. * Pointer to function destroying the VM instance.
* *
* This is a mandatory method and MUST NOT be set to NULL. * This is a mandatory method and MUST NOT be set to NULL.
*/ */
evmc_destroy_fn destroy; evmc_destroy_fn destroy;
/** /**
* Pointer to function executing a code by the EVM instance. * Pointer to function executing a code by the VM instance.
* *
* This is a mandatory method and MUST NOT be set to NULL. * This is a mandatory method and MUST NOT be set to NULL.
*/ */
@ -998,17 +904,6 @@ struct evmc_instance
*/ */
evmc_get_capabilities_fn get_capabilities; evmc_get_capabilities_fn get_capabilities;
/**
* Optional pointer to function setting the EVM instruction tracer.
*
* If the EVM does not support this feature the pointer can be NULL.
*
* @deprecated
* Since EVMC 6.3, the tracing API has been deprecated as there have been some
* design flaws discovered. New API is expected to be introduced in future.
*/
evmc_set_tracer_fn set_tracer;
/** /**
* Optional pointer to function modifying VM's options. * Optional pointer to function modifying VM's options.
* *
@ -1033,9 +928,9 @@ struct evmc_instance
* For example, the shared library with the "beta-interpreter" implementation may be named * For example, the shared library with the "beta-interpreter" implementation may be named
* `libbeta-interpreter.so`. * `libbeta-interpreter.so`.
* *
* @return EVM instance or NULL indicating instance creation failure. * @return The VM instance or NULL indicating instance creation failure.
*/ */
struct evmc_instance* evmc_create_example_vm(void); struct evmc_vm* evmc_create_example_vm(void);
#endif #endif
#if __cplusplus #if __cplusplus

View File

@ -334,49 +334,46 @@ public:
} }
}; };
/// @copybrief evmc_instance class Host;
/// @copybrief evmc_vm
/// ///
/// This is a RAII wrapper for evmc_instance and objects of this type /// This is a RAII wrapper for evmc_vm and objects of this type
/// automatically destroys the VM instance. /// automatically destroys the VM instance.
class vm class VM
{ {
public: public:
vm() noexcept = default; VM() noexcept = default;
/// Converting constructor from evmc_instance. /// Converting constructor from evmc_vm.
explicit vm(evmc_instance* instance) noexcept : m_instance{instance} {} explicit VM(evmc_vm* vm) noexcept : m_instance{vm} {}
/// Destructor responsible for automatically destroying the VM instance. /// Destructor responsible for automatically destroying the VM instance.
~vm() noexcept ~VM() noexcept
{ {
if (m_instance) if (m_instance)
m_instance->destroy(m_instance); m_instance->destroy(m_instance);
} }
vm(const vm&) = delete; VM(const VM&) = delete;
vm& operator=(const vm&) = delete; VM& operator=(const VM&) = delete;
/// Move constructor. /// Move constructor.
vm(vm&& other) noexcept : m_instance{other.m_instance} { other.m_instance = nullptr; } VM(VM&& other) noexcept : m_instance{other.m_instance} { other.m_instance = nullptr; }
/// Move assignment operator. /// Move assignment operator.
vm& operator=(vm&& other) noexcept VM& operator=(VM&& other) noexcept
{ {
this->~vm(); this->~VM();
m_instance = other.m_instance; m_instance = other.m_instance;
other.m_instance = nullptr; other.m_instance = nullptr;
return *this; return *this;
} }
/// The constructor that captures a VM instance and configures the instance /// The constructor that captures a VM instance and configures the instance
/// with provided list of options. /// with the provided list of options.
vm(evmc_instance* instance, inline VM(evmc_vm* vm,
std::initializer_list<std::pair<const char*, const char*>> options) noexcept std::initializer_list<std::pair<const char*, const char*>> options) noexcept;
: m_instance{instance}
{
for (auto option : options)
set_option(option.first, option.second);
}
/// Checks if contains a valid pointer to the VM instance. /// Checks if contains a valid pointer to the VM instance.
explicit operator bool() const noexcept { return m_instance != nullptr; } explicit operator bool() const noexcept { return m_instance != nullptr; }
@ -384,13 +381,13 @@ public:
/// Checks whenever the VM instance is ABI compatible with the current EVMC API. /// 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; } bool is_abi_compatible() const noexcept { return m_instance->abi_version == EVMC_ABI_VERSION; }
/// @copydoc evmc_instance::name /// @copydoc evmc_vm::name
char const* name() const noexcept { return m_instance->name; } char const* name() const noexcept { return m_instance->name; }
/// @copydoc evmc_instance::version /// @copydoc evmc_vm::version
char const* version() const noexcept { return m_instance->version; } char const* version() const noexcept { return m_instance->version; }
/// @copydoc evmc::instance::get_capabilities /// @copydoc evmc::vm::get_capabilities
evmc_capabilities_flagset get_capabilities() const noexcept evmc_capabilities_flagset get_capabilities() const noexcept
{ {
return m_instance->get_capabilities(m_instance); return m_instance->get_capabilities(m_instance);
@ -403,19 +400,53 @@ public:
} }
/// @copydoc evmc_execute() /// @copydoc evmc_execute()
result execute(evmc_context& ctx, result execute(const evmc_host_interface& host,
evmc_host_context* ctx,
evmc_revision rev, evmc_revision rev,
const evmc_message& msg, const evmc_message& msg,
const uint8_t* code, const uint8_t* code,
size_t code_size) noexcept size_t code_size) noexcept
{ {
return result{m_instance->execute(m_instance, &ctx, rev, &msg, code, code_size)}; 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.
inline result execute(Host& host,
evmc_revision rev,
const evmc_message& msg,
const uint8_t* code,
size_t code_size) noexcept;
/// 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: private:
evmc_instance* m_instance = nullptr; evmc_vm* m_instance = nullptr;
}; };
inline VM::VM(evmc_vm* vm,
std::initializer_list<std::pair<const char*, const char*>> options) noexcept
: m_instance{vm}
{
for (const auto& option : options)
set_option(option.first, option.second);
}
/// The EVMC Host interface /// The EVMC Host interface
class HostInterface class HostInterface
{ {
@ -471,46 +502,52 @@ public:
/// Wrapper around EVMC host context / host interface. /// Wrapper around EVMC host context / host interface.
/// ///
/// To be used by VM implementations as better alternative to using ::evmc_context directly. /// To be used by VM implementations as better alternative to using ::evmc_host_context directly.
class HostContext : public HostInterface class HostContext : public HostInterface
{ {
evmc_context* context = nullptr; const evmc_host_interface* host = nullptr;
evmc_host_context* context = nullptr;
evmc_tx_context tx_context = {}; evmc_tx_context tx_context = {};
public: public:
/// Implicit converting constructor from evmc_context. /// Default constructor for null Host context.
HostContext(evmc_context* ctx) noexcept : context{ctx} {} // NOLINT HostContext() = default;
/// Constructor from the EVMC Host primitives.
HostContext(const evmc_host_interface* interface, evmc_host_context* ctx) noexcept
: host{interface}, context{ctx}
{}
bool account_exists(const address& address) noexcept final bool account_exists(const address& address) noexcept final
{ {
return context->host->account_exists(context, &address); return host->account_exists(context, &address);
} }
bytes32 get_storage(const address& address, const bytes32& key) noexcept final bytes32 get_storage(const address& address, const bytes32& key) noexcept final
{ {
return context->host->get_storage(context, &address, &key); return host->get_storage(context, &address, &key);
} }
evmc_storage_status set_storage(const address& address, evmc_storage_status set_storage(const address& address,
const bytes32& key, const bytes32& key,
const bytes32& value) noexcept final const bytes32& value) noexcept final
{ {
return context->host->set_storage(context, &address, &key, &value); return host->set_storage(context, &address, &key, &value);
} }
uint256be get_balance(const address& address) noexcept final uint256be get_balance(const address& address) noexcept final
{ {
return context->host->get_balance(context, &address); return host->get_balance(context, &address);
} }
size_t get_code_size(const address& address) noexcept final size_t get_code_size(const address& address) noexcept final
{ {
return context->host->get_code_size(context, &address); return host->get_code_size(context, &address);
} }
bytes32 get_code_hash(const address& address) noexcept final bytes32 get_code_hash(const address& address) noexcept final
{ {
return context->host->get_code_hash(context, &address); return host->get_code_hash(context, &address);
} }
size_t copy_code(const address& address, size_t copy_code(const address& address,
@ -518,17 +555,17 @@ public:
uint8_t* buffer_data, uint8_t* buffer_data,
size_t buffer_size) noexcept final size_t buffer_size) noexcept final
{ {
return context->host->copy_code(context, &address, code_offset, buffer_data, buffer_size); return host->copy_code(context, &address, code_offset, buffer_data, buffer_size);
} }
void selfdestruct(const address& addr, const address& beneficiary) noexcept final void selfdestruct(const address& addr, const address& beneficiary) noexcept final
{ {
context->host->selfdestruct(context, &addr, &beneficiary); host->selfdestruct(context, &addr, &beneficiary);
} }
result call(const evmc_message& message) noexcept final result call(const evmc_message& message) noexcept final
{ {
return result{context->host->call(context, &message)}; return result{host->call(context, &message)};
} }
/// @copydoc HostInterface::get_tx_context() /// @copydoc HostInterface::get_tx_context()
@ -540,13 +577,13 @@ public:
evmc_tx_context get_tx_context() noexcept final evmc_tx_context get_tx_context() noexcept final
{ {
if (tx_context.block_timestamp == 0) if (tx_context.block_timestamp == 0)
tx_context = context->host->get_tx_context(context); tx_context = host->get_tx_context(context);
return tx_context; return tx_context;
} }
bytes32 get_block_hash(int64_t number) noexcept final bytes32 get_block_hash(int64_t number) noexcept final
{ {
return context->host->get_block_hash(context, number); return host->get_block_hash(context, number);
} }
void emit_log(const address& addr, void emit_log(const address& addr,
@ -555,7 +592,7 @@ public:
const bytes32 topics[], const bytes32 topics[],
size_t topics_count) noexcept final size_t topics_count) noexcept final
{ {
context->host->emit_log(context, &addr, data, data_size, topics, topics_count); host->emit_log(context, &addr, data, data_size, topics, topics_count);
} }
}; };
@ -563,89 +600,135 @@ public:
/// ///
/// When implementing EVMC Host, you can directly inherit from the evmc::Host class. /// When implementing EVMC Host, you can directly inherit from the evmc::Host class.
/// This way your implementation will be simpler by avoiding manual handling /// This way your implementation will be simpler by avoiding manual handling
/// of the ::evmc_context and the ::evmc_context::host. /// of the ::evmc_host_context and the ::evmc_host_interface.
class Host : public HostInterface, public evmc_context class Host : public HostInterface
{ {
public: public:
inline Host() noexcept; /// 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<evmc_host_context*>(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 <typename DerivedClass = Host>
static DerivedClass* from_context(evmc_host_context* context) noexcept
{
// Get pointer of the Host base class.
auto* h = reinterpret_cast<Host*>(context);
// Additional downcast, only possible if DerivedClass inherits from Host.
return static_cast<DerivedClass*>(h);
}
}; };
inline result VM::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);
}
namespace internal namespace internal
{ {
inline bool account_exists(evmc_context* h, const evmc_address* addr) noexcept inline bool account_exists(evmc_host_context* h, const evmc_address* addr) noexcept
{ {
return static_cast<Host*>(h)->account_exists(*addr); return Host::from_context(h)->account_exists(*addr);
} }
inline evmc_bytes32 get_storage(evmc_context* h,
inline evmc_bytes32 get_storage(evmc_host_context* h,
const evmc_address* addr, const evmc_address* addr,
const evmc_bytes32* key) noexcept const evmc_bytes32* key) noexcept
{ {
return static_cast<Host*>(h)->get_storage(*addr, *key); return Host::from_context(h)->get_storage(*addr, *key);
} }
inline evmc_storage_status set_storage(evmc_context* h,
inline evmc_storage_status set_storage(evmc_host_context* h,
const evmc_address* addr, const evmc_address* addr,
const evmc_bytes32* key, const evmc_bytes32* key,
const evmc_bytes32* value) noexcept const evmc_bytes32* value) noexcept
{ {
return static_cast<Host*>(h)->set_storage(*addr, *key, *value); return Host::from_context(h)->set_storage(*addr, *key, *value);
} }
inline evmc_uint256be get_balance(evmc_context* h, const evmc_address* addr) noexcept
inline evmc_uint256be get_balance(evmc_host_context* h, const evmc_address* addr) noexcept
{ {
return static_cast<Host*>(h)->get_balance(*addr); return Host::from_context(h)->get_balance(*addr);
} }
inline size_t get_code_size(evmc_context* h, const evmc_address* addr) noexcept
inline size_t get_code_size(evmc_host_context* h, const evmc_address* addr) noexcept
{ {
return static_cast<Host*>(h)->get_code_size(*addr); return Host::from_context(h)->get_code_size(*addr);
} }
inline evmc_bytes32 get_code_hash(evmc_context* h, const evmc_address* addr) noexcept
inline evmc_bytes32 get_code_hash(evmc_host_context* h, const evmc_address* addr) noexcept
{ {
return static_cast<Host*>(h)->get_code_hash(*addr); return Host::from_context(h)->get_code_hash(*addr);
} }
inline size_t copy_code(evmc_context* h,
inline size_t copy_code(evmc_host_context* h,
const evmc_address* addr, const evmc_address* addr,
size_t code_offset, size_t code_offset,
uint8_t* buffer_data, uint8_t* buffer_data,
size_t buffer_size) noexcept size_t buffer_size) noexcept
{ {
return static_cast<Host*>(h)->copy_code(*addr, code_offset, buffer_data, buffer_size); return Host::from_context(h)->copy_code(*addr, code_offset, buffer_data, buffer_size);
} }
inline void selfdestruct(evmc_context* h,
inline void selfdestruct(evmc_host_context* h,
const evmc_address* addr, const evmc_address* addr,
const evmc_address* beneficiary) noexcept const evmc_address* beneficiary) noexcept
{ {
static_cast<Host*>(h)->selfdestruct(*addr, *beneficiary); Host::from_context(h)->selfdestruct(*addr, *beneficiary);
} }
inline evmc_result call(evmc_context* h, const evmc_message* msg) noexcept
inline evmc_result call(evmc_host_context* h, const evmc_message* msg) noexcept
{ {
return static_cast<Host*>(h)->call(*msg).release_raw(); return Host::from_context(h)->call(*msg).release_raw();
} }
inline evmc_tx_context get_tx_context(evmc_context* h) noexcept
inline evmc_tx_context get_tx_context(evmc_host_context* h) noexcept
{ {
return static_cast<Host*>(h)->get_tx_context(); return Host::from_context(h)->get_tx_context();
} }
inline evmc_bytes32 get_block_hash(evmc_context* h, int64_t block_number) noexcept
inline evmc_bytes32 get_block_hash(evmc_host_context* h, int64_t block_number) noexcept
{ {
return static_cast<Host*>(h)->get_block_hash(block_number); return Host::from_context(h)->get_block_hash(block_number);
} }
inline void emit_log(evmc_context* h,
inline void emit_log(evmc_host_context* h,
const evmc_address* addr, const evmc_address* addr,
const uint8_t* data, const uint8_t* data,
size_t data_size, size_t data_size,
const evmc_bytes32 topics[], const evmc_bytes32 topics[],
size_t num_topics) noexcept size_t num_topics) noexcept
{ {
static_cast<Host*>(h)->emit_log(*addr, data, data_size, static_cast<const bytes32*>(topics), Host::from_context(h)->emit_log(*addr, data, data_size, static_cast<const bytes32*>(topics),
num_topics); num_topics);
} }
constexpr evmc_host_interface interface{
account_exists, get_storage, set_storage, get_balance, get_code_size, get_code_hash,
copy_code, selfdestruct, call, get_tx_context, get_block_hash, emit_log,
};
} // namespace internal } // namespace internal
inline Host::Host() noexcept : evmc_context{&evmc::internal::interface} {} 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 evmc

View File

@ -22,36 +22,35 @@
#include <string.h> #include <string.h>
/** /**
* Returns true if the VM instance has a compatible ABI version. * Returns true if the VM has a compatible ABI version.
*/ */
static inline int evmc_is_abi_compatible(struct evmc_instance* instance) static inline bool evmc_is_abi_compatible(struct evmc_vm* vm)
{ {
return instance->abi_version == EVMC_ABI_VERSION; return vm->abi_version == EVMC_ABI_VERSION;
} }
/** /**
* Returns the name of the VM instance. * Returns the name of the VM.
*/ */
static inline const char* evmc_vm_name(struct evmc_instance* instance) static inline const char* evmc_vm_name(struct evmc_vm* vm)
{ {
return instance->name; return vm->name;
} }
/** /**
* Returns the version of the VM instance. * Returns the version of the VM.
*/ */
static inline const char* evmc_vm_version(struct evmc_instance* instance) static inline const char* evmc_vm_version(struct evmc_vm* vm)
{ {
return instance->version; return vm->version;
} }
/** /**
* Checks if the VM instance has the given capability. * Checks if the VM has the given capability.
* *
* @see evmc_get_capabilities_fn * @see evmc_get_capabilities_fn
*/ */
static inline bool evmc_vm_has_capability(struct evmc_instance* vm, static inline bool evmc_vm_has_capability(struct evmc_vm* vm, enum evmc_capabilities capability)
enum evmc_capabilities capability)
{ {
return (vm->get_capabilities(vm) & (evmc_capabilities_flagset)capability) != 0; return (vm->get_capabilities(vm) & (evmc_capabilities_flagset)capability) != 0;
} }
@ -61,52 +60,39 @@ static inline bool evmc_vm_has_capability(struct evmc_instance* vm,
* *
* @see evmc_destroy_fn * @see evmc_destroy_fn
*/ */
static inline void evmc_destroy(struct evmc_instance* instance) static inline void evmc_destroy(struct evmc_vm* vm)
{ {
instance->destroy(instance); vm->destroy(vm);
} }
/** /**
* Sets the option for the VM instance, if the feature is supported by the VM. * Sets the option for the VM, if the feature is supported by the VM.
* *
* @see evmc_set_option_fn * @see evmc_set_option_fn
*/ */
static inline enum evmc_set_option_result evmc_set_option(struct evmc_instance* instance, static inline enum evmc_set_option_result evmc_set_option(struct evmc_vm* vm,
char const* name, char const* name,
char const* value) char const* value)
{ {
if (instance->set_option) if (vm->set_option)
return instance->set_option(instance, name, value); return vm->set_option(vm, name, value);
return EVMC_SET_OPTION_INVALID_NAME; return EVMC_SET_OPTION_INVALID_NAME;
} }
/**
* Sets the tracer callback for the VM instance, if the feature is supported by the VM.
*
* @see evmc_set_tracer_fn
*/
EVMC_DEPRECATED
static inline void evmc_set_tracer(struct evmc_instance* instance,
evmc_trace_callback callback,
struct evmc_tracer_context* context)
{
if (instance->set_tracer)
instance->set_tracer(instance, callback, context);
}
/** /**
* Executes code in the VM instance. * Executes code in the VM instance.
* *
* @see evmc_execute_fn. * @see evmc_execute_fn.
*/ */
static inline struct evmc_result evmc_execute(struct evmc_instance* instance, static inline struct evmc_result evmc_execute(struct evmc_vm* vm,
struct evmc_context* context, const struct evmc_host_interface* host,
struct evmc_host_context* context,
enum evmc_revision rev, enum evmc_revision rev,
const struct evmc_message* msg, const struct evmc_message* msg,
uint8_t const* code, uint8_t const* code,
size_t code_size) size_t code_size)
{ {
return instance->execute(instance, context, rev, msg, code, code_size); return vm->execute(vm, host, context, rev, msg, code, code_size);
} }
/// The evmc_result release function using free() for releasing the memory. /// The evmc_result release function using free() for releasing the memory.

View File

@ -152,8 +152,8 @@ evmc_create_fn evmc_load(const char* filename, enum evmc_loader_error_code* erro
char* base_name = prefixed_name + prefix_length; char* base_name = prefixed_name + prefix_length;
strcpy_sx(base_name, PATH_MAX_LENGTH, name_pos); strcpy_sx(base_name, PATH_MAX_LENGTH, name_pos);
// Trim the file extension. // Trim all file extensions.
char* ext_pos = strrchr(prefixed_name, '.'); char* ext_pos = strchr(prefixed_name, '.');
if (ext_pos) if (ext_pos)
*ext_pos = 0; *ext_pos = 0;
@ -163,15 +163,7 @@ evmc_create_fn evmc_load(const char* filename, enum evmc_loader_error_code* erro
*dash_pos++ = '_'; *dash_pos++ = '_';
// Search for the built function name. // Search for the built function name.
while ((create_fn = DLL_GET_CREATE_FN(handle, prefixed_name)) == NULL) create_fn = DLL_GET_CREATE_FN(handle, prefixed_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) if (!create_fn)
create_fn = DLL_GET_CREATE_FN(handle, "evmc_create"); create_fn = DLL_GET_CREATE_FN(handle, "evmc_create");
@ -196,8 +188,7 @@ const char* evmc_last_error_msg()
return m; return m;
} }
struct evmc_instance* evmc_load_and_create(const char* filename, struct evmc_vm* evmc_load_and_create(const char* filename, enum evmc_loader_error_code* error_code)
enum evmc_loader_error_code* error_code)
{ {
// First load the DLL. This also resets the last_error_msg; // First load the DLL. This also resets the last_error_msg;
evmc_create_fn create_fn = evmc_load(filename, error_code); evmc_create_fn create_fn = evmc_load(filename, error_code);
@ -207,21 +198,21 @@ struct evmc_instance* evmc_load_and_create(const char* filename,
enum evmc_loader_error_code ec = EVMC_LOADER_SUCCESS; enum evmc_loader_error_code ec = EVMC_LOADER_SUCCESS;
struct evmc_instance* instance = create_fn(); struct evmc_vm* vm = create_fn();
if (!instance) if (!vm)
{ {
ec = set_error(EVMC_LOADER_INSTANCE_CREATION_FAILURE, ec = set_error(EVMC_LOADER_VM_CREATION_FAILURE, "creating EVMC VM of %s has failed",
"creating EVMC instance of %s has failed", filename); filename);
goto exit; goto exit;
} }
if (!evmc_is_abi_compatible(instance)) if (!evmc_is_abi_compatible(vm))
{ {
ec = set_error(EVMC_LOADER_ABI_VERSION_MISMATCH, ec = set_error(EVMC_LOADER_ABI_VERSION_MISMATCH,
"EVMC ABI version %d of %s mismatches the expected version %d", "EVMC ABI version %d of %s mismatches the expected version %d",
instance->abi_version, filename, EVMC_ABI_VERSION); vm->abi_version, filename, EVMC_ABI_VERSION);
evmc_destroy(instance); evmc_destroy(vm);
instance = NULL; vm = NULL;
goto exit; goto exit;
} }
@ -229,7 +220,7 @@ exit:
if (error_code) if (error_code)
*error_code = ec; *error_code = ec;
return instance; return vm;
} }
/// Gets the token delimited by @p delim character of the string pointed by the @p str_ptr. /// Gets the token delimited by @p delim character of the string pointed by the @p str_ptr.
@ -255,11 +246,10 @@ static char* get_token(char** str_ptr, char delim)
return str; return str;
} }
struct evmc_instance* evmc_load_and_configure(const char* config, struct evmc_vm* evmc_load_and_configure(const char* config, enum evmc_loader_error_code* error_code)
enum evmc_loader_error_code* error_code)
{ {
enum evmc_loader_error_code ec = EVMC_LOADER_SUCCESS; enum evmc_loader_error_code ec = EVMC_LOADER_SUCCESS;
struct evmc_instance* instance = NULL; struct evmc_vm* vm = NULL;
char config_copy_buffer[PATH_MAX_LENGTH]; char config_copy_buffer[PATH_MAX_LENGTH];
if (strcpy_sx(config_copy_buffer, sizeof(config_copy_buffer), config) != 0) if (strcpy_sx(config_copy_buffer, sizeof(config_copy_buffer), config) != 0)
@ -273,14 +263,14 @@ struct evmc_instance* evmc_load_and_configure(const char* config,
char* options = config_copy_buffer; char* options = config_copy_buffer;
const char* path = get_token(&options, ','); const char* path = get_token(&options, ',');
instance = evmc_load_and_create(path, error_code); vm = evmc_load_and_create(path, error_code);
if (!instance) if (!vm)
return NULL; return NULL;
if (instance->set_option == NULL && strlen(options) != 0) if (vm->set_option == NULL && strlen(options) != 0)
{ {
ec = set_error(EVMC_LOADER_INVALID_OPTION_NAME, "%s (%s) does not support any options", ec = set_error(EVMC_LOADER_INVALID_OPTION_NAME, "%s (%s) does not support any options",
instance->name, path); vm->name, path);
goto exit; goto exit;
} }
@ -293,18 +283,18 @@ struct evmc_instance* evmc_load_and_configure(const char* config,
// The option variable will have the value, can be empty. // The option variable will have the value, can be empty.
const char* name = get_token(&option, '='); const char* name = get_token(&option, '=');
enum evmc_set_option_result r = instance->set_option(instance, name, option); enum evmc_set_option_result r = vm->set_option(vm, name, option);
switch (r) switch (r)
{ {
case EVMC_SET_OPTION_SUCCESS: case EVMC_SET_OPTION_SUCCESS:
break; break;
case EVMC_SET_OPTION_INVALID_NAME: case EVMC_SET_OPTION_INVALID_NAME:
ec = set_error(EVMC_LOADER_INVALID_OPTION_NAME, "%s (%s): unknown option '%s'", ec = set_error(EVMC_LOADER_INVALID_OPTION_NAME, "%s (%s): unknown option '%s'",
instance->name, path, name); vm->name, path, name);
goto exit; goto exit;
case EVMC_SET_OPTION_INVALID_VALUE: case EVMC_SET_OPTION_INVALID_VALUE:
ec = set_error(EVMC_LOADER_INVALID_OPTION_VALUE, ec = set_error(EVMC_LOADER_INVALID_OPTION_VALUE,
"%s (%s): unsupported value '%s' for option '%s'", instance->name, path, "%s (%s): unsupported value '%s' for option '%s'", vm->name, path,
option, name); option, name);
goto exit; goto exit;
} }
@ -315,9 +305,9 @@ exit:
*error_code = ec; *error_code = ec;
if (ec == EVMC_LOADER_SUCCESS) if (ec == EVMC_LOADER_SUCCESS)
return instance; return vm;
if (instance) if (vm)
evmc_destroy(instance); evmc_destroy(vm);
return NULL; return NULL;
} }

View File

@ -19,7 +19,7 @@ extern "C" {
#endif #endif
/** The function pointer type for EVMC create functions. */ /** The function pointer type for EVMC create functions. */
typedef struct evmc_instance* (*evmc_create_fn)(void); typedef struct evmc_vm* (*evmc_create_fn)(void);
/** Error codes for the EVMC loader. */ /** Error codes for the EVMC loader. */
enum evmc_loader_error_code enum evmc_loader_error_code
@ -37,7 +37,7 @@ enum evmc_loader_error_code
EVMC_LOADER_INVALID_ARGUMENT = 3, EVMC_LOADER_INVALID_ARGUMENT = 3,
/** The creation of a VM instance has failed. */ /** The creation of a VM instance has failed. */
EVMC_LOADER_INSTANCE_CREATION_FAILURE = 4, EVMC_LOADER_VM_CREATION_FAILURE = 4,
/** The ABI version of the VM instance has mismatched. */ /** The ABI version of the VM instance has mismatched. */
EVMC_LOADER_ABI_VERSION_MISMATCH = 5, EVMC_LOADER_ABI_VERSION_MISMATCH = 5,
@ -61,21 +61,16 @@ enum evmc_loader_error_code
* After the DLL is successfully loaded the function tries to find the EVM create function in the * After the DLL is successfully loaded the function tries to find the EVM create function in the
* library. The `filename` is used to guess the EVM name and the name of the create function. * library. The `filename` is used to guess the EVM name and the name of the create function.
* The create function name is constructed by the following rules. Consider example path: * The create function name is constructed by the following rules. Consider example path:
* "/ethereum/libexample-interpreter.so". * "/ethereum/libexample-interpreter.so.1.0".
* - the filename is taken from the path: * - the filename is taken from the path:
* "libexample-interpreter.so", * "libexample-interpreter.so.1.0",
* - the "lib" prefix and file extension are stripped from the name: * - the "lib" prefix and all file extensions are stripped from the name:
* "example-interpreter" * "example-interpreter"
* - all "-" are replaced with "_" to construct _base name_: * - all "-" are replaced with "_" to construct _base name_:
* "example_interpreter", * "example_interpreter",
* - the function name "evmc_create_" + _base name_ is searched in the library: * - the function name "evmc_create_" + _base name_ is searched in the library:
* "evmc_create_example_interpreter", * "evmc_create_example_interpreter",
* - if function not found, the _base name_ is shorten by skipping the first word separated by "_": * - if the function is not found, the function name "evmc_create" is searched in the library.
* "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. * 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. * Otherwise, the ::EVMC_LOADER_SYMBOL_NOT_FOUND error code is signaled and NULL is returned.
@ -98,7 +93,7 @@ evmc_create_fn evmc_load(const char* filename, enum evmc_loader_error_code* erro
* *
* This is a macro for creating the VM instance with the function returned from evmc_load(). * This is a macro for creating the VM instance with the function returned from evmc_load().
* The function signals the same errors as evmc_load() and additionally: * The function signals the same errors as evmc_load() and additionally:
* - ::EVMC_LOADER_INSTANCE_CREATION_FAILURE when the create function returns NULL, * - ::EVMC_LOADER_VM_CREATION_FAILURE when the create function returns NULL,
* - ::EVMC_LOADER_ABI_VERSION_MISMATCH when the created VM instance has ABI version different * - ::EVMC_LOADER_ABI_VERSION_MISMATCH when the created VM instance has ABI version different
* from the ABI version of this library (::EVMC_ABI_VERSION). * from the ABI version of this library (::EVMC_ABI_VERSION).
* *
@ -114,8 +109,7 @@ evmc_create_fn evmc_load(const char* filename, enum evmc_loader_error_code* erro
* ::EVMC_LOADER_SUCCESS on success or any other error code as described above. * ::EVMC_LOADER_SUCCESS on success or any other error code as described above.
* @return The pointer to the created VM or NULL in case of error. * @return The pointer to the created VM or NULL in case of error.
*/ */
struct evmc_instance* evmc_load_and_create(const char* filename, struct evmc_vm* evmc_load_and_create(const char* filename, enum evmc_loader_error_code* error_code);
enum evmc_loader_error_code* error_code);
/** /**
* Dynamically loads the EVMC module, then creates and configures the VM instance. * Dynamically loads the EVMC module, then creates and configures the VM instance.
@ -151,8 +145,8 @@ struct evmc_instance* evmc_load_and_create(const char* filename,
* ::EVMC_LOADER_SUCCESS on success or any other error code as described above. * ::EVMC_LOADER_SUCCESS on success or any other error code as described above.
* @return The pointer to the created VM or NULL in case of error. * @return The pointer to the created VM or NULL in case of error.
*/ */
struct evmc_instance* evmc_load_and_configure(const char* config, struct evmc_vm* evmc_load_and_configure(const char* config,
enum evmc_loader_error_code* error_code); enum evmc_loader_error_code* error_code);
/** /**
* Returns the human-readable message describing the most recent error * Returns the human-readable message describing the most recent error