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)
target_include_directories(example-vm PRIVATE ../include)

View File

@ -3,6 +3,7 @@
#include <stdlib.h>
#include "evm.h"
struct evm_uint256 balance(struct evm_env* env, struct evm_hash160 address)
{
struct evm_uint256 ret = { .words = { 1 } };
@ -64,7 +65,8 @@ int64_t call(
int main(int argc, char *argv[]) {
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()";
const size_t code_size = sizeof(code);
@ -74,23 +76,24 @@ int main(int argc, char *argv[]) {
int64_t gas = 200000;
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);
printf("Execution result:\n");
if (result.gas_left & EVM_EXCEPTION) {
printf(" EVM eception\n");
}
printf(" Gas used: %lld\n", gas - result.gas_left);
printf(" Gas left: %lld\n", result.gas_left);
printf(" Gas used: %ld\n", gas - result.gas_left);
printf(" Gas left: %ld\n", result.gas_left);
printf(" Output size: %zd\n", result.output_size);
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("\n");
evm_destroy_result(result);
evm_destroy(jit);
intf.release_result(&result);
intf.destroy(jit);
}

View File

@ -1,6 +1,5 @@
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
#include "evm.h"
struct evm_instance {
@ -19,7 +18,7 @@ EXPORT char const* evm_get_info(enum evm_info_key key)
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_call_fn call_fn)
{
@ -34,19 +33,24 @@ EXPORT struct evm_instance* evm_create(evm_query_fn query_fn,
return ret;
}
EXPORT void evm_destroy(struct evm_instance* evm)
static void evm_destroy(struct evm_instance* evm)
{
free(evm);
}
EXPORT bool evm_set_option(struct evm_instance* evm,
char const* name,
char const* value)
/// Example options.
///
/// 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,
enum evm_mode mode,
struct evm_hash256 code_hash,
@ -68,21 +72,18 @@ EXPORT struct evm_result evm_execute(struct evm_instance* instance,
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,
enum evm_mode mode,
struct evm_hash256 code_hash)
EXPORT struct evm_interface examplevm_get_interface()
{
return true;
}
EXPORT void evmjit_compile(struct evm_instance* instance,
enum evm_mode mode,
uint8_t const* code,
size_t code_size,
struct evm_hash256 code_hash)
{
}
struct evm_interface intf;
memset(&intf, 0, sizeof(struct evm_result));
intf.create = evm_create;
intf.destroy = evm_destroy;
intf.execute = evm_execute;
intf.release_result = evm_release_result;
intf.set_option = evm_set_option;
return intf;
}

View File

@ -12,11 +12,11 @@
///
/// @defgroup EVMC EVM-C
/// @{
#pragma once
#ifndef EVM_H
#define EVM_H
#include <stdint.h> // Definition of int64_t, uint64_t.
#include <stddef.h> // Definition of size_t.
#include <stdbool.h> // Definition of bool.
/// Allow implementation to inject some additional information about function
/// linkage and/or symbol visibility in the output library.
@ -245,6 +245,9 @@ enum evm_info_key {
};
/// 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?
/// @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 call_fn Pointer to call callback function. Nonnull.
/// @return Pointer to the created EVM instance.
EXPORT struct evm_instance* evm_create(evm_query_fn query_fn,
evm_update_fn update_fn,
evm_call_fn call_fn);
typedef struct evm_instance* (*evm_create_fn)(evm_query_fn query_fn,
evm_update_fn update_fn,
evm_call_fn call_fn);
/// Destroys the EVM instance.
///
/// @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.
@ -284,10 +287,10 @@ EXPORT void evm_destroy(struct evm_instance* evm);
/// @param evm The EVM instance to be configured.
/// @param name The option name. Cannot be null.
/// @param value The new option value. Cannot be null.
/// @return True if the option set successfully.
EXPORT bool evm_set_option(struct evm_instance* evm,
char const* name,
char const* value);
/// @return 1 if the option set successfully, 0 otherwise.
typedef int (*evm_set_option_fn)(struct evm_instance* evm,
char const* name,
char const* value);
/// EVM compatibility mode aka chain mode.
@ -317,16 +320,16 @@ enum evm_mode {
/// @param input_size The size of the input data.
/// @param value Call value.
/// @return All execution results.
EXPORT struct evm_result evm_execute(struct evm_instance* instance,
struct evm_env* env,
enum evm_mode mode,
struct evm_hash256 code_hash,
uint8_t const* code,
size_t code_size,
int64_t gas,
uint8_t const* input,
size_t input_size,
struct evm_uint256 value);
typedef struct evm_result (*evm_execute_fn)(struct evm_instance* instance,
struct evm_env* env,
enum evm_mode mode,
struct evm_hash256 code_hash,
uint8_t const* code,
size_t code_size,
int64_t gas,
uint8_t const* input,
size_t input_size,
struct evm_uint256 value);
/// 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
/// result itself it not modified by this function, but becomes
/// 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.
enum evm_code_status {
@ -352,21 +355,64 @@ enum evm_code_status {
/// Get information the status of the code in the VM.
EXPORT enum evm_code_status evm_get_code_status(struct evm_instance* instance,
enum evm_mode mode,
struct evm_hash256 code_hash);
typedef enum evm_code_status
(*evm_get_code_status_fn)(struct evm_instance* instance,
enum evm_mode mode,
struct evm_hash256 code_hash);
/// 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
/// JIT-like VMs.
EXPORT void evm_prepare_code(struct evm_instance* instance,
enum evm_mode mode,
uint8_t const* code,
size_t code_size,
struct evm_hash256 code_hash);
typedef void (*evm_prepare_code_fn)(struct evm_instance* instance,
enum evm_mode mode,
uint8_t const* code,
size_t code_size,
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
}
#endif
#endif // EVM_H
/// @}