forked from ethereum/solidity
-
Notifications
You must be signed in to change notification settings - Fork 0
/
EVMHost.h
162 lines (135 loc) · 5.73 KB
/
EVMHost.h
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
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
/*
This file is part of solidity.
solidity is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
solidity is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with solidity. If not, see <http://www.gnu.org/licenses/>.
*/
// SPDX-License-Identifier: GPL-3.0
/**
* EVM execution host, i.e. component that implements a simulated Ethereum blockchain
* for testing purposes.
*/
#pragma once
#include <test/evmc/mocked_host.hpp>
#include <test/evmc/evmc.hpp>
#include <test/evmc/evmc.h>
#include <liblangutil/EVMVersion.h>
#include <libsolutil/FixedHash.h>
#include <boost/filesystem.hpp>
namespace solidity::test
{
using Address = util::h160;
using StorageMap = std::map<evmc::bytes32, evmc::StorageValue>;
struct EVMPrecompileOutput {
bytes const output;
int64_t gas_used;
};
class EVMHost: public evmc::MockedHost
{
public:
// Verbatim features of MockedHost.
using MockedHost::account_exists;
using MockedHost::get_storage;
using MockedHost::set_storage;
using MockedHost::get_balance;
using MockedHost::get_code_size;
using MockedHost::get_code_hash;
using MockedHost::copy_code;
using MockedHost::get_tx_context;
using MockedHost::emit_log;
using MockedHost::access_account;
using MockedHost::access_storage;
// Modified features of MockedHost.
bool selfdestruct(evmc::address const& _addr, evmc::address const& _beneficiary) noexcept final;
evmc::Result call(evmc_message const& _message) noexcept final;
evmc::bytes32 get_block_hash(int64_t number) const noexcept final;
// Solidity testing specific features.
/// Tries to dynamically load an evmc vm supporting evm1 and caches the loaded VM.
/// @returns vmc::VM(nullptr) on failure.
static evmc::VM& getVM(std::string const& _path = {});
/// Tries to load all defined evmc vm shared libraries.
/// @param _vmPaths paths to multiple evmc shared libraries.
/// @throw Exception if multiple evm1 vms where loaded.
/// @returns true, if an evmc vm supporting evm1 was loaded properly,
static bool checkVmPaths(std::vector<boost::filesystem::path> const& _vmPaths);
explicit EVMHost(langutil::EVMVersion _evmVersion, evmc::VM& _vm);
/// Reset entire state (including accounts).
void reset();
/// Start new block.
void newBlock()
{
tx_context.block_number++;
tx_context.block_timestamp += 15;
recorded_logs.clear();
newTransactionFrame();
}
/// @returns contents of storage at @param _addr.
StorageMap const& get_address_storage(evmc::address const& _addr);
static Address convertFromEVMC(evmc::address const& _addr);
static evmc::address convertToEVMC(Address const& _addr);
static util::h256 convertFromEVMC(evmc::bytes32 const& _data);
static evmc::bytes32 convertToEVMC(util::h256 const& _data);
private:
/// Transfer value between accounts. Checks for sufficient balance.
void transfer(evmc::MockedAccount& _sender, evmc::MockedAccount& _recipient, u256 const& _value) noexcept;
/// Start a new transaction frame.
/// This will perform selfdestructs, apply storage status changes across all accounts,
/// and clear account/storage access indicator for EIP-2929.
void newTransactionFrame();
/// Records calls made via @param _message.
void recordCalls(evmc_message const& _message) noexcept;
static evmc::Result precompileECRecover(evmc_message const& _message) noexcept;
static evmc::Result precompileSha256(evmc_message const& _message) noexcept;
static evmc::Result precompileRipeMD160(evmc_message const& _message) noexcept;
static evmc::Result precompileIdentity(evmc_message const& _message) noexcept;
static evmc::Result precompileModExp(evmc_message const& _message) noexcept;
template <evmc_revision Revision>
static evmc::Result precompileALTBN128G1Add(evmc_message const& _message) noexcept;
template <evmc_revision Revision>
static evmc::Result precompileALTBN128G1Mul(evmc_message const& _message) noexcept;
template <evmc_revision Revision>
static evmc::Result precompileALTBN128PairingProduct(evmc_message const& _message) noexcept;
static evmc::Result precompileBlake2f(evmc_message const& _message) noexcept;
static evmc::Result precompileGeneric(evmc_message const& _message, std::map<bytes, EVMPrecompileOutput> const& _inOut) noexcept;
/// @returns a result object with gas usage and result data taken from @a _data.
/// The outcome will be a failure if the limit < required.
/// @note The return value is only valid as long as @a _data is alive!
static evmc::Result resultWithGas(int64_t gas_limit, int64_t gas_required, bytes const& _data) noexcept;
static evmc::Result resultWithFailure() noexcept;
evmc::VM& m_vm;
/// EVM version requested by the testing tool
langutil::EVMVersion m_evmVersion;
/// EVM version requested from EVMC (matches the above)
evmc_revision m_evmRevision;
};
class EVMHostPrinter
{
public:
/// Constructs a host printer object for state at @param _address.
explicit EVMHostPrinter(EVMHost& _host, evmc::address _address):
m_host(_host),
m_account(_address)
{}
/// @returns state at account maintained by host.
std::string state();
private:
/// Outputs storage at account to stateStream.
void storage();
/// Outputs call records for account to stateStream.
void callRecords();
/// Outputs balance of account to stateStream.
void balance();
/// Outputs self-destruct record for account to stateStream.
void selfdestructRecords();
std::ostringstream m_stateStream;
EVMHost& m_host;
evmc::address m_account;
};
}