diff --git a/Doxyfile b/Doxyfile index c555c2f..473c37e 100644 --- a/Doxyfile +++ b/Doxyfile @@ -101,7 +101,8 @@ WARN_LOGFILE = #--------------------------------------------------------------------------- INPUT = \ include/evmc/evmc.h include/evmc/helpers.h include/evmc/helpers.hpp include/evmc/loader.h include/evmc/utils.h include/evmc/instructions.h \ - docs/ + docs/ \ + examples/example_vm.c INPUT_ENCODING = UTF-8 FILE_PATTERNS = RECURSIVE = NO diff --git a/docs/EVMC.md b/docs/EVMC.md index 2d249a8..1332fc9 100644 --- a/docs/EVMC.md +++ b/docs/EVMC.md @@ -2,13 +2,14 @@ The EVMC is the low-level ABI between Ethereum Virtual Machines (EVMs) and Ethereum Clients. On the EVM-side it supports classic EVM1 and [eWASM]. -On the Client-side it defines the interface for EVM implementations +On the Client-side it defines the interface for EVM implementations to access Ethereum environment and state. # Guides - [Host Implementation Guide](@ref hostguide) +- [VM Implementation Guide](@ref vmguide) # Versioning {#versioning} @@ -22,13 +23,13 @@ can be referenced as EVMC ABIv3 or just EVMC 3. # Modules -- [EVMC](@ref EVMC) +- [EVMC](@ref EVMC) – the main component that defines API for VMs and Clients (Hosts). - [EVMC Loader](@ref loader) - – the library for loading VMs implemented as Dynamically Loaded Libraries (DLLs, shared objects). + – the library for loading VMs implemented as Dynamically Loaded Libraries (DLLs, shared objects). - [EVMC Helpers](@ref helpers) – a collection of utility functions for easier integration with EVMC. -- [EVM Instructions](@ref instructions) +- [EVM Instructions](@ref instructions) – the library with collection of metrics for EVM1 instruction set. - [EVMC VM Tester](@ref vmtester) – the EVMC-compatibility testing tool for VM implementations. @@ -42,10 +43,10 @@ can be referenced as EVMC ABIv3 or just EVMC 3. ## Terms 1. **VM** – An Ethereum Virtual Machine instance/implementation. -2. **Host** – An entity controlling the VM. - The Host requests code execution and responses to VM queries by callback +2. **Host** – An entity controlling the VM. + The Host requests code execution and responses to VM queries by callback functions. This usually represents an Ethereum Client. - + ## Responsibilities @@ -56,8 +57,8 @@ can be referenced as EVMC ABIv3 or just EVMC 3. counter. - Controls the call depth, including the exceptional termination of execution in case the maximum depth is reached. - - + + ### Host - Provides access to State. diff --git a/docs/Host_Guide.md b/docs/Host_Guide.md index f0124ad..cdd0266 100644 --- a/docs/Host_Guide.md +++ b/docs/Host_Guide.md @@ -20,7 +20,7 @@ When Host implementation is ready it's time to start using EVMC VMs. 1. Firstly, create a VM instance. You need to know what is the name of the "create" function in particular VM implementation. The EVMC recommends to name the - function by the VM codename, e.g. ::evmc_create_examplevm(). + function by the VM codename, e.g. ::evmc_create_example_vm(). Invoking the create function will give you the VM instance (::evmc_instance). It is recommended to create the VM instance once. diff --git a/docs/VM_Guide.md b/docs/VM_Guide.md new file mode 100644 index 0000000..66579f5 --- /dev/null +++ b/docs/VM_Guide.md @@ -0,0 +1,46 @@ +# EVMC VM Implementation Guide {#vmguide} + +> How to add EVMC interface to Your Ethereum VM implementation. + +## An example + +You can start with [the example implementation of EVMC VM interface in C](@ref example_vm.c). + +## VM instance + +The VM instance is described by the ::evmc_instance struct. It contains the +basic static information about the VM like name and version. The struct also +includes the VM methods (in form of function pointers) to allow the Host +to interact with the VM. + +Some methods are optional. The VM must implement at least all mandatory ones. + +The instance struct must also include the EVMC ABI version (::EVMC_ABI_VERSION) +it was build with. This allows the Host to check the ABI compatibility when +loading VMs dynamically. + +The VM instance is created and returned as a pointer from a special "create" +function. The EVMC recommends to name the function by the VM codename, +e.g. ::evmc_create_example_vm(). + +## VM methods implementation + +Each VM methods takes the pointer to the ::evmc_instance as the first argument. +The VM implementation can extend the ::evmc_instance struct for storing internal +data. This allow implementing the VM in object-oriented manner. + +The most important method is ::evmc_instance::execute() because it executes EVM code. +Remember that the Host is allowed to invoke the execute method concurrently +so do not store data related to a particular execution context in the VM instance. + +## Resource management + +All additional resources allocated when the VM instance is created must be +freed when the destroy method is invoked. + +The VM implementation can also attach additional resources to the ::evmc_result +of an execution. These resource must be freed when the ::evmc_result::release() +method is invoked. + + +*Have fun!* diff --git a/examples/example_vm.c b/examples/example_vm.c index 1a0b3d9..f75abe8 100644 --- a/examples/example_vm.c +++ b/examples/example_vm.c @@ -2,6 +2,15 @@ * Copyright 2018 The EVMC Authors. * Licensed under the Apache License, Version 2.0. See the LICENSE file. */ + +/// @file +/// Example implementation of the EVMC VM interface. +/// +/// This VM does not do anything useful except for showing +/// how EVMC VM API should be implemented. +/// The inplementation is done in C only, but could be done in C++ in very +/// similar way. + #include "example_vm.h" #include @@ -9,34 +18,33 @@ #include #include -#define STR(x) #x - -#if !defined(PROJECT_VERSION) -#define PROJECT_VERSION 0.0.0 -#endif +/// The example VM instance struct extending the evmc_instance. struct example_vm { - struct evmc_instance instance; - int verbose; - evmc_trace_callback trace_callback; - struct evmc_tracer_context* tracer_context; + struct evmc_instance instance; ///< The base struct. + int verbose; ///< The verbosity level. + evmc_trace_callback trace_callback; ///< The trace callback. + struct evmc_tracer_context* tracer_context; ///< The tracer context. }; -static void destroy(struct evmc_instance* evm) +/// The implementation of the evmc_instance::destroy() method. +static void destroy(struct evmc_instance* vm) { - free(evm); + free(vm); } +/// The example implementation of the evmc_instance::get_capabilities() method. static evmc_capabilities_flagset get_capabilities(struct evmc_instance* vm) { (void)vm; return EVMC_CAPABILITY_EVM1 | EVMC_CAPABILITY_EWASM; } -/// Example options. +/// Example VM options. /// -/// VMs are allowed to omit this function implementation. +/// The implementation of the evmc_instance::set_option() method. +/// VMs are allowed to omit this method implementation. static enum evmc_set_option_result set_option(struct evmc_instance* instance, const char* name, const char* value) @@ -60,16 +68,14 @@ static enum evmc_set_option_result set_option(struct evmc_instance* instance, return EVMC_SET_OPTION_INVALID_NAME; } -static void release_result(struct evmc_result const* result) -{ - (void)result; -} - -static void free_result_output_data(struct evmc_result const* result) +/// The implementation of the evmc_result::release() method that frees +/// the output buffer attached to the result object. +static void free_result_output_data(const struct evmc_result* result) { free((uint8_t*)result->output_data); } +/// The example implementation of the evmc_instance::execute() method. static struct evmc_result execute(struct evmc_instance* instance, struct evmc_context* context, enum evmc_revision rev, @@ -128,7 +134,6 @@ static struct evmc_result execute(struct evmc_instance* instance, return ret; } - ret.release = release_result; ret.status_code = EVMC_FAILURE; ret.gas_left = 0; @@ -138,6 +143,7 @@ static struct evmc_result execute(struct evmc_instance* instance, return ret; } +/// The implementation of the optional evmc_instance::set_tracer() method. static void set_tracer(struct evmc_instance* instance, evmc_trace_callback callback, struct evmc_tracer_context* context) @@ -147,6 +153,19 @@ static void set_tracer(struct evmc_instance* instance, vm->tracer_context = context; } + +/// @cond internal + +/// Stringify the argument. +#define STR(x) #x + +#if !defined(PROJECT_VERSION) +/// The dummy project version if not provided by the build system. +#define PROJECT_VERSION 0.0.0 +#endif + +/// @endcond + struct evmc_instance* evmc_create_example_vm() { struct evmc_instance init = { @@ -155,7 +174,7 @@ struct evmc_instance* evmc_create_example_vm() .version = STR(PROJECT_VERSION), .destroy = destroy, .execute = execute, - .get_capabilites = get_capabilities, + .get_capabilities = get_capabilities, .set_option = set_option, .set_tracer = set_tracer, }; diff --git a/include/evmc/evmc.h b/include/evmc/evmc.h index 656e477..8ba603b 100644 --- a/include/evmc/evmc.h +++ b/include/evmc/evmc.h @@ -876,7 +876,7 @@ struct evmc_instance * A Client SHOULD only rely on the value returned here if it has queried it after * it has called set_option. */ - evmc_get_capabilities_fn get_capabilites; + evmc_get_capabilities_fn get_capabilities; /** * Optional pointer to function setting the EVM instruction tracer. @@ -911,7 +911,7 @@ struct evmc_instance * * @return EVM instance or NULL indicating instance creation failure. */ -struct evmc_instance* evmc_create_examplevm(void); +struct evmc_instance* evmc_create_example_vm(void); #endif #if __cplusplus diff --git a/include/evmc/helpers.h b/include/evmc/helpers.h index 4ff91b6..55868d1 100644 --- a/include/evmc/helpers.h +++ b/include/evmc/helpers.h @@ -51,7 +51,7 @@ static inline const char* evmc_vm_version(struct evmc_instance* instance) static inline bool evmc_vm_has_capability(struct evmc_instance* vm, enum evmc_capabilities capability) { - return (vm->get_capabilites(vm) & (evmc_capabilities_flagset)capability) != 0; + return (vm->get_capabilities(vm) & (evmc_capabilities_flagset)capability) != 0; } /**