-
Notifications
You must be signed in to change notification settings - Fork 285
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
Conversation
eb7bc35
to
229995c
Compare
Codecov Report
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
Flags with carried forward coverage won't be shown. Click here to find out more.
|
cea1e32
to
e69c964
Compare
|
||
[[nodiscard]] const auto& get_destructs() const noexcept { return m_destructs; } | ||
|
||
[[nodiscard]] std::vector<Log>&& take_logs() noexcept { return std::move(m_logs); } |
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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); |
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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.
test/state/host.cpp
Outdated
{ | ||
bool Host::account_exists(const address& addr) const noexcept | ||
{ | ||
const auto* const acc = m_state.get_or_null(addr); |
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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.
test/state/state.hpp
Outdated
return nullptr; | ||
} | ||
|
||
Account& get_or_create(const address& addr) { return m_accounts[addr]; } |
There was a problem hiding this comment.
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
?
There was a problem hiding this comment.
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[]
?
There was a problem hiding this comment.
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) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What are these comments?
There was a problem hiding this comment.
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.
a0cdc84
to
7399a0c
Compare
7399a0c
to
bf42bde
Compare
test/state/state.hpp
Outdated
@@ -24,6 +24,24 @@ class State | |||
assert(r.second); | |||
return r.first->second; | |||
} | |||
|
|||
Account& get(const address& addr) |
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
noexcept
There was a problem hiding this comment.
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.cpp
Outdated
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(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
can be const
test/state/state.cpp
Outdated
if (sender_balance_check < tx_max_cost_512) | ||
return {}; | ||
|
||
sender_balance_check -= static_cast<intx::uint256>(tx_max_cost_512); |
There was a problem hiding this comment.
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
?
test/state/state.cpp
Outdated
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) |
There was a problem hiding this comment.
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)); |
There was a problem hiding this comment.
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
?
There was a problem hiding this comment.
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"?
test/state/host.cpp
Outdated
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. |
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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.
auto access_addresses_snapshot = m_accessed_addresses; | ||
auto logs_snapshot = m_logs.size(); | ||
|
||
auto result = execute_message(*msg); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
can be const?
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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
There was a problem hiding this comment.
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
test/state/host.cpp
Outdated
// TODO: Predefined warm addresses can be applied to the state cache before execution. | ||
|
||
// Transaction {sender,to} are always warm. | ||
if (addr == m_tx.to) |
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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" |
There was a problem hiding this comment.
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>
?
There was a problem hiding this comment.
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.
76ccc3b
to
5d2f2a7
Compare
8aa716a
to
0d6e918
Compare
40d0da0
to
6a9620d
Compare
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().
6a9620d
to
fd1d61c
Compare
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 inevmone::state::transition()
.These are used to execute all tests by the statetest runner.
The precompiles are not implemented.