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