From 61d533aad7d6e8fc80dd6624744d24e305c83d34 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Fri, 22 Sep 2017 18:50:20 +0200 Subject: [PATCH 1/6] EVM-C: Move ABI version from factory to instance --- examples/capi.c | 6 +++--- examples/examplevm.c | 12 ++++++++---- include/evm.h | 12 +++++++----- 3 files changed, 18 insertions(+), 12 deletions(-) diff --git a/examples/capi.c b/examples/capi.c index 7a67c45..a8092f7 100644 --- a/examples/capi.c +++ b/examples/capi.c @@ -128,10 +128,10 @@ static const struct evm_host example_host = { /// Example how the API is supposed to be used. int main(int argc, char *argv[]) { struct evm_factory factory = examplevm_get_factory(); - if (factory.abi_version != EVM_ABI_VERSION) - return 1; // Incompatible ABI version. - struct evm_instance* jit = factory.create(&example_host); + struct evm_instance* jit = factory.create(); + if (jit->abi_version != EVM_ABI_VERSION) + return 1; // Incompatible ABI version. uint8_t const code[] = "Place some EVM bytecode here"; const size_t code_size = sizeof(code); diff --git a/examples/examplevm.c b/examples/examplevm.c index 7840db0..1f938b7 100644 --- a/examples/examplevm.c +++ b/examples/examplevm.c @@ -112,17 +112,21 @@ static struct evm_result execute(struct evm_instance* instance, static struct evm_instance* evm_create(const struct evm_host* host) { + struct evm_instance init = { + .abi_version = EVM_ABI_VERSION, + .destroy = evm_destroy, + .execute = execute, + .set_option = evm_set_option + }; struct examplevm* vm = calloc(1, sizeof(struct examplevm)); struct evm_instance* interface = &vm->instance; - interface->destroy = evm_destroy; - interface->execute = execute; - interface->set_option = evm_set_option; + memcpy(interface, &init, sizeof(init)); vm->host = host; return interface; } struct evm_factory examplevm_get_factory() { - struct evm_factory factory = {EVM_ABI_VERSION, evm_create}; + struct evm_factory factory = {evm_create}; return factory; } diff --git a/include/evm.h b/include/evm.h index 406e020..acf30d9 100644 --- a/include/evm.h +++ b/include/evm.h @@ -437,6 +437,13 @@ typedef void (*evm_prepare_code_fn)(struct evm_instance* instance, /// /// Defines the base struct of the EVM implementation. struct evm_instance { + + /// EVM-C ABI version implemented by the EVM instance. + /// + /// For future use to detect ABI incompatibilities. The EVM-C ABI version + /// represented by this file is in ::EVM_ABI_VERSION. + const int abi_version; + /// Pointer to function destroying the EVM instance. evm_destroy_fn destroy; @@ -463,11 +470,6 @@ struct evm_instance { /// /// Provides ABI protection and method to create an EVM instance. struct evm_factory { - /// EVM-C ABI version implemented by the EVM factory and instance. - /// - /// For future use to detect ABI incompatibilities. The EVM-C ABI version - /// represented by this file is in ::EVM_ABI_VERSION. - int abi_version; /// Pointer to function creating and initializing the EVM instance. evm_create_fn create; From 5ff2b98c146d1ec675a6c346b61f77078e7f7e4b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Fri, 22 Sep 2017 19:16:52 +0200 Subject: [PATCH 2/6] EVM-C: Remove factory --- examples/capi.c | 4 +--- examples/examplevm.c | 9 +-------- include/evm.h | 28 ++++++---------------------- 3 files changed, 8 insertions(+), 33 deletions(-) diff --git a/examples/capi.c b/examples/capi.c index a8092f7..d5298d5 100644 --- a/examples/capi.c +++ b/examples/capi.c @@ -127,9 +127,7 @@ static const struct evm_host example_host = { /// Example how the API is supposed to be used. int main(int argc, char *argv[]) { - struct evm_factory factory = examplevm_get_factory(); - - struct evm_instance* jit = factory.create(); + struct evm_instance* jit = examplevm_create(); if (jit->abi_version != EVM_ABI_VERSION) return 1; // Incompatible ABI version. diff --git a/examples/examplevm.c b/examples/examplevm.c index 1f938b7..90c6202 100644 --- a/examples/examplevm.c +++ b/examples/examplevm.c @@ -110,7 +110,7 @@ static struct evm_result execute(struct evm_instance* instance, return ret; } -static struct evm_instance* evm_create(const struct evm_host* host) +struct evm_instance* examplevm_create() { struct evm_instance init = { .abi_version = EVM_ABI_VERSION, @@ -121,12 +121,5 @@ static struct evm_instance* evm_create(const struct evm_host* host) struct examplevm* vm = calloc(1, sizeof(struct examplevm)); struct evm_instance* interface = &vm->instance; memcpy(interface, &init, sizeof(init)); - vm->host = host; return interface; } - -struct evm_factory examplevm_get_factory() -{ - struct evm_factory factory = {evm_create}; - return factory; -} diff --git a/include/evm.h b/include/evm.h index acf30d9..b607aeb 100644 --- a/include/evm.h +++ b/include/evm.h @@ -332,14 +332,6 @@ struct evm_context { struct evm_instance; ///< Forward declaration. -/// Creates the EVM instance. -/// -/// Creates and initializes an EVM instance by providing the information -/// about runtime callback functions. -/// -/// @return Pointer to the created EVM instance. -typedef struct evm_instance* (*evm_create_fn)(); - /// Destroys the EVM instance. /// /// @param evm The EVM instance to be destroyed. @@ -466,25 +458,17 @@ struct evm_instance { evm_set_option_fn set_option; }; -/// The EVM instance factory. -/// -/// Provides ABI protection and method to create an EVM instance. -struct evm_factory { - - /// Pointer to function creating and initializing the EVM instance. - evm_create_fn create; -}; - // END Python CFFI declarations -/// Example of a function creating uninitialized instance of an example VM. +/// Example of a function creating an instance of an example EVM implementation. /// -/// Each EVM implementation is obligated to provided a function returning -/// an EVM instance. -/// The function has to be named as `_get_factory(void)`. +/// Each EVM implementation MUST provide a function returning an EVM instance. +/// The function SHOULD be named `_create(void)`. /// /// @return EVM instance. -struct evm_factory examplevm_get_factory(void); +/// @todo Specify if this function can return null pointer to indicate error. +/// @todo Can we return const pointer? +struct evm_instance* examplevm_create(void); #if __cplusplus From 431c9d2defc36eb8efe60ba5c5581cd0c48064b6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Fri, 22 Sep 2017 19:27:30 +0200 Subject: [PATCH 3/6] EVM-C: Rename evm_result_code -> evm_status_code --- examples/capi.c | 6 ++++-- examples/examplevm.c | 25 ++++++++++++++----------- include/evm.h | 21 +++++++++++---------- 3 files changed, 29 insertions(+), 23 deletions(-) diff --git a/examples/capi.c b/examples/capi.c index d5298d5..aa286aa 100644 --- a/examples/capi.c +++ b/examples/capi.c @@ -112,7 +112,7 @@ static void evm_log(struct evm_context* context, const struct evm_uint160be* add printf("EVM-C: LOG%d\n", (int)topics_count); } -static const struct evm_host example_host = { +static const struct evm_context_fn_table ctx_fn_table = { account_exists, get_storage, set_storage, @@ -139,11 +139,13 @@ int main(int argc, char *argv[]) { struct evm_uint160be addr = {{0, 1, 2,}}; int64_t gas = 200000; + struct evm_context ctx = {&ctx_fn_table}; + struct evm_message msg = {addr, addr, value, input, sizeof(input), code_hash, gas, 0}; struct evm_result result = - jit->execute(jit, NULL, EVM_HOMESTEAD, &msg, code, code_size); + jit->execute(jit, &ctx, EVM_HOMESTEAD, &msg, code, code_size); printf("Execution result:\n"); if (result.code != EVM_SUCCESS) { diff --git a/examples/examplevm.c b/examples/examplevm.c index 90c6202..27a5e3c 100644 --- a/examples/examplevm.c +++ b/examples/examplevm.c @@ -1,15 +1,15 @@ +#include + +#include +#include #include #include -#include -#include struct examplevm { struct evm_instance instance; - const struct evm_host* host; - - int example_option; + int verbose; }; static void evm_destroy(struct evm_instance* evm) @@ -25,11 +25,11 @@ int evm_set_option(struct evm_instance* instance, char const* value) { struct examplevm* vm = (struct examplevm*)instance; - if (strcmp(name, "example-option") == 0) { + if (strcmp(name, "verbose") == 0) { long int v = strtol(value, NULL, 0); if (v > INT_MAX || v < INT_MIN) return 0; - vm->example_option = (int)v; + vm->verbose = (int)v; return 1; } @@ -77,7 +77,7 @@ static struct evm_result execute(struct evm_instance* instance, const char counter[] = "600160005401600055"; if (code_size == strlen(return_address) && - strncmp((const char*)code, return_address, code_size)) { + strncmp((const char*)code, return_address, code_size) == 0) { static const size_t address_size = sizeof(msg->address); uint8_t* output_data = (uint8_t*)malloc(address_size); if (!output_data) { @@ -93,12 +93,12 @@ static struct evm_result execute(struct evm_instance* instance, return ret; } else if (code_size == strlen(counter) && - strncmp((const char*)code, counter, code_size)) { + strncmp((const char*)code, counter, code_size) == 0) { struct evm_uint256be value; const struct evm_uint256be index = {{0,}}; - vm->host->get_storage(&value, context, &msg->address, &index); + context->fn_table->get_storage(&value, context, &msg->address, &index); value.bytes[31] += 1; - vm->host->set_storage(context, &msg->address, &index, &value); + context->fn_table->set_storage(context, &msg->address, &index, &value); ret.code = EVM_SUCCESS; return ret; } @@ -107,6 +107,9 @@ static struct evm_result execute(struct evm_instance* instance, ret.code = EVM_FAILURE; ret.gas_left = 0; + if (vm->verbose) + printf("Execution done.\n"); + return ret; } diff --git a/include/evm.h b/include/evm.h index b607aeb..57af669 100644 --- a/include/evm.h +++ b/include/evm.h @@ -98,8 +98,8 @@ typedef void (*evm_get_block_hash_fn)(struct evm_uint256be* result, struct evm_context* context, int64_t number); -/// The execution result code. -enum evm_result_code { +/// The execution status code. +enum evm_status_code { EVM_SUCCESS = 0, ///< Execution finished with success. EVM_FAILURE = 1, ///< Generic execution failure. EVM_OUT_OF_GAS = 2, @@ -107,7 +107,7 @@ enum evm_result_code { EVM_BAD_JUMP_DESTINATION = 4, EVM_STACK_OVERFLOW = 5, EVM_STACK_UNDERFLOW = 6, - EVM_REVERT = 7, ///< Execution terminated with REVERT opcode. + EVM_REVERT = 7, ///< Execution terminated with REVERT opcode. /// EVM implementation internal error. /// @@ -132,7 +132,7 @@ typedef void (*evm_release_result_fn)(struct evm_result const* result); struct evm_result { /// The execution result code. /// FIXME: Rename to 'status' or 'status_code'. - enum evm_result_code code; + enum evm_status_code code; /// The amount of gas left after the execution. /// @@ -295,13 +295,13 @@ typedef void (*evm_call_fn)(struct evm_result* result, struct evm_context* context, const struct evm_message* msg); -/// The Host interface. +/// The context interface. /// /// The set of all callback functions expected by EVM instances. This is C -/// realisation of OOP interface (only virtual methods, no data). +/// realisation of vtable for OOP interface (only virtual methods, no data). /// Host implementations SHOULD create constant singletons of this (similarly /// to vtables) to lower the maintenance and memory management cost. -struct evm_host { +struct evm_context_fn_table { evm_account_exists_fn account_exists; evm_get_storage_fn get_storage; evm_set_storage_fn set_storage; @@ -325,8 +325,8 @@ struct evm_host { /// Optionally, The Host MAY include in the context additional data. struct evm_context { - /// Function table defining the context interface. - const struct evm_host* fn_table; + /// Function table defining the context interface (vtable). + const struct evm_context_fn_table* fn_table; }; @@ -434,6 +434,8 @@ struct evm_instance { /// /// For future use to detect ABI incompatibilities. The EVM-C ABI version /// represented by this file is in ::EVM_ABI_VERSION. + /// + /// @todo Consider removing this field. const int abi_version; /// Pointer to function destroying the EVM instance. @@ -467,7 +469,6 @@ struct evm_instance { /// /// @return EVM instance. /// @todo Specify if this function can return null pointer to indicate error. -/// @todo Can we return const pointer? struct evm_instance* examplevm_create(void); From 7448400879cb0220273a6e62c4441a6c4fd65a0a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Tue, 26 Sep 2017 16:51:10 +0200 Subject: [PATCH 4/6] EVM-C: Rename evm_result::code -> evm_result::status_code --- examples/capi.c | 6 +++--- examples/examplevm.c | 10 +++++----- include/evm.h | 9 ++++----- 3 files changed, 12 insertions(+), 13 deletions(-) diff --git a/examples/capi.c b/examples/capi.c index aa286aa..32b3f4e 100644 --- a/examples/capi.c +++ b/examples/capi.c @@ -88,7 +88,7 @@ static void call(struct evm_result* result, const struct evm_message* msg) { printf("EVM-C: CALL (depth: %d)\n", msg->depth); - result->code = EVM_FAILURE; + result->status_code = EVM_FAILURE; } static void get_tx_context(struct evm_tx_context* result, struct evm_context* context) @@ -148,8 +148,8 @@ int main(int argc, char *argv[]) { jit->execute(jit, &ctx, EVM_HOMESTEAD, &msg, code, code_size); printf("Execution result:\n"); - if (result.code != EVM_SUCCESS) { - printf(" EVM execution failure: %d\n", result.code); + if (result.status_code != EVM_SUCCESS) { + printf(" EVM execution failure: %d\n", result.status_code); } else { printf(" Gas used: %ld\n", gas - result.gas_left); printf(" Gas left: %ld\n", result.gas_left); diff --git a/examples/examplevm.c b/examples/examplevm.c index 27a5e3c..17db5d9 100644 --- a/examples/examplevm.c +++ b/examples/examplevm.c @@ -60,7 +60,7 @@ static struct evm_result execute(struct evm_instance* instance, "Welcome to Byzantium!" : "Hello Ethereum!"; ret.output_data = (const uint8_t*)error; ret.output_size = strlen(error); - ret.code = EVM_FAILURE; + ret.status_code = EVM_FAILURE; ret.release = NULL; // We don't need to release the constant messages. return ret; } @@ -82,11 +82,11 @@ static struct evm_result execute(struct evm_instance* instance, uint8_t* output_data = (uint8_t*)malloc(address_size); if (!output_data) { // malloc failed, report internal error. - ret.code = EVM_INTERNAL_ERROR; + ret.status_code = EVM_INTERNAL_ERROR; return ret; } memcpy(output_data, &msg->address, address_size); - ret.code = EVM_SUCCESS; + ret.status_code = EVM_SUCCESS; ret.output_data = output_data; ret.output_size = address_size; ret.release = &free_result_output_data; @@ -99,12 +99,12 @@ static struct evm_result execute(struct evm_instance* instance, context->fn_table->get_storage(&value, context, &msg->address, &index); value.bytes[31] += 1; context->fn_table->set_storage(context, &msg->address, &index, &value); - ret.code = EVM_SUCCESS; + ret.status_code = EVM_SUCCESS; return ret; } ret.release = evm_release_result; - ret.code = EVM_FAILURE; + ret.status_code = EVM_FAILURE; ret.gas_left = 0; if (vm->verbose) diff --git a/include/evm.h b/include/evm.h index 57af669..24d30ad 100644 --- a/include/evm.h +++ b/include/evm.h @@ -111,8 +111,8 @@ enum evm_status_code { /// EVM implementation internal error. /// - /// FIXME: We should rethink reporting internal errors. One of the options - /// it to allow using any negative value to represent internal errors. + /// @todo We should rethink reporting internal errors. One of the options + /// it to allow using any negative value to represent internal errors. EVM_INTERNAL_ERROR = -1, }; @@ -130,9 +130,8 @@ typedef void (*evm_release_result_fn)(struct evm_result const* result); /// The EVM code execution result. struct evm_result { - /// The execution result code. - /// FIXME: Rename to 'status' or 'status_code'. - enum evm_status_code code; + /// The execution status code. + enum evm_status_code status_code; /// The amount of gas left after the execution. /// From 52d6cc55a9f35d9d129bfa621ce41f389d2a3bd0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Tue, 26 Sep 2017 14:11:53 +0200 Subject: [PATCH 5/6] EVM-C: Rename evm_uint160be -> evm_address --- examples/capi.c | 26 +++++++++++++------------- include/evm.h | 26 +++++++++++++------------- 2 files changed, 26 insertions(+), 26 deletions(-) diff --git a/examples/capi.c b/examples/capi.c index 32b3f4e..74caf16 100644 --- a/examples/capi.c +++ b/examples/capi.c @@ -5,19 +5,19 @@ struct evm_uint256be balance(struct evm_context* context, - const struct evm_uint160be* address) + const struct evm_address* address) { struct evm_uint256be ret = {.bytes = {1, 2, 3, 4}}; return ret; } -struct evm_uint160be address(struct evm_context* context) +struct evm_address address(struct evm_context* context) { - struct evm_uint160be ret = {.bytes = {1, 2, 3, 4}}; + struct evm_address ret = {.bytes = {1, 2, 3, 4}}; return ret; } -static void print_address(const struct evm_uint160be* address) +static void print_address(const struct evm_address* address) { int i = 0; for (i = 0; i < sizeof(address->bytes); ++i) @@ -25,7 +25,7 @@ static void print_address(const struct evm_uint160be* address) } static int account_exists(struct evm_context* context, - const struct evm_uint160be* address) { + const struct evm_address* address) { printf("EVM-C: EXISTS @"); print_address(address); printf("\n"); @@ -34,7 +34,7 @@ static int account_exists(struct evm_context* context, static void get_storage(struct evm_uint256be* result, struct evm_context* context, - const struct evm_uint160be* address, + const struct evm_address* address, const struct evm_uint256be* key) { printf("EVM-C: SLOAD @"); @@ -43,7 +43,7 @@ static void get_storage(struct evm_uint256be* result, } static void set_storage(struct evm_context* context, - const struct evm_uint160be* address, + const struct evm_address* address, const struct evm_uint256be* key, const struct evm_uint256be* value) { @@ -54,7 +54,7 @@ static void set_storage(struct evm_context* context, static void get_balance(struct evm_uint256be* result, struct evm_context* context, - const struct evm_uint160be* address) + const struct evm_address* address) { printf("EVM-C: BALANCE @"); print_address(address); @@ -64,7 +64,7 @@ static void get_balance(struct evm_uint256be* result, static size_t get_code(const uint8_t** code, struct evm_context* context, - const struct evm_uint160be* address) + const struct evm_address* address) { printf("EVM-C: CODE @"); print_address(address); @@ -73,8 +73,8 @@ static size_t get_code(const uint8_t** code, } static void selfdestruct(struct evm_context* context, - const struct evm_uint160be* address, - const struct evm_uint160be* beneficiary) + const struct evm_address* address, + const struct evm_address* beneficiary) { printf("EVM-C: SELFDESTRUCT "); print_address(address); @@ -105,7 +105,7 @@ static void get_block_hash(struct evm_uint256be* result, struct evm_context* con /// EVM log callback. /// /// @note The `evm_log` name is used to avoid conflict with `log()` C function. -static void evm_log(struct evm_context* context, const struct evm_uint160be* address, +static void evm_log(struct evm_context* context, const struct evm_address* address, const uint8_t* data, size_t data_size, const struct evm_uint256be topics[], size_t topics_count) { @@ -136,7 +136,7 @@ int main(int argc, char *argv[]) { struct evm_uint256be code_hash = {.bytes = {1, 2, 3,}}; uint8_t const input[] = "Hello World!"; struct evm_uint256be value = {{1, 0,}}; - struct evm_uint160be addr = {{0, 1, 2,}}; + struct evm_address addr = {{0, 1, 2,}}; int64_t gas = 200000; struct evm_context ctx = {&ctx_fn_table}; diff --git a/include/evm.h b/include/evm.h index 24d30ad..924a8fb 100644 --- a/include/evm.h +++ b/include/evm.h @@ -49,7 +49,7 @@ struct evm_uint256be { /// Big-endian 160-bit hash suitable for keeping an Ethereum address. /// TODO: Rename to "address". -struct evm_uint160be { +struct evm_address { /// The 20 bytes of the hash. uint8_t bytes[20]; }; @@ -67,8 +67,8 @@ enum evm_flags { }; struct evm_message { - struct evm_uint160be address; - struct evm_uint160be sender; + struct evm_address address; + struct evm_address sender; struct evm_uint256be value; const uint8_t* input; size_t input_size; @@ -81,8 +81,8 @@ struct evm_message { struct evm_tx_context { struct evm_uint256be tx_gas_price; - struct evm_uint160be tx_origin; - struct evm_uint160be block_coinbase; + struct evm_address tx_origin; + struct evm_address block_coinbase; int64_t block_number; int64_t block_timestamp; int64_t block_gas_limit; @@ -196,7 +196,7 @@ struct evm_result { /// @param address The address of the account the query is about. /// @return 1 if exists, 0 otherwise. typedef int (*evm_account_exists_fn)(struct evm_context* context, - const struct evm_uint160be* address); + const struct evm_address* address); /// Get storage callback function. /// @@ -209,7 +209,7 @@ typedef int (*evm_account_exists_fn)(struct evm_context* context, /// @param key The index of the storage entry. typedef void (*evm_get_storage_fn)(struct evm_uint256be* result, struct evm_context* context, - const struct evm_uint160be* address, + const struct evm_address* address, const struct evm_uint256be* key); /// Set storage callback function. @@ -222,7 +222,7 @@ typedef void (*evm_get_storage_fn)(struct evm_uint256be* result, /// @param key The index of the storage entry. /// @param value The value to be stored. typedef void (*evm_set_storage_fn)(struct evm_context* context, - const struct evm_uint160be* address, + const struct evm_address* address, const struct evm_uint256be* key, const struct evm_uint256be* value); @@ -236,7 +236,7 @@ typedef void (*evm_set_storage_fn)(struct evm_context* context, /// @param address The address. typedef void (*evm_get_balance_fn)(struct evm_uint256be* result, struct evm_context* context, - const struct evm_uint160be* address); + const struct evm_address* address); /// Get code callback function. /// @@ -251,7 +251,7 @@ typedef void (*evm_get_balance_fn)(struct evm_uint256be* result, /// @return The size of the code. typedef size_t (*evm_get_code_fn)(const uint8_t** result_code, struct evm_context* context, - const struct evm_uint160be* address); + const struct evm_address* address); /// Selfdestruct callback function. /// @@ -262,8 +262,8 @@ typedef size_t (*evm_get_code_fn)(const uint8_t** result_code, /// @param beneficiary The address where the remaining ETH is going to be /// transferred. typedef void (*evm_selfdestruct_fn)(struct evm_context* context, - const struct evm_uint160be* address, - const struct evm_uint160be* beneficiary); + const struct evm_address* address, + const struct evm_address* beneficiary); /// Log callback function. /// @@ -278,7 +278,7 @@ typedef void (*evm_selfdestruct_fn)(struct evm_context* context, /// @param topics_count The number of the topics. Valid values are between /// 0 and 4 inclusively. typedef void (*evm_log_fn)(struct evm_context* context, - const struct evm_uint160be* address, + const struct evm_address* address, const uint8_t* data, size_t data_size, const struct evm_uint256be topics[], From b36e8d7188accbc3dc1b69e2857c4517ad148f23 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20Bylica?= Date: Mon, 2 Oct 2017 18:02:23 +0200 Subject: [PATCH 6/6] EVM-C: Allow returning NULL from create() functions --- include/evm.h | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/include/evm.h b/include/evm.h index 924a8fb..26ec690 100644 --- a/include/evm.h +++ b/include/evm.h @@ -466,8 +466,7 @@ struct evm_instance { /// Each EVM implementation MUST provide a function returning an EVM instance. /// The function SHOULD be named `_create(void)`. /// -/// @return EVM instance. -/// @todo Specify if this function can return null pointer to indicate error. +/// @return EVM instance or NULL indicating instance creation failure. struct evm_instance* examplevm_create(void);