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
*/
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_gas_limit; /**< The block gas limit. */
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.
@ -166,7 +172,7 @@ struct evmc_context;
* @param context The pointer to the Host execution context.
* @return The transaction context.
*/
typedef struct evmc_tx_context (*evmc_get_tx_context_fn)(struct evmc_context* context);
typedef struct evmc_tx_context (*evmc_get_tx_context_fn)(struct evmc_host_context* context);
/**
* 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
* 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.
@ -420,7 +426,8 @@ struct evmc_result
* @param address The address of the account the query is about.
* @return true if exists, false otherwise.
*/
typedef bool (*evmc_account_exists_fn)(struct evmc_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.
@ -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
* 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_bytes32* key);
@ -492,7 +499,7 @@ enum evmc_storage_status
* @param value The value to be stored.
* @return The effect on the storage item.
*/
typedef enum evmc_storage_status (*evmc_set_storage_fn)(struct evmc_context* context,
typedef enum evmc_storage_status (*evmc_set_storage_fn)(struct evmc_host_context* context,
const evmc_address* address,
const evmc_bytes32* key,
const evmc_bytes32* value);
@ -506,7 +513,7 @@ typedef enum evmc_storage_status (*evmc_set_storage_fn)(struct evmc_context* con
* @param address The address of the account.
* @return The balance of the given account or 0 if the account does not exist.
*/
typedef evmc_uint256be (*evmc_get_balance_fn)(struct evmc_context* context,
typedef evmc_uint256be (*evmc_get_balance_fn)(struct evmc_host_context* context,
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.
* @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.
@ -532,7 +540,7 @@ typedef size_t (*evmc_get_code_size_fn)(struct evmc_context* context, const evmc
* @param address The address of the account.
* @return The hash of the code in the account or null bytes if the account does not exist.
*/
typedef evmc_bytes32 (*evmc_get_code_hash_fn)(struct evmc_context* context,
typedef evmc_bytes32 (*evmc_get_code_hash_fn)(struct evmc_host_context* context,
const evmc_address* address);
/**
@ -544,8 +552,7 @@ typedef evmc_bytes32 (*evmc_get_code_hash_fn)(struct evmc_context* context,
* to the provided memory buffer up to the size of the buffer or the size of
* the code, whichever is smaller.
*
* @param context The pointer to the Client execution context.
* @see ::evmc_context.
* @param context The pointer to the Host execution context. See ::evmc_host_context.
* @param address The address of the account.
* @param code_offset The offset of the code to copy.
* @param buffer_data The pointer to the memory buffer allocated by the EVM
@ -553,7 +560,7 @@ typedef evmc_bytes32 (*evmc_get_code_hash_fn)(struct evmc_context* context,
* @param buffer_size The size of the memory buffer.
* @return The number of bytes copied to the buffer by the Client.
*/
typedef size_t (*evmc_copy_code_fn)(struct evmc_context* context,
typedef size_t (*evmc_copy_code_fn)(struct evmc_host_context* context,
const evmc_address* address,
size_t code_offset,
uint8_t* buffer_data,
@ -565,13 +572,11 @@ typedef size_t (*evmc_copy_code_fn)(struct evmc_context* context,
* This callback function is used by an EVM to SELFDESTRUCT given contract.
* The execution of the contract will not be stopped, that is up to the EVM.
*
* @param context The pointer to the Host execution context.
* @see ::evmc_context.
* @param context The pointer to the Host execution context. See ::evmc_host_context.
* @param address The address of the contract to be selfdestructed.
* @param beneficiary The address where the remaining ETH is going to be
* transferred.
* @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* beneficiary);
@ -580,16 +585,15 @@ typedef void (*evmc_selfdestruct_fn)(struct evmc_context* context,
*
* This callback function is used by an EVM to inform about a LOG that happened
* during an EVM bytecode execution.
* @param context The pointer to the Host execution context.
* @see ::evmc_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 data The pointer to unindexed data attached to the log.
* @param data_size The length of the data.
* @param topics The pointer to the array of topics attached to the log.
* @param topics_count The number of the topics. Valid values are between
* 0 and 4 inclusively.
* @param topics_count The number of the topics. Valid values are between 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 uint8_t* data,
size_t data_size,
@ -603,7 +607,7 @@ typedef void (*evmc_emit_log_fn)(struct evmc_context* context,
* @param msg The call parameters.
* @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);
/**
@ -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. */
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.
@ -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:
* - code cache behavior: on, off, read-only, ...
* - 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 value The new option value. NULL-terminated string. Cannot be NULL.
* @return The outcome of the operation.
*/
typedef enum evmc_set_option_result (*evmc_set_option_fn)(struct evmc_instance* evm,
typedef enum evmc_set_option_result (*evmc_set_option_fn)(struct evmc_vm* vm,
char const* name,
char const* value);
@ -762,6 +750,7 @@ enum evmc_revision
* The Petersburg revision.
*
* Other names: Constantinople2, ConstantinopleFix.
*
* https://eips.ethereum.org/EIPS/eip-1716
*/
EVMC_PETERSBURG = 6,
@ -773,23 +762,15 @@ enum evmc_revision
*/
EVMC_ISTANBUL = 7,
/**
* The Berlin revision.
*
* The spec draft: https://eips.ethereum.org/EIPS/eip-2070.
*/
EVMC_BERLIN = 8,
/** The maximum EVM revision supported. */
EVMC_MAX_REVISION = EVMC_ISTANBUL,
/**
* 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
EVMC_MAX_REVISION = EVMC_BERLIN
};
@ -798,19 +779,22 @@ enum evmc_revision
*
* This function MAY be invoked multiple times for a single VM instance.
*
* @param instance The VM instance. This argument MUST NOT be NULL.
* @param context The pointer to the Host execution context to be passed
* to the Host interface methods (::evmc_host_interface).
* This argument MUST NOT be NULL unless
* the @p instance has the ::EVMC_CAPABILITY_PRECOMPILES capability.
* @param vm The VM instance. This argument MUST NOT be NULL.
* @param host The Host interface. This argument MUST NOT be NULL unless
* the @p vm has the ::EVMC_CAPABILITY_PRECOMPILES capability.
* @param context The opaque pointer to the Host execution context.
* This argument MAY be NULL. The VM MUST pass the same
* pointer to the methods of the @p host interface.
* The VM MUST NOT dereference the pointer.
* @param rev The requested EVM specification revision.
* @param msg The call parameters. See ::evmc_message. This argument MUST NOT be NULL.
* @param code The reference to the code to be executed. This argument MAY be NULL.
* @param code_size The length of the code. If @p code is NULL this argument MUST be 0.
* @return The execution result.
*/
typedef struct evmc_result (*evmc_execute_fn)(struct evmc_instance* instance,
struct evmc_context* context,
typedef struct evmc_result (*evmc_execute_fn)(struct evmc_vm* vm,
const struct evmc_host_interface* host,
struct evmc_host_context* context,
enum evmc_revision rev,
const struct evmc_message* msg,
uint8_t const* code,
@ -855,98 +839,20 @@ 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.
* 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.
*/
typedef evmc_capabilities_flagset (*evmc_get_capabilities_fn)(struct evmc_instance* instance);
/**
* 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);
typedef evmc_capabilities_flagset (*evmc_get_capabilities_fn)(struct evmc_vm* vm);
/**
* The EVM instance.
* The VM instance.
*
* Defines the base struct of the VM implementation.
*/
struct evmc_instance
struct evmc_vm
{
/**
* EVMC ABI version implemented by the VM instance.
@ -973,14 +879,14 @@ struct evmc_instance
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.
*/
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.
*/
@ -998,17 +904,6 @@ struct evmc_instance
*/
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.
*
@ -1033,9 +928,9 @@ struct evmc_instance
* For example, the shared library with the "beta-interpreter" implementation may be named
* `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
#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.
class vm
class VM
{
public:
vm() noexcept = default;
VM() noexcept = default;
/// Converting constructor from evmc_instance.
explicit vm(evmc_instance* instance) noexcept : m_instance{instance} {}
/// Converting constructor from evmc_vm.
explicit VM(evmc_vm* vm) noexcept : m_instance{vm} {}
/// Destructor responsible for automatically destroying the VM instance.
~vm() noexcept
~VM() noexcept
{
if (m_instance)
m_instance->destroy(m_instance);
}
vm(const vm&) = delete;
vm& operator=(const vm&) = delete;
VM(const VM&) = delete;
VM& operator=(const VM&) = delete;
/// 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.
vm& operator=(vm&& other) noexcept
VM& operator=(VM&& other) noexcept
{
this->~vm();
this->~VM();
m_instance = other.m_instance;
other.m_instance = nullptr;
return *this;
}
/// The constructor that captures a VM instance and configures the instance
/// with provided list of options.
vm(evmc_instance* instance,
std::initializer_list<std::pair<const char*, const char*>> options) noexcept
: m_instance{instance}
{
for (auto option : options)
set_option(option.first, option.second);
}
/// with the provided list of options.
inline VM(evmc_vm* vm,
std::initializer_list<std::pair<const char*, const char*>> options) noexcept;
/// Checks if contains a valid pointer to the VM instance.
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.
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; }
/// @copydoc evmc_instance::version
/// @copydoc evmc_vm::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
{
return m_instance->get_capabilities(m_instance);
@ -403,19 +400,53 @@ public:
}
/// @copydoc evmc_execute()
result execute(evmc_context& ctx,
result execute(const evmc_host_interface& host,
evmc_host_context* ctx,
evmc_revision rev,
const evmc_message& msg,
const uint8_t* code,
size_t code_size) noexcept
{
return result{m_instance->execute(m_instance, &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:
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
class HostInterface
{
@ -471,46 +502,52 @@ public:
/// 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
{
evmc_context* context = nullptr;
const evmc_host_interface* host = nullptr;
evmc_host_context* context = nullptr;
evmc_tx_context tx_context = {};
public:
/// Implicit converting constructor from evmc_context.
HostContext(evmc_context* ctx) noexcept : context{ctx} {} // NOLINT
/// Default constructor for null Host context.
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
{
return context->host->account_exists(context, &address);
return host->account_exists(context, &address);
}
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,
const bytes32& key,
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
{
return context->host->get_balance(context, &address);
return host->get_balance(context, &address);
}
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
{
return context->host->get_code_hash(context, &address);
return host->get_code_hash(context, &address);
}
size_t copy_code(const address& address,
@ -518,17 +555,17 @@ public:
uint8_t* buffer_data,
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
{
context->host->selfdestruct(context, &addr, &beneficiary);
host->selfdestruct(context, &addr, &beneficiary);
}
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()
@ -540,13 +577,13 @@ public:
evmc_tx_context get_tx_context() noexcept final
{
if (tx_context.block_timestamp == 0)
tx_context = context->host->get_tx_context(context);
tx_context = host->get_tx_context(context);
return tx_context;
}
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,
@ -555,7 +592,7 @@ public:
const bytes32 topics[],
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.
/// This way your implementation will be simpler by avoiding manual handling
/// of the ::evmc_context and the ::evmc_context::host.
class Host : public HostInterface, public evmc_context
/// of the ::evmc_host_context and the ::evmc_host_interface.
class Host : public HostInterface
{
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
{
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_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_bytes32* key,
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,
size_t code_offset,
uint8_t* buffer_data,
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* 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 uint8_t* data,
size_t data_size,
const evmc_bytes32 topics[],
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);
}
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
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

View File

@ -22,36 +22,35 @@
#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
*/
static inline bool evmc_vm_has_capability(struct evmc_instance* vm,
enum evmc_capabilities capability)
static inline bool evmc_vm_has_capability(struct evmc_vm* vm, enum evmc_capabilities capability)
{
return (vm->get_capabilities(vm) & (evmc_capabilities_flagset)capability) != 0;
}
@ -61,52 +60,39 @@ static inline bool evmc_vm_has_capability(struct evmc_instance* vm,
*
* @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
*/
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* value)
{
if (instance->set_option)
return instance->set_option(instance, name, value);
if (vm->set_option)
return vm->set_option(vm, name, value);
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.
*
* @see evmc_execute_fn.
*/
static inline struct evmc_result evmc_execute(struct evmc_instance* instance,
struct evmc_context* context,
static inline struct evmc_result evmc_execute(struct evmc_vm* vm,
const struct evmc_host_interface* host,
struct evmc_host_context* context,
enum evmc_revision rev,
const struct evmc_message* msg,
uint8_t const* code,
size_t code_size)
{
return 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.

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;
strcpy_sx(base_name, PATH_MAX_LENGTH, name_pos);
// Trim the file extension.
char* ext_pos = strrchr(prefixed_name, '.');
// Trim all file extensions.
char* ext_pos = strchr(prefixed_name, '.');
if (ext_pos)
*ext_pos = 0;
@ -163,15 +163,7 @@ evmc_create_fn evmc_load(const char* filename, enum evmc_loader_error_code* erro
*dash_pos++ = '_';
// Search for the built function name.
while ((create_fn = DLL_GET_CREATE_FN(handle, prefixed_name)) == NULL)
{
// 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);
}
create_fn = DLL_GET_CREATE_FN(handle, prefixed_name);
if (!create_fn)
create_fn = DLL_GET_CREATE_FN(handle, "evmc_create");
@ -196,8 +188,7 @@ const char* evmc_last_error_msg()
return m;
}
struct evmc_instance* evmc_load_and_create(const char* filename,
enum evmc_loader_error_code* error_code)
struct evmc_vm* evmc_load_and_create(const char* filename, enum evmc_loader_error_code* error_code)
{
// First load the DLL. This also resets the last_error_msg;
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;
struct evmc_instance* instance = create_fn();
if (!instance)
struct evmc_vm* vm = create_fn();
if (!vm)
{
ec = set_error(EVMC_LOADER_INSTANCE_CREATION_FAILURE,
"creating EVMC instance of %s has failed", filename);
ec = set_error(EVMC_LOADER_VM_CREATION_FAILURE, "creating EVMC VM of %s has failed",
filename);
goto exit;
}
if (!evmc_is_abi_compatible(instance))
if (!evmc_is_abi_compatible(vm))
{
ec = set_error(EVMC_LOADER_ABI_VERSION_MISMATCH,
"EVMC ABI version %d of %s mismatches the expected version %d",
instance->abi_version, filename, EVMC_ABI_VERSION);
evmc_destroy(instance);
instance = NULL;
vm->abi_version, filename, EVMC_ABI_VERSION);
evmc_destroy(vm);
vm = NULL;
goto exit;
}
@ -229,7 +220,7 @@ exit:
if (error_code)
*error_code = ec;
return instance;
return vm;
}
/// 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;
}
struct evmc_instance* evmc_load_and_configure(const char* config,
enum evmc_loader_error_code* error_code)
struct evmc_vm* evmc_load_and_configure(const char* config, enum evmc_loader_error_code* error_code)
{
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];
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;
const char* path = get_token(&options, ',');
instance = evmc_load_and_create(path, error_code);
if (!instance)
vm = evmc_load_and_create(path, error_code);
if (!vm)
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",
instance->name, path);
vm->name, path);
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.
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)
{
case EVMC_SET_OPTION_SUCCESS:
break;
case EVMC_SET_OPTION_INVALID_NAME:
ec = set_error(EVMC_LOADER_INVALID_OPTION_NAME, "%s (%s): unknown option '%s'",
instance->name, path, name);
vm->name, path, name);
goto exit;
case EVMC_SET_OPTION_INVALID_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);
goto exit;
}
@ -315,9 +305,9 @@ exit:
*error_code = ec;
if (ec == EVMC_LOADER_SUCCESS)
return instance;
return vm;
if (instance)
evmc_destroy(instance);
if (vm)
evmc_destroy(vm);
return NULL;
}

View File

@ -19,7 +19,7 @@ extern "C" {
#endif
/** 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. */
enum evmc_loader_error_code
@ -37,7 +37,7 @@ enum evmc_loader_error_code
EVMC_LOADER_INVALID_ARGUMENT = 3,
/** 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. */
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
* 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:
* "/ethereum/libexample-interpreter.so".
* "/ethereum/libexample-interpreter.so.1.0".
* - the filename is taken from the path:
* "libexample-interpreter.so",
* - the "lib" prefix and file extension are stripped from the name:
* "libexample-interpreter.so.1.0",
* - the "lib" prefix and all file extensions are stripped from the name:
* "example-interpreter"
* - all "-" are replaced with "_" to construct _base name_:
* "example_interpreter",
* - the function name "evmc_create_" + _base name_ is searched in the library:
* "evmc_create_example_interpreter",
* - 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 function is not 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.
@ -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().
* 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
* 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.
* @return The pointer to the created VM or NULL in case of error.
*/
struct evmc_instance* evmc_load_and_create(const char* filename,
enum evmc_loader_error_code* error_code);
struct evmc_vm* evmc_load_and_create(const char* filename, enum evmc_loader_error_code* error_code);
/**
* Dynamically loads the EVMC module, then creates and configures the VM instance.
@ -151,7 +145,7 @@ struct evmc_instance* evmc_load_and_create(const char* filename,
* ::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.
*/
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);
/**