Coverage Report

Created: 2025-09-08 08:10

/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