/src/solidity/test/evmc/evmc.hpp
Line | Count | Source (jump to first uncovered line) |
1 | | // EVMC: Ethereum Client-VM Connector API. |
2 | | // Copyright 2018 The EVMC Authors. |
3 | | // Licensed under the Apache License, Version 2.0. |
4 | | #pragma once |
5 | | |
6 | | #include <evmc/evmc.h> |
7 | | #include <evmc/helpers.h> |
8 | | #include <evmc/hex.hpp> |
9 | | |
10 | | #include <functional> |
11 | | #include <initializer_list> |
12 | | #include <ostream> |
13 | | #include <string_view> |
14 | | #include <utility> |
15 | | |
16 | | static_assert(EVMC_LATEST_STABLE_REVISION <= EVMC_MAX_REVISION, |
17 | | "latest stable revision ill-defined"); |
18 | | |
19 | | /// EVMC C++ API - wrappers and bindings for C++ |
20 | | /// @ingroup cpp |
21 | | namespace evmc |
22 | | { |
23 | | /// The big-endian 160-bit hash suitable for keeping an Ethereum address. |
24 | | /// |
25 | | /// This type wraps C ::evmc_address to make sure objects of this type are always initialized. |
26 | | struct address : evmc_address |
27 | | { |
28 | | /// Default and converting constructor. |
29 | | /// |
30 | | /// Initializes bytes to zeros if not other @p init value provided. |
31 | 4.06M | constexpr address(evmc_address init = {}) noexcept : evmc_address{init} {} |
32 | | |
33 | | /// Converting constructor from unsigned integer value. |
34 | | /// |
35 | | /// This constructor assigns the @p v value to the last 8 bytes [12:19] |
36 | | /// in big-endian order. |
37 | | constexpr explicit address(uint64_t v) noexcept |
38 | | : evmc_address{{0, |
39 | | 0, |
40 | | 0, |
41 | | 0, |
42 | | 0, |
43 | | 0, |
44 | | 0, |
45 | | 0, |
46 | | 0, |
47 | | 0, |
48 | | 0, |
49 | | 0, |
50 | | static_cast<uint8_t>(v >> 56), |
51 | | static_cast<uint8_t>(v >> 48), |
52 | | static_cast<uint8_t>(v >> 40), |
53 | | static_cast<uint8_t>(v >> 32), |
54 | | static_cast<uint8_t>(v >> 24), |
55 | | static_cast<uint8_t>(v >> 16), |
56 | | static_cast<uint8_t>(v >> 8), |
57 | | static_cast<uint8_t>(v >> 0)}} |
58 | 230k | {} |
59 | | |
60 | | /// Explicit operator converting to bool. |
61 | | inline constexpr explicit operator bool() const noexcept; |
62 | | |
63 | | /// Implicit operator converting to bytes_view. |
64 | 0 | inline constexpr operator bytes_view() const noexcept { return {bytes, sizeof(bytes)}; } |
65 | | }; |
66 | | |
67 | | /// The fixed size array of 32 bytes for storing 256-bit EVM values. |
68 | | /// |
69 | | /// This type wraps C ::evmc_bytes32 to make sure objects of this type are always initialized. |
70 | | struct bytes32 : evmc_bytes32 |
71 | | { |
72 | | /// Default and converting constructor. |
73 | | /// |
74 | | /// Initializes bytes to zeros if not other @p init value provided. |
75 | 2.81M | constexpr bytes32(evmc_bytes32 init = {}) noexcept : evmc_bytes32{init} {} |
76 | | |
77 | | /// Converting constructor from unsigned integer value. |
78 | | /// |
79 | | /// This constructor assigns the @p v value to the last 8 bytes [24:31] |
80 | | /// in big-endian order. |
81 | | constexpr explicit bytes32(uint64_t v) noexcept |
82 | | : evmc_bytes32{{0, |
83 | | 0, |
84 | | 0, |
85 | | 0, |
86 | | 0, |
87 | | 0, |
88 | | 0, |
89 | | 0, |
90 | | 0, |
91 | | 0, |
92 | | 0, |
93 | | 0, |
94 | | 0, |
95 | | 0, |
96 | | 0, |
97 | | 0, |
98 | | 0, |
99 | | 0, |
100 | | 0, |
101 | | 0, |
102 | | 0, |
103 | | 0, |
104 | | 0, |
105 | | 0, |
106 | | static_cast<uint8_t>(v >> 56), |
107 | | static_cast<uint8_t>(v >> 48), |
108 | | static_cast<uint8_t>(v >> 40), |
109 | | static_cast<uint8_t>(v >> 32), |
110 | | static_cast<uint8_t>(v >> 24), |
111 | | static_cast<uint8_t>(v >> 16), |
112 | | static_cast<uint8_t>(v >> 8), |
113 | | static_cast<uint8_t>(v >> 0)}} |
114 | 271k | {} |
115 | | |
116 | | /// Explicit operator converting to bool. |
117 | | inline constexpr explicit operator bool() const noexcept; |
118 | | |
119 | | /// Implicit operator converting to bytes_view. |
120 | 0 | inline constexpr operator bytes_view() const noexcept { return {bytes, sizeof(bytes)}; } |
121 | | }; |
122 | | |
123 | | /// The alias for evmc::bytes32 to represent a big-endian 256-bit integer. |
124 | | using uint256be = bytes32; |
125 | | |
126 | | |
127 | | /// Loads 64 bits / 8 bytes of data from the given @p data array in big-endian order. |
128 | | inline constexpr uint64_t load64be(const uint8_t* data) noexcept |
129 | 74.6M | { |
130 | 74.6M | return (uint64_t{data[0]} << 56) | (uint64_t{data[1]} << 48) | (uint64_t{data[2]} << 40) | |
131 | 74.6M | (uint64_t{data[3]} << 32) | (uint64_t{data[4]} << 24) | (uint64_t{data[5]} << 16) | |
132 | 74.6M | (uint64_t{data[6]} << 8) | uint64_t{data[7]}; |
133 | 74.6M | } |
134 | | |
135 | | /// Loads 64 bits / 8 bytes of data from the given @p data array in little-endian order. |
136 | | inline constexpr uint64_t load64le(const uint8_t* data) noexcept |
137 | 26.4M | { |
138 | 26.4M | return uint64_t{data[0]} | (uint64_t{data[1]} << 8) | (uint64_t{data[2]} << 16) | |
139 | 26.4M | (uint64_t{data[3]} << 24) | (uint64_t{data[4]} << 32) | (uint64_t{data[5]} << 40) | |
140 | 26.4M | (uint64_t{data[6]} << 48) | (uint64_t{data[7]} << 56); |
141 | 26.4M | } |
142 | | |
143 | | /// Loads 32 bits / 4 bytes of data from the given @p data array in big-endian order. |
144 | | inline constexpr uint32_t load32be(const uint8_t* data) noexcept |
145 | 318k | { |
146 | 318k | return (uint32_t{data[0]} << 24) | (uint32_t{data[1]} << 16) | (uint32_t{data[2]} << 8) | |
147 | 318k | uint32_t{data[3]}; |
148 | 318k | } |
149 | | |
150 | | /// Loads 32 bits / 4 bytes of data from the given @p data array in little-endian order. |
151 | | inline constexpr uint32_t load32le(const uint8_t* data) noexcept |
152 | 8.26M | { |
153 | 8.26M | return uint32_t{data[0]} | (uint32_t{data[1]} << 8) | (uint32_t{data[2]} << 16) | |
154 | 8.26M | (uint32_t{data[3]} << 24); |
155 | 8.26M | } |
156 | | |
157 | | namespace fnv |
158 | | { |
159 | | constexpr auto prime = 0x100000001b3; ///< The 64-bit FNV prime number. |
160 | | constexpr auto offset_basis = 0xcbf29ce484222325; ///< The 64-bit FNV offset basis. |
161 | | |
162 | | /// The hashing transformation for 64-bit inputs based on the FNV-1a formula. |
163 | | inline constexpr uint64_t fnv1a_by64(uint64_t h, uint64_t x) noexcept |
164 | 9.16M | { |
165 | 9.16M | return (h ^ x) * prime; |
166 | 9.16M | } |
167 | | } // namespace fnv |
168 | | |
169 | | |
170 | | /// The "equal to" comparison operator for the evmc::address type. |
171 | | inline constexpr bool operator==(const address& a, const address& b) noexcept |
172 | 4.92M | { |
173 | 4.92M | return load64le(&a.bytes[0]) == load64le(&b.bytes[0]) && |
174 | 4.92M | load64le(&a.bytes[8]) == load64le(&b.bytes[8]) && |
175 | 4.92M | load32le(&a.bytes[16]) == load32le(&b.bytes[16]); |
176 | 4.92M | } |
177 | | |
178 | | /// The "not equal to" comparison operator for the evmc::address type. |
179 | | inline constexpr bool operator!=(const address& a, const address& b) noexcept |
180 | 0 | { |
181 | 0 | return !(a == b); |
182 | 0 | } |
183 | | |
184 | | /// The "less than" comparison operator for the evmc::address type. |
185 | | inline constexpr bool operator<(const address& a, const address& b) noexcept |
186 | 612k | { |
187 | 612k | return load64be(&a.bytes[0]) < load64be(&b.bytes[0]) || |
188 | 612k | (load64be(&a.bytes[0]) == load64be(&b.bytes[0]) && |
189 | 409k | (load64be(&a.bytes[8]) < load64be(&b.bytes[8]) || |
190 | 205k | (load64be(&a.bytes[8]) == load64be(&b.bytes[8]) && |
191 | 182k | load32be(&a.bytes[16]) < load32be(&b.bytes[16])))); |
192 | 612k | } |
193 | | |
194 | | /// The "greater than" comparison operator for the evmc::address type. |
195 | | inline constexpr bool operator>(const address& a, const address& b) noexcept |
196 | 0 | { |
197 | 0 | return b < a; |
198 | 0 | } |
199 | | |
200 | | /// The "less than or equal to" comparison operator for the evmc::address type. |
201 | | inline constexpr bool operator<=(const address& a, const address& b) noexcept |
202 | 259k | { |
203 | 259k | return !(b < a); |
204 | 259k | } |
205 | | |
206 | | /// The "greater than or equal to" comparison operator for the evmc::address type. |
207 | | inline constexpr bool operator>=(const address& a, const address& b) noexcept |
208 | 352k | { |
209 | 352k | return !(a < b); |
210 | 352k | } |
211 | | |
212 | | /// The "equal to" comparison operator for the evmc::bytes32 type. |
213 | | inline constexpr bool operator==(const bytes32& a, const bytes32& b) noexcept |
214 | 646k | { |
215 | 646k | return load64le(&a.bytes[0]) == load64le(&b.bytes[0]) && |
216 | 646k | load64le(&a.bytes[8]) == load64le(&b.bytes[8]) && |
217 | 646k | load64le(&a.bytes[16]) == load64le(&b.bytes[16]) && |
218 | 646k | load64le(&a.bytes[24]) == load64le(&b.bytes[24]); |
219 | 646k | } |
220 | | |
221 | | /// The "not equal to" comparison operator for the evmc::bytes32 type. |
222 | | inline constexpr bool operator!=(const bytes32& a, const bytes32& b) noexcept |
223 | 0 | { |
224 | 0 | return !(a == b); |
225 | 0 | } |
226 | | |
227 | | /// The "less than" comparison operator for the evmc::bytes32 type. |
228 | | inline constexpr bool operator<(const bytes32& a, const bytes32& b) noexcept |
229 | 5.88M | { |
230 | 5.88M | return load64be(&a.bytes[0]) < load64be(&b.bytes[0]) || |
231 | 5.88M | (load64be(&a.bytes[0]) == load64be(&b.bytes[0]) && |
232 | 5.42M | (load64be(&a.bytes[8]) < load64be(&b.bytes[8]) || |
233 | 5.08M | (load64be(&a.bytes[8]) == load64be(&b.bytes[8]) && |
234 | 4.98M | (load64be(&a.bytes[16]) < load64be(&b.bytes[16]) || |
235 | 4.92M | (load64be(&a.bytes[16]) == load64be(&b.bytes[16]) && |
236 | 4.82M | load64be(&a.bytes[24]) < load64be(&b.bytes[24])))))); |
237 | 5.88M | } |
238 | | |
239 | | /// The "greater than" comparison operator for the evmc::bytes32 type. |
240 | | inline constexpr bool operator>(const bytes32& a, const bytes32& b) noexcept |
241 | 0 | { |
242 | 0 | return b < a; |
243 | 0 | } |
244 | | |
245 | | /// The "less than or equal to" comparison operator for the evmc::bytes32 type. |
246 | | inline constexpr bool operator<=(const bytes32& a, const bytes32& b) noexcept |
247 | 0 | { |
248 | 0 | return !(b < a); |
249 | 0 | } |
250 | | |
251 | | /// The "greater than or equal to" comparison operator for the evmc::bytes32 type. |
252 | | inline constexpr bool operator>=(const bytes32& a, const bytes32& b) noexcept |
253 | 0 | { |
254 | 0 | return !(a < b); |
255 | 0 | } |
256 | | |
257 | | /// Checks if the given address is the zero address. |
258 | | inline constexpr bool is_zero(const address& a) noexcept |
259 | 0 | { |
260 | 0 | return a == address{}; |
261 | 0 | } |
262 | | |
263 | | inline constexpr address::operator bool() const noexcept |
264 | 0 | { |
265 | 0 | return !is_zero(*this); |
266 | 0 | } |
267 | | |
268 | | /// Checks if the given bytes32 object has all zero bytes. |
269 | | inline constexpr bool is_zero(const bytes32& a) noexcept |
270 | 146k | { |
271 | 146k | return a == bytes32{}; |
272 | 146k | } |
273 | | |
274 | | inline constexpr bytes32::operator bool() const noexcept |
275 | 76.7k | { |
276 | 76.7k | return !is_zero(*this); |
277 | 76.7k | } |
278 | | |
279 | | namespace literals |
280 | | { |
281 | | /// Converts a raw literal into value of type T. |
282 | | /// |
283 | | /// This function is expected to be used on literals in constexpr context only. |
284 | | /// In case the input is invalid the std::terminate() is called. |
285 | | /// TODO(c++20): Use consteval. |
286 | | template <typename T> |
287 | | constexpr T parse(std::string_view s) noexcept |
288 | 1.65M | { |
289 | 1.65M | return from_hex<T>(s).value(); |
290 | 1.65M | } evmc::bytes32 evmc::literals::parse<evmc::bytes32>(std::__1::basic_string_view<char, std::__1::char_traits<char> >) Line | Count | Source | 288 | 240k | { | 289 | 240k | return from_hex<T>(s).value(); | 290 | 240k | } |
evmc::address evmc::literals::parse<evmc::address>(std::__1::basic_string_view<char, std::__1::char_traits<char> >) Line | Count | Source | 288 | 1.41M | { | 289 | 1.41M | return from_hex<T>(s).value(); | 290 | 1.41M | } |
|
291 | | |
292 | | /// Literal for evmc::address. |
293 | | constexpr address operator""_address(const char* s) noexcept |
294 | 1.41M | { |
295 | 1.41M | return parse<address>(s); |
296 | 1.41M | } |
297 | | |
298 | | /// Literal for evmc::bytes32. |
299 | | constexpr bytes32 operator""_bytes32(const char* s) noexcept |
300 | 240k | { |
301 | 240k | return parse<bytes32>(s); |
302 | 240k | } |
303 | | } // namespace literals |
304 | | |
305 | | using namespace literals; |
306 | | |
307 | | |
308 | | /// @copydoc evmc_status_code_to_string |
309 | | inline const char* to_string(evmc_status_code status_code) noexcept |
310 | 0 | { |
311 | 0 | return evmc_status_code_to_string(status_code); |
312 | 0 | } |
313 | | |
314 | | /// @copydoc evmc_revision_to_string |
315 | | inline const char* to_string(evmc_revision rev) noexcept |
316 | 0 | { |
317 | 0 | return evmc_revision_to_string(rev); |
318 | 0 | } |
319 | | |
320 | | |
321 | | /// Alias for evmc_make_result(). |
322 | | constexpr auto make_result = evmc_make_result; |
323 | | |
324 | | /// @copydoc evmc_result |
325 | | /// |
326 | | /// This is a RAII wrapper for evmc_result and objects of this type |
327 | | /// automatically release attached resources. |
328 | | class Result : private evmc_result |
329 | | { |
330 | | public: |
331 | | using evmc_result::create_address; |
332 | | using evmc_result::gas_left; |
333 | | using evmc_result::gas_refund; |
334 | | using evmc_result::output_data; |
335 | | using evmc_result::output_size; |
336 | | using evmc_result::status_code; |
337 | | |
338 | | /// Creates the result from the provided arguments. |
339 | | /// |
340 | | /// The provided output is copied to memory allocated with malloc() |
341 | | /// and the evmc_result::release function is set to one invoking free(). |
342 | | /// |
343 | | /// @param _status_code The status code. |
344 | | /// @param _gas_left The amount of gas left. |
345 | | /// @param _gas_refund The amount of refunded gas. |
346 | | /// @param _output_data The pointer to the output. |
347 | | /// @param _output_size The output size. |
348 | | explicit Result(evmc_status_code _status_code, |
349 | | int64_t _gas_left, |
350 | | int64_t _gas_refund, |
351 | | const uint8_t* _output_data, |
352 | | size_t _output_size) noexcept |
353 | | : evmc_result{make_result(_status_code, _gas_left, _gas_refund, _output_data, _output_size)} |
354 | 0 | {} |
355 | | |
356 | | /// Creates the result without output. |
357 | | /// |
358 | | /// @param _status_code The status code. |
359 | | /// @param _gas_left The amount of gas left. |
360 | | /// @param _gas_refund The amount of refunded gas. |
361 | | explicit Result(evmc_status_code _status_code = EVMC_INTERNAL_ERROR, |
362 | | int64_t _gas_left = 0, |
363 | | int64_t _gas_refund = 0) noexcept |
364 | | : evmc_result{make_result(_status_code, _gas_left, _gas_refund, nullptr, 0)} |
365 | 3.08k | {} |
366 | | |
367 | | /// Creates the result of contract creation. |
368 | | /// |
369 | | /// @param _status_code The status code. |
370 | | /// @param _gas_left The amount of gas left. |
371 | | /// @param _gas_refund The amount of refunded gas. |
372 | | /// @param _create_address The address of the possibly created account. |
373 | | explicit Result(evmc_status_code _status_code, |
374 | | int64_t _gas_left, |
375 | | int64_t _gas_refund, |
376 | | const evmc_address& _create_address) noexcept |
377 | | : evmc_result{make_result(_status_code, _gas_left, _gas_refund, nullptr, 0)} |
378 | 0 | { |
379 | 0 | create_address = _create_address; |
380 | 0 | } |
381 | | |
382 | | /// Converting constructor from raw evmc_result. |
383 | | /// |
384 | | /// This object takes ownership of the resources of @p res. |
385 | 85.9k | explicit Result(const evmc_result& res) noexcept : evmc_result{res} {} |
386 | | |
387 | | /// Destructor responsible for automatically releasing attached resources. |
388 | | ~Result() noexcept |
389 | 174k | { |
390 | 174k | if (release != nullptr) |
391 | 19.8k | release(this); |
392 | 174k | } |
393 | | |
394 | | /// Move constructor. |
395 | | Result(Result&& other) noexcept : evmc_result{other} |
396 | 85.9k | { |
397 | 85.9k | other.release = nullptr; // Disable releasing of the rvalue object. |
398 | 85.9k | } |
399 | | |
400 | | /// Move assignment operator. |
401 | | /// |
402 | | /// The self-assignment MUST never happen. |
403 | | /// |
404 | | /// @param other The other result object. |
405 | | /// @return The reference to the left-hand side object. |
406 | | Result& operator=(Result&& other) noexcept |
407 | 0 | { |
408 | 0 | this->~Result(); // Release this object. |
409 | 0 | static_cast<evmc_result&>(*this) = other; // Copy data. |
410 | 0 | other.release = nullptr; // Disable releasing of the rvalue object. |
411 | 0 | return *this; |
412 | 0 | } |
413 | | |
414 | | /// Access the result object as a referenced to ::evmc_result. |
415 | 0 | evmc_result& raw() noexcept { return *this; } |
416 | | |
417 | | /// Access the result object as a const referenced to ::evmc_result. |
418 | 0 | const evmc_result& raw() const noexcept { return *this; } |
419 | | |
420 | | /// Releases the ownership and returns the raw copy of evmc_result. |
421 | | /// |
422 | | /// This method drops the ownership of the result |
423 | | /// (result's resources are not going to be released when this object is destructed). |
424 | | /// It is the caller's responsibility having the returned copy of the result to release it. |
425 | | /// This object MUST NOT be used after this method is invoked. |
426 | | /// |
427 | | /// @return The copy of this object converted to raw evmc_result. |
428 | | evmc_result release_raw() noexcept |
429 | 51.0k | { |
430 | 51.0k | const auto out = evmc_result{*this}; // Copy data. |
431 | 51.0k | this->release = nullptr; // Disable releasing of this object. |
432 | 51.0k | return out; |
433 | 51.0k | } |
434 | | }; |
435 | | |
436 | | |
437 | | /// The EVMC Host interface |
438 | | class HostInterface |
439 | | { |
440 | | public: |
441 | 10.1k | virtual ~HostInterface() noexcept = default; |
442 | | |
443 | | /// @copydoc evmc_host_interface::account_exists |
444 | | virtual bool account_exists(const address& addr) const noexcept = 0; |
445 | | |
446 | | /// @copydoc evmc_host_interface::get_storage |
447 | | virtual bytes32 get_storage(const address& addr, const bytes32& key) const noexcept = 0; |
448 | | |
449 | | /// @copydoc evmc_host_interface::set_storage |
450 | | virtual evmc_storage_status set_storage(const address& addr, |
451 | | const bytes32& key, |
452 | | const bytes32& value) noexcept = 0; |
453 | | |
454 | | /// @copydoc evmc_host_interface::get_balance |
455 | | virtual uint256be get_balance(const address& addr) const noexcept = 0; |
456 | | |
457 | | /// @copydoc evmc_host_interface::get_code_size |
458 | | virtual size_t get_code_size(const address& addr) const noexcept = 0; |
459 | | |
460 | | /// @copydoc evmc_host_interface::get_code_hash |
461 | | virtual bytes32 get_code_hash(const address& addr) const noexcept = 0; |
462 | | |
463 | | /// @copydoc evmc_host_interface::copy_code |
464 | | virtual size_t copy_code(const address& addr, |
465 | | size_t code_offset, |
466 | | uint8_t* buffer_data, |
467 | | size_t buffer_size) const noexcept = 0; |
468 | | |
469 | | /// @copydoc evmc_host_interface::selfdestruct |
470 | | virtual bool selfdestruct(const address& addr, const address& beneficiary) noexcept = 0; |
471 | | |
472 | | /// @copydoc evmc_host_interface::call |
473 | | virtual Result call(const evmc_message& msg) noexcept = 0; |
474 | | |
475 | | /// @copydoc evmc_host_interface::get_tx_context |
476 | | virtual evmc_tx_context get_tx_context() const noexcept = 0; |
477 | | |
478 | | /// @copydoc evmc_host_interface::get_block_hash |
479 | | virtual bytes32 get_block_hash(int64_t block_number) const noexcept = 0; |
480 | | |
481 | | /// @copydoc evmc_host_interface::emit_log |
482 | | virtual void emit_log(const address& addr, |
483 | | const uint8_t* data, |
484 | | size_t data_size, |
485 | | const bytes32 topics[], |
486 | | size_t num_topics) noexcept = 0; |
487 | | |
488 | | /// @copydoc evmc_host_interface::access_account |
489 | | virtual evmc_access_status access_account(const address& addr) noexcept = 0; |
490 | | |
491 | | /// @copydoc evmc_host_interface::access_storage |
492 | | virtual evmc_access_status access_storage(const address& addr, const bytes32& key) noexcept = 0; |
493 | | |
494 | | /// @copydoc evmc_host_interface::get_transient_storage |
495 | | virtual bytes32 get_transient_storage(const address& addr, |
496 | | const bytes32& key) const noexcept = 0; |
497 | | |
498 | | /// @copydoc evmc_host_interface::set_transient_storage |
499 | | virtual void set_transient_storage(const address& addr, |
500 | | const bytes32& key, |
501 | | const bytes32& value) noexcept = 0; |
502 | | }; |
503 | | |
504 | | |
505 | | /// Wrapper around EVMC host context / host interface. |
506 | | /// |
507 | | /// To be used by VM implementations as better alternative to using ::evmc_host_context directly. |
508 | | class HostContext : public HostInterface |
509 | | { |
510 | | const evmc_host_interface* host = nullptr; |
511 | | evmc_host_context* context = nullptr; |
512 | | |
513 | | public: |
514 | | /// Default constructor for null Host context. |
515 | | HostContext() = default; |
516 | | |
517 | | /// Constructor from the EVMC Host primitives. |
518 | | /// @param interface The reference to the Host interface. |
519 | | /// @param ctx The pointer to the Host context object. This parameter MAY be null. |
520 | | HostContext(const evmc_host_interface& interface, evmc_host_context* ctx) noexcept |
521 | | : host{&interface}, context{ctx} |
522 | 0 | {} |
523 | | |
524 | | bool account_exists(const address& address) const noexcept final |
525 | 0 | { |
526 | 0 | return host->account_exists(context, &address); |
527 | 0 | } |
528 | | |
529 | | bytes32 get_storage(const address& address, const bytes32& key) const noexcept final |
530 | 0 | { |
531 | 0 | return host->get_storage(context, &address, &key); |
532 | 0 | } |
533 | | |
534 | | evmc_storage_status set_storage(const address& address, |
535 | | const bytes32& key, |
536 | | const bytes32& value) noexcept final |
537 | 0 | { |
538 | 0 | return host->set_storage(context, &address, &key, &value); |
539 | 0 | } |
540 | | |
541 | | uint256be get_balance(const address& address) const noexcept final |
542 | 0 | { |
543 | 0 | return host->get_balance(context, &address); |
544 | 0 | } |
545 | | |
546 | | size_t get_code_size(const address& address) const noexcept final |
547 | 0 | { |
548 | 0 | return host->get_code_size(context, &address); |
549 | 0 | } |
550 | | |
551 | | bytes32 get_code_hash(const address& address) const noexcept final |
552 | 0 | { |
553 | 0 | return host->get_code_hash(context, &address); |
554 | 0 | } |
555 | | |
556 | | size_t copy_code(const address& address, |
557 | | size_t code_offset, |
558 | | uint8_t* buffer_data, |
559 | | size_t buffer_size) const noexcept final |
560 | 0 | { |
561 | 0 | return host->copy_code(context, &address, code_offset, buffer_data, buffer_size); |
562 | 0 | } |
563 | | |
564 | | bool selfdestruct(const address& addr, const address& beneficiary) noexcept final |
565 | 0 | { |
566 | 0 | return host->selfdestruct(context, &addr, &beneficiary); |
567 | 0 | } |
568 | | |
569 | | Result call(const evmc_message& message) noexcept final |
570 | 0 | { |
571 | 0 | return Result{host->call(context, &message)}; |
572 | 0 | } |
573 | | |
574 | | /// @copydoc HostInterface::get_tx_context() |
575 | 0 | evmc_tx_context get_tx_context() const noexcept final { return host->get_tx_context(context); } |
576 | | |
577 | | bytes32 get_block_hash(int64_t number) const noexcept final |
578 | 0 | { |
579 | 0 | return host->get_block_hash(context, number); |
580 | 0 | } |
581 | | |
582 | | void emit_log(const address& addr, |
583 | | const uint8_t* data, |
584 | | size_t data_size, |
585 | | const bytes32 topics[], |
586 | | size_t topics_count) noexcept final |
587 | 0 | { |
588 | 0 | host->emit_log(context, &addr, data, data_size, topics, topics_count); |
589 | 0 | } |
590 | | |
591 | | evmc_access_status access_account(const address& address) noexcept final |
592 | 0 | { |
593 | 0 | return host->access_account(context, &address); |
594 | 0 | } |
595 | | |
596 | | evmc_access_status access_storage(const address& address, const bytes32& key) noexcept final |
597 | 0 | { |
598 | 0 | return host->access_storage(context, &address, &key); |
599 | 0 | } |
600 | | |
601 | | bytes32 get_transient_storage(const address& address, const bytes32& key) const noexcept final |
602 | 0 | { |
603 | 0 | return host->get_transient_storage(context, &address, &key); |
604 | 0 | } |
605 | | |
606 | | void set_transient_storage(const address& address, |
607 | | const bytes32& key, |
608 | | const bytes32& value) noexcept final |
609 | 0 | { |
610 | 0 | host->set_transient_storage(context, &address, &key, &value); |
611 | 0 | } |
612 | | }; |
613 | | |
614 | | |
615 | | /// Abstract class to be used by Host implementations. |
616 | | /// |
617 | | /// When implementing EVMC Host, you can directly inherit from the evmc::Host class. |
618 | | /// This way your implementation will be simpler by avoiding manual handling |
619 | | /// of the ::evmc_host_context and the ::evmc_host_interface. |
620 | | class Host : public HostInterface |
621 | | { |
622 | | public: |
623 | | /// Provides access to the global host interface. |
624 | | /// @returns Reference to the host interface object. |
625 | | static const evmc_host_interface& get_interface() noexcept; |
626 | | |
627 | | /// Converts the Host object to the opaque host context pointer. |
628 | | /// @returns Pointer to evmc_host_context. |
629 | 85.9k | evmc_host_context* to_context() noexcept { return reinterpret_cast<evmc_host_context*>(this); } |
630 | | |
631 | | /// Converts the opaque host context pointer back to the original Host object. |
632 | | /// @tparam DerivedClass The class derived from the Host class. |
633 | | /// @param context The opaque host context pointer. |
634 | | /// @returns The pointer to DerivedClass. |
635 | | template <typename DerivedClass = Host> |
636 | | static DerivedClass* from_context(evmc_host_context* context) noexcept |
637 | 1.35M | { |
638 | | // Get pointer of the Host base class. |
639 | 1.35M | auto* h = reinterpret_cast<Host*>(context); |
640 | | |
641 | | // Additional downcast, only possible if DerivedClass inherits from Host. |
642 | 1.35M | return static_cast<DerivedClass*>(h); |
643 | 1.35M | } |
644 | | }; |
645 | | |
646 | | |
647 | | /// @copybrief evmc_vm |
648 | | /// |
649 | | /// This is a RAII wrapper for evmc_vm, and object of this type |
650 | | /// automatically destroys the VM instance. |
651 | | class VM |
652 | | { |
653 | | public: |
654 | | VM() noexcept = default; |
655 | | |
656 | | /// Converting constructor from evmc_vm. |
657 | 8 | explicit VM(evmc_vm* vm) noexcept : m_instance{vm} {} |
658 | | |
659 | | /// Destructor responsible for automatically destroying the VM instance. |
660 | | ~VM() noexcept |
661 | 0 | { |
662 | 0 | if (m_instance != nullptr) |
663 | 0 | m_instance->destroy(m_instance); |
664 | 0 | } |
665 | | |
666 | | VM(const VM&) = delete; |
667 | | VM& operator=(const VM&) = delete; |
668 | | |
669 | | /// Move constructor. |
670 | 0 | VM(VM&& other) noexcept : m_instance{other.m_instance} { other.m_instance = nullptr; } |
671 | | |
672 | | /// Move assignment operator. |
673 | | VM& operator=(VM&& other) noexcept |
674 | 0 | { |
675 | 0 | this->~VM(); |
676 | 0 | m_instance = other.m_instance; |
677 | 0 | other.m_instance = nullptr; |
678 | 0 | return *this; |
679 | 0 | } |
680 | | |
681 | | /// The constructor that captures a VM instance and configures the instance |
682 | | /// with the provided list of options. |
683 | | inline VM(evmc_vm* vm, |
684 | | std::initializer_list<std::pair<const char*, const char*>> options) noexcept; |
685 | | |
686 | | /// Checks if contains a valid pointer to the VM instance. |
687 | 10.1k | explicit operator bool() const noexcept { return m_instance != nullptr; } |
688 | | |
689 | | /// Checks whenever the VM instance is ABI compatible with the current EVMC API. |
690 | 0 | bool is_abi_compatible() const noexcept { return m_instance->abi_version == EVMC_ABI_VERSION; } |
691 | | |
692 | | /// @copydoc evmc_vm::name |
693 | 0 | char const* name() const noexcept { return m_instance->name; } |
694 | | |
695 | | /// @copydoc evmc_vm::version |
696 | 0 | char const* version() const noexcept { return m_instance->version; } |
697 | | |
698 | | /// Checks if the VM has the given capability. |
699 | | bool has_capability(evmc_capabilities capability) const noexcept |
700 | 0 | { |
701 | 0 | return (get_capabilities() & static_cast<evmc_capabilities_flagset>(capability)) != 0; |
702 | 0 | } |
703 | | |
704 | | /// @copydoc evmc_vm::get_capabilities |
705 | | evmc_capabilities_flagset get_capabilities() const noexcept |
706 | 0 | { |
707 | 0 | return m_instance->get_capabilities(m_instance); |
708 | 0 | } |
709 | | |
710 | | /// @copydoc evmc_set_option() |
711 | | evmc_set_option_result set_option(const char name[], const char value[]) noexcept |
712 | 0 | { |
713 | 0 | return evmc_set_option(m_instance, name, value); |
714 | 0 | } |
715 | | |
716 | | /// @copydoc evmc_execute() |
717 | | Result execute(const evmc_host_interface& host, |
718 | | evmc_host_context* ctx, |
719 | | evmc_revision rev, |
720 | | const evmc_message& msg, |
721 | | const uint8_t* code, |
722 | | size_t code_size) noexcept |
723 | 85.9k | { |
724 | 85.9k | return Result{m_instance->execute(m_instance, &host, ctx, rev, &msg, code, code_size)}; |
725 | 85.9k | } |
726 | | |
727 | | /// Convenient variant of the VM::execute() that takes reference to evmc::Host class. |
728 | | Result execute(Host& host, |
729 | | evmc_revision rev, |
730 | | const evmc_message& msg, |
731 | | const uint8_t* code, |
732 | | size_t code_size) noexcept |
733 | 85.9k | { |
734 | 85.9k | return execute(Host::get_interface(), host.to_context(), rev, msg, code, code_size); |
735 | 85.9k | } |
736 | | |
737 | | /// Executes code without the Host context. |
738 | | /// |
739 | | /// The same as |
740 | | /// execute(const evmc_host_interface&, evmc_host_context*, evmc_revision, |
741 | | /// const evmc_message&, const uint8_t*, size_t), |
742 | | /// but without providing the Host context and interface. |
743 | | /// This method is for experimental precompiles support where execution is |
744 | | /// guaranteed not to require any Host access. |
745 | | Result execute(evmc_revision rev, |
746 | | const evmc_message& msg, |
747 | | const uint8_t* code, |
748 | | size_t code_size) noexcept |
749 | 0 | { |
750 | 0 | return Result{ |
751 | 0 | m_instance->execute(m_instance, nullptr, nullptr, rev, &msg, code, code_size)}; |
752 | 0 | } |
753 | | |
754 | | /// Returns the pointer to C EVMC struct representing the VM. |
755 | | /// |
756 | | /// Gives access to the C EVMC VM struct to allow advanced interaction with the VM not supported |
757 | | /// by the C++ interface. Use as the last resort. |
758 | | /// This object still owns the VM after returning the pointer. The returned pointer MAY be null. |
759 | 0 | evmc_vm* get_raw_pointer() const noexcept { return m_instance; } |
760 | | |
761 | | private: |
762 | | evmc_vm* m_instance = nullptr; |
763 | | }; |
764 | | |
765 | | inline VM::VM(evmc_vm* vm, |
766 | | std::initializer_list<std::pair<const char*, const char*>> options) noexcept |
767 | | : m_instance{vm} |
768 | | { |
769 | | // This constructor is implemented outside of the class definition to workaround a doxygen bug. |
770 | | for (const auto& option : options) |
771 | | set_option(option.first, option.second); |
772 | | } |
773 | | |
774 | | |
775 | | namespace internal |
776 | | { |
777 | | inline bool account_exists(evmc_host_context* h, const evmc_address* addr) noexcept |
778 | 39.1k | { |
779 | 39.1k | return Host::from_context(h)->account_exists(*addr); |
780 | 39.1k | } |
781 | | |
782 | | inline evmc_bytes32 get_storage(evmc_host_context* h, |
783 | | const evmc_address* addr, |
784 | | const evmc_bytes32* key) noexcept |
785 | 145k | { |
786 | 145k | return Host::from_context(h)->get_storage(*addr, *key); |
787 | 145k | } |
788 | | |
789 | | inline evmc_storage_status set_storage(evmc_host_context* h, |
790 | | const evmc_address* addr, |
791 | | const evmc_bytes32* key, |
792 | | const evmc_bytes32* value) noexcept |
793 | 397k | { |
794 | 397k | return Host::from_context(h)->set_storage(*addr, *key, *value); |
795 | 397k | } |
796 | | |
797 | | inline evmc_uint256be get_balance(evmc_host_context* h, const evmc_address* addr) noexcept |
798 | 45.9k | { |
799 | 45.9k | return Host::from_context(h)->get_balance(*addr); |
800 | 45.9k | } |
801 | | |
802 | | inline size_t get_code_size(evmc_host_context* h, const evmc_address* addr) noexcept |
803 | 0 | { |
804 | 0 | return Host::from_context(h)->get_code_size(*addr); |
805 | 0 | } |
806 | | |
807 | | inline evmc_bytes32 get_code_hash(evmc_host_context* h, const evmc_address* addr) noexcept |
808 | 0 | { |
809 | 0 | return Host::from_context(h)->get_code_hash(*addr); |
810 | 0 | } |
811 | | |
812 | | inline size_t copy_code(evmc_host_context* h, |
813 | | const evmc_address* addr, |
814 | | size_t code_offset, |
815 | | uint8_t* buffer_data, |
816 | | size_t buffer_size) noexcept |
817 | 0 | { |
818 | 0 | return Host::from_context(h)->copy_code(*addr, code_offset, buffer_data, buffer_size); |
819 | 0 | } |
820 | | |
821 | | inline bool selfdestruct(evmc_host_context* h, |
822 | | const evmc_address* addr, |
823 | | const evmc_address* beneficiary) noexcept |
824 | 470 | { |
825 | 470 | return Host::from_context(h)->selfdestruct(*addr, *beneficiary); |
826 | 470 | } |
827 | | |
828 | | inline evmc_result call(evmc_host_context* h, const evmc_message* msg) noexcept |
829 | 51.0k | { |
830 | 51.0k | return Host::from_context(h)->call(*msg).release_raw(); |
831 | 51.0k | } |
832 | | |
833 | | inline evmc_tx_context get_tx_context(evmc_host_context* h) noexcept |
834 | 12.8k | { |
835 | 12.8k | return Host::from_context(h)->get_tx_context(); |
836 | 12.8k | } |
837 | | |
838 | | inline evmc_bytes32 get_block_hash(evmc_host_context* h, int64_t block_number) noexcept |
839 | 0 | { |
840 | 0 | return Host::from_context(h)->get_block_hash(block_number); |
841 | 0 | } |
842 | | |
843 | | inline void emit_log(evmc_host_context* h, |
844 | | const evmc_address* addr, |
845 | | const uint8_t* data, |
846 | | size_t data_size, |
847 | | const evmc_bytes32 topics[], |
848 | | size_t num_topics) noexcept |
849 | 0 | { |
850 | 0 | Host::from_context(h)->emit_log(*addr, data, data_size, static_cast<const bytes32*>(topics), |
851 | 0 | num_topics); |
852 | 0 | } |
853 | | |
854 | | inline evmc_access_status access_account(evmc_host_context* h, const evmc_address* addr) noexcept |
855 | 95.1k | { |
856 | 95.1k | return Host::from_context(h)->access_account(*addr); |
857 | 95.1k | } |
858 | | |
859 | | inline evmc_access_status access_storage(evmc_host_context* h, |
860 | | const evmc_address* addr, |
861 | | const evmc_bytes32* key) noexcept |
862 | 543k | { |
863 | 543k | return Host::from_context(h)->access_storage(*addr, *key); |
864 | 543k | } |
865 | | |
866 | | inline evmc_bytes32 get_transient_storage(evmc_host_context* h, |
867 | | const evmc_address* addr, |
868 | | const evmc_bytes32* key) noexcept |
869 | 3.04k | { |
870 | 3.04k | return Host::from_context(h)->get_transient_storage(*addr, *key); |
871 | 3.04k | } |
872 | | |
873 | | inline void set_transient_storage(evmc_host_context* h, |
874 | | const evmc_address* addr, |
875 | | const evmc_bytes32* key, |
876 | | const evmc_bytes32* value) noexcept |
877 | 18.4k | { |
878 | 18.4k | Host::from_context(h)->set_transient_storage(*addr, *key, *value); |
879 | 18.4k | } |
880 | | } // namespace internal |
881 | | |
882 | | inline const evmc_host_interface& Host::get_interface() noexcept |
883 | 85.9k | { |
884 | 85.9k | static constexpr evmc_host_interface interface = { |
885 | 85.9k | ::evmc::internal::account_exists, |
886 | 85.9k | ::evmc::internal::get_storage, |
887 | 85.9k | ::evmc::internal::set_storage, |
888 | 85.9k | ::evmc::internal::get_balance, |
889 | 85.9k | ::evmc::internal::get_code_size, |
890 | 85.9k | ::evmc::internal::get_code_hash, |
891 | 85.9k | ::evmc::internal::copy_code, |
892 | 85.9k | ::evmc::internal::selfdestruct, |
893 | 85.9k | ::evmc::internal::call, |
894 | 85.9k | ::evmc::internal::get_tx_context, |
895 | 85.9k | ::evmc::internal::get_block_hash, |
896 | 85.9k | ::evmc::internal::emit_log, |
897 | 85.9k | ::evmc::internal::access_account, |
898 | 85.9k | ::evmc::internal::access_storage, |
899 | 85.9k | ::evmc::internal::get_transient_storage, |
900 | 85.9k | ::evmc::internal::set_transient_storage, |
901 | 85.9k | }; |
902 | 85.9k | return interface; |
903 | 85.9k | } |
904 | | } // namespace evmc |
905 | | |
906 | | |
907 | | /// "Stream out" operator implementation for ::evmc_status_code. |
908 | | /// |
909 | | /// @note This is defined in global namespace to match ::evmc_status_code definition and allow |
910 | | /// convenient operator overloading usage. |
911 | | inline std::ostream& operator<<(std::ostream& os, evmc_status_code status_code) |
912 | 0 | { |
913 | 0 | return os << evmc::to_string(status_code); |
914 | 0 | } |
915 | | |
916 | | /// "Stream out" operator implementation for ::evmc_revision. |
917 | | /// |
918 | | /// @note This is defined in global namespace to match ::evmc_revision definition and allow |
919 | | /// convenient operator overloading usage. |
920 | | inline std::ostream& operator<<(std::ostream& os, evmc_revision rev) |
921 | 0 | { |
922 | 0 | return os << evmc::to_string(rev); |
923 | 0 | } |
924 | | |
925 | | namespace std |
926 | | { |
927 | | /// Hash operator template specialization for evmc::address. Needed for unordered containers. |
928 | | template <> |
929 | | struct hash<evmc::address> |
930 | | { |
931 | | /// Hash operator using FNV1a-based folding. |
932 | | constexpr size_t operator()(const evmc::address& s) const noexcept |
933 | 3.02M | { |
934 | 3.02M | using namespace evmc; |
935 | 3.02M | using namespace fnv; |
936 | 3.02M | return static_cast<size_t>(fnv1a_by64( |
937 | 3.02M | fnv1a_by64(fnv1a_by64(fnv::offset_basis, load64le(&s.bytes[0])), load64le(&s.bytes[8])), |
938 | 3.02M | load32le(&s.bytes[16]))); |
939 | 3.02M | } |
940 | | }; |
941 | | |
942 | | /// Hash operator template specialization for evmc::bytes32. Needed for unordered containers. |
943 | | template <> |
944 | | struct hash<evmc::bytes32> |
945 | | { |
946 | | /// Hash operator using FNV1a-based folding. |
947 | | constexpr size_t operator()(const evmc::bytes32& s) const noexcept |
948 | 23.3k | { |
949 | 23.3k | using namespace evmc; |
950 | 23.3k | using namespace fnv; |
951 | 23.3k | return static_cast<size_t>( |
952 | 23.3k | fnv1a_by64(fnv1a_by64(fnv1a_by64(fnv1a_by64(fnv::offset_basis, load64le(&s.bytes[0])), |
953 | 23.3k | load64le(&s.bytes[8])), |
954 | 23.3k | load64le(&s.bytes[16])), |
955 | 23.3k | load64le(&s.bytes[24]))); |
956 | 23.3k | } |
957 | | }; |
958 | | } // namespace std |