/*
This file is part of solidity.
solidity is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
solidity is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with solidity. If not, see .
*/
/**
* EVM execution host, i.e. component that implements a simulated Ethereum blockchain
* for testing purposes.
*/
#pragma once
#include
#include
#include
#include
namespace dev
{
namespace test
{
using Address = h160;
class EVMHost: public evmc::Host
{
public:
/// Tries to dynamically load libevmone. @returns nullptr on failure.
/// The path has to be provided for the first successful run and will be ignored
/// afterwards.
static evmc::VM* getVM(std::string const& _path = {});
explicit EVMHost(langutil::EVMVersion _evmVersion, evmc::VM* _vm = getVM());
struct Account
{
evmc::uint256be balance = {};
size_t nonce = 0;
bytes code;
evmc::bytes32 codeHash = {};
std::map storage;
};
struct LogEntry
{
Address address;
std::vector topics;
bytes data;
};
struct State
{
size_t blockNumber;
uint64_t timestamp;
std::map accounts;
std::vector logs;
};
Account* account(evmc::address const& _address)
{
// Make all precompiled contracts exist.
// Be future-proof and consider everything below 1024 as precompiled contract.
if (u160(convertFromEVMC(_address)) < 1024)
m_state.accounts[_address];
auto it = m_state.accounts.find(_address);
return it == m_state.accounts.end() ? nullptr : &it->second;
}
void reset() { m_state = State{}; m_currentAddress = {}; }
void newBlock()
{
m_state.blockNumber++;
m_state.timestamp += 15;
m_state.logs.clear();
}
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
{
if (Account* acc = account(_addr))
return acc->storage[_key];
return {};
}
evmc_storage_status set_storage(
evmc::address const& _addr,
evmc::bytes32 const& _key,
evmc::bytes32 const& _value
) noexcept;
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
{
if (Account const* acc = account(_addr))
return acc->code.size();
return 0;
}
evmc::bytes32 get_code_hash(evmc::address const& _addr) noexcept final
{
if (Account const* acc = account(_addr))
return acc->codeHash;
return {};
}
size_t copy_code(
evmc::address const& _addr,
size_t _codeOffset,
uint8_t* _bufferData,
size_t _bufferSize
) noexcept final
{
size_t i = 0;
if (Account const* acc = account(_addr))
for (; i < _bufferSize && _codeOffset + i < acc->code.size(); i++)
_bufferData[i] = acc->code[_codeOffset + i];
return i;
}
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;
void emit_log(
evmc::address const& _addr,
uint8_t const* _data,
size_t _dataSize,
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);
State m_state;
evmc::address m_currentAddress = {};
evmc::address m_coinbase = convertToEVMC(Address("0x7878787878787878787878787878787878787878"));
private:
evmc::result precompileECRecover(evmc_message const& _message) noexcept;
evmc::result precompileSha256(evmc_message const& _message) noexcept;
evmc::result precompileRipeMD160(evmc_message const& _message) noexcept;
evmc::result precompileIdentity(evmc_message const& _message) noexcept;
evmc::result precompileModExp(evmc_message const& _message) noexcept;
evmc::result precompileALTBN128G1Add(evmc_message const& _message) noexcept;
evmc::result precompileALTBN128G1Mul(evmc_message const& _message) noexcept;
evmc::result precompileALTBN128PairingProduct(evmc_message const& _message) noexcept;
evmc::result precompileGeneric(evmc_message const& _message, std::map const& _inOut) noexcept;
/// @returns a result object with no gas usage and result data taken from @a _data.
/// @note The return value is only valid as long as @a _data is alive!
static evmc::result resultWithGas(evmc_message const& _message, bytes const& _data) noexcept;
evmc::VM* m_vm = nullptr;
evmc_revision m_evmVersion;
};
}
}