forked from ethereum/aleth
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathExtVMFace.h
333 lines (280 loc) · 9.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
/*
This file is part of cpp-ethereum.
cpp-ethereum 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.
cpp-ethereum 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 cpp-ethereum. If not, see <http://www.gnu.org/licenses/>.
*/
/** @file ExtVMFace.h
* @author Gav Wood <i@gavwood.com>
* @date 2014
*/
#pragma once
#include <set>
#include <functional>
#include <boost/optional.hpp>
#include <libdevcore/Common.h>
#include <libdevcore/CommonData.h>
#include <libdevcore/RLP.h>
#include <libdevcore/SHA3.h>
#include <libevmcore/Instruction.h>
#include <libethcore/Common.h>
#include <libethcore/BlockHeader.h>
#include <libethcore/ChainOperationParams.h>
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;
};
enum class BlockPolarity
{
Unknown,
Dead,
Live
};
struct LogEntry
{
LogEntry() {}
LogEntry(RLP const& _r) { address = (Address)_r[0]; topics = _r[1].toVector<h256>(); data = _r[2].toBytes(); }
LogEntry(Address const& _address, h256s const& _ts, bytes&& _d): address(_address), topics(_ts), data(std::move(_d)) {}
void streamRLP(RLPStream& _s) const { _s.appendList(3) << address << topics << data; }
LogBloom bloom() const
{
LogBloom ret;
ret.shiftBloom<3>(sha3(address.ref()));
for (auto t: topics)
ret.shiftBloom<3>(sha3(t.ref()));
return ret;
}
Address address;
h256s topics;
bytes data;
};
using LogEntries = std::vector<LogEntry>;
struct LocalisedLogEntry: public LogEntry
{
LocalisedLogEntry() {}
explicit LocalisedLogEntry(LogEntry const& _le): LogEntry(_le) {}
explicit LocalisedLogEntry(
LogEntry const& _le,
h256 _special
):
LogEntry(_le),
isSpecial(true),
special(_special)
{}
explicit LocalisedLogEntry(
LogEntry const& _le,
h256 const& _blockHash,
BlockNumber _blockNumber,
h256 const& _transactionHash,
unsigned _transactionIndex,
unsigned _logIndex,
BlockPolarity _polarity = BlockPolarity::Unknown
):
LogEntry(_le),
blockHash(_blockHash),
blockNumber(_blockNumber),
transactionHash(_transactionHash),
transactionIndex(_transactionIndex),
logIndex(_logIndex),
polarity(_polarity),
mined(true)
{}
h256 blockHash;
BlockNumber blockNumber = 0;
h256 transactionHash;
unsigned transactionIndex = 0;
unsigned logIndex = 0;
BlockPolarity polarity = BlockPolarity::Unknown;
bool mined = false;
bool isSpecial = false;
h256 special;
};
using LocalisedLogEntries = std::vector<LocalisedLogEntry>;
inline LogBloom bloom(LogEntries const& _logs)
{
LogBloom ret;
for (auto const& l: _logs)
ret |= l.bloom();
return ret;
}
struct SubState
{
std::set<Address> suicides; ///< Any accounts that have suicided.
LogEntries logs; ///< Any logs.
u256 refunds; ///< Refund counter of SSTORE nonzero->zero.
SubState& operator+=(SubState const& _s)
{
suicides += _s.suicides;
refunds += _s.refunds;
logs += _s.logs;
return *this;
}
void clear()
{
suicides.clear();
logs.clear();
refunds = 0;
}
};
class ExtVMFace;
class LastBlockHashesFace;
class VM;
using OnOpFunc = std::function<void(uint64_t /*steps*/, uint64_t /* PC */, Instruction /*instr*/, bigint /*newMemSize*/, bigint /*gasCost*/, bigint /*gas*/, VM*, 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;
OnOpFunc onOp;
};
class EnvInfo
{
public:
EnvInfo(BlockHeader const& _current, LastBlockHashesFace const& _lh, u256 const& _gasUsed):
m_headerInfo(_current),
m_lastHashes(_lh),
m_gasUsed(_gasUsed)
{}
// Constructor with custom gasLimit - used in some synthetic scenarios like eth_estimateGas RPC method
EnvInfo(BlockHeader const& _current, LastBlockHashesFace const& _lh, u256 const& _gasUsed, u256 const& _gasLimit):
EnvInfo(_current, _lh, _gasUsed)
{
m_headerInfo.setGasLimit(_gasLimit);
}
BlockHeader const& header() const { return m_headerInfo; }
u256 const& number() const { return m_headerInfo.number(); }
Address const& author() const { return m_headerInfo.author(); }
u256 const& timestamp() const { return m_headerInfo.timestamp(); }
u256 const& difficulty() const { return m_headerInfo.difficulty(); }
u256 const& gasLimit() const { return m_headerInfo.gasLimit(); }
LastBlockHashesFace const& lastHashes() const { return m_lastHashes; }
u256 const& gasUsed() const { return m_gasUsed; }
private:
BlockHeader m_headerInfo;
LastBlockHashesFace const& m_lastHashes;
u256 m_gasUsed;
};
/**
* @brief Interface and null implementation of the class for specifying VM externalities.
*/
class ExtVMFace
{
public:
/// Null constructor.
ExtVMFace() = default;
/// Full constructor.
ExtVMFace(EnvInfo const& _envInfo, Address _myAddress, Address _caller, Address _origin, u256 _value, u256 _gasPrice, bytesConstRef _data, bytes _code, h256 const& _codeHash, unsigned _depth, bool _staticCall);
virtual ~ExtVMFace() = default;
ExtVMFace(ExtVMFace const&) = delete;
ExtVMFace& operator=(ExtVMFace const&) = delete;
/// Read storage location.
virtual u256 store(u256) { return 0; }
/// Write a value in storage.
virtual void setStore(u256, u256) {}
/// 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; }
/// Does the account exist?
virtual bool exists(Address) { return false; }
/// Suicide the associated contract and give proceeds to the given address.
virtual void suicide(Address) { sub.suicides.insert(myAddress); }
/// Create a new (contract) account.
virtual std::pair<h160, owning_bytes_ref> create(u256, u256&, bytesConstRef, Instruction, u256, OnOpFunc const&) = 0;
/// Make a new message call.
/// @returns success flag and output data, if any.
virtual std::pair<bool, owning_bytes_ref> call(CallParameters&) = 0;
/// Revert any changes made (by any of the other calls).
virtual void log(h256s&& _topics, bytesConstRef _data) { sub.logs.push_back(LogEntry(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
SubState sub; ///< Sub-band VM state (suicides, refund counter, logs).
unsigned depth = 0; ///< Depth of the present call.
bool staticCall = false; ///< Throw on state changing.
};
}
}