mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Update EVMC to 6.3.1
This commit is contained in:
parent
37c6ab4c38
commit
882cd3e285
@ -21,7 +21,6 @@
|
||||
|
||||
#include <test/EVMHost.h>
|
||||
|
||||
#include <test/evmc/helpers.hpp>
|
||||
#include <test/evmc/loader.h>
|
||||
|
||||
#include <libevmasm/GasMeter.h>
|
||||
@ -91,27 +90,27 @@ EVMHost::EVMHost(langutil::EVMVersion _evmVersion, evmc::vm* _vm):
|
||||
m_evmVersion = EVMC_PETERSBURG;
|
||||
}
|
||||
|
||||
evmc_storage_status EVMHost::set_storage(const evmc_address& _addr, const evmc_bytes32& _key, const evmc_bytes32& _value) noexcept
|
||||
evmc_storage_status EVMHost::set_storage(const evmc::address& _addr, const evmc::bytes32& _key, const evmc::bytes32& _value) noexcept
|
||||
{
|
||||
evmc_bytes32 previousValue = m_state.accounts[_addr].storage[_key];
|
||||
evmc::bytes32 previousValue = m_state.accounts[_addr].storage[_key];
|
||||
m_state.accounts[_addr].storage[_key] = _value;
|
||||
|
||||
// TODO EVMC_STORAGE_MODIFIED_AGAIN should be also used
|
||||
if (previousValue == _value)
|
||||
return EVMC_STORAGE_UNCHANGED;
|
||||
else if (previousValue == evmc_bytes32{})
|
||||
else if (previousValue == evmc::bytes32{})
|
||||
return EVMC_STORAGE_ADDED;
|
||||
else if (_value == evmc_bytes32{})
|
||||
else if (_value == evmc::bytes32{})
|
||||
return EVMC_STORAGE_DELETED;
|
||||
else
|
||||
return EVMC_STORAGE_MODIFIED;
|
||||
|
||||
}
|
||||
|
||||
void EVMHost::selfdestruct(const evmc_address& _addr, const evmc_address& _beneficiary) noexcept
|
||||
void EVMHost::selfdestruct(const evmc::address& _addr, const evmc::address& _beneficiary) noexcept
|
||||
{
|
||||
// TODO actual selfdestruct is even more complicated.
|
||||
evmc_uint256be balance = m_state.accounts[_addr].balance;
|
||||
evmc::uint256be balance = m_state.accounts[_addr].balance;
|
||||
m_state.accounts.erase(_addr);
|
||||
m_state.accounts[_beneficiary].balance = balance;
|
||||
}
|
||||
@ -190,7 +189,7 @@ evmc::result EVMHost::call(evmc_message const& _message) noexcept
|
||||
destination.balance = convertToEVMC(u256(convertFromEVMC(destination.balance)) + value);
|
||||
}
|
||||
|
||||
evmc_address currentAddress = m_currentAddress;
|
||||
evmc::address currentAddress = m_currentAddress;
|
||||
m_currentAddress = message.destination;
|
||||
evmc::result result = m_vm->execute(*this, m_evmVersion, message, code.data(), code.size());
|
||||
m_currentAddress = currentAddress;
|
||||
@ -231,16 +230,16 @@ evmc_tx_context EVMHost::get_tx_context() noexcept
|
||||
return ctx;
|
||||
}
|
||||
|
||||
evmc_bytes32 EVMHost::get_block_hash(int64_t _number) noexcept
|
||||
evmc::bytes32 EVMHost::get_block_hash(int64_t _number) noexcept
|
||||
{
|
||||
return convertToEVMC(u256("0x3737373737373737373737373737373737373737373737373737373737373737") + _number);
|
||||
}
|
||||
|
||||
void EVMHost::emit_log(
|
||||
evmc_address const& _addr,
|
||||
evmc::address const& _addr,
|
||||
uint8_t const* _data,
|
||||
size_t _dataSize,
|
||||
evmc_bytes32 const _topics[],
|
||||
evmc::bytes32 const _topics[],
|
||||
size_t _topicsCount
|
||||
) noexcept
|
||||
{
|
||||
@ -253,27 +252,27 @@ void EVMHost::emit_log(
|
||||
}
|
||||
|
||||
|
||||
Address EVMHost::convertFromEVMC(evmc_address const& _addr)
|
||||
Address EVMHost::convertFromEVMC(evmc::address const& _addr)
|
||||
{
|
||||
return Address(bytes(begin(_addr.bytes), end(_addr.bytes)));
|
||||
}
|
||||
|
||||
evmc_address EVMHost::convertToEVMC(Address const& _addr)
|
||||
evmc::address EVMHost::convertToEVMC(Address const& _addr)
|
||||
{
|
||||
evmc_address a;
|
||||
evmc::address a;
|
||||
for (size_t i = 0; i < 20; ++i)
|
||||
a.bytes[i] = _addr[i];
|
||||
return a;
|
||||
}
|
||||
|
||||
h256 EVMHost::convertFromEVMC(evmc_bytes32 const& _data)
|
||||
h256 EVMHost::convertFromEVMC(evmc::bytes32 const& _data)
|
||||
{
|
||||
return h256(bytes(begin(_data.bytes), end(_data.bytes)));
|
||||
}
|
||||
|
||||
evmc_bytes32 EVMHost::convertToEVMC(h256 const& _data)
|
||||
evmc::bytes32 EVMHost::convertToEVMC(h256 const& _data)
|
||||
{
|
||||
evmc_bytes32 d;
|
||||
evmc::bytes32 d;
|
||||
for (size_t i = 0; i < 32; ++i)
|
||||
d.bytes[i] = _data[i];
|
||||
return d;
|
||||
|
@ -23,7 +23,6 @@
|
||||
|
||||
#include <test/evmc/evmc.hpp>
|
||||
#include <test/evmc/evmc.h>
|
||||
#include <test/evmc/helpers.hpp>
|
||||
|
||||
#include <liblangutil/EVMVersion.h>
|
||||
|
||||
@ -47,11 +46,11 @@ public:
|
||||
|
||||
struct Account
|
||||
{
|
||||
evmc_uint256be balance = {};
|
||||
evmc::uint256be balance = {};
|
||||
size_t nonce = 0;
|
||||
bytes code;
|
||||
evmc_bytes32 codeHash = {};
|
||||
std::map<evmc_bytes32, evmc_bytes32> storage;
|
||||
evmc::bytes32 codeHash = {};
|
||||
std::map<evmc::bytes32, evmc::bytes32> storage;
|
||||
};
|
||||
|
||||
struct LogEntry
|
||||
@ -65,11 +64,11 @@ public:
|
||||
{
|
||||
size_t blockNumber;
|
||||
uint64_t timestamp;
|
||||
std::map<evmc_address, Account> accounts;
|
||||
std::map<evmc::address, Account> accounts;
|
||||
std::vector<LogEntry> logs;
|
||||
};
|
||||
|
||||
Account* account(evmc_address const& _address)
|
||||
Account* account(evmc::address const& _address)
|
||||
{
|
||||
// Make all precompiled contracts exist.
|
||||
// Be future-proof and consider everything below 1024 as precompiled contract.
|
||||
@ -87,12 +86,12 @@ public:
|
||||
m_state.logs.clear();
|
||||
}
|
||||
|
||||
bool account_exists(evmc_address const& _addr) noexcept final
|
||||
bool account_exists(evmc::address const& _addr) noexcept final
|
||||
{
|
||||
return account(_addr) != nullptr;
|
||||
}
|
||||
|
||||
evmc_bytes32 get_storage(evmc_address const& _addr, evmc_bytes32 const& _key) noexcept final
|
||||
evmc::bytes32 get_storage(evmc::address const& _addr, evmc::bytes32 const& _key) noexcept final
|
||||
{
|
||||
if (Account* acc = account(_addr))
|
||||
return acc->storage[_key];
|
||||
@ -100,26 +99,26 @@ public:
|
||||
}
|
||||
|
||||
evmc_storage_status set_storage(
|
||||
evmc_address const& _addr,
|
||||
evmc_bytes32 const& _key,
|
||||
evmc_bytes32 const& _value
|
||||
evmc::address const& _addr,
|
||||
evmc::bytes32 const& _key,
|
||||
evmc::bytes32 const& _value
|
||||
) noexcept;
|
||||
|
||||
evmc_uint256be get_balance(evmc_address const& _addr) noexcept final
|
||||
evmc::uint256be get_balance(evmc::address const& _addr) noexcept final
|
||||
{
|
||||
if (Account const* acc = account(_addr))
|
||||
return acc->balance;
|
||||
return {};
|
||||
}
|
||||
|
||||
size_t get_code_size(evmc_address const& _addr) noexcept final
|
||||
size_t get_code_size(evmc::address const& _addr) noexcept final
|
||||
{
|
||||
if (Account const* acc = account(_addr))
|
||||
return acc->code.size();
|
||||
return 0;
|
||||
}
|
||||
|
||||
evmc_bytes32 get_code_hash(evmc_address const& _addr) noexcept final
|
||||
evmc::bytes32 get_code_hash(evmc::address const& _addr) noexcept final
|
||||
{
|
||||
if (Account const* acc = account(_addr))
|
||||
return acc->codeHash;
|
||||
@ -127,7 +126,7 @@ public:
|
||||
}
|
||||
|
||||
size_t copy_code(
|
||||
evmc_address const& _addr,
|
||||
evmc::address const& _addr,
|
||||
size_t _codeOffset,
|
||||
uint8_t* _bufferData,
|
||||
size_t _bufferSize
|
||||
@ -140,31 +139,31 @@ public:
|
||||
return i;
|
||||
}
|
||||
|
||||
void selfdestruct(evmc_address const& _addr, evmc_address const& _beneficiary) noexcept;
|
||||
void selfdestruct(evmc::address const& _addr, evmc::address const& _beneficiary) noexcept;
|
||||
|
||||
evmc::result call(evmc_message const& _message) noexcept;
|
||||
|
||||
evmc_tx_context get_tx_context() noexcept;
|
||||
|
||||
evmc_bytes32 get_block_hash(int64_t number) noexcept;
|
||||
evmc::bytes32 get_block_hash(int64_t number) noexcept;
|
||||
|
||||
void emit_log(
|
||||
evmc_address const& _addr,
|
||||
evmc::address const& _addr,
|
||||
uint8_t const* _data,
|
||||
size_t _dataSize,
|
||||
evmc_bytes32 const _topics[],
|
||||
evmc::bytes32 const _topics[],
|
||||
size_t _topicsCount
|
||||
) noexcept;
|
||||
|
||||
static Address convertFromEVMC(evmc_address const& _addr);
|
||||
static evmc_address convertToEVMC(Address const& _addr);
|
||||
static h256 convertFromEVMC(evmc_bytes32 const& _data);
|
||||
static evmc_bytes32 convertToEVMC(h256 const& _data);
|
||||
static Address convertFromEVMC(evmc::address const& _addr);
|
||||
static evmc::address convertToEVMC(Address const& _addr);
|
||||
static h256 convertFromEVMC(evmc::bytes32 const& _data);
|
||||
static evmc::bytes32 convertToEVMC(h256 const& _data);
|
||||
|
||||
|
||||
State m_state;
|
||||
evmc_address m_currentAddress = {};
|
||||
evmc_address m_coinbase = convertToEVMC(Address("0x7878787878787878787878787878787878787878"));
|
||||
evmc::address m_currentAddress = {};
|
||||
evmc::address m_coinbase = convertToEVMC(Address("0x7878787878787878787878787878787878787878"));
|
||||
|
||||
private:
|
||||
evmc::result precompileECRecover(evmc_message const& _message) noexcept;
|
||||
|
@ -26,7 +26,6 @@
|
||||
|
||||
#include <test/evmc/evmc.hpp>
|
||||
#include <test/evmc/loader.h>
|
||||
#include <test/evmc/helpers.hpp>
|
||||
|
||||
#include <libdevcore/CommonIO.h>
|
||||
|
||||
@ -235,7 +234,7 @@ bool ExecutionFramework::storageEmpty(Address const& _addr)
|
||||
if (EVMHost::Account const* acc = m_evmHost->account(EVMHost::convertToEVMC(_addr)))
|
||||
{
|
||||
for (auto const& entry: acc->storage)
|
||||
if (!(entry.second == evmc_bytes32{}))
|
||||
if (!(entry.second == evmc::bytes32{}))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
|
@ -303,7 +303,10 @@ enum evmc_status_code
|
||||
* For example, the Client tries running a code in the EVM 1.5. If the
|
||||
* code is not supported there, the execution falls back to the EVM 1.0.
|
||||
*/
|
||||
EVMC_REJECTED = -2
|
||||
EVMC_REJECTED = -2,
|
||||
|
||||
/** The VM failed to allocate the amount of memory needed for execution. */
|
||||
EVMC_OUT_OF_MEMORY = -3
|
||||
};
|
||||
|
||||
/* Forward declaration. */
|
||||
@ -795,13 +798,15 @@ enum evmc_revision
|
||||
*
|
||||
* This function MAY be invoked multiple times for a single VM instance.
|
||||
*
|
||||
* @param instance The VM instance.
|
||||
* @param context The pointer to the Client execution context to be passed
|
||||
* to the callback functions. See ::evmc_context.
|
||||
* @param rev Requested EVM specification revision.
|
||||
* @param msg Call parameters. See ::evmc_message.
|
||||
* @param code Reference to the code to be executed.
|
||||
* @param code_size The length of the code.
|
||||
* @param instance The VM instance. This argument MUST NOT be NULL.
|
||||
* @param context The pointer to the Host execution context to be passed
|
||||
* to the Host interface methods (::evmc_host_interface).
|
||||
* This argument MUST NOT be NULL unless
|
||||
* the @p instance has the ::EVMC_CAPABILITY_PRECOMPILES capability.
|
||||
* @param rev The requested EVM specification revision.
|
||||
* @param msg The call parameters. See ::evmc_message. This argument MUST NOT be NULL.
|
||||
* @param code The reference to the code to be executed. This argument MAY be NULL.
|
||||
* @param code_size The length of the code. If @p code is NULL this argument MUST be 0.
|
||||
* @return The execution result.
|
||||
*/
|
||||
typedef struct evmc_result (*evmc_execute_fn)(struct evmc_instance* instance,
|
||||
@ -857,7 +862,11 @@ typedef uint32_t evmc_capabilities_flagset;
|
||||
*/
|
||||
typedef evmc_capabilities_flagset (*evmc_get_capabilities_fn)(struct evmc_instance* instance);
|
||||
|
||||
/** The opaque type representing a Client-side tracer object. */
|
||||
/**
|
||||
* The opaque type representing a Client-side tracer object.
|
||||
*
|
||||
* @deprecated Deprecated since EVMC 6.3, see evmc_instance::set_tracer().
|
||||
*/
|
||||
struct evmc_tracer_context;
|
||||
|
||||
/**
|
||||
@ -869,6 +878,8 @@ struct evmc_tracer_context;
|
||||
* This piece of information can be acquired by inspecting messages being sent to the EVM in
|
||||
* ::evmc_execute_fn and the results of the messages execution.
|
||||
*
|
||||
* @deprecated Deprecated since EVMC 6.3, see evmc_instance::set_tracer().
|
||||
*
|
||||
* @param context The pointer to the Client-side tracing context. This allows to
|
||||
* implement the tracer in OOP manner.
|
||||
* @param code_offset The current instruction position in the code.
|
||||
@ -916,6 +927,8 @@ typedef void (*evmc_trace_callback)(struct evmc_tracer_context* context,
|
||||
*
|
||||
* This will overwrite the previous settings (the callback and the context).
|
||||
*
|
||||
* @deprecated Deprecated since EVMC 6.3, see evmc_instance::set_tracer().
|
||||
*
|
||||
* @param instance The EVM instance.
|
||||
* @param callback The tracer callback function. This argument MAY be NULL to disable previously
|
||||
* set tracer.
|
||||
@ -989,6 +1002,10 @@ struct evmc_instance
|
||||
* Optional pointer to function setting the EVM instruction tracer.
|
||||
*
|
||||
* If the EVM does not support this feature the pointer can be NULL.
|
||||
*
|
||||
* @deprecated
|
||||
* Since EVMC 6.3, the tracing API has been deprecated as there have been some
|
||||
* design flaws discovered. New API is expected to be introduced in future.
|
||||
*/
|
||||
evmc_set_tracer_fn set_tracer;
|
||||
|
||||
|
@ -7,6 +7,7 @@
|
||||
#include <evmc/evmc.h>
|
||||
#include <evmc/helpers.h>
|
||||
|
||||
#include <functional>
|
||||
#include <initializer_list>
|
||||
#include <utility>
|
||||
|
||||
@ -14,6 +15,250 @@
|
||||
/// @ingroup cpp
|
||||
namespace evmc
|
||||
{
|
||||
/// The big-endian 160-bit hash suitable for keeping an Ethereum address.
|
||||
///
|
||||
/// This type wraps C ::evmc_address to make sure objects of this type are always initialized.
|
||||
struct address : evmc_address
|
||||
{
|
||||
/// Default and converting constructor.
|
||||
///
|
||||
/// Initializes bytes to zeros if not other @p init value provided.
|
||||
constexpr address(evmc_address init = {}) noexcept : evmc_address{init} {}
|
||||
|
||||
/// Explicit operator converting to bool.
|
||||
constexpr inline explicit operator bool() const noexcept;
|
||||
};
|
||||
|
||||
/// The fixed size array of 32 bytes for storing 256-bit EVM values.
|
||||
///
|
||||
/// This type wraps C ::evmc_bytes32 to make sure objects of this type are always initialized.
|
||||
struct bytes32 : evmc_bytes32
|
||||
{
|
||||
/// Default and converting constructor.
|
||||
///
|
||||
/// Initializes bytes to zeros if not other @p init value provided.
|
||||
constexpr bytes32(evmc_bytes32 init = {}) noexcept : evmc_bytes32{init} {}
|
||||
|
||||
/// Explicit operator converting to bool.
|
||||
constexpr inline explicit operator bool() const noexcept;
|
||||
};
|
||||
|
||||
/// The alias for evmc::bytes32 to represent a big-endian 256-bit integer.
|
||||
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]};
|
||||
}
|
||||
|
||||
/// Loads 32 bits / 4 bytes of data from the given @p bytes array in big-endian order.
|
||||
constexpr inline uint32_t load32be(const uint8_t* bytes) noexcept
|
||||
{
|
||||
return (uint32_t{bytes[0]} << 24) | (uint32_t{bytes[1]} << 16) | (uint32_t{bytes[2]} << 8) |
|
||||
uint32_t{bytes[3]};
|
||||
}
|
||||
|
||||
namespace fnv
|
||||
{
|
||||
constexpr auto prime = 0x100000001b3; ///< The 64-bit FNV prime number.
|
||||
constexpr auto offset_basis = 0xcbf29ce484222325; ///< The 64-bit FNV offset basis.
|
||||
|
||||
/// The hashing transformation for 64-bit inputs based on the FNV-1a formula.
|
||||
constexpr inline uint64_t fnv1a_by64(uint64_t h, uint64_t x) noexcept
|
||||
{
|
||||
return (h ^ x) * prime;
|
||||
}
|
||||
} // namespace fnv
|
||||
|
||||
|
||||
/// The "equal" 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.
|
||||
return load64be(&a.bytes[0]) == load64be(&b.bytes[0]) &&
|
||||
load64be(&a.bytes[8]) == load64be(&b.bytes[8]) &&
|
||||
load32be(&a.bytes[16]) == load32be(&b.bytes[16]);
|
||||
}
|
||||
|
||||
/// The "not equal" 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.
|
||||
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]));
|
||||
}
|
||||
|
||||
/// The "equal" 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[8]) == load64be(&b.bytes[8]) &&
|
||||
load64be(&a.bytes[16]) == load64be(&b.bytes[16]) &&
|
||||
load64be(&a.bytes[24]) == load64be(&b.bytes[24]);
|
||||
}
|
||||
|
||||
/// The "not equal" 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.
|
||||
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]));
|
||||
}
|
||||
|
||||
/// Checks if the given address is the zero address.
|
||||
constexpr inline bool is_zero(const address& a) noexcept
|
||||
{
|
||||
return a == address{};
|
||||
}
|
||||
|
||||
constexpr address::operator bool() const noexcept
|
||||
{
|
||||
return !is_zero(*this);
|
||||
}
|
||||
|
||||
/// Checks if the given bytes32 object has all zero bytes.
|
||||
constexpr inline bool is_zero(const bytes32& a) noexcept
|
||||
{
|
||||
return a == bytes32{};
|
||||
}
|
||||
|
||||
constexpr bytes32::operator bool() const noexcept
|
||||
{
|
||||
return !is_zero(*this);
|
||||
}
|
||||
|
||||
namespace literals
|
||||
{
|
||||
namespace internal
|
||||
{
|
||||
template <typename T, T... Ints>
|
||||
struct integer_sequence
|
||||
{
|
||||
};
|
||||
|
||||
template <uint8_t... Bytes>
|
||||
using byte_sequence = integer_sequence<uint8_t, Bytes...>;
|
||||
|
||||
template <char... Chars>
|
||||
using char_sequence = integer_sequence<char, Chars...>;
|
||||
|
||||
|
||||
template <typename, typename>
|
||||
struct concatenate;
|
||||
|
||||
template <uint8_t... Bytes1, uint8_t... Bytes2>
|
||||
struct concatenate<byte_sequence<Bytes1...>, byte_sequence<Bytes2...>>
|
||||
{
|
||||
using type = byte_sequence<Bytes1..., Bytes2...>;
|
||||
};
|
||||
|
||||
template <uint8_t D>
|
||||
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<uint8_t>(
|
||||
(D >= '0' && D <= '9') ? D - '0' : (D >= 'a' && D <= 'f') ? D - 'a' + 10 : D - 'A' + 10);
|
||||
}
|
||||
|
||||
|
||||
template <typename>
|
||||
struct parse_digits;
|
||||
|
||||
template <uint8_t Digit1, uint8_t Digit2>
|
||||
struct parse_digits<byte_sequence<Digit1, Digit2>>
|
||||
{
|
||||
using type = byte_sequence<static_cast<uint8_t>(parse_hex_digit<Digit1>() << 4) |
|
||||
parse_hex_digit<Digit2>()>;
|
||||
};
|
||||
|
||||
template <uint8_t Digit1, uint8_t Digit2, uint8_t... Rest>
|
||||
struct parse_digits<byte_sequence<Digit1, Digit2, Rest...>>
|
||||
{
|
||||
using type = typename concatenate<typename parse_digits<byte_sequence<Digit1, Digit2>>::type,
|
||||
typename parse_digits<byte_sequence<Rest...>>::type>::type;
|
||||
};
|
||||
|
||||
|
||||
template <typename, typename>
|
||||
struct parse_literal;
|
||||
|
||||
template <typename T, char Prefix1, char Prefix2, char... Literal>
|
||||
struct parse_literal<T, char_sequence<Prefix1, Prefix2, Literal...>>
|
||||
{
|
||||
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");
|
||||
|
||||
template <uint8_t... Bytes>
|
||||
static constexpr T create_from(byte_sequence<Bytes...>) noexcept
|
||||
{
|
||||
return T{{{Bytes...}}};
|
||||
}
|
||||
|
||||
static constexpr T get() noexcept
|
||||
{
|
||||
return create_from(typename parse_digits<byte_sequence<Literal...>>::type{});
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T, char Digit>
|
||||
struct parse_literal<T, char_sequence<Digit>>
|
||||
{
|
||||
static_assert(Digit == '0', "only 0 is allowed as a single digit literal");
|
||||
static constexpr T get() noexcept { return {}; }
|
||||
};
|
||||
|
||||
template <typename T, char... Literal>
|
||||
constexpr T parse() noexcept
|
||||
{
|
||||
return parse_literal<T, char_sequence<Literal...>>::get();
|
||||
}
|
||||
} // namespace internal
|
||||
|
||||
/// Literal for evmc::address.
|
||||
template <char... Literal>
|
||||
constexpr address operator"" _address() noexcept
|
||||
{
|
||||
return internal::parse<address, Literal...>();
|
||||
}
|
||||
|
||||
/// Literal for evmc::bytes32.
|
||||
template <char... Literal>
|
||||
constexpr bytes32 operator"" _bytes32() noexcept
|
||||
{
|
||||
return internal::parse<bytes32, Literal...>();
|
||||
}
|
||||
} // namespace literals
|
||||
|
||||
using namespace literals;
|
||||
|
||||
|
||||
/// Alias for evmc_make_result().
|
||||
constexpr auto make_result = evmc_make_result;
|
||||
|
||||
/// @copydoc evmc_result
|
||||
///
|
||||
/// This is a RAII wrapper for evmc_result and objects of this type
|
||||
@ -27,6 +272,22 @@ public:
|
||||
using evmc_result::output_size;
|
||||
using evmc_result::status_code;
|
||||
|
||||
/// Creates the result from the provided arguments.
|
||||
///
|
||||
/// The provided output is copied to memory allocated with malloc()
|
||||
/// and the evmc_result::release function is set to one invoking free().
|
||||
///
|
||||
/// @param _status_code The status code.
|
||||
/// @param _gas_left The amount of gas left.
|
||||
/// @param _output_data The pointer to the output.
|
||||
/// @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) noexcept
|
||||
: evmc_result{make_result(_status_code, _gas_left, _output_data, _output_size)}
|
||||
{}
|
||||
|
||||
/// Converting constructor from raw evmc_result.
|
||||
explicit result(evmc_result const& res) noexcept : evmc_result{res} {}
|
||||
|
||||
@ -80,11 +341,32 @@ public:
|
||||
class vm
|
||||
{
|
||||
public:
|
||||
vm() noexcept = default;
|
||||
|
||||
/// Converting constructor from evmc_instance.
|
||||
explicit vm(evmc_instance* instance) noexcept : m_instance{instance} {}
|
||||
|
||||
/// Destructor responsible for automatically destroying the VM instance.
|
||||
~vm() noexcept { m_instance->destroy(m_instance); }
|
||||
~vm() noexcept
|
||||
{
|
||||
if (m_instance)
|
||||
m_instance->destroy(m_instance);
|
||||
}
|
||||
|
||||
vm(const vm&) = delete;
|
||||
vm& operator=(const vm&) = delete;
|
||||
|
||||
/// Move constructor.
|
||||
vm(vm&& other) noexcept : m_instance{other.m_instance} { other.m_instance = nullptr; }
|
||||
|
||||
/// Move assignment operator.
|
||||
vm& operator=(vm&& other) noexcept
|
||||
{
|
||||
this->~vm();
|
||||
m_instance = other.m_instance;
|
||||
other.m_instance = nullptr;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// The constructor that captures a VM instance and configures the instance
|
||||
/// with provided list of options.
|
||||
@ -96,6 +378,9 @@ public:
|
||||
set_option(option.first, option.second);
|
||||
}
|
||||
|
||||
/// Checks if contains a valid pointer to the VM instance.
|
||||
explicit operator bool() const noexcept { return m_instance != nullptr; }
|
||||
|
||||
/// Checks whenever the VM instance is ABI compatible with the current EVMC API.
|
||||
bool is_abi_compatible() const noexcept { return m_instance->abi_version == EVMC_ABI_VERSION; }
|
||||
|
||||
@ -128,7 +413,7 @@ public:
|
||||
}
|
||||
|
||||
private:
|
||||
evmc_instance* const m_instance = nullptr;
|
||||
evmc_instance* m_instance = nullptr;
|
||||
};
|
||||
|
||||
/// The EVMC Host interface
|
||||
@ -138,35 +423,33 @@ public:
|
||||
virtual ~HostInterface() noexcept = default;
|
||||
|
||||
/// @copydoc evmc_host_interface::account_exists
|
||||
virtual bool account_exists(const evmc_address& addr) noexcept = 0;
|
||||
virtual bool account_exists(const address& addr) noexcept = 0;
|
||||
|
||||
/// @copydoc evmc_host_interface::get_storage
|
||||
virtual evmc_bytes32 get_storage(const evmc_address& addr,
|
||||
const evmc_bytes32& key) noexcept = 0;
|
||||
virtual bytes32 get_storage(const address& addr, const bytes32& key) noexcept = 0;
|
||||
|
||||
/// @copydoc evmc_host_interface::set_storage
|
||||
virtual evmc_storage_status set_storage(const evmc_address& addr,
|
||||
const evmc_bytes32& key,
|
||||
const evmc_bytes32& value) noexcept = 0;
|
||||
virtual evmc_storage_status set_storage(const address& addr,
|
||||
const bytes32& key,
|
||||
const bytes32& value) noexcept = 0;
|
||||
|
||||
/// @copydoc evmc_host_interface::get_balance
|
||||
virtual evmc_uint256be get_balance(const evmc_address& addr) noexcept = 0;
|
||||
virtual uint256be get_balance(const address& addr) noexcept = 0;
|
||||
|
||||
/// @copydoc evmc_host_interface::get_code_size
|
||||
virtual size_t get_code_size(const evmc_address& addr) noexcept = 0;
|
||||
virtual size_t get_code_size(const address& addr) noexcept = 0;
|
||||
|
||||
/// @copydoc evmc_host_interface::get_code_hash
|
||||
virtual evmc_bytes32 get_code_hash(const evmc_address& addr) noexcept = 0;
|
||||
virtual bytes32 get_code_hash(const address& addr) noexcept = 0;
|
||||
|
||||
/// @copydoc evmc_host_interface::copy_code
|
||||
virtual size_t copy_code(const evmc_address& addr,
|
||||
virtual size_t copy_code(const address& addr,
|
||||
size_t code_offset,
|
||||
uint8_t* buffer_data,
|
||||
size_t buffer_size) noexcept = 0;
|
||||
|
||||
/// @copydoc evmc_host_interface::selfdestruct
|
||||
virtual void selfdestruct(const evmc_address& addr,
|
||||
const evmc_address& beneficiary) noexcept = 0;
|
||||
virtual void selfdestruct(const address& addr, const address& beneficiary) noexcept = 0;
|
||||
|
||||
/// @copydoc evmc_host_interface::call
|
||||
virtual result call(const evmc_message& msg) noexcept = 0;
|
||||
@ -175,13 +458,13 @@ public:
|
||||
virtual evmc_tx_context get_tx_context() noexcept = 0;
|
||||
|
||||
/// @copydoc evmc_host_interface::get_block_hash
|
||||
virtual evmc_bytes32 get_block_hash(int64_t block_number) noexcept = 0;
|
||||
virtual bytes32 get_block_hash(int64_t block_number) noexcept = 0;
|
||||
|
||||
/// @copydoc evmc_host_interface::emit_log
|
||||
virtual void emit_log(const evmc_address& addr,
|
||||
virtual void emit_log(const address& addr,
|
||||
const uint8_t* data,
|
||||
size_t data_size,
|
||||
const evmc_bytes32 topics[],
|
||||
const bytes32 topics[],
|
||||
size_t num_topics) noexcept = 0;
|
||||
};
|
||||
|
||||
@ -198,39 +481,39 @@ public:
|
||||
/// Implicit converting constructor from evmc_context.
|
||||
HostContext(evmc_context* ctx) noexcept : context{ctx} {} // NOLINT
|
||||
|
||||
bool account_exists(const evmc_address& address) noexcept final
|
||||
bool account_exists(const address& address) noexcept final
|
||||
{
|
||||
return context->host->account_exists(context, &address);
|
||||
}
|
||||
|
||||
evmc_bytes32 get_storage(const evmc_address& address, const evmc_bytes32& key) noexcept final
|
||||
bytes32 get_storage(const address& address, const bytes32& key) noexcept final
|
||||
{
|
||||
return context->host->get_storage(context, &address, &key);
|
||||
}
|
||||
|
||||
evmc_storage_status set_storage(const evmc_address& address,
|
||||
const evmc_bytes32& key,
|
||||
const evmc_bytes32& value) noexcept final
|
||||
evmc_storage_status set_storage(const address& address,
|
||||
const bytes32& key,
|
||||
const bytes32& value) noexcept final
|
||||
{
|
||||
return context->host->set_storage(context, &address, &key, &value);
|
||||
}
|
||||
|
||||
evmc_uint256be get_balance(const evmc_address& address) noexcept final
|
||||
uint256be get_balance(const address& address) noexcept final
|
||||
{
|
||||
return context->host->get_balance(context, &address);
|
||||
}
|
||||
|
||||
size_t get_code_size(const evmc_address& address) noexcept final
|
||||
size_t get_code_size(const address& address) noexcept final
|
||||
{
|
||||
return context->host->get_code_size(context, &address);
|
||||
}
|
||||
|
||||
evmc_bytes32 get_code_hash(const evmc_address& address) noexcept final
|
||||
bytes32 get_code_hash(const address& address) noexcept final
|
||||
{
|
||||
return context->host->get_code_hash(context, &address);
|
||||
}
|
||||
|
||||
size_t copy_code(const evmc_address& address,
|
||||
size_t copy_code(const address& address,
|
||||
size_t code_offset,
|
||||
uint8_t* buffer_data,
|
||||
size_t buffer_size) noexcept final
|
||||
@ -238,9 +521,9 @@ public:
|
||||
return context->host->copy_code(context, &address, code_offset, buffer_data, buffer_size);
|
||||
}
|
||||
|
||||
void selfdestruct(const evmc_address& address, const evmc_address& beneficiary) noexcept final
|
||||
void selfdestruct(const address& addr, const address& beneficiary) noexcept final
|
||||
{
|
||||
context->host->selfdestruct(context, &address, &beneficiary);
|
||||
context->host->selfdestruct(context, &addr, &beneficiary);
|
||||
}
|
||||
|
||||
result call(const evmc_message& message) noexcept final
|
||||
@ -261,18 +544,18 @@ public:
|
||||
return tx_context;
|
||||
}
|
||||
|
||||
evmc_bytes32 get_block_hash(int64_t number) noexcept final
|
||||
bytes32 get_block_hash(int64_t number) noexcept final
|
||||
{
|
||||
return context->host->get_block_hash(context, number);
|
||||
}
|
||||
|
||||
void emit_log(const evmc_address& address,
|
||||
void emit_log(const address& addr,
|
||||
const uint8_t* data,
|
||||
size_t data_size,
|
||||
const evmc_bytes32 topics[],
|
||||
const bytes32 topics[],
|
||||
size_t topics_count) noexcept final
|
||||
{
|
||||
context->host->emit_log(context, &address, data, data_size, topics, topics_count);
|
||||
context->host->emit_log(context, &addr, data, data_size, topics, topics_count);
|
||||
}
|
||||
};
|
||||
|
||||
@ -351,7 +634,8 @@ inline void emit_log(evmc_context* h,
|
||||
const evmc_bytes32 topics[],
|
||||
size_t num_topics) noexcept
|
||||
{
|
||||
static_cast<Host*>(h)->emit_log(*addr, data, data_size, topics, num_topics);
|
||||
static_cast<Host*>(h)->emit_log(*addr, data, data_size, static_cast<const bytes32*>(topics),
|
||||
num_topics);
|
||||
}
|
||||
|
||||
constexpr evmc_host_interface interface{
|
||||
@ -360,6 +644,42 @@ constexpr evmc_host_interface interface{
|
||||
};
|
||||
} // namespace internal
|
||||
|
||||
inline Host::Host() noexcept : evmc_context{&internal::interface} {}
|
||||
inline Host::Host() noexcept : evmc_context{&evmc::internal::interface} {}
|
||||
|
||||
} // namespace evmc
|
||||
|
||||
|
||||
namespace std
|
||||
{
|
||||
/// Hash operator template specialization for evmc::address. Needed for unordered containers.
|
||||
template <>
|
||||
struct hash<evmc::address>
|
||||
{
|
||||
/// Hash operator using FNV1a-based folding.
|
||||
constexpr size_t operator()(const evmc::address& s) const noexcept
|
||||
{
|
||||
using namespace evmc;
|
||||
using namespace fnv;
|
||||
return static_cast<size_t>(fnv1a_by64(
|
||||
fnv1a_by64(fnv1a_by64(fnv::offset_basis, load64be(&s.bytes[0])), load64be(&s.bytes[8])),
|
||||
load32be(&s.bytes[16])));
|
||||
}
|
||||
};
|
||||
|
||||
/// Hash operator template specialization for evmc::bytes32. Needed for unordered containers.
|
||||
template <>
|
||||
struct hash<evmc::bytes32>
|
||||
{
|
||||
/// Hash operator using FNV1a-based folding.
|
||||
constexpr size_t operator()(const evmc::bytes32& s) const noexcept
|
||||
{
|
||||
using namespace evmc;
|
||||
using namespace fnv;
|
||||
return static_cast<size_t>(
|
||||
fnv1a_by64(fnv1a_by64(fnv1a_by64(fnv1a_by64(fnv::offset_basis, load64be(&s.bytes[0])),
|
||||
load64be(&s.bytes[8])),
|
||||
load64be(&s.bytes[16])),
|
||||
load64be(&s.bytes[24])));
|
||||
}
|
||||
};
|
||||
} // namespace std
|
||||
|
@ -18,6 +18,8 @@
|
||||
#pragma once
|
||||
|
||||
#include <evmc/evmc.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
/**
|
||||
* Returns true if the VM instance has a compatible ABI version.
|
||||
@ -83,6 +85,7 @@ static inline enum evmc_set_option_result evmc_set_option(struct evmc_instance*
|
||||
*
|
||||
* @see evmc_set_tracer_fn
|
||||
*/
|
||||
EVMC_DEPRECATED
|
||||
static inline void evmc_set_tracer(struct evmc_instance* instance,
|
||||
evmc_trace_callback callback,
|
||||
struct evmc_tracer_context* context)
|
||||
@ -106,6 +109,58 @@ static inline struct evmc_result evmc_execute(struct evmc_instance* instance,
|
||||
return instance->execute(instance, context, rev, msg, code, code_size);
|
||||
}
|
||||
|
||||
/// The evmc_result release function using free() for releasing the memory.
|
||||
///
|
||||
/// This function is used in the evmc_make_result(),
|
||||
/// but may be also used in other case if convenient.
|
||||
///
|
||||
/// @param result The result object.
|
||||
static void evmc_free_result_memory(const struct evmc_result* result)
|
||||
{
|
||||
free((uint8_t*)result->output_data);
|
||||
}
|
||||
|
||||
/// Creates the result from the provided arguments.
|
||||
///
|
||||
/// The provided output is copied to memory allocated with malloc()
|
||||
/// and the evmc_result::release function is set to one invoking free().
|
||||
///
|
||||
/// In case of memory allocation failure, the result has all fields zeroed
|
||||
/// and only evmc_result::status_code is set to ::EVMC_OUT_OF_MEMORY internal error.
|
||||
///
|
||||
/// @param status_code The status code.
|
||||
/// @param gas_left The amount of gas left.
|
||||
/// @param output_data The pointer to the output.
|
||||
/// @param output_size The output size.
|
||||
static inline struct evmc_result evmc_make_result(enum evmc_status_code status_code,
|
||||
int64_t gas_left,
|
||||
const uint8_t* output_data,
|
||||
size_t output_size)
|
||||
{
|
||||
struct evmc_result result;
|
||||
memset(&result, 0, sizeof(result));
|
||||
|
||||
if (output_size != 0)
|
||||
{
|
||||
uint8_t* buffer = (uint8_t*)malloc(output_size);
|
||||
|
||||
if (!buffer)
|
||||
{
|
||||
result.status_code = EVMC_OUT_OF_MEMORY;
|
||||
return result;
|
||||
}
|
||||
|
||||
memcpy(buffer, output_data, output_size);
|
||||
result.output_data = buffer;
|
||||
result.output_size = output_size;
|
||||
result.release = evmc_free_result_memory;
|
||||
}
|
||||
|
||||
result.status_code = status_code;
|
||||
result.gas_left = gas_left;
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Releases the resources allocated to the execution result.
|
||||
*
|
||||
|
@ -12,58 +12,78 @@
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <evmc/evmc.h>
|
||||
#include <evmc/evmc.hpp>
|
||||
|
||||
#include <cstring>
|
||||
#include <functional>
|
||||
|
||||
using evmc::is_zero;
|
||||
|
||||
/// The comparator for std::map<evmc_address, ...>.
|
||||
EVMC_DEPRECATED
|
||||
inline bool operator<(const evmc_address& a, const evmc_address& b)
|
||||
{
|
||||
return std::memcmp(a.bytes, b.bytes, sizeof(a.bytes)) < 0;
|
||||
}
|
||||
|
||||
/// The comparator for std::map<evmc_bytes32, ...>.
|
||||
EVMC_DEPRECATED
|
||||
inline bool operator<(const evmc_bytes32& a, const evmc_bytes32& b)
|
||||
{
|
||||
return std::memcmp(a.bytes, b.bytes, sizeof(a.bytes)) < 0;
|
||||
}
|
||||
|
||||
/// The comparator for equality.
|
||||
EVMC_DEPRECATED
|
||||
inline bool operator==(const evmc_address& a, const evmc_address& b)
|
||||
{
|
||||
return std::memcmp(a.bytes, b.bytes, sizeof(a.bytes)) == 0;
|
||||
}
|
||||
|
||||
/// The comparator for equality.
|
||||
EVMC_DEPRECATED
|
||||
inline bool operator==(const evmc_bytes32& a, const evmc_bytes32& b)
|
||||
{
|
||||
return std::memcmp(a.bytes, b.bytes, sizeof(a.bytes)) == 0;
|
||||
}
|
||||
|
||||
/// Check if the address is zero (all bytes are zeros).
|
||||
inline bool is_zero(const evmc_address& address) noexcept
|
||||
/// Parameters for the fnv1a hash function, specialized by the hash result size (size_t).
|
||||
///
|
||||
/// The values for the matching size are taken from
|
||||
/// https://en.wikipedia.org/wiki/Fowler%E2%80%93Noll%E2%80%93Vo_hash_function#FNV_hash_parameters.
|
||||
///
|
||||
/// @tparam size The size of the hash result (size_t).
|
||||
template <size_t size>
|
||||
struct fnv1_params
|
||||
{
|
||||
return address == evmc_address{};
|
||||
}
|
||||
};
|
||||
|
||||
/// Check if the hash is zero (all bytes are zeros).
|
||||
inline bool is_zero(const evmc_bytes32& x) noexcept
|
||||
/// Parameters for the fnv1a hash function, specialized for the hash result of 4 bytes.
|
||||
template <>
|
||||
struct fnv1_params<4>
|
||||
{
|
||||
return x == evmc_bytes32{};
|
||||
}
|
||||
static constexpr auto prime = 0x1000193; ///< The FNV prime.
|
||||
static constexpr auto offset_basis = 0x811c9dc5; ///< The FNV offset basis.
|
||||
};
|
||||
|
||||
/// FNV1a hash function with 64-bit result.
|
||||
inline uint64_t fnv1a_64(const uint8_t* ptr, size_t len)
|
||||
/// Parameters for the fnv1a hash function, specialized for the hash result of 8 bytes.
|
||||
template <>
|
||||
struct fnv1_params<8>
|
||||
{
|
||||
constexpr uint64_t prime = 1099511628211ULL;
|
||||
constexpr uint64_t offset_basis = 14695981039346656037ULL;
|
||||
static constexpr auto prime = 0x100000001b3; ///< The FNV prime.
|
||||
static constexpr auto offset_basis = 0xcbf29ce484222325; ///< The FNV offset basis.
|
||||
};
|
||||
|
||||
uint64_t ret = offset_basis;
|
||||
/// FNV1a hash function.
|
||||
inline size_t fnv1a(const uint8_t* ptr, size_t len) noexcept
|
||||
{
|
||||
using params = fnv1_params<sizeof(size_t)>;
|
||||
|
||||
auto ret = size_t{params::offset_basis};
|
||||
for (size_t i = 0; i < len; i++)
|
||||
{
|
||||
ret ^= ptr[i];
|
||||
ret *= prime;
|
||||
ret *= params::prime;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
@ -72,25 +92,23 @@ namespace std
|
||||
{
|
||||
/// Hash operator template specialization for evmc_address needed for unordered containers.
|
||||
template <>
|
||||
struct hash<evmc_address>
|
||||
struct EVMC_DEPRECATED hash<evmc_address>
|
||||
{
|
||||
/// Hash operator using FNV1a.
|
||||
std::enable_if<sizeof(size_t) == 8, std::size_t>::type operator()(const evmc_address& s) const
|
||||
noexcept
|
||||
size_t operator()(const evmc_address& s) const noexcept
|
||||
{
|
||||
return fnv1a_64(s.bytes, sizeof(s.bytes));
|
||||
return fnv1a(s.bytes, sizeof(s.bytes));
|
||||
}
|
||||
};
|
||||
|
||||
/// Hash operator template needed for std::unordered_set and others using hashes.
|
||||
template <>
|
||||
struct hash<evmc_bytes32>
|
||||
struct EVMC_DEPRECATED hash<evmc_bytes32>
|
||||
{
|
||||
/// Hash operator using FNV1a.
|
||||
std::enable_if<sizeof(size_t) == 8, std::size_t>::type operator()(const evmc_bytes32& s) const
|
||||
noexcept
|
||||
size_t operator()(const evmc_bytes32& s) const noexcept
|
||||
{
|
||||
return fnv1a_64(s.bytes, sizeof(s.bytes));
|
||||
return fnv1a(s.bytes, sizeof(s.bytes));
|
||||
}
|
||||
};
|
||||
} // namespace std
|
||||
|
@ -42,20 +42,14 @@
|
||||
#define ATTR_FORMAT(...)
|
||||
#endif
|
||||
|
||||
#if _WIN32
|
||||
#define strcpy_sx strcpy_s
|
||||
#else
|
||||
/*
|
||||
* Limited variant of strcpy_s().
|
||||
*
|
||||
* Provided for C standard libraries where strcpy_s() is not available.
|
||||
* The availability check might need to adjusted for other C standard library implementations.
|
||||
*/
|
||||
#if !defined(EVMC_LOADER_MOCK)
|
||||
static
|
||||
#endif
|
||||
int
|
||||
strcpy_sx(char* restrict dest, size_t destsz, const char* restrict src)
|
||||
strcpy_sx(char* dest, size_t destsz, const char* src)
|
||||
{
|
||||
size_t len = strlen(src);
|
||||
if (len >= destsz)
|
||||
@ -70,7 +64,6 @@ static
|
||||
dest[len] = 0;
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
#define PATH_MAX_LENGTH 4096
|
||||
|
||||
@ -238,3 +231,93 @@ exit:
|
||||
|
||||
return instance;
|
||||
}
|
||||
|
||||
/// Gets the token delimited by @p delim character of the string pointed by the @p str_ptr.
|
||||
/// If the delimiter is not found, the whole string is returned.
|
||||
/// The @p str_ptr is also slided after the delimiter or to the string end
|
||||
/// if the delimiter is not found (in this case the @p str_ptr points to an empty string).
|
||||
static char* get_token(char** str_ptr, char delim)
|
||||
{
|
||||
char* str = *str_ptr;
|
||||
char* delim_pos = strchr(str, delim);
|
||||
if (delim_pos)
|
||||
{
|
||||
// If the delimiter is found, null it to get null-terminated prefix
|
||||
// and slide the str_ptr after the delimiter.
|
||||
*delim_pos = '\0';
|
||||
*str_ptr = delim_pos + 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Otherwise, slide the str_ptr to the end and return the whole string as the prefix.
|
||||
*str_ptr += strlen(str);
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
struct evmc_instance* evmc_load_and_configure(const char* config,
|
||||
enum evmc_loader_error_code* error_code)
|
||||
{
|
||||
enum evmc_loader_error_code ec = EVMC_LOADER_SUCCESS;
|
||||
struct evmc_instance* instance = NULL;
|
||||
|
||||
char config_copy_buffer[PATH_MAX_LENGTH];
|
||||
if (strcpy_sx(config_copy_buffer, sizeof(config_copy_buffer), config) != 0)
|
||||
{
|
||||
ec = set_error(EVMC_LOADER_INVALID_ARGUMENT,
|
||||
"invalid argument: configuration is too long (maximum allowed length is %d)",
|
||||
(int)sizeof(config_copy_buffer));
|
||||
goto exit;
|
||||
}
|
||||
|
||||
char* options = config_copy_buffer;
|
||||
const char* path = get_token(&options, ',');
|
||||
|
||||
instance = evmc_load_and_create(path, error_code);
|
||||
if (!instance)
|
||||
return NULL;
|
||||
|
||||
if (instance->set_option == NULL && strlen(options) != 0)
|
||||
{
|
||||
ec = set_error(EVMC_LOADER_INVALID_OPTION_NAME, "%s (%s) does not support any options",
|
||||
instance->name, path);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
|
||||
while (strlen(options) != 0)
|
||||
{
|
||||
char* option = get_token(&options, ',');
|
||||
|
||||
// Slit option into name and value by taking the name token.
|
||||
// The option variable will have the value, can be empty.
|
||||
const char* name = get_token(&option, '=');
|
||||
|
||||
enum evmc_set_option_result r = instance->set_option(instance, name, option);
|
||||
switch (r)
|
||||
{
|
||||
case EVMC_SET_OPTION_SUCCESS:
|
||||
break;
|
||||
case EVMC_SET_OPTION_INVALID_NAME:
|
||||
ec = set_error(EVMC_LOADER_INVALID_OPTION_NAME, "%s (%s): unknown option '%s'",
|
||||
instance->name, path, name);
|
||||
goto exit;
|
||||
case EVMC_SET_OPTION_INVALID_VALUE:
|
||||
ec = set_error(EVMC_LOADER_INVALID_OPTION_VALUE,
|
||||
"%s (%s): unsupported value '%s' for option '%s'", instance->name, path,
|
||||
option, name);
|
||||
goto exit;
|
||||
}
|
||||
}
|
||||
|
||||
exit:
|
||||
if (error_code)
|
||||
*error_code = ec;
|
||||
|
||||
if (ec == EVMC_LOADER_SUCCESS)
|
||||
return instance;
|
||||
|
||||
if (instance)
|
||||
evmc_destroy(instance);
|
||||
return NULL;
|
||||
}
|
||||
|
@ -40,7 +40,13 @@ enum evmc_loader_error_code
|
||||
EVMC_LOADER_INSTANCE_CREATION_FAILURE = 4,
|
||||
|
||||
/** The ABI version of the VM instance has mismatched. */
|
||||
EVMC_LOADER_ABI_VERSION_MISMATCH = 5
|
||||
EVMC_LOADER_ABI_VERSION_MISMATCH = 5,
|
||||
|
||||
/** The VM option is invalid. */
|
||||
EVMC_LOADER_INVALID_OPTION_NAME = 6,
|
||||
|
||||
/** The VM option value is invalid. */
|
||||
EVMC_LOADER_INVALID_OPTION_VALUE = 7
|
||||
};
|
||||
|
||||
/**
|
||||
@ -111,6 +117,43 @@ evmc_create_fn evmc_load(const char* filename, enum evmc_loader_error_code* erro
|
||||
struct evmc_instance* evmc_load_and_create(const char* filename,
|
||||
enum evmc_loader_error_code* error_code);
|
||||
|
||||
/**
|
||||
* Dynamically loads the EVMC module, then creates and configures the VM instance.
|
||||
*
|
||||
* This function performs the following actions atomically:
|
||||
* - loads the EVMC module (as evmc_load()),
|
||||
* - creates the VM instance,
|
||||
* - configures the VM instance with options provided in the @p config parameter.
|
||||
*
|
||||
* The configuration string (@p config) has the following syntax:
|
||||
*
|
||||
* <path> ("," <option-name> ["=" <option-value>])*
|
||||
*
|
||||
* In this syntax, an option without a value can be specified (`,option,`)
|
||||
* as a shortcut for using empty value (`,option=,`).
|
||||
*
|
||||
* Options are passed to a VM in the order they are specified in the configuration string.
|
||||
* It is up to the VM implementation how to handle duplicated options and other conflicts.
|
||||
*
|
||||
* Example configuration string:
|
||||
*
|
||||
* ./modules/vm.so,engine=compiler,trace,verbosity=2
|
||||
*
|
||||
* The function signals the same errors as evmc_load_and_create() and additionally:
|
||||
* - ::EVMC_LOADER_INVALID_OPTION_NAME
|
||||
* when the provided options list contains an option unknown for the VM,
|
||||
* - ::EVMC_LOADER_INVALID_OPTION_VALUE
|
||||
* when there exists unsupported value for a given VM option.
|
||||
|
||||
*
|
||||
* @param config The path to the EVMC module with additional configuration options.
|
||||
* @param error_code The pointer to the error code. If not NULL the value is set to
|
||||
* ::EVMC_LOADER_SUCCESS on success or any other error code as described above.
|
||||
* @return The pointer to the created VM or NULL in case of error.
|
||||
*/
|
||||
struct evmc_instance* evmc_load_and_configure(const char* config,
|
||||
enum evmc_loader_error_code* error_code);
|
||||
|
||||
/**
|
||||
* Returns the human-readable message describing the most recent error
|
||||
* that occurred in EVMC loading since the last call to this function.
|
||||
|
Loading…
Reference in New Issue
Block a user