-
Notifications
You must be signed in to change notification settings - Fork 4
/
Copy pathExtVMFace.h
368 lines (300 loc) · 11.7 KB
/
ExtVMFace.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
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
// Aleth: Ethereum C++ client, tools and libraries.
// Copyright 2014-2019 Aleth Authors.
// Licensed under the GNU General Public License, Version 3.
#pragma once
#include "Instruction.h"
#include <libdevcore/Common.h>
#include <libdevcore/CommonData.h>
#include <libdevcore/SHA3.h>
#include <mcp/common/numbers.hpp>
#include <mcp/common/EVMSchedule.h>
#include <mcp/common/utility.hpp>
#include <mcp/core/log_entry.hpp>
#include <mcp/core/block_store.hpp>
#include <mcp/db/database.hpp>
#include <evmc/evmc.hpp>
#include <boost/optional.hpp>
#include <functional>
#include <set>
namespace mcp
{
class iblock_cache;
}
namespace dev
{
namespace eth
{
/// Reference to a slice of buffer that also owns the buffer.
///
/// This is extension to the concept C++ STL library names as array_view
/// (also known as gsl::span, array_ref, here vector_ref) -- reference to
/// continuous non-modifiable memory. The extension makes the object also owning
/// the referenced buffer.
///
/// This type is used by VMs to return output coming from RETURN instruction.
/// To avoid memory copy, a VM returns its whole memory + the information what
/// part of this memory is actually the output. This simplifies the VM design,
/// because there are multiple options how the output will be used (can be
/// ignored, part of it copied, or all of it copied). The decision what to do
/// with it was moved out of VM interface making VMs "stateless".
///
/// The type is movable, but not copyable. Default constructor available.
class owning_bytes_ref : public vector_ref<byte const>
{
public:
owning_bytes_ref() = default;
/// @param _bytes The buffer.
/// @param _begin The index of the first referenced byte.
/// @param _size The number of referenced bytes.
owning_bytes_ref(bytes&& _bytes, size_t _begin, size_t _size) : m_bytes(std::move(_bytes))
{
// Set the reference *after* the buffer is moved to avoid
// pointer invalidation.
retarget(&m_bytes[_begin], _size);
}
owning_bytes_ref(owning_bytes_ref const&) = delete;
owning_bytes_ref(owning_bytes_ref&&) = default;
owning_bytes_ref& operator=(owning_bytes_ref const&) = delete;
owning_bytes_ref& operator=(owning_bytes_ref&&) = default;
/// Moves the bytes vector out of here. The object cannot be used any more.
bytes&& takeBytes()
{
reset(); // Reset reference just in case.
return std::move(m_bytes);
}
private:
bytes m_bytes;
};
struct SubState
{
std::set<Address> selfdestructs; ///< Any accounts that have selfdestructed.
mcp::log_entries logs; ///< Any logs.
int64_t refunds = 0; ///< Refund counter for storage changes.
SubState& operator+=(SubState const& _s)
{
selfdestructs += _s.selfdestructs;
refunds += _s.refunds;
logs += _s.logs;
return *this;
}
void clear()
{
selfdestructs.clear();
logs.clear();
refunds = 0;
}
};
class ExtVMFace;
class LastBlockHashesFace;
class VMFace;
using OnOpFunc = std::function<void(uint64_t /*steps*/, uint64_t /* PC */, Instruction /*instr*/,
bigint /*newMemSize*/, bigint /*gasCost*/, bigint /*gas*/, VMFace const*, ExtVMFace const*)>;
struct CallParameters
{
CallParameters() = default;
CallParameters(Address _senderAddress, Address _codeAddress, Address _receiveAddress,
u256 _valueTransfer, u256 _apparentValue, u256 _gas, bytesConstRef _data,
OnOpFunc _onOpFunc)
: senderAddress(_senderAddress),
codeAddress(_codeAddress),
receiveAddress(_receiveAddress),
valueTransfer(_valueTransfer),
apparentValue(_apparentValue),
gas(_gas),
data(_data),
onOp(_onOpFunc)
{}
Address senderAddress;
Address codeAddress;
Address receiveAddress;
u256 valueTransfer;
u256 apparentValue;
u256 gas;
bytesConstRef data;
bool staticCall = false;
std::shared_ptr<Instruction> op;
OnOpFunc onOp;
};
class McInfo
{
public:
McInfo() = default;
McInfo(uint64_t const & bn, uint64_t const & mci_a, uint64_t const & mc_timestamp_a, uint64_t const & mc_last_summary_mci_a,
Address const& _author) :
block_number(bn),
mci(mci_a),
mc_timestamp(mc_timestamp_a),
mc_last_summary_mci(mc_last_summary_mci_a),
author(_author)
{
};
uint64_t block_number;
uint64_t mci;
uint64_t mc_timestamp;
uint64_t mc_last_summary_mci;
Address author;
};
class EnvInfo
{
public:
EnvInfo(mcp::db::db_transaction & transaction_a, mcp::block_store & store_a, std::shared_ptr<mcp::iblock_cache> cache_a, McInfo const & mci_info_a,
u256 const& _chainID)
:transaction(transaction_a), store(store_a),cache(cache_a), m_mci_info(mci_info_a), m_chainID(_chainID)
{};
mcp::db::db_transaction & transaction;
mcp::block_store& store;
std::shared_ptr<mcp::iblock_cache> cache;
uint64_t number() const { return m_mci_info.block_number; }
Address const& author() const { return m_mci_info.author; }
uint64_t mci() const { return m_mci_info.mci; }
uint64_t mc_timestamp() const { return m_mci_info.mc_timestamp; }
uint64_t timestamp() const { return m_mci_info.mc_timestamp; }
uint64_t const& gasLimit() const { return mcp::tx_max_gas; }
uint64_t mc_last_summary_mci() const { return m_mci_info.mc_last_summary_mci; }
u256 const& chainID() const { return m_chainID; }
private:
McInfo m_mci_info;
u256 m_chainID;
};
/// Represents a call result.
///
/// @todo: Replace with evmc_result in future.
struct CallResult
{
evmc_status_code status;
owning_bytes_ref output;
CallResult(evmc_status_code status, owning_bytes_ref&& output)
: status{status}, output{std::move(output)}
{}
};
/// Represents a CREATE result.
///
/// @todo: Replace with evmc_result in future.
struct CreateResult
{
evmc_status_code status;
owning_bytes_ref output;
h160 address;
CreateResult(evmc_status_code status, owning_bytes_ref&& output, h160 const& address)
: status{status}, output{std::move(output)}, address{address}
{}
};
/**
* @brief Interface and null implementation of the class for specifying VM externalities.
*/
class ExtVMFace
{
public:
/// Full constructor.
ExtVMFace(EnvInfo const& _envInfo, Address _myAddress, Address _caller, Address _origin,
u256 _value, u256 _gasPrice, bytesConstRef _data, bytes _code, h256 const& _codeHash,
u256 const& _version, unsigned _depth, bool _isCreate, bool _staticCall);
ExtVMFace(ExtVMFace const&) = delete;
ExtVMFace& operator=(ExtVMFace const&) = delete;
virtual ~ExtVMFace() = default;
/// Read storage location.
virtual u256 store(u256) { return 0; }
/// Write a value in storage.
virtual void setStore(u256, u256) {}
/// Read original storage value (before modifications in the current transaction).
virtual u256 originalStorageValue(u256 const&) { return 0; }
/// Read address's balance.
virtual u256 balance(Address) { return 0; }
/// Read address's code.
virtual bytes const& codeAt(Address) { return NullBytes; }
/// @returns the size of the code in bytes at the given address.
virtual size_t codeSizeAt(Address) { return 0; }
/// @returns the hash of the code at the given address.
virtual h256 codeHashAt(Address) { return h256{}; }
/// Does the account exist?
virtual bool exists(Address) { return false; }
/// Selfdestruct the associated contract and give proceeds to the given address.
///
/// @param beneficiary The address of the account which will receive ETH
/// from the selfdestructed account.
virtual bool selfdestruct(Address beneficiary)
{
(void)beneficiary;
sub.selfdestructs.insert(myAddress);
return true;
}
/// Create a new (contract) account.
virtual CreateResult create(u256, u256&, bytesConstRef, Instruction, u256, OnOpFunc const&) = 0;
/// Make a new message call.
virtual CallResult call(CallParameters&) = 0;
/// Revert any changes made (by any of the other calls).
virtual void log(h256s&& _topics, bytesConstRef _data)
{
sub.logs.push_back(mcp::log_entry(myAddress, std::move(_topics), _data.toBytes()));
}
/// Hash of a block if within the last 256 blocks, or h256() otherwise.
virtual h256 blockHash(u256 _number) = 0;
/// Get the execution environment information.
EnvInfo const& envInfo() const { return m_envInfo; }
/// Return the EVM gas-price schedule for this execution context.
virtual EVMSchedule const& evmSchedule() const { return DefaultSchedule; }
private:
EnvInfo const& m_envInfo;
public:
// TODO: make private
Address myAddress; ///< Address associated with executing code (a contract, or contract-to-be).
Address caller; ///< Address which sent the message (either equal to origin or a contract).
Address origin; ///< Original transactor.
u256 value; ///< Value (in Wei) that was passed to this address.
u256 gasPrice; ///< Price of gas (that we already paid).
bytesConstRef data; ///< Current input data.
bytes code; ///< Current code that is executing.
h256 codeHash; ///< SHA3 hash of the executing code
u256 version; ///< Version of the VM to execute code
u256 salt; ///< Values used in new address construction by CREATE2
SubState sub; ///< Sub-band VM state (selfdestructs, refund counter, logs).
unsigned depth = 0; ///< Depth of the present call.
bool isCreate = false; ///< Is this a CREATE call?
bool staticCall = false; ///< Throw on state changing.
};
class EvmCHost : public evmc::Host
{
public:
explicit EvmCHost(ExtVMFace& _extVM) : m_extVM{_extVM} {}
bool account_exists(const evmc::address& _addr) const noexcept override;
evmc::bytes32 get_storage(const evmc::address& _addr, const evmc::bytes32& _key) const
noexcept override;
evmc_storage_status set_storage(const evmc::address& _addr, const evmc::bytes32& _key,
const evmc::bytes32& _value) noexcept override;
evmc::uint256be get_balance(const evmc::address& _addr) const noexcept override;
size_t get_code_size(const evmc::address& _addr) const noexcept override;
evmc::bytes32 get_code_hash(const evmc::address& _addr) const noexcept override;
size_t copy_code(const evmc::address& _addr, size_t _codeOffset, uint8_t* _bufferData,
size_t _bufferSize) const noexcept override;
bool selfdestruct(
const evmc::address& _addr, const evmc::address& _beneficiary) noexcept override;
evmc::Result call(const evmc_message& _msg) noexcept override;
evmc_tx_context get_tx_context() const noexcept override;
evmc::bytes32 get_block_hash(int64_t _blockNumber) const noexcept override;
void emit_log(const evmc::address& _addr, const uint8_t* _data, size_t _dataSize,
const evmc::bytes32 _topics[], size_t _numTopics) noexcept override;
evmc_access_status access_account(const evmc::address& addr) noexcept override;
private:
evmc_access_status access_storage(const evmc::address& addr, const evmc::bytes32& key) noexcept override;
evmc::Result create(evmc_message const& _msg) noexcept;
private:
ExtVMFace& m_extVM;
};
inline evmc::address toEvmC(Address const& _addr)
{
return reinterpret_cast<evmc_address const&>(_addr);
}
inline evmc_uint256be toEvmC(h256 const& _h)
{
return reinterpret_cast<evmc_uint256be const&>(_h);
}
inline u256 fromEvmC(evmc_uint256be const& _n)
{
return fromBigEndian<u256>(_n.bytes);
}
inline Address fromEvmC(evmc::address const& _addr)
{
return reinterpret_cast<Address const&>(_addr);
}
} // namespace eth
} // namespace dev