Merge pull request #7831 from ethereum/mocked-host

Use evmc::MockedHost moar
This commit is contained in:
chriseth 2019-12-03 21:27:50 +01:00 committed by GitHub
commit 37d776a1a6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 65 additions and 202 deletions

View File

@ -98,33 +98,25 @@ EVMHost::EVMHost(langutil::EVMVersion _evmVersion, evmc::VM& _vm):
evmc::address address{};
address.bytes[19] = precompiledAddress;
// 1wei
m_state.accounts[address].balance.bytes[31] = 1;
accounts[address].balance.bytes[31] = 1;
}
}
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];
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{})
return EVMC_STORAGE_ADDED;
else if (_value == evmc::bytes32{})
return EVMC_STORAGE_DELETED;
else
return EVMC_STORAGE_MODIFIED;
// TODO: support short literals in EVMC and use them here
tx_context.block_difficulty = convertToEVMC(u256("200000000"));
tx_context.block_gas_limit = 20000000;
tx_context.block_coinbase = 0x7878787878787878787878787878787878787878_address;
tx_context.tx_gas_price = convertToEVMC(u256("3000000000"));
tx_context.tx_origin = 0x9292929292929292929292929292929292929292_address;
// Mainnet according to EIP-155
tx_context.chain_id = convertToEVMC(u256(1));
}
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;
m_state.accounts.erase(_addr);
m_state.accounts[_beneficiary].balance = balance;
evmc::uint256be balance = accounts[_addr].balance;
accounts.erase(_addr);
accounts[_beneficiary].balance = balance;
}
evmc::result EVMHost::call(evmc_message const& _message) noexcept
@ -146,12 +138,12 @@ evmc::result EVMHost::call(evmc_message const& _message) noexcept
else if (_message.destination == 0x0000000000000000000000000000000000000008_address && m_evmVersion >= langutil::EVMVersion::byzantium())
return precompileALTBN128PairingProduct(_message);
State stateBackup = m_state;
auto const stateBackup = accounts;
u256 value{convertFromEVMC(_message.value)};
Account& sender = m_state.accounts[_message.sender];
auto& sender = accounts[_message.sender];
bytes code;
evmc::bytes code;
evmc_message message = _message;
if (message.depth == 0)
@ -163,7 +155,7 @@ evmc::result EVMHost::call(evmc_message const& _message) noexcept
{
evmc::result result({});
result.status_code = EVMC_OUT_OF_GAS;
m_state = stateBackup;
accounts = stateBackup;
return result;
}
}
@ -177,23 +169,23 @@ evmc::result EVMHost::call(evmc_message const& _message) noexcept
asBytes(to_string(sender.nonce++))
));
message.destination = convertToEVMC(createAddress);
code = bytes(message.input_data, message.input_data + message.input_size);
code = evmc::bytes(message.input_data, message.input_data + message.input_size);
}
else if (message.kind == EVMC_DELEGATECALL)
{
code = m_state.accounts[message.destination].code;
code = accounts[message.destination].code;
message.destination = m_currentAddress;
}
else if (message.kind == EVMC_CALLCODE)
{
code = m_state.accounts[message.destination].code;
code = accounts[message.destination].code;
message.destination = m_currentAddress;
}
else
code = m_state.accounts[message.destination].code;
code = accounts[message.destination].code;
//TODO CREATE2
Account& destination = m_state.accounts[message.destination];
auto& destination = accounts[message.destination];
if (value != 0 && message.kind != EVMC_DELEGATECALL && message.kind != EVMC_CALLCODE)
{
@ -218,55 +210,22 @@ evmc::result EVMHost::call(evmc_message const& _message) noexcept
else
{
result.create_address = message.destination;
destination.code = bytes(result.output_data, result.output_data + result.output_size);
destination.codeHash = convertToEVMC(keccak256(destination.code));
destination.code = evmc::bytes(result.output_data, result.output_data + result.output_size);
destination.codehash = convertToEVMC(keccak256({result.output_data, result.output_size}));
}
}
if (result.status_code != EVMC_SUCCESS)
m_state = stateBackup;
accounts = stateBackup;
return result;
}
evmc_tx_context EVMHost::get_tx_context() const noexcept
{
evmc_tx_context ctx = {};
ctx.block_timestamp = m_state.timestamp;
ctx.block_number = m_state.blockNumber;
ctx.block_coinbase = m_coinbase;
// TODO: support short literals in EVMC and use them here
ctx.block_difficulty = convertToEVMC(u256("200000000"));
ctx.block_gas_limit = 20000000;
ctx.tx_gas_price = convertToEVMC(u256("3000000000"));
ctx.tx_origin = 0x9292929292929292929292929292929292929292_address;
// Mainnet according to EIP-155
ctx.chain_id = convertToEVMC(u256(1));
return ctx;
}
evmc::bytes32 EVMHost::get_block_hash(int64_t _number) const noexcept
{
return convertToEVMC(u256("0x3737373737373737373737373737373737373737373737373737373737373737") + _number);
}
void EVMHost::emit_log(
evmc::address const& _addr,
uint8_t const* _data,
size_t _dataSize,
evmc::bytes32 const _topics[],
size_t _topicsCount
) noexcept
{
LogEntry entry;
entry.address = convertFromEVMC(_addr);
for (size_t i = 0; i < _topicsCount; ++i)
entry.topics.emplace_back(convertFromEVMC(_topics[i]));
entry.data = bytes(_data, _data + _dataSize);
m_state.logs.emplace_back(std::move(entry));
}
Address EVMHost::convertFromEVMC(evmc::address const& _addr)
{
return Address(bytes(begin(_addr.bytes), end(_addr.bytes)));

View File

@ -21,6 +21,7 @@
#pragma once
#include <test/evmc/mocked_host.hpp>
#include <test/evmc/evmc.hpp>
#include <test/evmc/evmc.h>
@ -34,9 +35,12 @@ namespace test
{
using Address = h160;
class EVMHost: public evmc::Host
class EVMHost: public evmc::MockedHost
{
public:
using MockedHost::get_code_size;
using MockedHost::get_balance;
/// 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.
@ -44,134 +48,33 @@ public:
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<evmc::bytes32, evmc::bytes32> storage;
};
struct LogEntry
{
Address address;
std::vector<h256> topics;
bytes data;
};
struct State
{
size_t blockNumber;
uint64_t timestamp;
std::map<evmc::address, Account> accounts;
std::vector<LogEntry> logs;
};
Account const* account(evmc::address const& _address) const
{
auto it = m_state.accounts.find(_address);
return it == m_state.accounts.end() ? nullptr : &it->second;
}
Account* account(evmc::address const& _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 reset() { accounts.clear(); m_currentAddress = {}; }
void newBlock()
{
m_state.blockNumber++;
m_state.timestamp += 15;
m_state.logs.clear();
tx_context.block_number++;
tx_context.block_timestamp += 15;
recorded_logs.clear();
}
bool account_exists(evmc::address const& _addr) const noexcept final
{
return account(_addr) != nullptr;
return evmc::MockedHost::account_exists(_addr);
}
evmc::bytes32 get_storage(evmc::address const& _addr, evmc::bytes32 const& _key) const noexcept final
{
if (auto* acc = account(_addr))
{
auto it = acc->storage.find(_key);
if (it != acc->storage.end())
return it->second;
}
return {};
}
void selfdestruct(evmc::address const& _addr, evmc::address const& _beneficiary) noexcept final;
evmc_storage_status set_storage(
evmc::address const& _addr,
evmc::bytes32 const& _key,
evmc::bytes32 const& _value
) noexcept;
evmc::result call(evmc_message const& _message) noexcept final;
evmc::uint256be get_balance(evmc::address const& _addr) const noexcept final
{
if (Account const* acc = account(_addr))
return acc->balance;
return {};
}
size_t get_code_size(evmc::address const& _addr) const noexcept final
{
if (Account const* acc = account(_addr))
return acc->code.size();
return 0;
}
evmc::bytes32 get_code_hash(evmc::address const& _addr) const 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
) const 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() const noexcept;
evmc::bytes32 get_block_hash(int64_t number) const noexcept;
void emit_log(
evmc::address const& _addr,
uint8_t const* _data,
size_t _dataSize,
evmc::bytes32 const _topics[],
size_t _topicsCount
) noexcept;
evmc::bytes32 get_block_hash(int64_t number) const noexcept final;
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::address m_currentAddress = {};
static evmc::result precompileECRecover(evmc_message const& _message) noexcept;
static evmc::result precompileSha256(evmc_message const& _message) noexcept;
static evmc::result precompileRipeMD160(evmc_message const& _message) noexcept;

View File

@ -25,7 +25,6 @@
#include <test/EVMHost.h>
#include <test/evmc/evmc.hpp>
#include <test/evmc/loader.h>
#include <libdevcore/CommonIO.h>
@ -56,7 +55,7 @@ ExecutionFramework::ExecutionFramework(langutil::EVMVersion _evmVersion):
m_evmHost->reset();
for (size_t i = 0; i < 10; i++)
m_evmHost->m_state.accounts[EVMHost::convertToEVMC(account(i))].balance =
m_evmHost->accounts[EVMHost::convertToEVMC(account(i))].balance =
EVMHost::convertToEVMC(u256(1) << 100);
}
@ -89,12 +88,12 @@ std::pair<bool, string> ExecutionFramework::compareAndCreateMessage(
u256 ExecutionFramework::gasLimit() const
{
return {m_evmHost->get_tx_context().block_gas_limit};
return {m_evmHost->tx_context.block_gas_limit};
}
u256 ExecutionFramework::gasPrice() const
{
return {EVMHost::convertFromEVMC(m_evmHost->get_tx_context().tx_gas_price)};
return {EVMHost::convertFromEVMC(m_evmHost->tx_context.tx_gas_price)};
}
u256 ExecutionFramework::blockHash(u256 const& _number) const
@ -104,7 +103,7 @@ u256 ExecutionFramework::blockHash(u256 const& _number) const
u256 ExecutionFramework::blockNumber() const
{
return m_evmHost->m_state.blockNumber;
return m_evmHost->tx_context.block_number;
}
void ExecutionFramework::sendMessage(bytes const& _data, bool _isCreation, u256 const& _value)
@ -178,7 +177,7 @@ void ExecutionFramework::sendEther(Address const& _addr, u256 const& _amount)
size_t ExecutionFramework::currentTimestamp()
{
return m_evmHost->get_tx_context().block_timestamp;
return m_evmHost->tx_context.block_timestamp;
}
size_t ExecutionFramework::blockTimestamp(u256 _block)
@ -201,27 +200,30 @@ bool ExecutionFramework::addressHasCode(Address const& _addr)
size_t ExecutionFramework::numLogs() const
{
return m_evmHost->m_state.logs.size();
return m_evmHost->recorded_logs.size();
}
size_t ExecutionFramework::numLogTopics(size_t _logIdx) const
{
return m_evmHost->m_state.logs.at(_logIdx).topics.size();
return m_evmHost->recorded_logs.at(_logIdx).topics.size();
}
h256 ExecutionFramework::logTopic(size_t _logIdx, size_t _topicIdx) const
{
return m_evmHost->m_state.logs.at(_logIdx).topics.at(_topicIdx);
return EVMHost::convertFromEVMC(m_evmHost->recorded_logs.at(_logIdx).topics.at(_topicIdx));
}
Address ExecutionFramework::logAddress(size_t _logIdx) const
{
return m_evmHost->m_state.logs.at(_logIdx).address;
return EVMHost::convertFromEVMC(m_evmHost->recorded_logs.at(_logIdx).creator);
}
bytes const& ExecutionFramework::logData(size_t _logIdx) const
bytes ExecutionFramework::logData(size_t _logIdx) const
{
return m_evmHost->m_state.logs.at(_logIdx).data;
const auto& data = m_evmHost->recorded_logs.at(_logIdx).data;
// TODO: Return a copy of log data, because this is expected from REQUIRE_LOG_DATA(),
// but reference type like string_view would be preferable.
return {data.begin(), data.end()};
}
u256 ExecutionFramework::balanceAt(Address const& _addr)
@ -231,10 +233,11 @@ u256 ExecutionFramework::balanceAt(Address const& _addr)
bool ExecutionFramework::storageEmpty(Address const& _addr)
{
if (EVMHost::Account const* acc = m_evmHost->account(EVMHost::convertToEVMC(_addr)))
const auto it = m_evmHost->accounts.find(EVMHost::convertToEVMC(_addr));
if (it != m_evmHost->accounts.end())
{
for (auto const& entry: acc->storage)
if (!(entry.second == evmc::bytes32{}))
for (auto const& entry: it->second.storage)
if (!(entry.second.value == evmc::bytes32{}))
return false;
}
return true;

View File

@ -266,7 +266,7 @@ protected:
size_t numLogTopics(size_t _logIdx) const;
h256 logTopic(size_t _logIdx, size_t _topicIdx) const;
Address logAddress(size_t _logIdx) const;
bytes const& logData(size_t _logIdx) const;
bytes logData(size_t _logIdx) const;
langutil::EVMVersion m_evmVersion;
solidity::OptimiserSettings m_optimiserSettings = solidity::OptimiserSettings::minimal();

View File

@ -27,7 +27,6 @@
#include <boost/test/unit_test.hpp>
#include <string>
#include <tuple>
using namespace std;
using namespace dev::test;
@ -280,8 +279,7 @@ protected:
}
};
size_t const m_biddingTime = size_t(7 * 24 * 3600);
size_t const m_renewalInterval = size_t(365 * 24 * 3600);
int64_t const m_biddingTime = 7 * 24 * 3600;
};
}
@ -417,7 +415,7 @@ BOOST_AUTO_TEST_CASE(auction_simple)
BOOST_CHECK_EQUAL(registrar.owner(name), 0);
// "wait" until auction end
m_evmHost->m_state.timestamp += m_biddingTime + 10;
m_evmHost->tx_context.block_timestamp += m_biddingTime + 10;
// trigger auction again
registrar.reserve(name);
BOOST_CHECK_EQUAL(registrar.owner(name), m_sender);
@ -429,7 +427,7 @@ BOOST_AUTO_TEST_CASE(auction_bidding)
string name = "x";
unsigned startTime = 0x776347e2;
m_evmHost->m_state.timestamp = startTime;
m_evmHost->tx_context.block_timestamp = startTime;
RegistrarInterface registrar(*this);
// initiate auction
@ -437,19 +435,19 @@ BOOST_AUTO_TEST_CASE(auction_bidding)
registrar.reserve(name);
BOOST_CHECK_EQUAL(registrar.owner(name), 0);
// overbid self
m_evmHost->m_state.timestamp = startTime + m_biddingTime - 10;
m_evmHost->tx_context.block_timestamp = startTime + m_biddingTime - 10;
registrar.setNextValue(12);
registrar.reserve(name);
// another bid by someone else
sendEther(account(1), 10 * ether);
m_sender = account(1);
m_evmHost->m_state.timestamp = startTime + 2 * m_biddingTime - 50;
m_evmHost->tx_context.block_timestamp = startTime + 2 * m_biddingTime - 50;
registrar.setNextValue(13);
registrar.reserve(name);
BOOST_CHECK_EQUAL(registrar.owner(name), 0);
// end auction by first bidder (which is not highest) trying to overbid again (too late)
m_sender = account(0);
m_evmHost->m_state.timestamp = startTime + 4 * m_biddingTime;
m_evmHost->tx_context.block_timestamp = startTime + 4 * m_biddingTime;
registrar.setNextValue(20);
registrar.reserve(name);
BOOST_CHECK_EQUAL(registrar.owner(name), account(1));

View File

@ -1135,7 +1135,7 @@ BOOST_AUTO_TEST_CASE(blockchain)
}
}
)";
m_evmHost->m_coinbase = EVMHost::convertToEVMC(Address("0x1212121212121212121212121212121212121212"));
m_evmHost->tx_context.block_coinbase = EVMHost::convertToEVMC(Address("0x1212121212121212121212121212121212121212"));
m_evmHost->newBlock();
m_evmHost->newBlock();
m_evmHost->newBlock();