TLA Line data Source code
1 : // evmone: Fast Ethereum Virtual Machine implementation
2 : // Copyright 2022 The evmone Authors.
3 : // SPDX-License-Identifier: Apache-2.0
4 :
5 : #pragma once
6 :
7 : #include "account.hpp"
8 : #include "bloom_filter.hpp"
9 : #include "hash_utils.hpp"
10 : #include <cassert>
11 : #include <optional>
12 : #include <variant>
13 : #include <vector>
14 :
15 : namespace evmone::state
16 : {
17 : /// The Ethereum State: the collection of accounts mapped by their addresses.
18 : ///
19 : /// TODO: This class is copyable for testing. Consider making it non-copyable.
20 : class State
21 : {
22 : struct JournalBase
23 : {
24 : address addr;
25 : };
26 :
27 : struct JournalBalanceChange : JournalBase
28 : {
29 : intx::uint256 prev_balance;
30 : };
31 :
32 : struct JournalTouched : JournalBase
33 : {};
34 :
35 : struct JournalStorageChange : JournalBase
36 : {
37 : bytes32 key;
38 : bytes32 prev_value;
39 : evmc_access_status prev_access_status;
40 : };
41 :
42 : struct JournalTransientStorageChange : JournalBase
43 : {
44 : bytes32 key;
45 : bytes32 prev_value;
46 : };
47 :
48 : struct JournalNonceBump : JournalBase
49 : {};
50 :
51 : struct JournalCreate : JournalBase
52 : {
53 : bool existed;
54 : };
55 :
56 : struct JournalDestruct : JournalBase
57 : {};
58 :
59 : struct JournalAccessAccount : JournalBase
60 : {};
61 :
62 : using JournalEntry =
63 : std::variant<JournalBalanceChange, JournalTouched, JournalStorageChange, JournalNonceBump,
64 : JournalCreate, JournalTransientStorageChange, JournalDestruct, JournalAccessAccount>;
65 :
66 : std::unordered_map<address, Account> m_accounts;
67 :
68 : /// The state journal: the list of changes made in the state
69 : /// with information how to revert them.
70 : std::vector<JournalEntry> m_journal;
71 :
72 : public:
73 : /// Inserts the new account at the address.
74 : /// There must not exist any account under this address before.
75 : Account& insert(const address& addr, Account account = {});
76 :
77 : /// Returns the pointer to the account at the address if the account exists. Null otherwise.
78 : Account* find(const address& addr) noexcept;
79 :
80 : /// Gets the account at the address (the account must exist).
81 : Account& get(const address& addr) noexcept;
82 :
83 : /// Gets an existing account or inserts new account.
84 : Account& get_or_insert(const address& addr, Account account = {});
85 :
86 CBC 318 : [[nodiscard]] auto& get_accounts() noexcept { return m_accounts; }
87 :
88 53 : [[nodiscard]] const auto& get_accounts() const noexcept { return m_accounts; }
89 :
90 : /// Returns the state journal checkpoint. It can be later used to in rollback()
91 : /// to revert changes newer than the checkpoint.
92 105 : [[nodiscard]] size_t checkpoint() const noexcept { return m_journal.size(); }
93 :
94 : /// Reverts state changes made after the checkpoint.
95 : void rollback(size_t checkpoint);
96 :
97 : /// Methods performing changes to the state which can be reverted by rollback().
98 : /// @{
99 :
100 : /// Touches (as in EIP-161) an existing account or inserts new erasable account.
101 : Account& touch(const address& addr);
102 :
103 : void journal_balance_change(const address& addr, const intx::uint256& prev_balance);
104 :
105 : void journal_storage_change(const address& addr, const bytes32& key, const StorageValue& value);
106 :
107 : void journal_transient_storage_change(
108 : const address& addr, const bytes32& key, const bytes32& value);
109 :
110 : void journal_bump_nonce(const address& addr);
111 :
112 : void journal_create(const address& addr, bool existed);
113 :
114 : void journal_destruct(const address& addr);
115 :
116 : void journal_access_account(const address& addr);
117 :
118 : /// @}
119 : };
120 :
121 : struct Ommer
122 : {
123 : address beneficiary; ///< Ommer block beneficiary address.
124 : uint32_t delta = 0; ///< Difference between current and ommer block number.
125 : };
126 :
127 : struct Withdrawal
128 : {
129 : uint64_t index = 0;
130 : uint64_t validator_index = 0;
131 : address recipient;
132 : uint64_t amount_in_gwei = 0; ///< The amount is denominated in gwei.
133 :
134 : /// Returns withdrawal amount in wei.
135 UBC 0 : [[nodiscard]] intx::uint256 get_amount() const noexcept
136 : {
137 0 : return intx::uint256{amount_in_gwei} * 1'000'000'000;
138 : }
139 : };
140 :
141 : struct BlockInfo
142 : {
143 : /// Max amount of blob gas allowed in block. It's constant now but can be dynamic in the future.
144 : static constexpr int64_t MAX_BLOB_GAS_PER_BLOCK = 786432;
145 :
146 : int64_t number = 0;
147 : int64_t timestamp = 0;
148 : int64_t parent_timestamp = 0;
149 : int64_t gas_limit = 0;
150 : address coinbase;
151 : int64_t difficulty = 0;
152 : int64_t parent_difficulty = 0;
153 : hash256 parent_ommers_hash;
154 : bytes32 prev_randao;
155 : hash256 parent_beacon_block_root;
156 : uint64_t base_fee = 0;
157 :
158 : /// The "excess blob gas" parameter from EIP-4844
159 : /// for computing the blob gas price in the current block.
160 : uint64_t excess_blob_gas = 0;
161 :
162 : /// The blob gas price parameter from EIP-4844.
163 : /// This values is not stored in block headers directly but computed from excess_blob_gas.
164 : intx::uint256 blob_base_fee = 0;
165 :
166 : std::vector<Ommer> ommers;
167 : std::vector<Withdrawal> withdrawals;
168 : std::unordered_map<int64_t, hash256> known_block_hashes;
169 : };
170 :
171 : using AccessList = std::vector<std::pair<address, std::vector<bytes32>>>;
172 :
173 : struct Transaction
174 : {
175 : /// The type of the transaction.
176 : ///
177 : /// The format is defined by EIP-2718: Typed Transaction Envelope.
178 : /// https://eips.ethereum.org/EIPS/eip-2718.
179 : enum class Type : uint8_t
180 : {
181 : /// The legacy RLP-encoded transaction without leading "type" byte.
182 : legacy = 0,
183 :
184 : /// The typed transaction with optional account/storage access list.
185 : /// Introduced by EIP-2930 https://eips.ethereum.org/EIPS/eip-2930.
186 : access_list = 1,
187 :
188 : /// The typed transaction with priority gas price.
189 : /// Introduced by EIP-1559 https://eips.ethereum.org/EIPS/eip-1559.
190 : eip1559 = 2,
191 :
192 : /// The typed blob transaction (with array of blob hashes).
193 : /// Introduced by EIP-4844 https://eips.ethereum.org/EIPS/eip-4844.
194 : blob = 3,
195 : };
196 :
197 : /// Returns amount of blob gas used by this transaction
198 CBC 53 : [[nodiscard]] int64_t blob_gas_used() const
199 : {
200 : static constexpr auto GAS_PER_BLOB = 0x20000;
201 53 : return GAS_PER_BLOB * static_cast<int64_t>(blob_hashes.size());
202 : }
203 :
204 : Type type = Type::legacy;
205 : bytes data;
206 : int64_t gas_limit;
207 : intx::uint256 max_gas_price;
208 : intx::uint256 max_priority_gas_price;
209 : intx::uint256 max_blob_gas_price;
210 : address sender;
211 : std::optional<address> to;
212 : intx::uint256 value;
213 : AccessList access_list;
214 : std::vector<bytes32> blob_hashes;
215 : uint64_t chain_id = 0;
216 : uint64_t nonce = 0;
217 : intx::uint256 r;
218 : intx::uint256 s;
219 : uint8_t v = 0;
220 : };
221 :
222 : struct Log
223 : {
224 : address addr;
225 : bytes data;
226 : std::vector<hash256> topics;
227 : };
228 :
229 : /// Transaction Receipt
230 : ///
231 : /// This struct is used in two contexts:
232 : /// 1. As the formally specified, RLP-encode transaction receipt included in the Ethereum blocks.
233 : /// 2. As the internal representation of the transaction execution result.
234 : /// These both roles share most, but not all the information. There are some fields that cannot be
235 : /// assigned in the single transaction execution context. There are also fields that are not a part
236 : /// of the RLP-encoded transaction receipts.
237 : /// TODO: Consider splitting the struct into two based on the duality explained above.
238 : struct TransactionReceipt
239 : {
240 : Transaction::Type type = Transaction::Type::legacy;
241 : evmc_status_code status = EVMC_INTERNAL_ERROR;
242 :
243 : /// Amount of gas used by this transaction.
244 : int64_t gas_used = 0;
245 :
246 : /// Amount of gas used by this and previous transactions in the block.
247 : int64_t cumulative_gas_used = 0;
248 : std::vector<Log> logs;
249 : BloomFilter logs_bloom_filter;
250 :
251 : /// Root hash of the state after this transaction. Used only in old pre-Byzantium transactions.
252 : std::optional<bytes32> post_state;
253 : };
254 :
255 : /// Computes the current blob gas price based on the excess blob gas.
256 : intx::uint256 compute_blob_gas_price(uint64_t excess_blob_gas) noexcept;
257 :
258 : /// Finalize state after applying a "block" of transactions.
259 : ///
260 : /// Applies block reward to coinbase, withdrawals (post Shanghai) and deletes empty touched accounts
261 : /// (post Spurious Dragon).
262 : void finalize(State& state, evmc_revision rev, const address& coinbase,
263 : std::optional<uint64_t> block_reward, std::span<const Ommer> ommers,
264 : std::span<const Withdrawal> withdrawals);
265 :
266 : [[nodiscard]] std::variant<TransactionReceipt, std::error_code> transition(State& state,
267 : const BlockInfo& block, const Transaction& tx, evmc_revision rev, evmc::VM& vm,
268 : int64_t block_gas_left, int64_t blob_gas_left);
269 :
270 : std::variant<int64_t, std::error_code> validate_transaction(const Account& sender_acc,
271 : const BlockInfo& block, const Transaction& tx, evmc_revision rev, int64_t block_gas_left,
272 : int64_t blob_gas_left) noexcept;
273 :
274 : /// Performs the system call.
275 : ///
276 : /// Executes code at pre-defined accounts from the system sender (0xff...fe).
277 : /// The sender's nonce is not increased.
278 : void system_call(State& state, const BlockInfo& block, evmc_revision rev, evmc::VM& vm);
279 :
280 : /// Defines how to RLP-encode a Transaction.
281 : [[nodiscard]] bytes rlp_encode(const Transaction& tx);
282 :
283 : /// Defines how to RLP-encode a TransactionReceipt.
284 : [[nodiscard]] bytes rlp_encode(const TransactionReceipt& receipt);
285 :
286 : /// Defines how to RLP-encode a Log.
287 : [[nodiscard]] bytes rlp_encode(const Log& log);
288 :
289 : /// Defines how to RLP-encode a Withdrawal.
290 : [[nodiscard]] bytes rlp_encode(const Withdrawal& withdrawal);
291 :
292 : } // namespace evmone::state
|