2016-08-22 17:22:34 +00:00
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include "evm.h"
|
|
|
|
|
2016-12-20 15:50:23 +00:00
|
|
|
|
|
|
|
struct examplevm
|
|
|
|
{
|
|
|
|
struct evm_instance instance;
|
2017-01-20 12:38:11 +00:00
|
|
|
evm_query_state_fn query_fn;
|
2017-01-20 13:02:35 +00:00
|
|
|
evm_update_state_fn update_fn;
|
2016-08-22 17:22:34 +00:00
|
|
|
evm_call_fn call_fn;
|
2017-01-18 22:26:48 +00:00
|
|
|
evm_get_tx_context_fn get_tx_context_fn;
|
2017-01-19 21:39:21 +00:00
|
|
|
evm_get_block_hash_fn get_block_hash_fn;
|
2016-08-22 17:22:34 +00:00
|
|
|
};
|
|
|
|
|
2016-08-23 10:58:09 +00:00
|
|
|
static void evm_destroy(struct evm_instance* evm)
|
2016-08-22 17:22:34 +00:00
|
|
|
{
|
|
|
|
free(evm);
|
|
|
|
}
|
|
|
|
|
2016-08-23 19:24:22 +00:00
|
|
|
/// Example options.
|
|
|
|
///
|
|
|
|
/// VMs are allowed to omit this function implementation.
|
|
|
|
int evm_set_option(struct evm_instance* evm,
|
|
|
|
char const* name,
|
|
|
|
char const* value)
|
|
|
|
{
|
|
|
|
if (strcmp(name, "example-option") == 0)
|
|
|
|
return 1;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2016-09-27 15:14:19 +00:00
|
|
|
static void evm_release_result(struct evm_result const* result)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2017-04-24 15:32:28 +00:00
|
|
|
static void free_result_output_data(struct evm_result const* result)
|
|
|
|
{
|
|
|
|
free((uint8_t*)result->output_data);
|
|
|
|
}
|
|
|
|
|
2016-08-23 10:58:09 +00:00
|
|
|
static struct evm_result evm_execute(struct evm_instance* instance,
|
2016-08-22 17:22:34 +00:00
|
|
|
struct evm_env* env,
|
|
|
|
enum evm_mode mode,
|
2016-08-31 09:40:02 +00:00
|
|
|
struct evm_uint256be code_hash,
|
2016-08-22 17:22:34 +00:00
|
|
|
uint8_t const* code,
|
|
|
|
size_t code_size,
|
2017-01-12 15:45:14 +00:00
|
|
|
struct evm_message message)
|
2016-08-22 17:22:34 +00:00
|
|
|
{
|
2016-09-28 14:50:13 +00:00
|
|
|
struct evm_result ret = {};
|
2017-04-24 15:32:28 +00:00
|
|
|
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);
|
|
|
|
ret.code = EVM_FAILURE;
|
|
|
|
ret.release = NULL; // We don't need to release the constant messages.
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
struct examplevm* vm = (struct examplevm*)instance;
|
|
|
|
|
2017-04-25 15:01:46 +00:00
|
|
|
// Simulate executing by checking for some code patterns.
|
|
|
|
// Solidity inline assembly is used in the examples instead of EVM bytecode.
|
2016-08-22 17:22:34 +00:00
|
|
|
|
2017-04-25 15:01:46 +00:00
|
|
|
// 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)) {
|
2017-04-24 15:32:28 +00:00
|
|
|
union evm_variant query_result;
|
|
|
|
vm->query_fn(&query_result, env, EVM_ADDRESS, NULL);
|
|
|
|
static const size_t address_size = sizeof(query_result.address);
|
|
|
|
uint8_t* output_data = (uint8_t*)malloc(address_size);
|
2017-04-25 15:01:46 +00:00
|
|
|
if (!output_data) {
|
|
|
|
// malloc failed, report internal error.
|
|
|
|
ret.code = EVM_INTERNAL_ERROR;
|
|
|
|
return ret;
|
|
|
|
}
|
2017-01-12 15:45:14 +00:00
|
|
|
memcpy(output_data, &message.address, address_size);
|
2017-04-24 15:32:28 +00:00
|
|
|
ret.code = EVM_SUCCESS;
|
|
|
|
ret.output_data = output_data;
|
|
|
|
ret.output_size = address_size;
|
|
|
|
ret.release = &free_result_output_data;
|
2017-04-25 17:05:49 +00:00
|
|
|
ret.context = NULL; // We don't need another pointer.
|
2017-04-24 15:32:28 +00:00
|
|
|
return ret;
|
|
|
|
}
|
2016-08-22 17:22:34 +00:00
|
|
|
|
2016-09-27 15:14:19 +00:00
|
|
|
ret.release = evm_release_result;
|
2016-08-25 11:44:34 +00:00
|
|
|
ret.code = EVM_FAILURE;
|
2016-08-22 17:22:34 +00:00
|
|
|
ret.gas_left = 0;
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2017-01-20 12:38:11 +00:00
|
|
|
static struct evm_instance* evm_create(evm_query_state_fn query_fn,
|
2017-01-20 13:02:35 +00:00
|
|
|
evm_update_state_fn update_fn,
|
2017-01-18 22:26:48 +00:00
|
|
|
evm_call_fn call_fn,
|
2017-01-19 21:39:21 +00:00
|
|
|
evm_get_tx_context_fn get_tx_context_fn,
|
|
|
|
evm_get_block_hash_fn get_block_hash_fn)
|
2016-12-20 15:50:23 +00:00
|
|
|
{
|
|
|
|
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;
|
2017-01-18 22:26:48 +00:00
|
|
|
vm->get_tx_context_fn = get_tx_context_fn;
|
2017-01-19 21:39:21 +00:00
|
|
|
vm->get_block_hash_fn = get_block_hash_fn;
|
2016-12-20 15:50:23 +00:00
|
|
|
return interface;
|
|
|
|
}
|
|
|
|
|
|
|
|
struct evm_factory examplevm_get_factory()
|
2016-08-22 17:22:34 +00:00
|
|
|
{
|
2016-12-20 15:50:23 +00:00
|
|
|
struct evm_factory factory = {EVM_ABI_VERSION, evm_create};
|
|
|
|
return factory;
|
2016-09-28 14:50:13 +00:00
|
|
|
}
|