helpers, cpp: Add evmc_make_result() for constructing results

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.
This commit is contained in:
Paweł Bylica 2019-06-28 12:05:34 +02:00
parent e4ae2162c5
commit 55329d8dfa
No known key found for this signature in database
GPG Key ID: 7A0C037434FE77EF
3 changed files with 57 additions and 15 deletions

View File

@ -7,8 +7,6 @@
#include <evmc/evmc.h>
#include <evmc/helpers.h>
#include <algorithm>
#include <cstdlib>
#include <functional>
#include <initializer_list>
#include <utility>
@ -257,6 +255,10 @@ constexpr bytes32 operator"" _bytes32() noexcept
using namespace literals;
/// 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
@ -283,19 +285,8 @@ public:
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} {}

View File

@ -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.
@ -107,6 +109,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.
*

View File

@ -492,4 +492,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(evmc::address{c.create_address}, evmc::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);
}