evmc/examples/examplevm/examplevm.c

127 lines
3.7 KiB
C
Raw Normal View History

2018-03-28 13:40:18 +00:00
#include <evmc.h>
#include <limits.h>
#include <stdio.h>
2016-08-22 17:22:34 +00:00
#include <stdlib.h>
#include <string.h>
struct examplevm
{
2018-03-28 13:09:07 +00:00
struct evmc_instance instance;
int verbose;
2016-08-22 17:22:34 +00:00
};
2018-03-28 13:09:07 +00:00
static void evmc_destroy(struct evmc_instance* evm)
2016-08-22 17:22:34 +00:00
{
free(evm);
}
/// Example options.
///
/// VMs are allowed to omit this function implementation.
2018-04-13 06:39:47 +00:00
int evmc_set_option(struct evmc_instance* instance, char const* name, char const* value)
{
2017-04-25 18:07:50 +00:00
struct examplevm* vm = (struct examplevm*)instance;
2018-04-13 06:39:47 +00:00
if (strcmp(name, "verbose") == 0)
{
2017-04-25 18:07:50 +00:00
long int v = strtol(value, NULL, 0);
if (v > INT_MAX || v < INT_MIN)
return 0;
vm->verbose = (int)v;
return 1;
2017-04-25 18:07:50 +00:00
}
return 0;
}
2018-03-28 13:09:07 +00:00
static void evmc_release_result(struct evmc_result const* result)
{
(void)result;
}
2018-03-28 13:09:07 +00:00
static void free_result_output_data(struct evmc_result const* result)
{
free((uint8_t*)result->output_data);
}
static struct evmc_result execute(struct evmc_instance* instance, struct evmc_context* context,
enum evmc_revision rev, const struct evmc_message* msg, const uint8_t* code, size_t code_size)
2016-08-22 17:22:34 +00:00
{
2018-04-13 06:39:47 +00:00
struct evmc_result ret = {.status_code = EVMC_INTERNAL_ERROR};
if (code_size == 0)
{
// In case of empty code return a fancy error message.
2018-04-13 06:39:47 +00:00
const char* error = rev == EVMC_BYZANTIUM ? "Welcome to Byzantium!" : "Hello Ethereum!";
ret.output_data = (const uint8_t*)error;
ret.output_size = strlen(error);
2018-03-28 13:09:07 +00:00
ret.status_code = EVMC_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()) }`.
2017-04-25 18:07:50 +00:00
const char return_address[] = "30600052596000f3";
// Assembly: `{ sstore(0, add(sload(0), 1)) }`
const char counter[] = "600160005401600055";
if (code_size == strlen(return_address) &&
2018-04-13 06:39:47 +00:00
strncmp((const char*)code, return_address, code_size) == 0)
{
static const size_t address_size = sizeof(msg->destination);
uint8_t* output_data = (uint8_t*)malloc(address_size);
2018-04-13 06:39:47 +00:00
if (!output_data)
{
2017-04-25 15:01:46 +00:00
// malloc failed, report internal error.
2018-03-28 13:09:07 +00:00
ret.status_code = EVMC_INTERNAL_ERROR;
2017-04-25 15:01:46 +00:00
return ret;
}
memcpy(output_data, &msg->destination, address_size);
2018-03-28 13:09:07 +00:00
ret.status_code = EVMC_SUCCESS;
ret.output_data = output_data;
ret.output_size = address_size;
ret.release = &free_result_output_data;
return ret;
}
2018-04-13 06:39:47 +00:00
else if (code_size == strlen(counter) && strncmp((const char*)code, counter, code_size) == 0)
{
2018-03-28 13:09:07 +00:00
struct evmc_uint256be value;
2018-04-13 06:39:47 +00:00
const struct evmc_uint256be index = {{0}};
context->fn_table->get_storage(&value, context, &msg->destination, &index);
value.bytes[31] += 1;
context->fn_table->set_storage(context, &msg->destination, &index, &value);
2018-03-28 13:09:07 +00:00
ret.status_code = EVMC_SUCCESS;
2017-04-25 18:07:50 +00:00
return ret;
}
2016-08-22 17:22:34 +00:00
2018-03-28 13:09:07 +00:00
ret.release = evmc_release_result;
ret.status_code = EVMC_FAILURE;
2016-08-22 17:22:34 +00:00
ret.gas_left = 0;
if (vm->verbose)
printf("Execution done.\n");
2016-08-22 17:22:34 +00:00
return ret;
}
2018-03-28 13:09:07 +00:00
struct evmc_instance* examplevm_create()
{
2018-03-28 13:09:07 +00:00
struct evmc_instance init = {
.abi_version = EVMC_ABI_VERSION,
2018-04-17 09:11:07 +00:00
.name = "examplevm",
.version = "0.0.0",
2018-03-28 13:09:07 +00:00
.destroy = evmc_destroy,
.execute = execute,
2018-04-13 06:39:47 +00:00
.set_option = evmc_set_option,
};
struct examplevm* vm = calloc(1, sizeof(struct examplevm));
2018-03-28 13:09:07 +00:00
struct evmc_instance* interface = &vm->instance;
memcpy(interface, &init, sizeof(init));
return interface;
}