This repository has been archived by the owner on Oct 28, 2021. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 2.2k
/
State.h
372 lines (287 loc) · 14.4 KB
/
State.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
369
370
371
// Aleth: Ethereum C++ client, tools and libraries.
// Copyright 2013-2019 Aleth Authors.
// Licensed under the GNU General Public License, Version 3.
#pragma once
#include "Account.h"
#include "GasPricer.h"
#include "SecureTrieDB.h"
#include "Transaction.h"
#include "TransactionReceipt.h"
#include <libdevcore/Common.h>
#include <libdevcore/OverlayDB.h>
#include <libdevcore/RLP.h>
#include <libethcore/BlockHeader.h>
#include <libethcore/Exceptions.h>
#include <libethereum/CodeSizeCache.h>
#include <libevm/ExtVMFace.h>
#include <array>
#include <unordered_map>
namespace dev
{
namespace test { class ImportTest; class StateLoader; }
namespace eth
{
// Import-specific errinfos
using errinfo_uncleIndex = boost::error_info<struct tag_uncleIndex, unsigned>;
using errinfo_currentNumber = boost::error_info<struct tag_currentNumber, u256>;
using errinfo_uncleNumber = boost::error_info<struct tag_uncleNumber, u256>;
using errinfo_unclesExcluded = boost::error_info<struct tag_unclesExcluded, h256Hash>;
using errinfo_block = boost::error_info<struct tag_block, bytes>;
using errinfo_now = boost::error_info<struct tag_now, unsigned>;
using errinfo_transactionIndex = boost::error_info<struct tag_transactionIndex, unsigned>;
using errinfo_vmtrace = boost::error_info<struct tag_vmtrace, std::string>;
using errinfo_receipts = boost::error_info<struct tag_receipts, std::vector<bytes>>;
using errinfo_transaction = boost::error_info<struct tag_transaction, bytes>;
using errinfo_phase = boost::error_info<struct tag_phase, unsigned>;
using errinfo_required_LogBloom = boost::error_info<struct tag_required_LogBloom, LogBloom>;
using errinfo_got_LogBloom = boost::error_info<struct tag_get_LogBloom, LogBloom>;
using LogBloomRequirementError = boost::tuple<errinfo_required_LogBloom, errinfo_got_LogBloom>;
class BlockChain;
class State;
class TransactionQueue;
struct VerifiedBlockRef;
enum class BaseState
{
PreExisting,
Empty
};
enum class Permanence
{
Reverted,
Committed,
Uncommitted ///< Uncommitted state for change log readings in tests.
};
DEV_SIMPLE_EXCEPTION(InvalidAccountStartNonceInState);
DEV_SIMPLE_EXCEPTION(IncorrectAccountStartNonceInState);
class SealEngineFace;
class Executive;
/// An atomic state changelog entry.
struct Change
{
enum Kind: int
{
/// Account balance changed. Change::value contains the amount the
/// balance was increased by.
Balance,
/// Account storage was modified. Change::key contains the storage key,
/// Change::value the storage value.
Storage,
/// Account storage root was modified. Change::value contains the old
/// account storage root.
StorageRoot,
/// Account nonce was changed.
Nonce,
/// Account was created (it was not existing before).
Create,
/// New code was added to an account (by "create" message execution).
Code,
/// Account was touched for the first time.
Touch
};
Kind kind; ///< The kind of the change.
Address address; ///< Changed account address.
u256 value; ///< Change value, e.g. balance, storage and nonce.
u256 key; ///< Storage key. Last because used only in one case.
/// Helper constructor to make change log update more readable.
Change(Kind _kind, Address const& _addr, u256 const& _value = 0):
kind(_kind), address(_addr), value(_value)
{
}
/// Helper constructor especially for storage change log.
Change(Address const& _addr, u256 const& _key, u256 const& _value):
kind(Storage), address(_addr), value(_value), key(_key)
{}
/// Helper constructor for nonce change log.
Change(Address const& _addr, u256 const& _value):
kind(Nonce), address(_addr), value(_value)
{}
};
using ChangeLog = std::vector<Change>;
/**
* Model of an Ethereum state, essentially a facade for the trie.
*
* Allows you to query the state of accounts as well as creating and modifying
* accounts. It has built-in caching for various aspects of the state.
*
* # State Changelog
*
* Any atomic change to any account is registered and appended in the changelog.
* In case some changes must be reverted, the changes are popped from the
* changelog and undone. For possible atomic changes list @see Change::Kind.
* The changelog is managed by savepoint(), rollback() and commit() methods.
*/
class State
{
friend class ExtVM;
friend class dev::test::ImportTest;
friend class dev::test::StateLoader;
friend class BlockChain;
public:
enum class CommitBehaviour
{
KeepEmptyAccounts,
RemoveEmptyAccounts
};
using AddressMap = std::map<h256, Address>;
/// Default constructor; creates with a blank database prepopulated with the genesis block.
explicit State(u256 const& _accountStartNonce): State(_accountStartNonce, OverlayDB(), BaseState::Empty) {}
/// Basic state object from database.
/// Use the default when you already have a database and you just want to make a State object
/// which uses it. If you have no preexisting database then set BaseState to something other
/// than BaseState::PreExisting in order to prepopulate the Trie.
explicit State(u256 const& _accountStartNonce, OverlayDB const& _db, BaseState _bs = BaseState::PreExisting);
enum NullType { Null };
State(NullType): State(Invalid256, OverlayDB(), BaseState::Empty) {}
/// Copy state object.
State(State const& _s);
/// Copy state object.
State& operator=(State const& _s);
/// Open a DB - useful for passing into the constructor & keeping for other states that are necessary.
static OverlayDB openDB(boost::filesystem::path const& _path, h256 const& _genesisHash, WithExisting _we = WithExisting::Trust);
OverlayDB const& db() const { return m_db; }
OverlayDB& db() { return m_db; }
/// Populate the state from the given AccountMap. Just uses dev::eth::commit().
void populateFrom(AccountMap const& _map);
/// @returns the set containing all addresses currently in use in Ethereum.
/// @warning This is slowslowslow. Don't use it unless you want to lock the object for seconds or minutes at a time.
/// @throws InterfaceNotSupported if compiled without ETH_FATDB.
std::unordered_map<Address, u256> addresses() const;
/// @returns the map with maximum _maxResults elements containing hash->addresses and the next
/// address hash. This method faster then addresses() const;
std::pair<AddressMap, h256> addresses(h256 const& _begin, size_t _maxResults) const;
/// Execute a given transaction.
/// This will change the state accordingly.
std::pair<ExecutionResult, TransactionReceipt> execute(EnvInfo const& _envInfo, SealEngineFace const& _sealEngine, Transaction const& _t, Permanence _p = Permanence::Committed, OnOpFunc const& _onOp = OnOpFunc());
/// Execute @a _txCount transactions of a given block.
/// This will change the state accordingly.
void executeBlockTransactions(Block const& _block, unsigned _txCount, LastBlockHashesFace const& _lastHashes, SealEngineFace const& _sealEngine);
/// Check if the address is in use.
bool addressInUse(Address const& _address) const;
/// Check if the account exists in the state and is non empty (nonce > 0 || balance > 0 || code nonempty).
/// These two notions are equivalent after EIP158.
bool accountNonemptyAndExisting(Address const& _address) const;
/// Check if the address contains executable code.
bool addressHasCode(Address const& _address) const;
/// Get an account's balance.
/// @returns 0 if the address has never been used.
u256 balance(Address const& _id) const;
/// Add some amount to balance.
/// Will initialise the address if it has never been used.
void addBalance(Address const& _id, u256 const& _amount);
/// Subtract the @p _value amount from the balance of @p _addr account.
/// @throws NotEnoughCash if the balance of the account is less than the
/// amount to be subtrackted (also in case the account does not exist).
void subBalance(Address const& _addr, u256 const& _value);
/// Set the balance of @p _addr to @p _value.
/// Will instantiate the address if it has never been used.
void setBalance(Address const& _addr, u256 const& _value);
/**
* @brief Transfers "the balance @a _value between two accounts.
* @param _from Account from which @a _value will be deducted.
* @param _to Account to which @a _value will be added.
* @param _value Amount to be transferred.
*/
void transferBalance(Address const& _from, Address const& _to, u256 const& _value) { subBalance(_from, _value); addBalance(_to, _value); }
/// Get the root of the storage of an account.
h256 storageRoot(Address const& _contract) const;
/// Get the value of a storage position of an account.
/// @returns 0 if no account exists at that address.
u256 storage(Address const& _contract, u256 const& _memory) const;
/// Set the value of a storage position of an account.
void setStorage(Address const& _contract, u256 const& _location, u256 const& _value);
/// Get the original value of a storage position of an account (before modifications saved in
/// account cache).
/// @returns 0 if no account exists at that address.
u256 originalStorageValue(Address const& _contract, u256 const& _key) const;
/// Clear the storage root hash of an account to the hash of the empty trie.
void clearStorage(Address const& _contract);
/// Create a contract at the given address (with unset code and unchanged balance).
void createContract(Address const& _address);
/// Sets the code of the account. Must only be called during / after contract creation.
void setCode(Address const& _address, bytes&& _code, u256 const& _version);
/// Delete an account (used for processing selfdestructs).
void kill(Address _a);
/// Get the storage of an account.
/// @note This is expensive. Don't use it unless you need to.
/// @returns map of hashed keys to key-value pairs or empty map if no account exists at that address.
std::map<h256, std::pair<u256, u256>> storage(Address const& _contract) const;
/// Get the code of an account.
/// @returns bytes() if no account exists at that address.
/// @warning The reference to the code is only valid until the access to
/// other account. Do not keep it.
bytes const& code(Address const& _addr) const;
/// Get the code hash of an account.
/// @returns EmptySHA3 if no account exists at that address or if there is no code associated with the address.
h256 codeHash(Address const& _contract) const;
/// Get the byte-size of the code of an account.
/// @returns code(_contract).size(), but utilizes CodeSizeHash.
size_t codeSize(Address const& _contract) const;
/// Get contract account's version.
/// @returns 0 if no account exists at that address.
u256 version(Address const& _contract) const;
/// Increament the account nonce.
void incNonce(Address const& _id);
/// Set the account nonce.
void setNonce(Address const& _addr, u256 const& _newNonce);
/// Get the account nonce -- the number of transactions it has sent.
/// @returns 0 if the address has never been used.
u256 getNonce(Address const& _addr) const;
/// The hash of the root of our state tree.
h256 rootHash() const { return m_state.root(); }
/// Commit all changes waiting in the address cache to the DB.
/// @param _commitBehaviour whether or not to remove empty accounts during commit.
void commit(CommitBehaviour _commitBehaviour);
/// Resets any uncommitted changes to the cache.
void setRoot(h256 const& _root);
/// Get the account start nonce. May be required.
u256 const& accountStartNonce() const { return m_accountStartNonce; }
u256 const& requireAccountStartNonce() const;
void noteAccountStartNonce(u256 const& _actual);
/// Mark account as touched and keep it touched even in case of rollback
void unrevertableTouch(Address const& _addr);
/// Create a savepoint in the state changelog.
/// @return The savepoint index that can be used in rollback() function.
size_t savepoint() const;
/// Revert all recent changes up to the given @p _savepoint savepoint.
void rollback(size_t _savepoint);
ChangeLog const& changeLog() const { return m_changeLog; }
private:
/// Turns all "touched" empty accounts into non-alive accounts.
void removeEmptyAccounts();
/// @returns the account at the given address or a null pointer if it does not exist.
/// The pointer is valid until the next access to the state or account.
Account const* account(Address const& _addr) const;
/// @returns the account at the given address or a null pointer if it does not exist.
/// The pointer is valid until the next access to the state or account.
Account* account(Address const& _addr);
/// Purges non-modified entries in m_cache if it grows too large.
void clearCacheIfTooLarge() const;
void createAccount(Address const& _address, Account const&& _account);
/// @returns true when normally halted; false when exceptionally halted; throws when internal VM
/// exception occurred.
bool executeTransaction(Executive& _e, Transaction const& _t, OnOpFunc const& _onOp);
/// Our overlay for the state tree.
OverlayDB m_db;
/// Our state tree, as an OverlayDB DB.
SecureTrieDB<Address, OverlayDB> m_state;
/// Our address cache. This stores the states of each address that has (or at least might have)
/// been changed.
mutable std::unordered_map<Address, Account> m_cache;
/// Tracks entries in m_cache that can potentially be purged if it grows too large.
mutable std::vector<Address> m_unchangedCacheEntries;
/// Tracks addresses that are known to not exist.
mutable std::set<Address> m_nonExistingAccountsCache;
/// Tracks all addresses touched so far.
AddressHash m_touched;
/// Tracks addresses that were touched and should stay touched in case of rollback
AddressHash m_unrevertablyTouched;
u256 m_accountStartNonce;
friend std::ostream& operator<<(std::ostream& _out, State const& _s);
ChangeLog m_changeLog;
};
std::ostream& operator<<(std::ostream& _out, State const& _s);
State& createIntermediateState(State& o_s, Block const& _block, unsigned _txIndex, BlockChain const& _bc);
template <class DB>
AddressHash commit(AccountMap const& _cache, SecureTrieDB<Address, DB>& _state);
}
}