Skip to content

Commit

Permalink
helpers, cpp: Add evmc_make_result() for constructing results
Browse files Browse the repository at this point in the history
This moves the evmc_result construction logic from evmc::result() constructor to helper.h. This function is now exposed as a C helper, C++ evmc::make_result() helper and used in the evmc::result() constructor.
This is convenient for VM implementations which need to construct C evmc_result, not C++ evmc::result.
  • Loading branch information
chfast committed Jun 28, 2019
1 parent 9a0552f commit d55ce64
Show file tree
Hide file tree
Showing 3 changed files with 56 additions and 14 deletions.
19 changes: 5 additions & 14 deletions include/evmc/evmc.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,16 @@
#include <evmc/helpers.h>

#include <algorithm>
#include <cstdlib>
#include <initializer_list>
#include <utility>

/// EVMC C++ API - wrappers and bindings for C++
/// @ingroup cpp
namespace evmc
{
/// Alias for evmc_make_result().
constexpr auto make_result = evmc_make_result;

/// @copydoc evmc_result
///
/// This is a RAII wrapper for evmc_result and objects of this type
Expand All @@ -42,19 +44,8 @@ class result : private evmc_result
int64_t _gas_left,
const uint8_t* _output_data,
size_t _output_size) noexcept
: evmc_result{_status_code, _gas_left, nullptr, _output_size, {}, {}, {}}
{
if (output_size != 0)
{
auto mem = static_cast<uint8_t*>(std::malloc(output_size));
std::copy_n(_output_data, output_size, mem);
output_data = mem;
release = [](const evmc_result* r) noexcept
{
std::free(const_cast<uint8_t*>(r->output_data));
};
}
}
: evmc_result{make_result(_status_code, _gas_left, _output_data, _output_size)}
{}

/// Converting constructor from raw evmc_result.
explicit result(evmc_result const& res) noexcept : evmc_result{res} {}
Expand Down
42 changes: 42 additions & 0 deletions include/evmc/helpers.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@
#pragma once

#include <evmc/evmc.h>
#include <stdlib.h>
#include <string.h>

/**
* Returns true if the VM instance has a compatible ABI version.
Expand Down Expand Up @@ -106,6 +108,46 @@ static inline struct evmc_result evmc_execute(struct evmc_instance* instance,
return instance->execute(instance, context, rev, msg, code, code_size);
}

/// The evmc_result release function using free() for releasing the memory.
///
/// This function is used in the evmc_make_result(),
/// but may be also used in other case if convenient.
///
/// @param result The result object.
static void evmc_free_result_memory(const struct evmc_result* result)
{
free((uint8_t*)result->output_data);
}

/// Creates the result from the provided arguments.
///
/// The provided output is copied to memory allocated with malloc()
/// and the evmc_result::release function is set to one invoking free().
///
/// @param status_code The status code.
/// @param gas_left The amount of gas left.
/// @param output_data The pointer to the output.
/// @param output_size The output size.
static inline struct evmc_result evmc_make_result(enum evmc_status_code status_code,
int64_t gas_left,
const uint8_t* output_data,
size_t output_size)
{
struct evmc_result result;
memset(&result, 0, sizeof(result));
result.status_code = status_code;
result.gas_left = gas_left;
result.output_size = output_size;
if (output_size != 0)
{
uint8_t* buffer = (uint8_t*)malloc(output_size);
memcpy(buffer, output_data, output_size);
result.output_data = buffer;
result.release = evmc_free_result_memory;
}
return result;
}

/**
* Releases the resources allocated to the execution result.
*
Expand Down
9 changes: 9 additions & 0 deletions test/unittests/test_cpp.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -220,4 +220,13 @@ TEST(cpp, result_create)
ASSERT_EQ(r.output_size, 2);
EXPECT_EQ(r.output_data[0], 1);
EXPECT_EQ(r.output_data[1], 2);

auto c = evmc::make_result(r.status_code, r.gas_left, r.output_data, r.output_size);
EXPECT_EQ(c.status_code, r.status_code);
EXPECT_EQ(c.gas_left, r.gas_left);
ASSERT_EQ(c.output_size, r.output_size);
EXPECT_EQ(c.create_address, r.create_address);
ASSERT_TRUE(c.release);
EXPECT_TRUE(std::memcmp(c.output_data, r.output_data, c.output_size) == 0);
c.release(&c);
}

0 comments on commit d55ce64

Please sign in to comment.