Skip to content

Commit bf0cbbf

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 2d9694d commit bf0cbbf

File tree

2 files changed

+221
-67
lines changed

2 files changed

+221
-67
lines changed

category/rpc/eth_call.cpp

Lines changed: 77 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -122,82 +122,92 @@ namespace
122122
BlockState block_state{tdb, vm};
123123
// avoid conflict with block reward txn
124124
Incarnation const incarnation{block_number, Incarnation::LAST_TX - 1u};
125-
State state{block_state, incarnation};
126-
127-
for (auto const &[addr, state_delta] : state_overrides.override_sets) {
128-
// address
129-
Address address{};
130-
std::memcpy(address.bytes, addr.data(), sizeof(Address));
131-
132-
// This would avoid seg-fault on storage override for non-existing
133-
// accounts
134-
auto const &account = state.recent_account(address);
135-
if (MONAD_UNLIKELY(!account.has_value())) {
136-
state.create_contract(address);
137-
}
138-
139-
if (state_delta.balance.has_value()) {
140-
auto const balance = intx::be::unsafe::load<uint256_t>(
141-
state_delta.balance.value().data());
142-
if (balance >
143-
intx::be::load<uint256_t>(
144-
state.get_current_balance_pessimistic(address))) {
145-
state.add_to_balance(
146-
address,
147-
balance - intx::be::load<uint256_t>(
148-
state.get_current_balance_pessimistic(
149-
address)));
125+
{
126+
State state{block_state, incarnation};
127+
128+
for (auto const &[addr, state_delta] :
129+
state_overrides.override_sets) {
130+
// address
131+
Address address{};
132+
std::memcpy(address.bytes, addr.data(), sizeof(Address));
133+
134+
// This would avoid seg-fault on storage override for
135+
// non-existing accounts
136+
auto const &account = state.recent_account(address);
137+
if (MONAD_UNLIKELY(!account.has_value())) {
138+
state.create_contract(address);
150139
}
151-
else {
152-
state.subtract_from_balance(
153-
address,
140+
141+
if (state_delta.balance.has_value()) {
142+
auto const balance = intx::be::unsafe::load<uint256_t>(
143+
state_delta.balance.value().data());
144+
if (balance >
154145
intx::be::load<uint256_t>(
155-
state.get_current_balance_pessimistic(address)) -
156-
balance);
146+
state.get_current_balance_pessimistic(address))) {
147+
state.add_to_balance(
148+
address,
149+
balance - intx::be::load<uint256_t>(
150+
state.get_current_balance_pessimistic(
151+
address)));
152+
}
153+
else {
154+
state.subtract_from_balance(
155+
address,
156+
intx::be::load<uint256_t>(
157+
state.get_current_balance_pessimistic(
158+
address)) -
159+
balance);
160+
}
157161
}
158-
}
159-
160-
if (state_delta.nonce.has_value()) {
161-
state.set_nonce(address, state_delta.nonce.value());
162-
}
163162

164-
if (state_delta.code.has_value()) {
165-
byte_string const code{
166-
state_delta.code.value().data(),
167-
state_delta.code.value().size()};
168-
state.set_code(address, code);
169-
}
163+
if (state_delta.nonce.has_value()) {
164+
state.set_nonce(address, state_delta.nonce.value());
165+
}
170166

171-
auto const update_state =
172-
[&](std::map<byte_string, byte_string> const &diff) {
173-
for (auto const &[key, value] : diff) {
174-
bytes32_t storage_key;
175-
bytes32_t storage_value;
176-
std::memcpy(
177-
storage_key.bytes, key.data(), sizeof(bytes32_t));
178-
std::memcpy(
179-
storage_value.bytes,
180-
value.data(),
181-
sizeof(bytes32_t));
182-
183-
state.set_storage(address, storage_key, storage_value);
184-
}
185-
};
167+
if (state_delta.code.has_value()) {
168+
byte_string const code{
169+
state_delta.code.value().data(),
170+
state_delta.code.value().size()};
171+
state.set_code(address, code);
172+
}
186173

187-
// Remove single storage
188-
if (!state_delta.state_diff.empty()) {
189-
// we need to access the account first before accessing its
190-
// storage
191-
(void)state.get_nonce(address);
192-
update_state(state_delta.state_diff);
193-
}
174+
auto const update_state =
175+
[&](std::map<byte_string, byte_string> const &diff) {
176+
for (auto const &[key, value] : diff) {
177+
bytes32_t storage_key;
178+
bytes32_t storage_value;
179+
std::memcpy(
180+
storage_key.bytes,
181+
key.data(),
182+
sizeof(bytes32_t));
183+
std::memcpy(
184+
storage_value.bytes,
185+
value.data(),
186+
sizeof(bytes32_t));
187+
188+
state.set_storage(
189+
address, storage_key, storage_value);
190+
}
191+
};
192+
193+
// Remove single storage
194+
if (!state_delta.state_diff.empty()) {
195+
// we need to access the account first before accessing its
196+
// storage
197+
(void)state.get_nonce(address);
198+
update_state(state_delta.state_diff);
199+
}
194200

195-
// Remove all override
196-
if (!state_delta.state.empty()) {
197-
state.set_to_state_incarnation(address);
198-
update_state(state_delta.state);
201+
// Remove all override
202+
if (!state_delta.state.empty()) {
203+
state.set_to_state_incarnation(address);
204+
update_state(state_delta.state);
205+
}
199206
}
207+
MONAD_ASSERT(block_state.can_merge(state));
208+
block_state.merge(state);
200209
}
210+
State state{block_state, incarnation};
201211

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

category/rpc/eth_call_test.cpp

Lines changed: 144 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1653,3 +1653,147 @@ TEST_F(EthCallFixture, contract_deployment_success_with_state_trace)
16531653
monad_state_override_destroy(state_override);
16541654
monad_eth_call_executor_destroy(executor);
16551655
}
1656+
1657+
TEST_F(EthCallFixture, prestate_state_overrides)
1658+
{
1659+
for (uint64_t i = 0; i < 256; ++i) {
1660+
commit_sequential(tdb, {}, {}, BlockHeader{.number = i});
1661+
}
1662+
1663+
static constexpr auto from = Address{};
1664+
1665+
std::string tx_data =
1666+
"0x604580600e600039806000f350fe7fffffffffffffffffffffffffffffffffffffff"
1667+
"ffffffffffffffffffffffffe03601600081602082378035828234f580151560395781"
1668+
"82fd5b8082525050506014600cf3";
1669+
1670+
Transaction tx{
1671+
.gas_limit = 200000u, .data = evmc::from_hex(tx_data).value()};
1672+
BlockHeader header{.number = 256};
1673+
1674+
commit_sequential(tdb, {}, {}, header);
1675+
1676+
auto const rlp_tx = to_vec(rlp::encode_transaction(tx));
1677+
auto const rlp_header = to_vec(rlp::encode_block_header(header));
1678+
auto const rlp_sender =
1679+
to_vec(rlp::encode_address(std::make_optional(from)));
1680+
auto const rlp_block_id = to_vec(rlp_finalized_id);
1681+
1682+
auto executor = create_executor(dbname.string());
1683+
auto state_override = monad_state_override_create();
1684+
add_override_address(state_override, from.bytes, sizeof(Address));
1685+
set_override_balance(
1686+
state_override,
1687+
from.bytes,
1688+
sizeof(Address),
1689+
(0xFFFF_bytes32).bytes,
1690+
sizeof(bytes32_t));
1691+
set_override_nonce(state_override, from.bytes, sizeof(Address), 1024);
1692+
uint8_t code[] = {0x00, 0x01, 0x02, 0x03, 0x04};
1693+
set_override_code(
1694+
state_override, from.bytes, sizeof(Address), code, sizeof(code));
1695+
1696+
struct callback_context prestate_ctx;
1697+
struct callback_context statediff_ctx;
1698+
1699+
// PreState trace
1700+
{
1701+
boost::fibers::future<void> f = prestate_ctx.promise.get_future();
1702+
monad_eth_call_executor_submit(
1703+
executor,
1704+
CHAIN_CONFIG_MONAD_DEVNET,
1705+
rlp_tx.data(),
1706+
rlp_tx.size(),
1707+
rlp_header.data(),
1708+
rlp_header.size(),
1709+
rlp_sender.data(),
1710+
rlp_sender.size(),
1711+
header.number,
1712+
rlp_block_id.data(),
1713+
rlp_block_id.size(),
1714+
state_override,
1715+
complete_callback,
1716+
(void *)&prestate_ctx,
1717+
PRESTATE_TRACER,
1718+
true);
1719+
f.get();
1720+
1721+
ASSERT_TRUE(prestate_ctx.result->status_code == EVMC_SUCCESS);
1722+
1723+
std::vector<uint8_t> const encoded_pre_state_trace(
1724+
prestate_ctx.result->encoded_trace,
1725+
prestate_ctx.result->encoded_trace +
1726+
prestate_ctx.result->encoded_trace_len);
1727+
1728+
auto const expected = R"({
1729+
"0x0000000000000000000000000000000000000000": {
1730+
"balance": "0xffff",
1731+
"code": "0x0001020304",
1732+
"nonce": 1024
1733+
},
1734+
"0x8f40531f4fd16955712e2a83bdc817515853b9ea": {
1735+
"balance": "0x0"
1736+
}
1737+
})";
1738+
EXPECT_EQ(
1739+
nlohmann::json::parse(expected),
1740+
nlohmann::json::from_cbor(encoded_pre_state_trace));
1741+
}
1742+
1743+
// StateDelta Trace
1744+
{
1745+
boost::fibers::future<void> f = statediff_ctx.promise.get_future();
1746+
monad_eth_call_executor_submit(
1747+
executor,
1748+
CHAIN_CONFIG_MONAD_DEVNET,
1749+
rlp_tx.data(),
1750+
rlp_tx.size(),
1751+
rlp_header.data(),
1752+
rlp_header.size(),
1753+
rlp_sender.data(),
1754+
rlp_sender.size(),
1755+
header.number,
1756+
rlp_block_id.data(),
1757+
rlp_block_id.size(),
1758+
state_override,
1759+
complete_callback,
1760+
(void *)&statediff_ctx,
1761+
STATEDIFF_TRACER,
1762+
true);
1763+
f.get();
1764+
1765+
ASSERT_TRUE(statediff_ctx.result->status_code == EVMC_SUCCESS);
1766+
1767+
std::vector<uint8_t> const encoded_state_deltas_trace(
1768+
statediff_ctx.result->encoded_trace,
1769+
statediff_ctx.result->encoded_trace +
1770+
statediff_ctx.result->encoded_trace_len);
1771+
1772+
auto const expected = R"({
1773+
"post":{
1774+
"0x0000000000000000000000000000000000000000":{
1775+
"nonce": 1025
1776+
},
1777+
"0x8f40531f4fd16955712e2a83bdc817515853b9ea":{
1778+
"balance": "0x0",
1779+
"code": "0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe03601600081602082378035828234f58015156039578182fd5b8082525050506014600cf3",
1780+
"nonce": 1
1781+
}
1782+
},
1783+
"pre":{
1784+
"0x0000000000000000000000000000000000000000":{
1785+
"balance": "0xffff",
1786+
"code": "0x0001020304",
1787+
"nonce": 1024
1788+
}
1789+
}
1790+
})";
1791+
1792+
EXPECT_EQ(
1793+
nlohmann::json::parse(expected),
1794+
nlohmann::json::from_cbor(encoded_state_deltas_trace));
1795+
}
1796+
1797+
monad_state_override_destroy(state_override);
1798+
monad_eth_call_executor_destroy(executor);
1799+
}

0 commit comments

Comments
 (0)