2019-07-08 14:04:52 +00:00
|
|
|
/*
|
|
|
|
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 <http://www.gnu.org/licenses/>.
|
|
|
|
*/
|
|
|
|
/**
|
|
|
|
* EVM execution host, i.e. component that implements a simulated Ethereum blockchain
|
|
|
|
* for testing purposes.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#pragma once
|
|
|
|
|
|
|
|
#include <test/evmc/evmc.hpp>
|
|
|
|
#include <test/evmc/evmc.h>
|
|
|
|
|
|
|
|
#include <liblangutil/EVMVersion.h>
|
|
|
|
|
|
|
|
#include <libdevcore/FixedHash.h>
|
|
|
|
|
|
|
|
namespace dev
|
|
|
|
{
|
|
|
|
namespace test
|
|
|
|
{
|
|
|
|
using Address = h160;
|
|
|
|
|
|
|
|
class EVMHost: public evmc::Host
|
|
|
|
{
|
|
|
|
public:
|
2019-07-16 17:05:13 +00:00
|
|
|
/// 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 = {});
|
|
|
|
|
2019-06-26 16:42:24 +00:00
|
|
|
explicit EVMHost(langutil::EVMVersion _evmVersion, evmc::vm* _vm = getVM());
|
2019-07-08 14:04:52 +00:00
|
|
|
|
|
|
|
struct Account
|
|
|
|
{
|
2019-11-07 10:34:12 +00:00
|
|
|
evmc::uint256be balance = {};
|
2019-07-08 14:04:52 +00:00
|
|
|
size_t nonce = 0;
|
|
|
|
bytes code;
|
2019-11-07 10:34:12 +00:00
|
|
|
evmc::bytes32 codeHash = {};
|
|
|
|
std::map<evmc::bytes32, evmc::bytes32> storage;
|
2019-07-08 14:04:52 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
struct LogEntry
|
|
|
|
{
|
|
|
|
Address address;
|
|
|
|
std::vector<h256> topics;
|
|
|
|
bytes data;
|
|
|
|
};
|
|
|
|
|
|
|
|
struct State
|
|
|
|
{
|
|
|
|
size_t blockNumber;
|
|
|
|
uint64_t timestamp;
|
2019-11-07 10:34:12 +00:00
|
|
|
std::map<evmc::address, Account> accounts;
|
2019-07-08 14:04:52 +00:00
|
|
|
std::vector<LogEntry> logs;
|
|
|
|
};
|
|
|
|
|
2019-11-07 10:34:12 +00:00
|
|
|
Account* account(evmc::address const& _address)
|
2019-07-08 14:04:52 +00:00
|
|
|
{
|
2019-07-11 16:46:17 +00:00
|
|
|
// 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];
|
2019-07-08 14:04:52 +00:00
|
|
|
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();
|
|
|
|
}
|
|
|
|
|
2019-11-07 10:34:12 +00:00
|
|
|
bool account_exists(evmc::address const& _addr) noexcept final
|
2019-07-08 14:04:52 +00:00
|
|
|
{
|
|
|
|
return account(_addr) != nullptr;
|
|
|
|
}
|
|
|
|
|
2019-11-07 10:34:12 +00:00
|
|
|
evmc::bytes32 get_storage(evmc::address const& _addr, evmc::bytes32 const& _key) noexcept final
|
2019-07-08 14:04:52 +00:00
|
|
|
{
|
|
|
|
if (Account* acc = account(_addr))
|
|
|
|
return acc->storage[_key];
|
|
|
|
return {};
|
|
|
|
}
|
|
|
|
|
|
|
|
evmc_storage_status set_storage(
|
2019-11-07 10:34:12 +00:00
|
|
|
evmc::address const& _addr,
|
|
|
|
evmc::bytes32 const& _key,
|
|
|
|
evmc::bytes32 const& _value
|
2019-07-08 14:04:52 +00:00
|
|
|
) noexcept;
|
|
|
|
|
2019-11-07 10:34:12 +00:00
|
|
|
evmc::uint256be get_balance(evmc::address const& _addr) noexcept final
|
2019-07-08 14:04:52 +00:00
|
|
|
{
|
|
|
|
if (Account const* acc = account(_addr))
|
|
|
|
return acc->balance;
|
|
|
|
return {};
|
|
|
|
}
|
|
|
|
|
2019-11-07 10:34:12 +00:00
|
|
|
size_t get_code_size(evmc::address const& _addr) noexcept final
|
2019-07-08 14:04:52 +00:00
|
|
|
{
|
|
|
|
if (Account const* acc = account(_addr))
|
|
|
|
return acc->code.size();
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2019-11-07 10:34:12 +00:00
|
|
|
evmc::bytes32 get_code_hash(evmc::address const& _addr) noexcept final
|
2019-07-08 14:04:52 +00:00
|
|
|
{
|
|
|
|
if (Account const* acc = account(_addr))
|
|
|
|
return acc->codeHash;
|
|
|
|
return {};
|
|
|
|
}
|
|
|
|
|
|
|
|
size_t copy_code(
|
2019-11-07 10:34:12 +00:00
|
|
|
evmc::address const& _addr,
|
2019-07-08 14:04:52 +00:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2019-11-07 10:34:12 +00:00
|
|
|
void selfdestruct(evmc::address const& _addr, evmc::address const& _beneficiary) noexcept;
|
2019-07-08 14:04:52 +00:00
|
|
|
|
|
|
|
evmc::result call(evmc_message const& _message) noexcept;
|
|
|
|
|
|
|
|
evmc_tx_context get_tx_context() noexcept;
|
|
|
|
|
2019-11-07 10:34:12 +00:00
|
|
|
evmc::bytes32 get_block_hash(int64_t number) noexcept;
|
2019-07-08 14:04:52 +00:00
|
|
|
|
|
|
|
void emit_log(
|
2019-11-07 10:34:12 +00:00
|
|
|
evmc::address const& _addr,
|
2019-07-08 14:04:52 +00:00
|
|
|
uint8_t const* _data,
|
|
|
|
size_t _dataSize,
|
2019-11-07 10:34:12 +00:00
|
|
|
evmc::bytes32 const _topics[],
|
2019-07-08 14:04:52 +00:00
|
|
|
size_t _topicsCount
|
|
|
|
) noexcept;
|
|
|
|
|
2019-11-07 10:34:12 +00:00
|
|
|
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);
|
2019-07-08 14:04:52 +00:00
|
|
|
|
|
|
|
|
|
|
|
State m_state;
|
2019-11-07 10:34:12 +00:00
|
|
|
evmc::address m_currentAddress = {};
|
|
|
|
evmc::address m_coinbase = convertToEVMC(Address("0x7878787878787878787878787878787878787878"));
|
2019-07-08 14:04:52 +00:00
|
|
|
|
|
|
|
private:
|
2019-07-11 16:46:17 +00:00
|
|
|
evmc::result precompileECRecover(evmc_message const& _message) noexcept;
|
2019-07-08 14:04:52 +00:00
|
|
|
evmc::result precompileSha256(evmc_message const& _message) noexcept;
|
2019-07-11 16:46:17 +00:00
|
|
|
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<bytes, bytes> 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;
|
2019-07-08 14:04:52 +00:00
|
|
|
|
2019-06-26 16:42:24 +00:00
|
|
|
evmc::vm* m_vm = nullptr;
|
2019-07-08 14:04:52 +00:00
|
|
|
evmc_revision m_evmVersion;
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|