diff --git a/src/ethereum/forks/amsterdam/block_access_lists/tracker.py b/src/ethereum/forks/amsterdam/block_access_lists/tracker.py index 66a4f1ebbd..0ea945e7b1 100644 --- a/src/ethereum/forks/amsterdam/block_access_lists/tracker.py +++ b/src/ethereum/forks/amsterdam/block_access_lists/tracker.py @@ -97,7 +97,7 @@ class StateChangeTracker: """ Cache of pre-transaction balance values, keyed by address. This cache is cleared at the start of each transaction and used by - finalize_transaction_changes to filter out balance changes where + normalize_balance_changes to filter out balance changes where the final balance equals the initial balance. """ @@ -293,7 +293,7 @@ def capture_pre_balance( to ensure we capture the pre-transaction balance correctly. The cache is cleared at the beginning of each transaction. - This is used by finalize_transaction_changes to determine which balance + This is used by normalize_balance_changes to determine which balance changes should be filtered out. Parameters @@ -331,9 +331,7 @@ def track_balance_change( Track a balance change for an account. Records the new balance after any balance-affecting operation, including - transfers, gas payments, block rewards, and withdrawals. The balance is - encoded as a 16-byte value (uint128) which is sufficient for the total - ETH supply. + transfers, gas payments, block rewards, and withdrawals. Parameters ---------- @@ -454,7 +452,7 @@ def handle_in_transaction_selfdestruct( code changes from the current transaction are also removed. Note: Balance changes are handled separately by - finalize_transaction_changes. + normalize_balance_changes. Parameters ---------- @@ -495,22 +493,25 @@ def handle_in_transaction_selfdestruct( ] -def finalize_transaction_changes( +def normalize_balance_changes( tracker: StateChangeTracker, state: "State" ) -> None: """ - Finalize changes for the current transaction. + Normalize balance changes for the current block access index. - This method is called at the end of each transaction execution to filter - out spurious balance changes. It removes all balance changes for addresses - where the post-transaction balance equals the pre-transaction balance. + This method filters out spurious balance changes by removing all balance + changes for addresses where the post-execution balance equals the + pre-execution balance. This is crucial for handling cases like: - In-transaction self-destructs where an account with 0 balance is created and destroyed, resulting in no net balance change - Round-trip transfers where an account receives and sends equal amounts + - Zero-amount withdrawals where the balance doesn't actually change - Only actual state changes are recorded in the Block Access List. + This should be called at the end of any operation that tracks balance + changes (transactions, withdrawals, etc.). Only actual state changes are + recorded in the Block Access List. Parameters ---------- diff --git a/src/ethereum/forks/amsterdam/fork.py b/src/ethereum/forks/amsterdam/fork.py index b70d5090d3..29680df285 100644 --- a/src/ethereum/forks/amsterdam/fork.py +++ b/src/ethereum/forks/amsterdam/fork.py @@ -32,8 +32,9 @@ from .block_access_lists.builder import build_block_access_list from .block_access_lists.rlp_utils import compute_block_access_list_hash from .block_access_lists.tracker import ( - finalize_transaction_changes, + capture_pre_balance, handle_in_transaction_selfdestruct, + normalize_balance_changes, set_block_access_index, track_balance_change, ) @@ -1022,9 +1023,9 @@ def process_transaction( ) destroy_account(block_env.state, address) - # EIP-7928: Finalize transaction changes + # EIP-7928: Normalize balance changes for this transaction # Remove balance changes where post-tx balance equals pre-tx balance - finalize_transaction_changes( + normalize_balance_changes( block_env.state.change_tracker, block_env.state, ) @@ -1067,6 +1068,12 @@ def increase_recipient_balance(recipient: Account) -> None: rlp.encode(wd), ) + # Capture pre-balance before modification (even for zero withdrawals) + # This ensures the address appears in BAL per EIP-7928 + capture_pre_balance( + block_env.state.change_tracker, wd.address, block_env.state + ) + modify_state(block_env.state, wd.address, increase_recipient_balance) # Track balance change for BAL @@ -1076,6 +1083,14 @@ def increase_recipient_balance(recipient: Account) -> None: block_env.state.change_tracker, wd.address, U256(new_balance) ) + # EIP-7928: Normalize balance changes for this withdrawal + # Remove balance changes where post-withdrawal balance + # equals pre-withdrawal balance + normalize_balance_changes( + block_env.state.change_tracker, + block_env.state, + ) + if account_exists_and_is_empty(block_env.state, wd.address): destroy_account(block_env.state, wd.address)