Merge pull request #187 from ethereum/cpp

Add C++ wrappers/bindings for VM
This commit is contained in:
Paweł Bylica 2019-01-23 13:58:22 +01:00 committed by GitHub
commit 600143690e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 158 additions and 6 deletions

View File

@ -1,6 +1,6 @@
/* EVMC: Ethereum Client-VM Connector API.
* Copyright 2018 The EVMC Authors.
* Licensed under the Apache License, Version 2.0. See the LICENSE file.
* Copyright 2019 The EVMC Authors.
* Licensed under the Apache License, Version 2.0.
*/
/// @file
@ -158,6 +158,7 @@ static void set_tracer(struct evmc_instance* instance,
/// Stringify the argument.
#define STR(x) #x
#define XSTR(x) STR(x)
#if !defined(PROJECT_VERSION)
/// The dummy project version if not provided by the build system.
@ -171,7 +172,7 @@ struct evmc_instance* evmc_create_example_vm()
struct evmc_instance init = {
.abi_version = EVMC_ABI_VERSION,
.name = "example_vm",
.version = STR(PROJECT_VERSION),
.version = XSTR(PROJECT_VERSION),
.destroy = destroy,
.execute = execute,
.get_capabilities = get_capabilities,

View File

@ -8,7 +8,15 @@
#include <evmc/evmc.h>
#include <evmc/utils.h>
#ifdef __cplusplus
extern "C" {
#endif
/**
* Creates EVMC Example VM.
*/
EVMC_EXPORT struct evmc_instance* evmc_create_example_vm(void);
#ifdef __cplusplus
}
#endif

79
include/evmc/evmc.hpp Normal file
View File

@ -0,0 +1,79 @@
/* EVMC: Ethereum Client-VM Connector API.
* Copyright 2019 The EVMC Authors.
* Licensed under the Apache License, Version 2.0.
*/
/// @file
/// EVMC C++ API - wrappers and bindings for C++.
#include <evmc/evmc.h>
#include <evmc/helpers.h>
#include <initializer_list>
#include <utility>
namespace evmc
{
class result : public evmc_result
{
public:
explicit result(evmc_result const& res) noexcept : evmc_result{res} {}
~result() noexcept
{
if (release)
release(this);
}
result(result&& other) noexcept : evmc_result{other}
{
// Disable releaser of the rvalue object.
other.release = nullptr;
}
result(result const&) = delete;
result& operator=(result other) noexcept
{
std::swap(*this, other);
return *this;
}
};
class vm
{
public:
explicit vm(evmc_instance* instance) noexcept : m_instance{instance} {}
~vm() noexcept { m_instance->destroy(m_instance); }
vm(evmc_instance* instance, std::initializer_list<std::pair<const char*, const char*>> options)
: m_instance{instance}
{
for (auto option : options)
set_option(option.first, option.second);
}
bool is_abi_compatible() const noexcept { return m_instance->abi_version == EVMC_ABI_VERSION; }
char const* name() const noexcept { return m_instance->name; }
char const* version() const noexcept { return m_instance->version; }
evmc_set_option_result set_option(const char name[], const char value[]) noexcept
{
return evmc_set_option(m_instance, name, value);
}
result execute(evmc_context& ctx,
evmc_revision rev,
const evmc_message& msg,
const uint8_t* code,
size_t code_size) noexcept
{
return result{m_instance->execute(m_instance, &ctx, rev, &msg, code, code_size)};
}
private:
evmc_instance* const m_instance = nullptr;
};
} // namespace evmc

View File

@ -1,6 +1,6 @@
# EVMC: Ethereum Client-VM Connector API.
# Copyright 2018 The EVMC Authors.
# Licensed under the Apache License, Version 2.0. See the LICENSE file.
# Copyright 2019 The EVMC Authors.
# Licensed under the Apache License, Version 2.0.
add_subdirectory(instructions)
add_subdirectory(loader)

View File

@ -39,11 +39,12 @@ add_custom_command(
add_executable(
evmc-test
test_cpp.cpp
test_helpers.cpp
test_instructions.cpp
test_loader.cpp
)
target_link_libraries(evmc-test PRIVATE instructions loader GTest::gtest GTest::main)
target_link_libraries(evmc-test PRIVATE evmc-example-vm instructions loader GTest::gtest GTest::main)
set_target_properties(evmc-test PROPERTIES RUNTIME_OUTPUT_DIRECTORY ..)
add_dependencies(evmc-test vm-mock)

View File

@ -0,0 +1,63 @@
// EVMC: Ethereum Client-VM Connector API.
// Copyright 2019 The EVMC Authors.
// Licensed under the Apache License, Version 2.0.
#include "../../examples/example_vm.h"
#include <evmc/evmc.hpp>
#include <gtest/gtest.h>
#include <cstring>
TEST(cpp, result)
{
static int release_called = 0;
release_called = 0;
{
EXPECT_EQ(release_called, 0);
auto raw_result = evmc_result{};
raw_result.output_data = static_cast<uint8_t*>(std::malloc(13));
raw_result.release = [](const evmc_result* r) {
std::free(const_cast<uint8_t*>(r->output_data));
++release_called;
};
auto res1 = evmc::result{raw_result};
auto res2 = std::move(res1);
EXPECT_EQ(release_called, 0);
[](evmc::result) {}(std::move(res2));
EXPECT_EQ(release_called, 1);
}
EXPECT_EQ(release_called, 1);
}
TEST(cpp, vm)
{
auto vm = evmc::vm{evmc_create_example_vm()};
EXPECT_TRUE(vm.is_abi_compatible());
auto r = vm.set_option("verbose", "3");
EXPECT_EQ(r, EVMC_SET_OPTION_SUCCESS);
EXPECT_EQ(vm.name(), std::string{"example_vm"});
EXPECT_NE(vm.version()[0], 0);
auto ctx = evmc_context{};
auto res = vm.execute(ctx, EVMC_MAX_REVISION, {}, nullptr, 0);
EXPECT_EQ(res.status_code, EVMC_FAILURE);
}
TEST(cpp, vm_set_option)
{
evmc_instance raw_instance = {EVMC_ABI_VERSION, "", "", nullptr,
nullptr, nullptr, nullptr, nullptr};
raw_instance.destroy = [](evmc_instance*) {};
auto vm = evmc::vm{&raw_instance};
EXPECT_EQ(vm.set_option("1", "2"), EVMC_SET_OPTION_INVALID_NAME);
}