forked from ethereum/evmone
-
Notifications
You must be signed in to change notification settings - Fork 0
/
evm_fixture.hpp
105 lines (85 loc) · 3.6 KB
/
evm_fixture.hpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
// evmone: Fast Ethereum Virtual Machine implementation
// Copyright 2019-2020 The evmone Authors.
// SPDX-License-Identifier: Apache-2.0
#pragma once
#include "evmone/eof.hpp"
#include <evmc/mocked_host.hpp>
#include <gtest/gtest.h>
#include <intx/intx.hpp>
#include <test/utils/bytecode.hpp>
#define EXPECT_STATUS(STATUS_CODE) \
EXPECT_EQ(result.status_code, STATUS_CODE); \
if constexpr (STATUS_CODE != EVMC_SUCCESS && STATUS_CODE != EVMC_REVERT) \
{ \
EXPECT_EQ(result.gas_left, 0); \
} \
(void)0
#define EXPECT_GAS_USED(STATUS_CODE, GAS_USED) \
EXPECT_EQ(result.status_code, STATUS_CODE); \
EXPECT_EQ(gas_used, GAS_USED)
#define EXPECT_OUTPUT_INT(X) \
ASSERT_EQ(result.output_size, sizeof(intx::uint256)); \
EXPECT_EQ(hex({result.output_data, result.output_size}), \
hex({intx::be::store<evmc_bytes32>(intx::uint256{X}).bytes, sizeof(evmc_bytes32)}))
namespace evmone::test
{
/// The "evm" test fixture with generic unit tests for EVMC-compatible VM implementations.
class evm : public testing::TestWithParam<evmc::VM*>
{
protected:
/// Reports if execution is done by evmone/Advanced.
static bool is_advanced() noexcept;
/// The VM handle.
evmc::VM& vm;
/// The EVM revision for unit test execution. Byzantium by default.
/// TODO: Add alias evmc::revision.
evmc_revision rev = EVMC_BYZANTIUM;
/// The message to be executed by a unit test (with execute() method).
/// TODO: Add evmc::message with default constructor.
evmc_message msg{};
/// The result of execution (available after execute() is invoked).
evmc::Result result;
/// The result output. Updated by execute().
bytes_view output;
/// The total amount of gas used during execution.
int64_t gas_used = 0;
evmc::MockedHost host;
evm() noexcept : vm{*GetParam()} {}
/// Executes the supplied code.
///
/// @param gas The gas limit for execution.
/// @param code The EVM bytecode.
/// @param input The EVM "calldata" input.
/// The execution result will be available in the `result` field.
/// The `gas_used` field will be updated accordingly.
void execute(int64_t gas, const bytecode& code, bytes_view input = {}) noexcept
{
msg.input_data = input.data();
msg.input_size = input.size();
msg.gas = gas;
if (rev >= EVMC_BERLIN) // Add EIP-2929 tweak.
{
host.access_account(msg.sender);
host.access_account(msg.recipient);
}
if (rev >= EVMC_PRAGUE && is_eof_container(code))
{
ASSERT_EQ(get_error_message(validate_eof(rev, ContainerKind::runtime, code)),
get_error_message(EOFValidationError::success));
}
result = vm.execute(host, rev, msg, code.data(), code.size());
output = {result.output_data, result.output_size};
gas_used = msg.gas - result.gas_left;
}
/// Executes the supplied code.
///
/// @param code The EVM bytecode.
/// @param input The EVM "calldata" input.
/// The execution result will be available in the `result` field.
/// The `gas_used` field will be updated accordingly.
void execute(const bytecode& code, bytes_view input = {}) noexcept
{
execute(std::numeric_limits<int64_t>::max(), code, input);
}
};
} // namespace evmone::test