Skip to content

Commit 1a8f6dd

Browse files
committed
[eth_call] Fix interaction between prestate tracers and state overrides.
The problem is that state overrides are applied to `State::current` accounts, whereas the prestate trace is computed from `State::original`. Thus prestate tracers do not respect state overrides. In this patch, we merge the state overrides into the block state before execution, and create a new `State` instance with this updated block state, meaning that the former `State::current` accounts will be `State::original` in the new state instance. This new state instance is then passed to execution.
1 parent 52234ef commit 1a8f6dd

File tree

2 files changed

+470
-67
lines changed

2 files changed

+470
-67
lines changed

category/rpc/monad_executor.cpp

Lines changed: 77 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -211,82 +211,92 @@ namespace
211211
BlockState block_state{tdb, vm};
212212
// avoid conflict with block reward txn
213213
Incarnation const incarnation{block_number, Incarnation::LAST_TX - 1u};
214-
State state{block_state, incarnation};
215-
216-
for (auto const &[addr, state_delta] : state_overrides.override_sets) {
217-
// address
218-
Address address{};
219-
std::memcpy(address.bytes, addr.data(), sizeof(Address));
220-
221-
// This would avoid seg-fault on storage override for non-existing
222-
// accounts
223-
auto const &account = state.recent_account(address);
224-
if (MONAD_UNLIKELY(!account.has_value())) {
225-
state.create_contract(address);
226-
}
227-
228-
if (state_delta.balance.has_value()) {
229-
auto const balance = intx::be::unsafe::load<uint256_t>(
230-
state_delta.balance.value().data());
231-
if (balance >
232-
intx::be::load<uint256_t>(
233-
state.get_current_balance_pessimistic(address))) {
234-
state.add_to_balance(
235-
address,
236-
balance - intx::be::load<uint256_t>(
237-
state.get_current_balance_pessimistic(
238-
address)));
214+
{
215+
State state{block_state, incarnation};
216+
217+
for (auto const &[addr, state_delta] :
218+
state_overrides.override_sets) {
219+
// address
220+
Address address{};
221+
std::memcpy(address.bytes, addr.data(), sizeof(Address));
222+
223+
// This would avoid seg-fault on storage override for
224+
// non-existing accounts
225+
auto const &account = state.recent_account(address);
226+
if (MONAD_UNLIKELY(!account.has_value())) {
227+
state.create_contract(address);
239228
}
240-
else {
241-
state.subtract_from_balance(
242-
address,
229+
230+
if (state_delta.balance.has_value()) {
231+
auto const balance = intx::be::unsafe::load<uint256_t>(
232+
state_delta.balance.value().data());
233+
if (balance >
243234
intx::be::load<uint256_t>(
244-
state.get_current_balance_pessimistic(address)) -
245-
balance);
235+
state.get_current_balance_pessimistic(address))) {
236+
state.add_to_balance(
237+
address,
238+
balance - intx::be::load<uint256_t>(
239+
state.get_current_balance_pessimistic(
240+
address)));
241+
}
242+
else {
243+
state.subtract_from_balance(
244+
address,
245+
intx::be::load<uint256_t>(
246+
state.get_current_balance_pessimistic(
247+
address)) -
248+
balance);
249+
}
246250
}
247-
}
248251

249-
if (state_delta.nonce.has_value()) {
250-
state.set_nonce(address, state_delta.nonce.value());
251-
}
252-
253-
if (state_delta.code.has_value()) {
254-
byte_string const code{
255-
state_delta.code.value().data(),
256-
state_delta.code.value().size()};
257-
state.set_code(address, code);
258-
}
252+
if (state_delta.nonce.has_value()) {
253+
state.set_nonce(address, state_delta.nonce.value());
254+
}
259255

260-
auto const update_state =
261-
[&](std::map<byte_string, byte_string> const &diff) {
262-
for (auto const &[key, value] : diff) {
263-
bytes32_t storage_key;
264-
bytes32_t storage_value;
265-
std::memcpy(
266-
storage_key.bytes, key.data(), sizeof(bytes32_t));
267-
std::memcpy(
268-
storage_value.bytes,
269-
value.data(),
270-
sizeof(bytes32_t));
271-
272-
state.set_storage(address, storage_key, storage_value);
273-
}
274-
};
256+
if (state_delta.code.has_value()) {
257+
byte_string const code{
258+
state_delta.code.value().data(),
259+
state_delta.code.value().size()};
260+
state.set_code(address, code);
261+
}
275262

276-
// Remove single storage
277-
if (!state_delta.state_diff.empty()) {
278-
// we need to access the account first before accessing its
279-
// storage
280-
(void)state.get_nonce(address);
281-
update_state(state_delta.state_diff);
282-
}
263+
auto const update_state =
264+
[&](std::map<byte_string, byte_string> const &diff) {
265+
for (auto const &[key, value] : diff) {
266+
bytes32_t storage_key;
267+
bytes32_t storage_value;
268+
std::memcpy(
269+
storage_key.bytes,
270+
key.data(),
271+
sizeof(bytes32_t));
272+
std::memcpy(
273+
storage_value.bytes,
274+
value.data(),
275+
sizeof(bytes32_t));
276+
277+
state.set_storage(
278+
address, storage_key, storage_value);
279+
}
280+
};
281+
282+
// Remove single storage
283+
if (!state_delta.state_diff.empty()) {
284+
// we need to access the account first before accessing its
285+
// storage
286+
(void)state.get_nonce(address);
287+
update_state(state_delta.state_diff);
288+
}
283289

284-
// Remove all override
285-
if (!state_delta.state.empty()) {
286-
state.set_to_state_incarnation(address);
287-
update_state(state_delta.state);
290+
// Remove all override
291+
if (!state_delta.state.empty()) {
292+
state.set_to_state_incarnation(address);
293+
update_state(state_delta.state);
294+
}
288295
}
296+
MONAD_ASSERT(block_state.can_merge(state));
297+
block_state.merge(state);
289298
}
299+
State state{block_state, incarnation};
290300

291301
// validate_transaction expects nonce to match.
292302
// However, eth_call doesn't take a nonce parameter.

0 commit comments

Comments
 (0)