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

Add implementation of evmc::Host and state transition #484

Merged
merged 5 commits into from
Oct 27, 2022

Conversation

chfast
Copy link
Member

@chfast chfast commented Jul 15, 2022

This implements state transition as application of a single transaction to a predefined state. Most of the logic is in the evmc::Host implementation plus the transaction specific handling in evmone::state::transition().

These are used to execute all tests by the statetest runner.

The precompiles are not implemented.

@chfast chfast force-pushed the state_transition branch 2 times, most recently from eb7bc35 to 229995c Compare July 15, 2022 17:27
@codecov
Copy link

codecov bot commented Jul 15, 2022

Codecov Report

Merging #484 (6a9620d) into master (8314df3) will decrease coverage by 1.10%.
The diff coverage is 80.71%.

❗ Current head 6a9620d differs from pull request most recent head fd1d61c. Consider uploading reports for the commit fd1d61c to get more accurate results

Additional details and impacted files
@@            Coverage Diff             @@
##           master     #484      +/-   ##
==========================================
- Coverage   99.08%   97.97%   -1.11%     
==========================================
  Files          54       59       +5     
  Lines        5348     5680     +332     
==========================================
+ Hits         5299     5565     +266     
- Misses         49      115      +66     
Flag Coverage Δ
blockchaintests 77.78% <ø> (ø)
statetests 26.82% <99.63%> (+19.25%) ⬆️
unittests 91.70% <2.68%> (-5.56%) ⬇️

Flags with carried forward coverage won't be shown. Click here to find out more.

Impacted Files Coverage Δ
test/statetest/statetest.hpp 100.00% <ø> (ø)
test/state/host.hpp 40.00% <40.00%> (ø)
test/state/precompiles.cpp 66.66% <66.66%> (ø)
test/state/state.cpp 79.74% <79.74%> (ø)
test/state/host.cpp 80.54% <80.54%> (ø)
test/statetest/statetest_runner.cpp 81.25% <81.25%> (ø)
test/state/state.hpp 88.46% <86.36%> (-11.54%) ⬇️
test/statetest/statetest.cpp 94.59% <92.85%> (-5.41%) ⬇️
test/state/account.hpp 100.00% <100.00%> (ø)
test/statetest/statetest_loader.cpp 80.86% <100.00%> (ø)
... and 4 more

@chfast chfast requested review from axic, gumb0 and yperbasis August 1, 2022 12:01
@chfast chfast force-pushed the state_transition branch 2 times, most recently from cea1e32 to e69c964 Compare August 26, 2022 11:49

[[nodiscard]] const auto& get_destructs() const noexcept { return m_destructs; }

[[nodiscard]] std::vector<Log>&& take_logs() noexcept { return std::move(m_logs); }
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is this moving while the others are just references?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We return the logs in the end so we can move them out of the Host. The other structures are discarded.


