Skip to content

Commit

Permalink
Merge pull request #112 from ethereum/evmc-v3
Browse files Browse the repository at this point in the history
EVM-C v3
  • Loading branch information
chfast authored May 10, 2017
2 parents d7c7605 + 26b2b97 commit 40151fd
Show file tree
Hide file tree
Showing 11 changed files with 442 additions and 273 deletions.
52 changes: 33 additions & 19 deletions examples/capi.c
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@
#include "evm.h"


struct evm_uint256be balance(struct evm_env* env, struct evm_uint160be address)
struct evm_uint256be balance(struct evm_env* env,
const struct evm_uint160be* address)
{
struct evm_uint256be ret = {.bytes = {1, 2, 3, 4}};
return ret;
Expand All @@ -19,19 +20,21 @@ struct evm_uint160be address(struct evm_env* env)
static void query(union evm_variant* result,
struct evm_env* env,
enum evm_query_key key,
const union evm_variant* arg) {
const struct evm_uint160be* address,
const struct evm_uint256be* storage_key) {
printf("EVM-C: QUERY %d\n", key);
switch (key) {
case EVM_GAS_LIMIT:
result->int64 = 314;
case EVM_CODE_BY_ADDRESS:
result->data = NULL;
result->data_size = 0;
break;

case EVM_BALANCE:
result->uint256be = balance(env, arg->address);
result->uint256be = balance(env, address);
break;

case EVM_ADDRESS:
result->address = address(env);
case EVM_ACCOUNT_EXISTS:
result->int64 = 0;
break;

default:
Expand All @@ -41,6 +44,7 @@ static void query(union evm_variant* result,

static void update(struct evm_env* env,
enum evm_update_key key,
const struct evm_uint160be* addr,
const union evm_variant* arg1,
const union evm_variant* arg2)
{
Expand All @@ -49,38 +53,48 @@ static void update(struct evm_env* env,

static int64_t call(
struct evm_env* _opaqueEnv,
enum evm_call_kind _kind,
int64_t _gas,
const struct evm_uint160be* _address,
const struct evm_uint256be* _value,
uint8_t const* _inputData,
size_t _inputSize,
const struct evm_message* _msg,
uint8_t* _outputData,
size_t _outputSize
)
{
printf("EVM-C: CALL %d\n", _kind);
printf("EVM-C: CALL (depth: %d)\n", _msg->depth);
return EVM_CALL_FAILURE;
}

static void get_tx_context(struct evm_tx_context* result, struct evm_env* env)
{

}

static void get_block_hash(struct evm_uint256be* result, struct evm_env* env,
int64_t number)
{

}

/// Example how the API is supposed to be used.
int main(int argc, char *argv[]) {
struct evm_factory factory = examplevm_get_factory();
if (factory.abi_version != EVM_ABI_VERSION)
return 1; // Incompatible ABI version.

struct evm_instance* jit = factory.create(query, update, call);
struct evm_instance* jit = factory.create(query, update, call,
get_tx_context, get_block_hash);

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,}};
uint8_t const input[] = "Hello World!";
struct evm_uint256be value = {{1, 0, 0, 0}};

struct evm_uint256be value = {{1, 0,}};
struct evm_uint160be addr = {{0, 1, 2,}};
int64_t gas = 200000;

struct evm_message msg = {addr, addr, value, input, sizeof(input),
code_hash, gas, 0};

struct evm_result result =
jit->execute(jit, NULL, EVM_HOMESTEAD, code_hash, code, code_size, gas,
input, sizeof(input), value);
jit->execute(jit, NULL, EVM_HOMESTEAD, &msg, code, code_size);

printf("Execution result:\n");
if (result.code != EVM_SUCCESS) {
Expand Down
84 changes: 55 additions & 29 deletions examples/examplevm.c
Original file line number Diff line number Diff line change
@@ -1,14 +1,19 @@
#include <stdlib.h>
#include <string.h>
#include <limits.h>
#include "evm.h"


struct examplevm
{
struct evm_instance instance;
evm_query_fn query_fn;
evm_update_fn update_fn;
evm_query_state_fn query_fn;
evm_update_state_fn update_fn;
evm_call_fn call_fn;
evm_get_tx_context_fn get_tx_context_fn;
evm_get_block_hash_fn get_block_hash_fn;

int example_option;
};

static void evm_destroy(struct evm_instance* evm)
Expand All @@ -19,12 +24,19 @@ static void evm_destroy(struct evm_instance* evm)
/// Example options.
///
/// VMs are allowed to omit this function implementation.
int evm_set_option(struct evm_instance* evm,
int evm_set_option(struct evm_instance* instance,
char const* name,
char const* value)
{
if (strcmp(name, "example-option") == 0)
struct examplevm* vm = (struct examplevm*)instance;
if (strcmp(name, "example-option") == 0) {
long int v = strtol(value, NULL, 0);
if (v > INT_MAX || v < INT_MIN)
return 0;
vm->example_option = (int)v;
return 1;
}

return 0;
}

Expand All @@ -37,24 +49,20 @@ static void free_result_output_data(struct evm_result const* result)
free((uint8_t*)result->output_data);
}

static struct evm_result evm_execute(struct evm_instance* instance,
struct evm_env* env,
enum evm_mode mode,
struct evm_uint256be code_hash,
uint8_t const* code,
size_t code_size,
int64_t gas,
uint8_t const* input,
size_t input_size,
struct evm_uint256be value)
static struct evm_result execute(struct evm_instance* instance,
struct evm_env* env,
enum evm_mode mode,
const struct evm_message* msg,
const uint8_t* code,
size_t code_size)
{
struct evm_result ret = {};
if (code_size == 0) {
// In case of empty code return a fancy error message.
const char* msg = mode == EVM_METROPOLIS ?
"Welcome to Metropolis!" : "Hello Ethereum!";
ret.output_data = (const uint8_t*)msg;
ret.output_size = strlen(msg);
const char* error = mode == EVM_METROPOLIS ?
"Welcome to Metropolis!" : "Hello Ethereum!";
ret.output_data = (const uint8_t*)error;
ret.output_size = strlen(error);
ret.code = EVM_FAILURE;
ret.release = NULL; // We don't need to release the constant messages.
return ret;
Expand All @@ -66,26 +74,40 @@ static struct evm_result evm_execute(struct evm_instance* instance,
// Solidity inline assembly is used in the examples instead of EVM bytecode.

// Assembly: `{ mstore(0, address()) return(0, msize()) }`.
const char return_by_address[] = "30600052596000f3";
if (code_size == strlen(return_by_address) &&
strncmp((const char*)code, return_by_address, code_size)) {
union evm_variant query_result;
vm->query_fn(&query_result, env, EVM_ADDRESS, NULL);
static const size_t address_size = sizeof(query_result.address);
const char return_address[] = "30600052596000f3";

// Assembly: `{ sstore(0, add(sload(0), 1)) }`
const char counter[] = "600160005401600055";

if (code_size == strlen(return_address) &&
strncmp((const char*)code, return_address, code_size)) {
static const size_t address_size = sizeof(msg->address);
uint8_t* output_data = (uint8_t*)malloc(address_size);
if (!output_data) {
// malloc failed, report internal error.
ret.code = EVM_INTERNAL_ERROR;
return ret;
}
memcpy(output_data, &query_result.address, address_size);
memcpy(output_data, &msg->address, address_size);
ret.code = EVM_SUCCESS;
ret.output_data = output_data;
ret.output_size = address_size;
ret.release = &free_result_output_data;
ret.context = NULL; // We don't need another pointer.
return ret;
}
else if (code_size == strlen(counter) &&
strncmp((const char*)code, counter, code_size)) {
union evm_variant value;
const struct evm_uint256be index = {{0,}};
vm->query_fn(&value, env, EVM_SLOAD, &msg->address, &index);
value.uint256be.bytes[31] += 1;
union evm_variant arg;
arg.uint256be = index;
vm->update_fn(env, EVM_SSTORE, &msg->address, &arg, &value);
ret.code = EVM_SUCCESS;
return ret;
}

ret.release = evm_release_result;
ret.code = EVM_FAILURE;
Expand All @@ -94,18 +116,22 @@ static struct evm_result evm_execute(struct evm_instance* instance,
return ret;
}

static struct evm_instance* evm_create(evm_query_fn query_fn,
evm_update_fn update_fn,
evm_call_fn call_fn)
static struct evm_instance* evm_create(evm_query_state_fn query_fn,
evm_update_state_fn update_fn,
evm_call_fn call_fn,
evm_get_tx_context_fn get_tx_context_fn,
evm_get_block_hash_fn get_block_hash_fn)
{
struct examplevm* vm = calloc(1, sizeof(struct examplevm));
struct evm_instance* interface = &vm->instance;
interface->destroy = evm_destroy;
interface->execute = evm_execute;
interface->execute = execute;
interface->set_option = evm_set_option;
vm->query_fn = query_fn;
vm->update_fn = update_fn;
vm->call_fn = call_fn;
vm->get_tx_context_fn = get_tx_context_fn;
vm->get_block_hash_fn = get_block_hash_fn;
return interface;
}

Expand Down
Loading

0 comments on commit 40151fd

Please sign in to comment.