6969 commit_transaction_frame ,
7070 create_child_frame ,
7171 get_block_access_index ,
72- handle_in_transaction_selfdestruct ,
7372 increment_block_access_index ,
7473 merge_on_success ,
7574 normalize_balance_changes_for_transaction ,
7675 track_address ,
7776 track_balance_change ,
77+ track_nonce_change ,
78+ track_selfdestruct ,
7879)
7980from .transactions import (
8081 AccessListTransaction ,
@@ -647,8 +648,12 @@ def process_system_transaction(
647648 authorizations = (),
648649 index_in_block = None ,
649650 tx_hash = None ,
651+ state_changes = system_tx_state_changes ,
650652 )
651653
654+ # Create call frame as child of tx frame
655+ call_frame = create_child_frame (tx_env .state_changes )
656+
652657 system_tx_message = Message (
653658 block_env = block_env ,
654659 tx_env = tx_env ,
@@ -667,14 +672,14 @@ def process_system_transaction(
667672 accessed_storage_keys = set (),
668673 disable_precompiles = False ,
669674 parent_evm = None ,
670- transaction_state_changes = system_tx_state_changes ,
675+ state_changes = call_frame ,
671676 )
672677
673678 system_tx_output = process_message_call (system_tx_message )
674679
675- # Merge system transaction changes back to block frame
680+ # Commit system transaction changes to block frame
676681 # System transactions always succeed (or block is invalid)
677- merge_on_success ( system_tx_state_changes )
682+ commit_transaction_frame ( tx_env . state_changes )
678683
679684 return system_tx_output
680685
@@ -909,7 +914,9 @@ def process_transaction(
909914 # The frame will read the current block_access_index from the block frame
910915 increment_block_access_index (block_env .block_state_changes )
911916 tx_state_changes = create_child_frame (block_env .block_state_changes )
917+ block_access_index = get_block_access_index (block_env .block_state_changes )
912918
919+ # Capture coinbase pre-balance for net-zero filtering
913920 coinbase_pre_balance = get_account (
914921 block_env .state , block_env .coinbase
915922 ).balance
@@ -947,16 +954,30 @@ def process_transaction(
947954 effective_gas_fee = tx .gas * effective_gas_price
948955
949956 gas = tx .gas - intrinsic_gas
950- increment_nonce (block_env .state , sender , tx_state_changes )
957+
958+ # Track sender nonce increment
959+ increment_nonce (block_env .state , sender )
960+ sender_nonce_after = get_account (block_env .state , sender ).nonce
961+ track_nonce_change (
962+ tx_state_changes , sender , U64 (sender_nonce_after ), block_access_index
963+ )
964+
965+ # Track sender balance deduction for gas fee
966+ sender_balance_before = get_account (block_env .state , sender ).balance
967+ track_address (tx_state_changes , sender )
968+ capture_pre_balance (tx_state_changes , sender , sender_balance_before )
951969
952970 sender_balance_after_gas_fee = (
953971 Uint (sender_account .balance ) - effective_gas_fee - blob_gas_fee
954972 )
955973 set_account_balance (
956- block_env .state ,
974+ block_env .state , sender , U256 (sender_balance_after_gas_fee )
975+ )
976+ track_balance_change (
977+ tx_state_changes ,
957978 sender ,
958979 U256 (sender_balance_after_gas_fee ),
959- tx_state_changes ,
980+ block_access_index ,
960981 )
961982
962983 access_list_addresses = set ()
@@ -991,13 +1012,13 @@ def process_transaction(
9911012 authorizations = authorizations ,
9921013 index_in_block = index ,
9931014 tx_hash = get_transaction_hash (encode_transaction (tx )),
1015+ state_changes = tx_state_changes ,
9941016 )
9951017
9961018 message = prepare_message (
9971019 block_env ,
9981020 tx_env ,
9991021 tx ,
1000- tx_state_changes ,
10011022 )
10021023
10031024 tx_output = process_message_call (message )
@@ -1027,22 +1048,26 @@ def process_transaction(
10271048 sender_balance_after_refund = get_account (
10281049 block_env .state , sender
10291050 ).balance + U256 (gas_refund_amount )
1030- set_account_balance (
1031- block_env .state ,
1051+ set_account_balance (block_env .state , sender , sender_balance_after_refund )
1052+ track_balance_change (
1053+ tx_env .state_changes ,
10321054 sender ,
10331055 sender_balance_after_refund ,
1034- tx_state_changes ,
1056+ block_access_index ,
10351057 )
10361058
10371059 coinbase_balance_after_mining_fee = get_account (
10381060 block_env .state , block_env .coinbase
10391061 ).balance + U256 (transaction_fee )
10401062
10411063 set_account_balance (
1042- block_env .state ,
1064+ block_env .state , block_env .coinbase , coinbase_balance_after_mining_fee
1065+ )
1066+ track_balance_change (
1067+ tx_env .state_changes ,
10431068 block_env .coinbase ,
10441069 coinbase_balance_after_mining_fee ,
1045- tx_state_changes ,
1070+ block_access_index ,
10461071 )
10471072
10481073 if coinbase_balance_after_mining_fee == 0 and account_exists_and_is_empty (
@@ -1078,19 +1103,17 @@ def process_transaction(
10781103 # into block frame. Must happen AFTER destroy_account so net-zero filtering
10791104 # sees the correct post-transaction balance (0 for destroyed accounts).
10801105 normalize_balance_changes_for_transaction (
1081- tx_state_changes ,
1082- BlockAccessIndex (
1083- get_block_access_index (block_env .block_state_changes )
1084- ),
1106+ tx_env .state_changes ,
1107+ block_access_index ,
10851108 block_env .state ,
10861109 )
10871110
1088- commit_transaction_frame (tx_state_changes )
1111+ commit_transaction_frame (tx_env . state_changes )
10891112
1090- # EIP-7928: Handle in-transaction self-destruct normalization AFTER merge
1113+ # EIP-7928: Track in-transaction self-destruct normalization AFTER merge
10911114 # Convert storage writes to reads and remove nonce/code changes
10921115 for address in tx_output .accounts_to_delete :
1093- handle_in_transaction_selfdestruct (
1116+ track_selfdestruct (
10941117 block_env .block_state_changes ,
10951118 address ,
10961119 BlockAccessIndex (
@@ -1107,6 +1130,10 @@ def process_withdrawals(
11071130 """
11081131 Increase the balance of the withdrawing account.
11091132 """
1133+ # Get block access index for withdrawals (post-exec phase)
1134+ block_access_index = get_block_access_index (block_env .block_state_changes )
1135+
1136+ # Capture pre-state for withdrawal balance filtering
11101137 withdrawal_addresses = {wd .address for wd in withdrawals }
11111138 for address in withdrawal_addresses :
11121139 pre_balance = get_account (block_env .state , address ).balance
@@ -1129,20 +1156,20 @@ def increase_recipient_balance(recipient: Account) -> None:
11291156
11301157 new_balance = get_account (block_env .state , wd .address ).balance
11311158 track_balance_change (
1132- block_env .block_state_changes , wd .address , new_balance
1159+ block_env .block_state_changes ,
1160+ wd .address ,
1161+ new_balance ,
1162+ block_access_index ,
11331163 )
11341164
11351165 if account_exists_and_is_empty (block_env .state , wd .address ):
11361166 destroy_account (block_env .state , wd .address )
11371167
11381168 # EIP-7928: Normalize balance changes after all withdrawals
11391169 # Filters out net-zero changes
1140-
11411170 normalize_balance_changes_for_transaction (
11421171 block_env .block_state_changes ,
1143- BlockAccessIndex (
1144- get_block_access_index (block_env .block_state_changes )
1145- ),
1172+ block_access_index ,
11461173 block_env .state ,
11471174 )
11481175
0 commit comments