#1709 fixed one instance of this: an account warmed up by a cold access and then reverted was reported in StateDiff::deleted_accounts. The artifact still appears when the account is inserted some other way and ends up empty.
The shortest case is a transaction to an address that does not exist — state_transition.tx_legacy, where 0xc0de is not in the pre-state:
tx.to = To; // no code, no value
execute_message() inserts the recipient with erase_if_empty, it ends empty, and build_diff() puts it in deleted_accounts. Same for a non-existent SELFDESTRUCT beneficiary (state_transition.touch_nonexistent_sd, 0x4e).
build_diff() skips m.nonexistent (set only when a revert restores the account) and m.just_created (set only by CREATE). There is no flag for "inserted because it was touched", so these fall through to the erase_if_empty branch.
As with #1709 the state is correct — applying such a delete is a no-op — so only the diff is affected.
Scale: adding this to the state_transition fixture fails 28 of 132 tests on master:
for (const auto& a : receipt.state_diff.deleted_accounts)
EXPECT_TRUE(pre.contains(a)) << a << ": deleted, never existed";
Related, and already noted in the TODO below: modified_accounts also lists accounts that were only read or warmed, with nonce and balance unchanged — e.g. state_transition.touch_access_list_storage_only, where 0x5a is warmed by the access list alone.
#1717 adds an in_diff expectation to the state_transition fixture, which can be used to pin down whatever behaviour is decided here.
#1709 fixed one instance of this: an account warmed up by a cold access and then reverted was reported in
StateDiff::deleted_accounts. The artifact still appears when the account is inserted some other way and ends up empty.The shortest case is a transaction to an address that does not exist —
state_transition.tx_legacy, where0xc0deis not in the pre-state:execute_message()inserts the recipient witherase_if_empty, it ends empty, andbuild_diff()puts it indeleted_accounts. Same for a non-existent SELFDESTRUCT beneficiary (state_transition.touch_nonexistent_sd,0x4e).build_diff()skipsm.nonexistent(set only when a revert restores the account) andm.just_created(set only by CREATE). There is no flag for "inserted because it was touched", so these fall through to theerase_if_emptybranch.As with #1709 the state is correct — applying such a delete is a no-op — so only the diff is affected.
Scale: adding this to the
state_transitionfixture fails 28 of 132 tests on master:Related, and already noted in the TODO below:
modified_accountsalso lists accounts that were only read or warmed, with nonce and balance unchanged — e.g.state_transition.touch_access_list_storage_only, where0x5ais warmed by the access list alone.#1717 adds an
in_diffexpectation to thestate_transitionfixture, which can be used to pin down whatever behaviour is decided here.