From fc47787b7966e1c5a295544177fd0d13baf2b3c4 Mon Sep 17 00:00:00 2001 From: Alex Beregszaszi Date: Mon, 22 Aug 2016 18:22:34 +0100 Subject: [PATCH 1/7] EVM-C: include ExampleVM --- examples/examplevm.c | 88 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 88 insertions(+) create mode 100644 examples/examplevm.c diff --git a/examples/examplevm.c b/examples/examplevm.c new file mode 100644 index 0000000..a6c4246 --- /dev/null +++ b/examples/examplevm.c @@ -0,0 +1,88 @@ +#include +#include +#include +#include "evm.h" + +struct evm_instance { + evm_query_fn query_fn; + evm_update_fn update_fn; + evm_call_fn call_fn; +}; + +EXPORT char const* evm_get_info(enum evm_info_key key) +{ + switch(key) { + case EVM_NAME: return "ExampleVM"; break; + case EVM_VERSION: return "git"; break; + } + + return ""; +} + +EXPORT 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; +} + +EXPORT void evm_destroy(struct evm_instance* evm) +{ + free(evm); +} + +EXPORT bool evm_set_option(struct evm_instance* evm, + char const* name, + char const* value) +{ + return false; +} + +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) +{ + struct evm_result ret; + + memset(&ret, 0, sizeof(struct evm_result)); + + // Execute code and refer to callbacks: instance->query_fn() + + ret.gas_left = 0; + + return ret; +} + +EXPORT void evm_destroy_result(struct evm_result result) +{ +} + +EXPORT bool evmjit_is_code_ready(struct evm_instance* instance, + enum evm_mode mode, + struct evm_hash256 code_hash) +{ + 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) +{ +} From 2b46c72c391ae7dc1f682c9c859d7866be780d6f Mon Sep 17 00:00:00 2001 From: Alex Beregszaszi Date: Mon, 22 Aug 2016 18:24:30 +0100 Subject: [PATCH 2/7] EVM-C: trying to fix Doxygen for evm_update_fn --- include/evm.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/evm.h b/include/evm.h index 98e4cb8..a59cd73 100644 --- a/include/evm.h +++ b/include/evm.h @@ -191,7 +191,7 @@ enum evm_update_key { /// ----------------------| -------------------- | -------------------- /// ::EVM_SSTORE | evm_variant::uint256 | evm_variant::uint256 /// ::EVM_LOG | evm_variant::data | evm_variant::data -/// ::EVM_SELFDESTRUCT | evm_variant::address | +/// ::EVM_SELFDESTRUCT | evm_variant::address | n/a typedef void (*evm_update_fn)(struct evm_env* env, enum evm_update_key key, union evm_variant arg1, From 787644293c0a56709a88e2ac02483614e1e145aa Mon Sep 17 00:00:00 2001 From: Alex Beregszaszi Date: Mon, 22 Aug 2016 18:25:13 +0100 Subject: [PATCH 3/7] EVM-C: highlight CREATE in evm_call_fn --- include/evm.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/include/evm.h b/include/evm.h index a59cd73..fd9bf60 100644 --- a/include/evm.h +++ b/include/evm.h @@ -215,13 +215,13 @@ enum evm_call_kind { /// of CREATE. /// @param value The value sent to the callee. The endowment in case of /// CREATE. -/// @param input The call input data or the create init code. +/// @param input The call input data or the CREATE init code. /// @param input_size The size of the input data. /// @param output The reference to the memory where the call output is to -/// be copied. In case of create, the memory is guaranteed +/// be copied. In case of CREATE, the memory is guaranteed /// to be at least 160 bytes to hold the address of the /// created contract. -/// @param output_data The size of the output data. In case of create, expected +/// @param output_data The size of the output data. In case of CREATE, expected /// value is 160. /// @return If non-negative - the amount of gas left, /// If negative - an exception occurred during the call/create. From 9c3ff6d4b3b0336e17dade4029baba22547239c3 Mon Sep 17 00:00:00 2001 From: Alex Beregszaszi Date: Mon, 22 Aug 2016 18:25:35 +0100 Subject: [PATCH 4/7] EVM-C: response is 20 bytes address to CREATE (and not 160 bytes) --- include/evm.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/evm.h b/include/evm.h index fd9bf60..d6cec2c 100644 --- a/include/evm.h +++ b/include/evm.h @@ -219,10 +219,10 @@ enum evm_call_kind { /// @param input_size The size of the input data. /// @param output The reference to the memory where the call output is to /// be copied. In case of CREATE, the memory is guaranteed -/// to be at least 160 bytes to hold the address of the +/// to be at least 20 bytes to hold the address of the /// created contract. /// @param output_data The size of the output data. In case of CREATE, expected -/// value is 160. +/// value is 20. /// @return If non-negative - the amount of gas left, /// If negative - an exception occurred during the call/create. /// There is no need to set 0 address in the output in this case. From 8ae6f4eae68815c2b0a149823e99b4b946901ed4 Mon Sep 17 00:00:00 2001 From: Alex Beregszaszi Date: Mon, 22 Aug 2016 18:26:37 +0100 Subject: [PATCH 5/7] EVM-C: mark evm_hash160 big-endian --- include/evm.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/evm.h b/include/evm.h index d6cec2c..e0d4cb1 100644 --- a/include/evm.h +++ b/include/evm.h @@ -39,7 +39,7 @@ struct evm_uint256 { uint64_t words[4]; }; -/// 160-bit hash suitable for keeping an Ethereum address. +/// Big-endian 160-bit hash suitable for keeping an Ethereum address. struct evm_hash160 { /// The 20 bytes of the hash. uint8_t bytes[20]; From 2bb6a4a6901702954e5844bad5e83c3f385169f2 Mon Sep 17 00:00:00 2001 From: Alex Beregszaszi Date: Mon, 22 Aug 2016 21:39:34 +0100 Subject: [PATCH 6/7] EVM-C: include ExampleVM in CMake --- examples/CMakeLists.txt | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index 1ceaeea..f938d71 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -1,2 +1,5 @@ add_library(example-capi STATIC EXCLUDE_FROM_ALL capi.c) -target_include_directories(example-capi PRIVATE ../include) \ No newline at end of file +target_include_directories(example-capi PRIVATE ../include) + +add_library(example-vm STATIC EXCLUDE_FROM_ALL examplevm.c) +target_include_directories(example-vm PRIVATE ../include) From 8c2f9d44e8313ca825440dc9021964c1c03ae1f9 Mon Sep 17 00:00:00 2001 From: Alex Beregszaszi Date: Mon, 22 Aug 2016 21:51:43 +0100 Subject: [PATCH 7/7] EVM-C: improve capi.c and compile against ExampleVM --- examples/CMakeLists.txt | 7 +++-- examples/capi.c | 67 ++++++++++++++++++++++++++++++++++++++--- 2 files changed, 67 insertions(+), 7 deletions(-) diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index f938d71..ee599ab 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -1,5 +1,6 @@ -add_library(example-capi STATIC EXCLUDE_FROM_ALL capi.c) -target_include_directories(example-capi PRIVATE ../include) - add_library(example-vm STATIC EXCLUDE_FROM_ALL examplevm.c) target_include_directories(example-vm PRIVATE ../include) + +add_executable(example-capi EXCLUDE_FROM_ALL capi.c) +target_include_directories(example-capi PRIVATE ../include) +target_link_libraries(example-capi PRIVATE example-vm) diff --git a/examples/capi.c b/examples/capi.c index cd16381..01b8d3e 100644 --- a/examples/capi.c +++ b/examples/capi.c @@ -1,11 +1,25 @@ +#include +#include +#include #include "evm.h" -struct evm_uint256 balance(struct evm_env*, struct evm_hash160 address); +struct evm_uint256 balance(struct evm_env* env, struct evm_hash160 address) +{ + struct evm_uint256 ret = { .words = { 1 } }; + return ret; +} + +struct evm_hash160 address(struct evm_env* env) +{ + struct evm_hash160 ret = { .bytes = { 1, 2, 3, 4 } }; + return ret; +} union evm_variant query(struct evm_env* env, enum evm_query_key key, union evm_variant arg) { union evm_variant result; + printf("EVM-C: QUERY %d\n", key); switch (key) { case EVM_GAS_LIMIT: result.int64 = 314; break; @@ -13,25 +27,70 @@ union evm_variant query(struct evm_env* env, result.uint256 = balance(env, arg.address); break; + case EVM_ADDRESS: + result.address = address(env); + break; + default: result.int64 = 0; break; } return result; } +void update(struct evm_env* env, + enum evm_update_key key, + union evm_variant arg1, + union evm_variant arg2) +{ + printf("EVM-C: UPDATE %d\n", key); +} + +int64_t call( + struct evm_env* _opaqueEnv, + enum evm_call_kind _kind, + int64_t _gas, + struct evm_hash160 _address, + struct evm_uint256 _value, + uint8_t const* _inputData, + size_t _inputSize, + uint8_t* _outputData, + size_t _outputSize +) +{ + printf("EVM-C: CALL %d\n", _kind); + return EVM_EXCEPTION; +} + /// Example how the API is supposed to be used. -void example() { - struct evm_instance* jit = evm_create(query, 0, 0); +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); char const code[] = "exec()"; + const size_t code_size = sizeof(code); struct evm_hash256 code_hash = {.words = {1, 2, 3}}; char const input[] = "Hello World!"; struct evm_uint256 value = {{1, 0, 0, 0}}; int64_t gas = 200000; struct evm_result result = - evm_execute(jit, NULL, code_hash, code, sizeof(code), gas, input, + evm_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(" Output size: %zd\n", result.output_size); + + printf(" Output: "); + for (int i = 0; i < result.output_size; i++) { + printf("%02x ", result.output_data[i]); + } + printf("\n"); + evm_destroy_result(result); evm_destroy(jit); }