mirror of
https://github.com/status-im/evmc.git
synced 2025-02-22 16:08:22 +00:00
Merge pull request #80: EVM-C: Support multiple VMs
This commit is contained in:
commit
cead905a2e
@ -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)
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
104
include/evm.h
104
include/evm.h
@ -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
|
||||
/// @}
|
||||
|
Loading…
x
Reference in New Issue
Block a user