Skip to content
Open
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
55 changes: 55 additions & 0 deletions category/execution/ethereum/state3/state.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,61 @@ State::State(
{
}

State::State(
BlockState &block_state, Incarnation const incarnation,
bool const relaxed_validation, Overrides const &state_overrides)
: block_state_{block_state}
, incarnation_{incarnation}
, relaxed_validation_{relaxed_validation}
{
for (auto const &[address, state_delta] : state_overrides) {
OriginalAccountState &original_account_state =
this->original_account_state(address);
if (!original_account_state.account_.has_value()) {
original_account_state.account_ =
Account{.incarnation = incarnation};
}
Account &account = original_account_state.account_.value();

if (state_delta.balance.has_value()) {
account.balance = state_delta.balance.value();
}

if (state_delta.nonce.has_value()) {
account.nonce = state_delta.nonce.value();
}

if (state_delta.code.has_value()) {
auto const code = state_delta.code.value();
auto const code_hash = to_bytes(keccak256(code));
code_[code_hash] = block_state_.vm().try_insert_varcode(
code_hash, vm::make_shared_intercode(code));
account.code_hash = code_hash;
}

auto const update_state =
[&](std::map<bytes32_t, bytes32_t> const &diff) {
for (auto const &[key, value] : diff) {
(void)original_account_state.set_storage(
key, value, bytes32_t{});
}
};

// Remove single storage
if (!state_delta.state_diff.empty()) {
// we need to access the account first before accessing its
// storage
update_state(state_delta.state_diff);
}

// Remove all override
if (!state_delta.state.empty()) {
account.incarnation = incarnation;
update_state(state_delta.state);
}
}
}

State::Map<Address, OriginalAccountState> const &State::original() const
{
return original_;
Expand Down
19 changes: 17 additions & 2 deletions category/execution/ethereum/state3/state.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
#include <category/execution/ethereum/core/account.hpp>
#include <category/execution/ethereum/core/address.hpp>
#include <category/execution/ethereum/core/receipt.hpp>
#include <category/execution/ethereum/state2/block_state.hpp>
#include <category/execution/ethereum/state3/account_state.hpp>
#include <category/execution/ethereum/state3/version_stack.hpp>
#include <category/execution/ethereum/types/incarnation.hpp>
Expand All @@ -33,13 +34,12 @@

#include <cstddef>
#include <cstdint>
#include <map>
#include <optional>
#include <vector>

MONAD_NAMESPACE_BEGIN

class BlockState;

class State
{
template <typename K, typename V>
Expand Down Expand Up @@ -71,9 +71,24 @@ class State

std::optional<Account> &current_account(Address const &);

public:
struct Override
{
std::optional<uint256_t> balance{std::nullopt};
std::optional<uint64_t> nonce{std::nullopt};
std::optional<byte_string> code{std::nullopt};
std::map<bytes32_t, bytes32_t> state{};
std::map<bytes32_t, bytes32_t> state_diff{};
};

using Overrides = std::map<Address, Override>;

public:
State(BlockState &, Incarnation, bool relaxed_validation = false);

State(
BlockState &, Incarnation, bool relaxed_validation, Overrides const &);

State(State &&) = delete;
State(State const &) = delete;
State &operator=(State &&) = delete;
Expand Down
124 changes: 28 additions & 96 deletions category/rpc/eth_call.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -69,16 +69,7 @@ using namespace monad::vm;

struct monad_state_override
{
struct monad_state_override_object
{
std::optional<byte_string> balance{std::nullopt};
std::optional<uint64_t> nonce{std::nullopt};
std::optional<byte_string> code{std::nullopt};
std::map<byte_string, byte_string> state{};
std::map<byte_string, byte_string> state_diff{};
};

std::map<byte_string, monad_state_override_object> override_sets;
std::map<Address, State::Override> override_sets{};
};

namespace
Expand All @@ -90,7 +81,6 @@ namespace
"failure to submit eth_call to thread pool: queue size exceeded";
char const *const TIMEOUT_ERR_MSG =
"failure to execute eth_call: queuing time exceeded timeout threshold";
using StateOverrideObj = monad_state_override::monad_state_override_object;

template <Traits traits>
Result<evmc::Result> eth_call_impl(
Expand Down Expand Up @@ -122,79 +112,8 @@ namespace
BlockState block_state{tdb, vm};
// avoid conflict with block reward txn
Incarnation const incarnation{block_number, Incarnation::LAST_TX - 1u};
State state{block_state, incarnation};

for (auto const &[addr, state_delta] : state_overrides.override_sets) {
// address
Address address{};
std::memcpy(address.bytes, addr.data(), sizeof(Address));

// This would avoid seg-fault on storage override for non-existing
// accounts
auto const &account = state.recent_account(address);
if (MONAD_UNLIKELY(!account.has_value())) {
state.create_contract(address);
}

if (state_delta.balance.has_value()) {
auto const balance = intx::be::unsafe::load<uint256_t>(
state_delta.balance.value().data());
if (balance >
intx::be::load<uint256_t>(state.get_balance(address))) {
state.add_to_balance(
address,
balance - intx::be::load<uint256_t>(
state.get_balance(address)));
}
else {
state.subtract_from_balance(
address,
intx::be::load<uint256_t>(state.get_balance(address)) -
balance);
}
}

if (state_delta.nonce.has_value()) {
state.set_nonce(address, state_delta.nonce.value());
}

if (state_delta.code.has_value()) {
byte_string const code{
state_delta.code.value().data(),
state_delta.code.value().size()};
state.set_code(address, code);
}

auto const update_state =
[&](std::map<byte_string, byte_string> const &diff) {
for (auto const &[key, value] : diff) {
bytes32_t storage_key;
bytes32_t storage_value;
std::memcpy(
storage_key.bytes, key.data(), sizeof(bytes32_t));
std::memcpy(
storage_value.bytes,
value.data(),
sizeof(bytes32_t));

state.set_storage(address, storage_key, storage_value);
}
};

// Remove single storage
if (!state_delta.state_diff.empty()) {
// we need to access the account first before accessing its
// storage
(void)state.get_nonce(address);
update_state(state_delta.state_diff);
}

// Remove all override
if (!state_delta.state.empty()) {
state.set_to_state_incarnation(address);
update_state(state_delta.state);
}
}
State state{
block_state, incarnation, false, state_overrides.override_sets};

// validate_transaction expects nonce to match.
// However, eth_call doesn't take a nonce parameter.
Expand Down Expand Up @@ -266,10 +185,11 @@ void add_override_address(

MONAD_ASSERT(addr);
MONAD_ASSERT(addr_len == sizeof(Address));
byte_string const address{addr, addr + addr_len};
Address address;
std::memcpy(address.bytes, addr, sizeof(Address));

MONAD_ASSERT(m->override_sets.find(address) == m->override_sets.end());
m->override_sets.emplace(address, StateOverrideObj{});
m->override_sets.emplace(address, State::Override{});
}

void set_override_balance(
Expand All @@ -281,11 +201,13 @@ void set_override_balance(

MONAD_ASSERT(addr);
MONAD_ASSERT(addr_len == sizeof(Address));
byte_string const address{addr, addr + addr_len};
Address address;
std::memcpy(address.bytes, addr, sizeof(Address));
MONAD_ASSERT(m->override_sets.find(address) != m->override_sets.end());

MONAD_ASSERT(balance);
byte_string const b{balance, balance + balance_len};
MONAD_ASSERT(balance_len == sizeof(uint256_t));
uint256_t const b = intx::be::unsafe::load<uint256_t>(balance);
m->override_sets[address].balance = std::move(b);
}

Expand All @@ -297,7 +219,8 @@ void set_override_nonce(

MONAD_ASSERT(addr);
MONAD_ASSERT(addr_len == sizeof(Address));
byte_string const address{addr, addr + addr_len};
Address address;
std::memcpy(address.bytes, addr, sizeof(Address));
MONAD_ASSERT(m->override_sets.find(address) != m->override_sets.end());

m->override_sets[address].nonce = nonce;
Expand All @@ -311,7 +234,8 @@ void set_override_code(

MONAD_ASSERT(addr);
MONAD_ASSERT(addr_len == sizeof(Address));
byte_string const address{addr, addr + addr_len};
Address address;
std::memcpy(address.bytes, addr, sizeof(Address));
MONAD_ASSERT(m->override_sets.find(address) != m->override_sets.end());

MONAD_ASSERT(code);
Expand All @@ -328,15 +252,19 @@ void set_override_state_diff(

MONAD_ASSERT(addr);
MONAD_ASSERT(addr_len == sizeof(Address));
byte_string const address{addr, addr + addr_len};
Address address;
std::memcpy(address.bytes, addr, sizeof(Address));
MONAD_ASSERT(m->override_sets.find(address) != m->override_sets.end());

MONAD_ASSERT(key);
MONAD_ASSERT(key_len == sizeof(bytes32_t));
byte_string const k{key, key + key_len};
bytes32_t k;
std::memcpy(k.bytes, key, sizeof(bytes32_t));

MONAD_ASSERT(value);
byte_string const v{value, value + value_len};
MONAD_ASSERT(value_len == sizeof(bytes32_t));
bytes32_t v;
std::memcpy(v.bytes, value, sizeof(bytes32_t));

auto &state_object = m->override_sets[address].state_diff;
MONAD_ASSERT(state_object.find(k) == state_object.end());
Expand All @@ -352,15 +280,19 @@ void set_override_state(

MONAD_ASSERT(addr);
MONAD_ASSERT(addr_len == sizeof(Address));
byte_string const address{addr, addr + addr_len};
Address address;
std::memcpy(address.bytes, addr, sizeof(Address));
MONAD_ASSERT(m->override_sets.find(address) != m->override_sets.end());

MONAD_ASSERT(key);
MONAD_ASSERT(key_len == sizeof(bytes32_t));
byte_string const k{key, key + key_len};
bytes32_t k;
std::memcpy(k.bytes, key, sizeof(bytes32_t));

MONAD_ASSERT(value);
byte_string const v{value, value + value_len};
MONAD_ASSERT(value_len == sizeof(bytes32_t));
bytes32_t v;
std::memcpy(v.bytes, value, sizeof(bytes32_t));

auto &state_object = m->override_sets[address].state;
MONAD_ASSERT(state_object.find(k) == state_object.end());
Expand Down
Loading
Loading