mirror of https://github.com/status-im/evmc.git
Merge pull request #187 from ethereum/cpp
Add C++ wrappers/bindings for VM
This commit is contained in:
commit
600143690e
|
@ -1,6 +1,6 @@
|
||||||
/* EVMC: Ethereum Client-VM Connector API.
|
/* EVMC: Ethereum Client-VM Connector API.
|
||||||
* Copyright 2018 The EVMC Authors.
|
* Copyright 2019 The EVMC Authors.
|
||||||
* Licensed under the Apache License, Version 2.0. See the LICENSE file.
|
* Licensed under the Apache License, Version 2.0.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/// @file
|
/// @file
|
||||||
|
@ -158,6 +158,7 @@ static void set_tracer(struct evmc_instance* instance,
|
||||||
|
|
||||||
/// Stringify the argument.
|
/// Stringify the argument.
|
||||||
#define STR(x) #x
|
#define STR(x) #x
|
||||||
|
#define XSTR(x) STR(x)
|
||||||
|
|
||||||
#if !defined(PROJECT_VERSION)
|
#if !defined(PROJECT_VERSION)
|
||||||
/// The dummy project version if not provided by the build system.
|
/// 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 = {
|
struct evmc_instance init = {
|
||||||
.abi_version = EVMC_ABI_VERSION,
|
.abi_version = EVMC_ABI_VERSION,
|
||||||
.name = "example_vm",
|
.name = "example_vm",
|
||||||
.version = STR(PROJECT_VERSION),
|
.version = XSTR(PROJECT_VERSION),
|
||||||
.destroy = destroy,
|
.destroy = destroy,
|
||||||
.execute = execute,
|
.execute = execute,
|
||||||
.get_capabilities = get_capabilities,
|
.get_capabilities = get_capabilities,
|
||||||
|
|
|
@ -8,7 +8,15 @@
|
||||||
#include <evmc/evmc.h>
|
#include <evmc/evmc.h>
|
||||||
#include <evmc/utils.h>
|
#include <evmc/utils.h>
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates EVMC Example VM.
|
* Creates EVMC Example VM.
|
||||||
*/
|
*/
|
||||||
EVMC_EXPORT struct evmc_instance* evmc_create_example_vm(void);
|
EVMC_EXPORT struct evmc_instance* evmc_create_example_vm(void);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
|
@ -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
|
|
@ -1,6 +1,6 @@
|
||||||
# EVMC: Ethereum Client-VM Connector API.
|
# EVMC: Ethereum Client-VM Connector API.
|
||||||
# Copyright 2018 The EVMC Authors.
|
# Copyright 2019 The EVMC Authors.
|
||||||
# Licensed under the Apache License, Version 2.0. See the LICENSE file.
|
# Licensed under the Apache License, Version 2.0.
|
||||||
|
|
||||||
add_subdirectory(instructions)
|
add_subdirectory(instructions)
|
||||||
add_subdirectory(loader)
|
add_subdirectory(loader)
|
||||||
|
|
|
@ -39,11 +39,12 @@ add_custom_command(
|
||||||
|
|
||||||
add_executable(
|
add_executable(
|
||||||
evmc-test
|
evmc-test
|
||||||
|
test_cpp.cpp
|
||||||
test_helpers.cpp
|
test_helpers.cpp
|
||||||
test_instructions.cpp
|
test_instructions.cpp
|
||||||
test_loader.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 ..)
|
set_target_properties(evmc-test PROPERTIES RUNTIME_OUTPUT_DIRECTORY ..)
|
||||||
add_dependencies(evmc-test vm-mock)
|
add_dependencies(evmc-test vm-mock)
|
||||||
|
|
|
@ -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);
|
||||||
|
}
|
Loading…
Reference in New Issue