diff --git a/test/evmc/README.md b/test/evmc/README.md index 436a47e68..1d5d55422 100644 --- a/test/evmc/README.md +++ b/test/evmc/README.md @@ -1,3 +1,3 @@ # EVMC -This is an import of [EVMC](https://github.com/ethereum/evmc) version [7.1.0](https://github.com/ethereum/evmc/releases/tag/v7.1.0). +This is an import of [EVMC](https://github.com/ethereum/evmc) version [7.2.0](https://github.com/ethereum/evmc/releases/tag/v7.2.0). diff --git a/test/evmc/evmc.h b/test/evmc/evmc.h index 3fc3ca610..51d9f842a 100644 --- a/test/evmc/evmc.h +++ b/test/evmc/evmc.h @@ -345,8 +345,8 @@ struct evmc_result /** * The amount of gas left after the execution. * - * If evmc_result::code is not ::EVMC_SUCCESS nor ::EVMC_REVERT - * the value MUST be 0. + * If evmc_result::status_code is neither ::EVMC_SUCCESS nor ::EVMC_REVERT + * the value MUST be 0. */ int64_t gas_left; diff --git a/test/evmc/evmc.hpp b/test/evmc/evmc.hpp index 0b44cd12c..36f9063b3 100644 --- a/test/evmc/evmc.hpp +++ b/test/evmc/evmc.hpp @@ -25,6 +25,33 @@ struct address : evmc_address /// Initializes bytes to zeros if not other @p init value provided. constexpr address(evmc_address init = {}) noexcept : evmc_address{init} {} + /// Converting constructor from unsigned integer value. + /// + /// This constructor assigns the @p v value to the last 8 bytes [12:19] + /// in big-endian order. + constexpr explicit address(uint64_t v) noexcept + : evmc_address{{0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + static_cast(v >> 56), + static_cast(v >> 48), + static_cast(v >> 40), + static_cast(v >> 32), + static_cast(v >> 24), + static_cast(v >> 16), + static_cast(v >> 8), + static_cast(v >> 0)}} + {} + /// Explicit operator converting to bool. constexpr inline explicit operator bool() const noexcept; }; @@ -39,6 +66,45 @@ struct bytes32 : evmc_bytes32 /// Initializes bytes to zeros if not other @p init value provided. constexpr bytes32(evmc_bytes32 init = {}) noexcept : evmc_bytes32{init} {} + /// Converting constructor from unsigned integer value. + /// + /// This constructor assigns the @p v value to the last 8 bytes [24:31] + /// in big-endian order. + constexpr explicit bytes32(uint64_t v) noexcept + : evmc_bytes32{{0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + static_cast(v >> 56), + static_cast(v >> 48), + static_cast(v >> 40), + static_cast(v >> 32), + static_cast(v >> 24), + static_cast(v >> 16), + static_cast(v >> 8), + static_cast(v >> 0)}} + {} + /// Explicit operator converting to bool. constexpr inline explicit operator bool() const noexcept; }; @@ -50,7 +116,6 @@ using uint256be = bytes32; /// Loads 64 bits / 8 bytes of data from the given @p bytes array in big-endian order. constexpr inline uint64_t load64be(const uint8_t* bytes) noexcept { - // TODO: Report bug in clang incorrectly optimizing this with AVX2 enabled. return (uint64_t{bytes[0]} << 56) | (uint64_t{bytes[1]} << 48) | (uint64_t{bytes[2]} << 40) | (uint64_t{bytes[3]} << 32) | (uint64_t{bytes[4]} << 24) | (uint64_t{bytes[5]} << 16) | (uint64_t{bytes[6]} << 8) | uint64_t{bytes[7]}; @@ -76,7 +141,7 @@ constexpr inline uint64_t fnv1a_by64(uint64_t h, uint64_t x) noexcept } // namespace fnv -/// The "equal" comparison operator for the evmc::address type. +/// The "equal to" comparison operator for the evmc::address type. constexpr bool operator==(const address& a, const address& b) noexcept { // TODO: Report bug in clang keeping unnecessary bswap. @@ -85,23 +150,41 @@ constexpr bool operator==(const address& a, const address& b) noexcept load32be(&a.bytes[16]) == load32be(&b.bytes[16]); } -/// The "not equal" comparison operator for the evmc::address type. +/// The "not equal to" comparison operator for the evmc::address type. constexpr bool operator!=(const address& a, const address& b) noexcept { return !(a == b); } -/// The "less" comparison operator for the evmc::address type. +/// The "less than" comparison operator for the evmc::address type. constexpr bool operator<(const address& a, const address& b) noexcept { return load64be(&a.bytes[0]) < load64be(&b.bytes[0]) || (load64be(&a.bytes[0]) == load64be(&b.bytes[0]) && - load64be(&a.bytes[8]) < load64be(&b.bytes[8])) || - (load64be(&a.bytes[8]) == load64be(&b.bytes[8]) && - load32be(&a.bytes[16]) < load32be(&b.bytes[16])); + (load64be(&a.bytes[8]) < load64be(&b.bytes[8]) || + (load64be(&a.bytes[8]) == load64be(&b.bytes[8]) && + load32be(&a.bytes[16]) < load32be(&b.bytes[16])))); } -/// The "equal" comparison operator for the evmc::bytes32 type. +/// The "greater than" comparison operator for the evmc::address type. +constexpr bool operator>(const address& a, const address& b) noexcept +{ + return b < a; +} + +/// The "less than or equal to" comparison operator for the evmc::address type. +constexpr bool operator<=(const address& a, const address& b) noexcept +{ + return !(b < a); +} + +/// The "greater than or equal to" comparison operator for the evmc::address type. +constexpr bool operator>=(const address& a, const address& b) noexcept +{ + return !(a < b); +} + +/// The "equal to" comparison operator for the evmc::bytes32 type. constexpr bool operator==(const bytes32& a, const bytes32& b) noexcept { return load64be(&a.bytes[0]) == load64be(&b.bytes[0]) && @@ -110,22 +193,40 @@ constexpr bool operator==(const bytes32& a, const bytes32& b) noexcept load64be(&a.bytes[24]) == load64be(&b.bytes[24]); } -/// The "not equal" comparison operator for the evmc::bytes32 type. +/// The "not equal to" comparison operator for the evmc::bytes32 type. constexpr bool operator!=(const bytes32& a, const bytes32& b) noexcept { return !(a == b); } -/// The "less" comparison operator for the evmc::bytes32 type. +/// The "less than" comparison operator for the evmc::bytes32 type. constexpr bool operator<(const bytes32& a, const bytes32& b) noexcept { return load64be(&a.bytes[0]) < load64be(&b.bytes[0]) || (load64be(&a.bytes[0]) == load64be(&b.bytes[0]) && - load64be(&a.bytes[8]) < load64be(&b.bytes[8])) || - (load64be(&a.bytes[8]) == load64be(&b.bytes[8]) && - load64be(&a.bytes[16]) < load64be(&b.bytes[16])) || - (load64be(&a.bytes[16]) == load64be(&b.bytes[16]) && - load64be(&a.bytes[24]) < load64be(&b.bytes[24])); + (load64be(&a.bytes[8]) < load64be(&b.bytes[8]) || + (load64be(&a.bytes[8]) == load64be(&b.bytes[8]) && + (load64be(&a.bytes[16]) < load64be(&b.bytes[16]) || + (load64be(&a.bytes[16]) == load64be(&b.bytes[16]) && + load64be(&a.bytes[24]) < load64be(&b.bytes[24])))))); +} + +/// The "greater than" comparison operator for the evmc::bytes32 type. +constexpr bool operator>(const bytes32& a, const bytes32& b) noexcept +{ + return b < a; +} + +/// The "less than or equal to" comparison operator for the evmc::bytes32 type. +constexpr bool operator<=(const bytes32& a, const bytes32& b) noexcept +{ + return !(b < a); +} + +/// The "greater than or equal to" comparison operator for the evmc::bytes32 type. +constexpr bool operator>=(const bytes32& a, const bytes32& b) noexcept +{ + return !(a < b); } /// Checks if the given address is the zero address. @@ -154,108 +255,72 @@ namespace literals { namespace internal { -template -struct integer_sequence +constexpr size_t length(const char* s) noexcept { -}; - -template -using byte_sequence = integer_sequence; - -template -using char_sequence = integer_sequence; - - -template -struct concatenate; - -template -struct concatenate, byte_sequence> -{ - using type = byte_sequence; -}; - -template -constexpr uint8_t parse_hex_digit() noexcept -{ - static_assert((D >= '0' && D <= '9') || (D >= 'a' && D <= 'f') || (D >= 'A' && D <= 'F'), - "literal must be hexadecimal integer"); - return static_cast( - (D >= '0' && D <= '9') ? D - '0' : (D >= 'a' && D <= 'f') ? D - 'a' + 10 : D - 'A' + 10); + return (*s != '\0') ? length(s + 1) + 1 : 0; } - -template -struct parse_digits; - -template -struct parse_digits> +constexpr int from_hex(char c) noexcept { - using type = byte_sequence(parse_hex_digit() << 4) | - parse_hex_digit()>; -}; + return (c >= 'a' && c <= 'f') ? c - ('a' - 10) : + (c >= 'A' && c <= 'F') ? c - ('A' - 10) : c - '0'; +} -template -struct parse_digits> +constexpr uint8_t byte(const char* s, size_t i) noexcept { - using type = typename concatenate>::type, - typename parse_digits>::type>::type; -}; + return static_cast((from_hex(s[2 * i]) << 4) | from_hex(s[2 * i + 1])); +} +template +T from_hex(const char*) noexcept; -template -struct parse_literal; - -template -struct parse_literal> +template <> +constexpr bytes32 from_hex(const char* s) noexcept { - static_assert(Prefix1 == '0' && Prefix2 == 'x', "literal must be in hexadecimal notation"); - static_assert(sizeof...(Literal) == sizeof(T) * 2, "literal must match the result type size"); + return { + {{byte(s, 0), byte(s, 1), byte(s, 2), byte(s, 3), byte(s, 4), byte(s, 5), byte(s, 6), + byte(s, 7), byte(s, 8), byte(s, 9), byte(s, 10), byte(s, 11), byte(s, 12), byte(s, 13), + byte(s, 14), byte(s, 15), byte(s, 16), byte(s, 17), byte(s, 18), byte(s, 19), byte(s, 20), + byte(s, 21), byte(s, 22), byte(s, 23), byte(s, 24), byte(s, 25), byte(s, 26), byte(s, 27), + byte(s, 28), byte(s, 29), byte(s, 30), byte(s, 31)}}}; +} - template - static constexpr T create_from(byte_sequence) noexcept - { - return T{{{Bytes...}}}; - } - - static constexpr T get() noexcept - { - return create_from(typename parse_digits>::type{}); - } -}; - -template -struct parse_literal> +template <> +constexpr address from_hex
(const char* s) noexcept { - static_assert(Digit == '0', "only 0 is allowed as a single digit literal"); - static constexpr T get() noexcept { return {}; } -}; + return { + {{byte(s, 0), byte(s, 1), byte(s, 2), byte(s, 3), byte(s, 4), byte(s, 5), byte(s, 6), + byte(s, 7), byte(s, 8), byte(s, 9), byte(s, 10), byte(s, 11), byte(s, 12), byte(s, 13), + byte(s, 14), byte(s, 15), byte(s, 16), byte(s, 17), byte(s, 18), byte(s, 19)}}}; +} -template -constexpr T parse() noexcept +template +constexpr T from_literal(const char* s) { - return parse_literal>::get(); + return (s[0] == '0' && s[1] == '\0') ? + T{} : + !(s[0] == '0' && s[1] == 'x') ? + throw "literal must be in hexadecimal notation" : + (length(s + 2) != sizeof(T) * 2) ? throw "literal must match the result type size" : + from_hex(s + 2); } } // namespace internal /// Literal for evmc::address. -template -constexpr address operator"" _address() noexcept +constexpr address operator""_address(const char* s) noexcept { - return internal::parse(); + return internal::from_literal
(s); } /// Literal for evmc::bytes32. -template -constexpr bytes32 operator"" _bytes32() noexcept +constexpr bytes32 operator""_bytes32(const char* s) noexcept { - return internal::parse(); + return internal::from_literal(s); } } // namespace literals using namespace literals; - /// Alias for evmc_make_result(). constexpr auto make_result = evmc_make_result; @@ -626,6 +691,13 @@ public: m_instance->execute(m_instance, nullptr, nullptr, rev, &msg, code, code_size)}; } + /// Returns the pointer to C EVMC struct representing the VM. + /// + /// Gives access to the C EVMC VM struct to allow advanced interaction with the VM not supported + /// by the C++ interface. Use as the last resort. + /// This object still owns the VM after returning the pointer. The returned pointer MAY be null. + evmc_vm* get_raw_pointer() const noexcept { return m_instance; } + private: evmc_vm* m_instance = nullptr; }; diff --git a/test/evmc/mocked_host.hpp b/test/evmc/mocked_host.hpp index 2ff1701a4..57f0cb79b 100644 --- a/test/evmc/mocked_host.hpp +++ b/test/evmc/mocked_host.hpp @@ -133,10 +133,11 @@ public: /// The record of all SELFDESTRUCTs from the selfdestruct() method. std::vector recorded_selfdestructs; -protected: +private: /// The copy of call inputs for the recorded_calls record. std::vector m_recorded_calls_inputs; +public: /// Record an account access. /// @param addr The address of the accessed account. void record_account_access(const address& addr) const