mirror of https://github.com/status-im/evmc.git
commit
4ee5aff2d4
|
@ -1,8 +1,8 @@
|
|||
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 examplevm.c)
|
||||
target_include_directories(example-vm PRIVATE ../include)
|
||||
|
||||
add_executable(example-capi EXCLUDE_FROM_ALL capi.c)
|
||||
add_executable(example-capi capi.c)
|
||||
target_include_directories(example-capi PRIVATE ../include)
|
||||
target_link_libraries(example-capi PRIVATE example-vm)
|
||||
|
|
|
@ -16,41 +16,43 @@ struct evm_uint160be address(struct evm_env* env)
|
|||
return ret;
|
||||
}
|
||||
|
||||
union evm_variant query(struct evm_env* env,
|
||||
enum evm_query_key key,
|
||||
union evm_variant arg) {
|
||||
union evm_variant result;
|
||||
static void query(union evm_variant* result,
|
||||
struct evm_env* env,
|
||||
enum evm_query_key key,
|
||||
const union evm_variant* arg) {
|
||||
printf("EVM-C: QUERY %d\n", key);
|
||||
switch (key) {
|
||||
case EVM_GAS_LIMIT: result.int64 = 314; break;
|
||||
case EVM_GAS_LIMIT:
|
||||
result->int64 = 314;
|
||||
break;
|
||||
|
||||
case EVM_BALANCE:
|
||||
result.uint256be = balance(env, arg.address);
|
||||
result->uint256be = balance(env, arg->address);
|
||||
break;
|
||||
|
||||
case EVM_ADDRESS:
|
||||
result.address = address(env);
|
||||
result->address = address(env);
|
||||
break;
|
||||
|
||||
default: result.int64 = 0; break;
|
||||
default:
|
||||
result->int64 = 0;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void update(struct evm_env* env,
|
||||
enum evm_update_key key,
|
||||
union evm_variant arg1,
|
||||
union evm_variant arg2)
|
||||
static void update(struct evm_env* env,
|
||||
enum evm_update_key key,
|
||||
const union evm_variant* arg1,
|
||||
const union evm_variant* arg2)
|
||||
{
|
||||
printf("EVM-C: UPDATE %d\n", key);
|
||||
}
|
||||
|
||||
int64_t call(
|
||||
static int64_t call(
|
||||
struct evm_env* _opaqueEnv,
|
||||
enum evm_call_kind _kind,
|
||||
int64_t _gas,
|
||||
struct evm_uint160be _address,
|
||||
struct evm_uint256be _value,
|
||||
const struct evm_uint160be* _address,
|
||||
const struct evm_uint256be* _value,
|
||||
uint8_t const* _inputData,
|
||||
size_t _inputSize,
|
||||
uint8_t* _outputData,
|
||||
|
@ -63,19 +65,22 @@ int64_t call(
|
|||
|
||||
/// Example how the API is supposed to be used.
|
||||
int main(int argc, char *argv[]) {
|
||||
struct evm_interface intf = examplevm_get_interface();
|
||||
struct evm_instance* jit = intf.create(query, update, call);
|
||||
struct evm_factory factory = examplevm_get_factory();
|
||||
if (factory.abi_version != EVM_ABI_VERSION)
|
||||
return 1; // Incompatible ABI version.
|
||||
|
||||
char const code[] = "exec()";
|
||||
struct evm_instance* jit = factory.create(query, update, call);
|
||||
|
||||
uint8_t const code[] = "Place some EVM bytecode here";
|
||||
const size_t code_size = sizeof(code);
|
||||
struct evm_uint256be code_hash = {.bytes = {1, 2, 3,}};
|
||||
char const input[] = "Hello World!";
|
||||
uint8_t const input[] = "Hello World!";
|
||||
struct evm_uint256be value = {{1, 0, 0, 0}};
|
||||
|
||||
int64_t gas = 200000;
|
||||
struct evm_result result =
|
||||
intf.execute(jit, NULL, EVM_HOMESTEAD, code_hash, (const uint8_t *)code, code_size, gas, (const uint8_t *)input,
|
||||
sizeof(input), value);
|
||||
jit->execute(jit, NULL, EVM_HOMESTEAD, code_hash, code, code_size, gas,
|
||||
input, sizeof(input), value);
|
||||
|
||||
printf("Execution result:\n");
|
||||
if (result.code != EVM_SUCCESS) {
|
||||
|
@ -94,5 +99,5 @@ int main(int argc, char *argv[]) {
|
|||
}
|
||||
|
||||
result.release(&result);
|
||||
intf.destroy(jit);
|
||||
jit->destroy(jit);
|
||||
}
|
||||
|
|
|
@ -2,27 +2,15 @@
|
|||
#include <string.h>
|
||||
#include "evm.h"
|
||||
|
||||
struct evm_instance {
|
||||
|
||||
struct examplevm
|
||||
{
|
||||
struct evm_instance instance;
|
||||
evm_query_fn query_fn;
|
||||
evm_update_fn update_fn;
|
||||
evm_call_fn call_fn;
|
||||
};
|
||||
|
||||
static struct evm_instance* evm_create(evm_query_fn query_fn,
|
||||
evm_update_fn update_fn,
|
||||
evm_call_fn call_fn)
|
||||
{
|
||||
struct evm_instance *ret = calloc(1, sizeof(struct evm_instance));
|
||||
|
||||
if (ret) {
|
||||
ret->query_fn = query_fn;
|
||||
ret->update_fn = update_fn;
|
||||
ret->call_fn = call_fn;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void evm_destroy(struct evm_instance* evm)
|
||||
{
|
||||
free(evm);
|
||||
|
@ -66,13 +54,23 @@ static struct evm_result evm_execute(struct evm_instance* instance,
|
|||
return ret;
|
||||
}
|
||||
|
||||
struct evm_interface examplevm_get_interface()
|
||||
static struct evm_instance* evm_create(evm_query_fn query_fn,
|
||||
evm_update_fn update_fn,
|
||||
evm_call_fn call_fn)
|
||||
{
|
||||
struct evm_interface intf = {};
|
||||
intf.abi_version = EVM_ABI_VERSION;
|
||||
intf.create = evm_create;
|
||||
intf.destroy = evm_destroy;
|
||||
intf.execute = evm_execute;
|
||||
intf.set_option = evm_set_option;
|
||||
return intf;
|
||||
struct examplevm* vm = calloc(1, sizeof(struct examplevm));
|
||||
struct evm_instance* interface = &vm->instance;
|
||||
interface->destroy = evm_destroy;
|
||||
interface->execute = evm_execute;
|
||||
interface->set_option = evm_set_option;
|
||||
vm->query_fn = query_fn;
|
||||
vm->update_fn = update_fn;
|
||||
vm->call_fn = call_fn;
|
||||
return interface;
|
||||
}
|
||||
|
||||
struct evm_factory examplevm_get_factory()
|
||||
{
|
||||
struct evm_factory factory = {EVM_ABI_VERSION, evm_create};
|
||||
return factory;
|
||||
}
|
||||
|
|
102
include/evm.h
102
include/evm.h
|
@ -25,7 +25,7 @@ extern "C" {
|
|||
// BEGIN Python CFFI declarations
|
||||
|
||||
/// The EVM-C ABI version number matching the interface declared in this file.
|
||||
static const uint32_t EVM_ABI_VERSION = 0;
|
||||
enum { EVM_ABI_VERSION = 0 };
|
||||
|
||||
/// Big-endian 256-bit integer.
|
||||
///
|
||||
|
@ -55,7 +55,7 @@ enum evm_result_code {
|
|||
EVM_STACK_UNDERFLOW = 6,
|
||||
};
|
||||
|
||||
struct evm_result;
|
||||
struct evm_result; ///< Forward declaration.
|
||||
|
||||
/// Releases resources assigned to an execution result.
|
||||
///
|
||||
|
@ -77,25 +77,12 @@ struct evm_result {
|
|||
/// The value is valid only if evm_result::code == ::EVM_SUCCESS.
|
||||
int64_t gas_left;
|
||||
|
||||
union
|
||||
{
|
||||
struct
|
||||
{
|
||||
/// The reference to output data. The memory containing the output
|
||||
/// data is owned by EVM and is freed with evm_result::release().
|
||||
uint8_t const* output_data;
|
||||
/// The reference to output data. The memory containing the output
|
||||
/// data is owned by EVM and is freed with evm_result::release().
|
||||
uint8_t const* output_data;
|
||||
|
||||
/// The size of the output data.
|
||||
size_t output_size;
|
||||
};
|
||||
|
||||
/// The address of the successfully created contract.
|
||||
///
|
||||
/// This field has valid value only if the evm_result comes from a
|
||||
/// successful CREATE opcode execution
|
||||
/// (i.e. evm_call_fn(..., EVM_CREATE, ...)).
|
||||
struct evm_uint160be create_address;
|
||||
};
|
||||
/// The size of the output data.
|
||||
size_t output_size;
|
||||
|
||||
/// The pointer to the result release implementation.
|
||||
///
|
||||
|
@ -242,9 +229,10 @@ union evm_variant {
|
|||
/// @param arg evm_variant::uint256be The index of the storage entry.
|
||||
/// @result evm_variant::uint256be The current value of the storage entry.
|
||||
///
|
||||
typedef union evm_variant (*evm_query_fn)(struct evm_env* env,
|
||||
enum evm_query_key key,
|
||||
union evm_variant arg);
|
||||
typedef void (*evm_query_fn)(union evm_variant* result,
|
||||
struct evm_env* env,
|
||||
enum evm_query_key key,
|
||||
const union evm_variant* arg);
|
||||
|
||||
/// The update callback key.
|
||||
enum evm_update_key {
|
||||
|
@ -282,8 +270,8 @@ enum evm_update_key {
|
|||
/// @param arg2 n/a
|
||||
typedef void (*evm_update_fn)(struct evm_env* env,
|
||||
enum evm_update_key key,
|
||||
union evm_variant arg1,
|
||||
union evm_variant arg2);
|
||||
const union evm_variant* arg1,
|
||||
const union evm_variant* arg2);
|
||||
|
||||
/// The kind of call-like instruction.
|
||||
enum evm_call_kind {
|
||||
|
@ -293,8 +281,8 @@ enum evm_call_kind {
|
|||
EVM_CREATE = 3 ///< Request CREATE. Semantic of some params changes.
|
||||
};
|
||||
|
||||
/// The flag indicating call failure in evm_call_fn().
|
||||
static const int64_t EVM_CALL_FAILURE = INT64_MIN;
|
||||
/// The flag indicating call failure in evm_call_fn() -- highest bit set.
|
||||
static const int64_t EVM_CALL_FAILURE = 0x8000000000000000;
|
||||
|
||||
/// Pointer to the callback function supporting EVM calls.
|
||||
///
|
||||
|
@ -321,23 +309,20 @@ typedef int64_t (*evm_call_fn)(
|
|||
struct evm_env* env,
|
||||
enum evm_call_kind kind,
|
||||
int64_t gas,
|
||||
struct evm_uint160be address,
|
||||
struct evm_uint256be value,
|
||||
const struct evm_uint160be* address,
|
||||
const struct evm_uint256be* value,
|
||||
uint8_t const* input,
|
||||
size_t input_size,
|
||||
uint8_t* output,
|
||||
size_t output_size);
|
||||
|
||||
|
||||
/// Opaque type representing a EVM instance.
|
||||
struct evm_instance;
|
||||
struct evm_instance; ///< Forward declaration.
|
||||
|
||||
/// Creates new EVM instance.
|
||||
/// Creates the EVM instance.
|
||||
///
|
||||
/// Creates new EVM instance. The instance must be destroyed in evm_destroy().
|
||||
/// Single instance is thread-safe and can be shared by many threads. Having
|
||||
/// **multiple instances is safe but discouraged** as it has not benefits over
|
||||
/// having the singleton.
|
||||
/// Creates and initializes an EVM instance by providing the information
|
||||
/// about runtime callback functions.
|
||||
///
|
||||
/// @param query_fn Pointer to query callback function. Nonnull.
|
||||
/// @param update_fn Pointer to update callback function. Nonnull.
|
||||
|
@ -438,23 +423,14 @@ typedef void (*evm_prepare_code_fn)(struct evm_instance* instance,
|
|||
uint8_t const* code,
|
||||
size_t code_size);
|
||||
|
||||
/// VM interface.
|
||||
/// The EVM instance.
|
||||
///
|
||||
/// Defines the implementation of EVM-C interface for a VM.
|
||||
struct evm_interface {
|
||||
/// EVM-C ABI version implemented by the VM.
|
||||
///
|
||||
/// For future use to detect ABI incompatibilities. The EVM-C ABI version
|
||||
/// represented by this file is in ::EVM_ABI_VERSION.
|
||||
uint32_t abi_version;
|
||||
|
||||
/// Pointer to function creating a VM's instance.
|
||||
evm_create_fn create;
|
||||
|
||||
/// Pointer to function destroying a VM's instance.
|
||||
/// Defines the base struct of the EVM implementation.
|
||||
struct evm_instance {
|
||||
/// Pointer to function destroying the EVM instance.
|
||||
evm_destroy_fn destroy;
|
||||
|
||||
/// Pointer to function execuing a code in a VM.
|
||||
/// Pointer to function executing a code by the EVM instance.
|
||||
evm_execute_fn execute;
|
||||
|
||||
/// Optional pointer to function returning a status of a code.
|
||||
|
@ -473,16 +449,30 @@ struct evm_interface {
|
|||
evm_set_option_fn set_option;
|
||||
};
|
||||
|
||||
/// The EVM instance factory.
|
||||
///
|
||||
/// 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;
|
||||
};
|
||||
|
||||
// END Python CFFI declarations
|
||||
|
||||
/// Example of a function exporting an interface for an example VM.
|
||||
/// Example of a function creating uninitialized instance of 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(void)`.
|
||||
/// Each EVM implementation is obligated to provided a function returning
|
||||
/// an EVM instance.
|
||||
/// The function has to be named as `<vm-name>_get_factory(void)`.
|
||||
///
|
||||
/// @return VM interface
|
||||
struct evm_interface examplevm_get_interface(void);
|
||||
/// @return EVM instance.
|
||||
struct evm_factory examplevm_get_factory(void);
|
||||
|
||||
|
||||
#if __cplusplus
|
||||
|
|
Loading…
Reference in New Issue