Extract state printing to a separate class.

This commit is contained in:
Bhargava Shastry 2021-03-10 12:00:18 +01:00
parent 24f42c5541
commit 8023fdb537
3 changed files with 87 additions and 67 deletions

View File

@ -133,6 +133,10 @@ EVMHost::EVMHost(langutil::EVMVersion _evmVersion, evmc::VM& _vm):
// Mainnet according to EIP-155 // Mainnet according to EIP-155
tx_context.chain_id = evmc::uint256be{1}; tx_context.chain_id = evmc::uint256be{1};
// Reserve space for recording calls.
if (!recorded_calls.capacity())
recorded_calls.reserve(max_recorded_calls);
reset(); reset();
} }
@ -174,9 +178,6 @@ void EVMHost::selfdestruct(const evmc::address& _addr, const evmc::address& _ben
void EVMHost::recordCalls(evmc_message const& _message) noexcept void EVMHost::recordCalls(evmc_message const& _message) noexcept
{ {
if (recorded_calls.empty())
recorded_calls.reserve(max_recorded_calls);
if (recorded_calls.size() < max_recorded_calls) if (recorded_calls.size() < max_recorded_calls)
recorded_calls.emplace_back(_message); recorded_calls.emplace_back(_message);
} }
@ -786,7 +787,50 @@ StorageMap const& EVMHost::get_address_storage(evmc::address const& _addr)
return accounts[_addr].storage; return accounts[_addr].storage;
} }
void EVMHost::printCallRecords(std::ostringstream& _os) const noexcept string EVMHostPrinter::state()
{
// Print state and execution trace.
if (host.account_exists(account))
{
storage();
balance();
}
else
selfdestructRecords();
callRecords();
return stateStream.str();
}
void EVMHostPrinter::storage()
{
for (auto const& [slot, value]: host.get_address_storage(account))
if (host.get_storage(account, slot))
stateStream << host.convertFromEVMC(slot)
<< ": "
<< host.convertFromEVMC(value.value)
<< endl;
}
void EVMHostPrinter::balance()
{
stateStream << "BALANCE "
<< host.convertFromEVMC(host.get_balance(account))
<< endl;
}
void EVMHostPrinter::selfdestructRecords()
{
for (auto const& record: host.recorded_selfdestructs)
stateStream << "SELFDESTRUCT"
<< " BENEFICIARY "
<< host.convertFromEVMC(record.beneficiary)
<< " BALANCE "
<< host.convertFromEVMC(record.balance)
<< endl;
}
void EVMHostPrinter::callRecords()
{ {
static const auto callKind = [](evmc_call_kind _kind) -> string static const auto callKind = [](evmc_call_kind _kind) -> string
{ {
@ -807,43 +851,9 @@ void EVMHost::printCallRecords(std::ostringstream& _os) const noexcept
} }
}; };
for (auto const& record: recorded_calls) for (auto const& record: host.recorded_calls)
_os << callKind(record.kind) stateStream << callKind(record.kind)
<< " VALUE " << " VALUE "
<< convertFromEVMC(record.value) << host.convertFromEVMC(record.value)
<< endl; << endl;
} }
void EVMHost::printSelfdestructRecords(ostringstream& _os) const noexcept
{
for (auto const& record: recorded_selfdestructs)
_os << "SELFDESTRUCT"
<< " BENEFICIARY "
<< convertFromEVMC(record.beneficiary)
<< " BALANCE "
<< convertFromEVMC(record.balance)
<< endl;
}
void EVMHost::printBalance(evmc::address const& _addr, ostringstream& _os) const noexcept
{
_os << "BALANCE " << convertFromEVMC(get_balance(_addr)) << endl;
}
string EVMHost::dumpState(evmc::address _addr)
{
ostringstream stateStream;
// Print state and execution trace.
if (account_exists(_addr))
{
printStorageAt(_addr, stateStream);
printBalance(_addr, stateStream);
}
else
printSelfdestructRecords(stateStream);
printCallRecords(stateStream);
return stateStream.str();
}

View File

@ -87,23 +87,11 @@ public:
return m_vm.has_capability(capability); return m_vm.has_capability(capability);
} }
/// @returns the state as a string. State includes storage at and balance
/// of account at @param _addr and execution trace of the host post reset.
std::string dumpState(evmc::address _addr);
private: private:
evmc::address m_currentAddress = {}; evmc::address m_currentAddress = {};
/// Records calls made via @param _message. /// Records calls made via @param _message.
void recordCalls(evmc_message const& _message) noexcept; void recordCalls(evmc_message const& _message) noexcept;
/// Prints contents of storage at @param _addr to @param _os.
void printStorageAt(evmc::address const& _addr, std::ostringstream& _os);
/// Prints call summary to @param _os.
void printCallRecords(std::ostringstream& _os) const noexcept;
/// Print self destruct records to @param _os.
void printSelfdestructRecords(std::ostringstream& _os) const noexcept;
/// Print balance of @param _addr to @param _os.
void printBalance(evmc::address const& _addr, std::ostringstream& _os) const noexcept;
static evmc::result precompileECRecover(evmc_message const& _message) noexcept; static evmc::result precompileECRecover(evmc_message const& _message) noexcept;
static evmc::result precompileSha256(evmc_message const& _message) noexcept; static evmc::result precompileSha256(evmc_message const& _message) noexcept;
@ -125,5 +113,27 @@ private:
evmc_revision m_evmRevision; evmc_revision m_evmRevision;
}; };
struct EVMHostPrinter
{
/// Constructs a host printer object for state at @param _address.
explicit EVMHostPrinter(EVMHost& _host, evmc::address _address):
host(_host),
account(_address)
{}
/// @returns state at account maintained by host.
std::string state();
/// Outputs storage at account to stateStream.
void storage();
/// Outputs call records for account to stateStream.
void callRecords();
/// Outputs balance of account to stateStream.
void balance();
/// Outputs self-destruct record for account to stateStream.
void selfdestructRecords();
std::ostringstream stateStream;
EVMHost& host;
evmc::address account;
};
} }

View File

@ -120,7 +120,7 @@ DEFINE_PROTO_FUZZER(Program const& _input)
"Unoptimised call failed." "Unoptimised call failed."
); );
ostringstream unoptimizedState; ostringstream unoptimizedState;
unoptimizedState << hostContext.dumpState(deployResult.create_address); unoptimizedState << EVMHostPrinter{hostContext, deployResult.create_address}.state();
settings.runYulOptimiser = true; settings.runYulOptimiser = true;
settings.optimizeStackAllocation = true; settings.optimizeStackAllocation = true;
@ -160,7 +160,7 @@ DEFINE_PROTO_FUZZER(Program const& _input)
"Optimised call failed." "Optimised call failed."
); );
ostringstream optimizedState; ostringstream optimizedState;
optimizedState << hostContext.dumpState(deployResultOpt.create_address); optimizedState << EVMHostPrinter{hostContext, deployResultOpt.create_address}.state();
int64_t constexpr tolerance = 1000; int64_t constexpr tolerance = 1000;
if (callResult.gas_left > callResultOpt.gas_left) if (callResult.gas_left > callResultOpt.gas_left)