Merge pull request #80: EVM-C: Support multiple VMs

This commit is contained in:
Paweł Bylica 2016-08-24 10:15:14 +02:00 committed by GitHub
commit cead905a2e
4 changed files with 110 additions and 58 deletions

View File

@ -1,3 +1,5 @@
add_compile_options("-Wno-extra") # Override -Wextra, I don't know better option.
add_library(example-vm STATIC EXCLUDE_FROM_ALL examplevm.c) add_library(example-vm STATIC EXCLUDE_FROM_ALL examplevm.c)
target_include_directories(example-vm PRIVATE ../include) target_include_directories(example-vm PRIVATE ../include)

View File

@ -3,6 +3,7 @@
#include <stdlib.h> #include <stdlib.h>
#include "evm.h" #include "evm.h"
struct evm_uint256 balance(struct evm_env* env, struct evm_hash160 address) struct evm_uint256 balance(struct evm_env* env, struct evm_hash160 address)
{ {
struct evm_uint256 ret = { .words = { 1 } }; struct evm_uint256 ret = { .words = { 1 } };
@ -64,7 +65,8 @@ int64_t call(
int main(int argc, char *argv[]) { int main(int argc, char *argv[]) {
printf("Using VM: %s (%s)\n", evm_get_info(EVM_NAME), evm_get_info(EVM_VERSION)); printf("Using VM: %s (%s)\n", evm_get_info(EVM_NAME), evm_get_info(EVM_VERSION));
struct evm_instance* jit = evm_create(query, update, call); struct evm_interface intf = examplevm_get_interface();
struct evm_instance* jit = intf.create(query, update, call);
char const code[] = "exec()"; char const code[] = "exec()";
const size_t code_size = sizeof(code); const size_t code_size = sizeof(code);
@ -74,23 +76,24 @@ int main(int argc, char *argv[]) {
int64_t gas = 200000; int64_t gas = 200000;
struct evm_result result = struct evm_result result =
evm_execute(jit, NULL, EVM_HOMESTEAD, code_hash, (const uint8_t *)code, code_size, gas, (const uint8_t *)input, intf.execute(jit, NULL, EVM_HOMESTEAD, code_hash, (const uint8_t *)code, code_size, gas, (const uint8_t *)input,
sizeof(input), value); sizeof(input), value);
printf("Execution result:\n"); printf("Execution result:\n");
if (result.gas_left & EVM_EXCEPTION) { if (result.gas_left & EVM_EXCEPTION) {
printf(" EVM eception\n"); printf(" EVM eception\n");
} }
printf(" Gas used: %lld\n", gas - result.gas_left); printf(" Gas used: %ld\n", gas - result.gas_left);
printf(" Gas left: %lld\n", result.gas_left); printf(" Gas left: %ld\n", result.gas_left);
printf(" Output size: %zd\n", result.output_size); printf(" Output size: %zd\n", result.output_size);
printf(" Output: "); printf(" Output: ");
for (int i = 0; i < result.output_size; i++) { size_t i = 0;
for (i = 0; i < result.output_size; i++) {
printf("%02x ", result.output_data[i]); printf("%02x ", result.output_data[i]);
} }
printf("\n"); printf("\n");
evm_destroy_result(result); intf.release_result(&result);
evm_destroy(jit); intf.destroy(jit);
} }

View File

@ -1,6 +1,5 @@
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <stdbool.h>
#include "evm.h" #include "evm.h"
struct evm_instance { struct evm_instance {
@ -19,7 +18,7 @@ EXPORT char const* evm_get_info(enum evm_info_key key)
return ""; return "";
} }
EXPORT struct evm_instance* evm_create(evm_query_fn query_fn, static struct evm_instance* evm_create(evm_query_fn query_fn,
evm_update_fn update_fn, evm_update_fn update_fn,
evm_call_fn call_fn) evm_call_fn call_fn)
{ {
@ -34,19 +33,24 @@ EXPORT struct evm_instance* evm_create(evm_query_fn query_fn,
return ret; return ret;
} }
EXPORT void evm_destroy(struct evm_instance* evm) static void evm_destroy(struct evm_instance* evm)
{ {
free(evm); free(evm);
} }
EXPORT bool evm_set_option(struct evm_instance* evm, /// Example options.
char const* name, ///
char const* value) /// VMs are allowed to omit this function implementation.
int evm_set_option(struct evm_instance* evm,
char const* name,
char const* value)
{ {
return false; if (strcmp(name, "example-option") == 0)
return 1;
return 0;
} }
EXPORT struct evm_result evm_execute(struct evm_instance* instance, static struct evm_result evm_execute(struct evm_instance* instance,
struct evm_env* env, struct evm_env* env,
enum evm_mode mode, enum evm_mode mode,
struct evm_hash256 code_hash, struct evm_hash256 code_hash,
@ -68,21 +72,18 @@ EXPORT struct evm_result evm_execute(struct evm_instance* instance,
return ret; return ret;
} }
EXPORT void evm_destroy_result(struct evm_result result) static void evm_release_result(struct evm_result const* result)
{ {
} }
EXPORT bool evmjit_is_code_ready(struct evm_instance* instance, EXPORT struct evm_interface examplevm_get_interface()
enum evm_mode mode,
struct evm_hash256 code_hash)
{ {
return true; struct evm_interface intf;
} memset(&intf, 0, sizeof(struct evm_result));
intf.create = evm_create;
EXPORT void evmjit_compile(struct evm_instance* instance, intf.destroy = evm_destroy;
enum evm_mode mode, intf.execute = evm_execute;
uint8_t const* code, intf.release_result = evm_release_result;
size_t code_size, intf.set_option = evm_set_option;
struct evm_hash256 code_hash) return intf;
{ }
}

View File

@ -12,11 +12,11 @@
/// ///
/// @defgroup EVMC EVM-C /// @defgroup EVMC EVM-C
/// @{ /// @{
#pragma once #ifndef EVM_H
#define EVM_H
#include <stdint.h> // Definition of int64_t, uint64_t. #include <stdint.h> // Definition of int64_t, uint64_t.
#include <stddef.h> // Definition of size_t. #include <stddef.h> // Definition of size_t.
#include <stdbool.h> // Definition of bool.
/// Allow implementation to inject some additional information about function /// Allow implementation to inject some additional information about function
/// linkage and/or symbol visibility in the output library. /// linkage and/or symbol visibility in the output library.
@ -245,6 +245,9 @@ enum evm_info_key {
}; };
/// Request information about the EVM implementation. /// Request information about the EVM implementation.
/// FIXME: I don't think we need this, as we don't go towards fully dynamic
/// solution (DLLs, dlopen()). User should know a priori what he is
/// integrating with.
/// ///
/// @param key What do you want to know? /// @param key What do you want to know?
/// @return Requested information as a c-string. Nonnull. /// @return Requested information as a c-string. Nonnull.
@ -264,14 +267,14 @@ struct evm_instance;
/// @param update_fn Pointer to update callback function. Nonnull. /// @param update_fn Pointer to update callback function. Nonnull.
/// @param call_fn Pointer to call callback function. Nonnull. /// @param call_fn Pointer to call callback function. Nonnull.
/// @return Pointer to the created EVM instance. /// @return Pointer to the created EVM instance.
EXPORT struct evm_instance* evm_create(evm_query_fn query_fn, typedef struct evm_instance* (*evm_create_fn)(evm_query_fn query_fn,
evm_update_fn update_fn, evm_update_fn update_fn,
evm_call_fn call_fn); evm_call_fn call_fn);
/// Destroys the EVM instance. /// Destroys the EVM instance.
/// ///
/// @param evm The EVM instance to be destroyed. /// @param evm The EVM instance to be destroyed.
EXPORT void evm_destroy(struct evm_instance* evm); typedef void (*evm_destroy_fn)(struct evm_instance* evm);
/// Configures the EVM instance. /// Configures the EVM instance.
@ -284,10 +287,10 @@ EXPORT void evm_destroy(struct evm_instance* evm);
/// @param evm The EVM instance to be configured. /// @param evm The EVM instance to be configured.
/// @param name The option name. Cannot be null. /// @param name The option name. Cannot be null.
/// @param value The new option value. Cannot be null. /// @param value The new option value. Cannot be null.
/// @return True if the option set successfully. /// @return 1 if the option set successfully, 0 otherwise.
EXPORT bool evm_set_option(struct evm_instance* evm, typedef int (*evm_set_option_fn)(struct evm_instance* evm,
char const* name, char const* name,
char const* value); char const* value);
/// EVM compatibility mode aka chain mode. /// EVM compatibility mode aka chain mode.
@ -317,16 +320,16 @@ enum evm_mode {
/// @param input_size The size of the input data. /// @param input_size The size of the input data.
/// @param value Call value. /// @param value Call value.
/// @return All execution results. /// @return All execution results.
EXPORT struct evm_result evm_execute(struct evm_instance* instance, typedef struct evm_result (*evm_execute_fn)(struct evm_instance* instance,
struct evm_env* env, struct evm_env* env,
enum evm_mode mode, enum evm_mode mode,
struct evm_hash256 code_hash, struct evm_hash256 code_hash,
uint8_t const* code, uint8_t const* code,
size_t code_size, size_t code_size,
int64_t gas, int64_t gas,
uint8_t const* input, uint8_t const* input,
size_t input_size, size_t input_size,
struct evm_uint256 value); struct evm_uint256 value);
/// Releases resources assigned to an execution result. /// Releases resources assigned to an execution result.
/// ///
@ -336,7 +339,7 @@ EXPORT struct evm_result evm_execute(struct evm_instance* instance,
/// @param result The execution result which resource are to be released. The /// @param result The execution result which resource are to be released. The
/// result itself it not modified by this function, but becomes /// result itself it not modified by this function, but becomes
/// invalid and user should discard it as well. /// invalid and user should discard it as well.
EXPORT void evm_release_result(struct evm_result const* result); typedef void (*evm_release_result_fn)(struct evm_result const* result);
/// Status of a code in VM. Useful for JIT-like implementations. /// Status of a code in VM. Useful for JIT-like implementations.
enum evm_code_status { enum evm_code_status {
@ -352,21 +355,64 @@ enum evm_code_status {
/// Get information the status of the code in the VM. /// Get information the status of the code in the VM.
EXPORT enum evm_code_status evm_get_code_status(struct evm_instance* instance, typedef enum evm_code_status
enum evm_mode mode, (*evm_get_code_status_fn)(struct evm_instance* instance,
struct evm_hash256 code_hash); enum evm_mode mode,
struct evm_hash256 code_hash);
/// Request preparation of the code for faster execution. It is not required /// Request preparation of the code for faster execution. It is not required
/// to execute the code but allows compilation of the code ahead of time in /// to execute the code but allows compilation of the code ahead of time in
/// JIT-like VMs. /// JIT-like VMs.
EXPORT void evm_prepare_code(struct evm_instance* instance, typedef void (*evm_prepare_code_fn)(struct evm_instance* instance,
enum evm_mode mode, enum evm_mode mode,
uint8_t const* code, uint8_t const* code,
size_t code_size, size_t code_size,
struct evm_hash256 code_hash); struct evm_hash256 code_hash);
/// VM interface.
///
/// Defines the implementation of EVM-C interface for a VM.
struct evm_interface {
/// Pointer to function creating a VM's instance.
evm_create_fn create;
/// Pointer to function destroying a VM's instance.
evm_destroy_fn destroy;
/// Pointer to function execuing a code in a VM.
evm_execute_fn execute;
/// Pointer to function releasing an execution result.
evm_release_result_fn release_result;
/// Optional pointer to function returning a status of a code.
///
/// If the VM does not support this feature the pointer can be NULL.
evm_get_code_status_fn get_code_status;
/// Optional pointer to function compiling a code.
///
/// If the VM does not support this feature the pointer can be NULL.
evm_prepare_code_fn prepare_code;
/// Optional pointer to function modifying VM's options.
///
/// If the VM does not support this feature the pointer can be NULL.
evm_set_option_fn set_option;
};
/// Example of a function exporting an interface for an example VM.
///
/// Each VM implementation is obligates to provided a function returning
/// VM's interface. The function has to be named as `<vm-name>_get_interface()`.
///
/// @return VM interface
struct evm_interface examplevm_get_interface();
#if __cplusplus #if __cplusplus
} }
#endif #endif
#endif // EVM_H
/// @} /// @}