Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use evmc::MockedHost moar #7831

Merged
merged 8 commits into from
Dec 3, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
89 changes: 24 additions & 65 deletions test/EVMHost.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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)
Expand All @@ -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;
}
}
Expand All @@ -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)
{
Expand All @@ -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)));
Expand Down
125 changes: 14 additions & 111 deletions test/EVMHost.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@

#pragma once

#include <test/evmc/mocked_host.hpp>
#include <test/evmc/evmc.hpp>
#include <test/evmc/evmc.h>

Expand All @@ -34,144 +35,46 @@ 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.
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<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;
private:
evmc::address m_currentAddress = {};
evmc::address m_coinbase = convertToEVMC(Address("0x7878787878787878787878787878787878787878"));

private:
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;
Expand Down
Loading