bytes32 Host::get_storage(const address& addr, const bytes32& key) const noexcept
{
const auto& acc = m_state.get(addr);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wouldn't this put it into the hot list?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This assumes the account must exist already. And it is hot already.

{
bool Host::account_exists(const address& addr) const noexcept
{
const auto* const acc = m_state.get_or_null(addr);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wouldn't this also put it into the hot list?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This will not (it will not create an account if it doesn't exist). And I believe it should not - this is related to old call cost penalty check. But we should have a test which check if this does not affect account access list.

return nullptr;
}

Account& get_or_create(const address& addr) { return m_accounts[addr]; }
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hm, so will get() fail if the account doesn't exists? Or why do you need get_or_create?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

maybe this is just operator[] ?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I replaced single operator[] with this ugly names because I want to know where new accounts are created (in the context of State cache). This already requires one more round of redesign and probably one more when state journal will be introduced.

From the current usage I need should replace this one with:
get_or_create(address, Account{...}) because I often need to modify the created account straight away.

for (size_t case_index = 0; case_index != cases.size(); ++case_index)
{
SCOPED_TRACE(std::string{evmc::to_string(rev)} + '/' + std::to_string(case_index));
// if (rev != EVMC_FRONTIER)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What are these comments?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There are for debugging. You can narrow a test to single revision and/or case.

@@ -24,6 +24,24 @@ class State
assert(r.second);
return r.first->second;
}

Account& get(const address& addr)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should there be const version?

Copy link
Member

@gumb0 gumb0 Sep 23, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also for other methods below

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

noexcept

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The const version is not required because the only user of this is Host having non-const reference.

test/state/state.hpp Outdated Show resolved Hide resolved
typename std::unordered_map<Key, T, Hash, KeyEqual, Alloc>::size_type erase_if(
std::unordered_map<Key, T, Hash, KeyEqual, Alloc>& c, Pred pred)
{
auto old_size = c.size();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can be const

if (sender_balance_check < tx_max_cost_512)
return {};

sender_balance_check -= static_cast<intx::uint256>(tx_max_cost_512);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why not check sender_acc.balance >= tx_max_cost_512 + tx.value ?

std::optional<std::vector<Log>> transition(
State& state, const BlockInfo& block, const Transaction& tx, evmc_revision rev, evmc::VM& vm)
{
if (rev < EVMC_LONDON && tx.kind == Transaction::Kind::eip1559)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe makes sense to extract transaction-related checks into a separate transaction validity funtion.


Host host{rev, vm, state, block, tx};

const auto result = host.call(build_message(tx, execution_gas_limit));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Where do sender and recipient get their touched flag set? inside call?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In Host::call() for CALL only: recipient_acc.touched = true;.
Sender is not touched.
Are you confused by "touched" vs "warm"?

auto& new_acc = m_state.get_or_create(msg.recipient);
if (m_rev >= EVMC_SPURIOUS_DRAGON)
new_acc.nonce = 1;
new_acc.storage.clear(); // In case of collision.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

confused why this is needed, doesn't it return error above in case of collision?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The collision check ignores storage so you can have an "empty" account with non-empty storage (only in tests though). I have better version of this with better comments and I should bring it here.

test/state/host.cpp Outdated Show resolved Hide resolved
test/state/host.cpp Outdated Show resolved Hide resolved
auto access_addresses_snapshot = m_accessed_addresses;
auto logs_snapshot = m_logs.size();

auto result = execute_message(*msg);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can be const?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No because we have to move it.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you mean to return value? copy will be elided even if it's const I think

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, but Result is move-only type

// TODO: Predefined warm addresses can be applied to the state cache before execution.

// Transaction {sender,to} are always warm.
if (addr == m_tx.to)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not add all these and access list to m_accessed_addresses in Host constructor?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

On todo list. I have it done already so I will include the change.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done, but a lot of new code landed.

// Copyright 2022 The evmone Authors.
// SPDX-License-Identifier: Apache-2.0

#include "../state/mpt_hash.hpp"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Better <test/state/mpt_hash.hpp> ?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Doesn't work. I probably would need to specify additional include paths what does not sound worth it.

test/statetest/statetest.cpp Outdated Show resolved Hide resolved
test/state/state.hpp Outdated Show resolved Hide resolved
@chfast chfast force-pushed the state_transition branch 3 times, most recently from 8aa716a to 0d6e918 Compare October 21, 2022 10:35
@chfast chfast force-pushed the state_transition branch 2 times, most recently from 40d0da0 to 6a9620d Compare October 27, 2022 12:11
chfast and others added 5 commits October 27, 2022 14:45
This implements state transition as application of a single transaction
to a predefined state. Most of the logic is in evmc::Host implementation
plus the transaction specific handling in evmone::state::transition().
@chfast chfast merged commit faf64b2 into master Oct 27, 2022
@chfast chfast deleted the state_transition branch October 27, 2022 13:56
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants