2020 Bytecode ,
2121 Environment ,
2222 Fork ,
23+ Header ,
2324 Op ,
2425 StateTestFiller ,
2526 Storage ,
@@ -295,11 +296,14 @@ def test_auth_refund_block_gas_accounting(
295296 fork : Fork ,
296297) -> None :
297298 """
298- Test block gas accounting with authorization existing-account refund.
299-
300- The auth refund goes to state_gas_reservoir, not to refund_counter.
301- Block regular gas is unaffected by the auth refund — it reduces
302- intrinsic_state_gas, which only affects block_state_gas_used.
299+ Verify block gas accounting with an authorization refund for an
300+ existing account.
301+
302+ The refund for an existing authority goes to the state gas
303+ reservoir and does not alter the intrinsic state gas carried into
304+ block accounting. Block state gas used reflects the worst case
305+ intrinsic state gas component regardless of how many authorities
306+ were existing accounts.
303307 """
304308 gas_limit_cap = fork .transaction_gas_limit_cap ()
305309 assert gas_limit_cap is not None
@@ -326,9 +330,15 @@ def test_auth_refund_block_gas_accounting(
326330 sender = sender ,
327331 )
328332
333+ # State gas component dominates the tx regular component, so the
334+ # block header gas_used equals the worst case intrinsic state gas.
335+ # A mutating refund would reduce this value; the immutable behavior
336+ # keeps it at the worst case.
329337 blockchain_test (
330338 pre = pre ,
331- blocks = [Block (txs = [tx ])],
339+ blocks = [
340+ Block (txs = [tx ], header_verify = Header (gas_used = auth_state_gas ))
341+ ],
332342 post = {},
333343 )
334344
@@ -1022,3 +1032,187 @@ def test_auth_refund_bypasses_one_fifth_cap(
10221032
10231033 post = {contract : Account (storage = storage )}
10241034 state_test (env = env , pre = pre , post = post , tx = tx )
1035+
1036+
1037+ @pytest .mark .parametrize (
1038+ "num_auths" ,
1039+ [
1040+ pytest .param (1 , id = "one_auth" ),
1041+ pytest .param (3 , id = "three_auths" ),
1042+ ],
1043+ )
1044+ @pytest .mark .valid_from ("EIP8037" )
1045+ def test_existing_account_auth_header_gas_used_uses_worst_case (
1046+ blockchain_test : BlockchainTestFiller ,
1047+ pre : Alloc ,
1048+ fork : Fork ,
1049+ num_auths : int ,
1050+ ) -> None :
1051+ """
1052+ Verify the block header gas_used reflects the worst case intrinsic
1053+ state gas when all authorities are existing accounts.
1054+
1055+ Intrinsic state gas is set at transaction validation and does not
1056+ change during execution. When an authorization targets an existing
1057+ account, the account creation component of state gas is refunded
1058+ to the reservoir only and is not subtracted from the intrinsic
1059+ state gas that feeds block accounting.
1060+ """
1061+ gas_limit_cap = fork .transaction_gas_limit_cap ()
1062+ assert gas_limit_cap is not None
1063+ worst_case_state_gas = fork .transaction_intrinsic_state_gas (
1064+ authorization_count = num_auths ,
1065+ )
1066+
1067+ contract = pre .deploy_contract (code = Op .STOP )
1068+
1069+ # All authorities exist in pre state.
1070+ authorization_list = [
1071+ AuthorizationTuple (address = contract , nonce = 0 , signer = pre .fund_eoa ())
1072+ for _ in range (num_auths )
1073+ ]
1074+
1075+ tx = Transaction (
1076+ to = contract ,
1077+ gas_limit = gas_limit_cap + worst_case_state_gas ,
1078+ authorization_list = authorization_list ,
1079+ sender = pre .fund_eoa (),
1080+ )
1081+
1082+ blockchain_test (
1083+ pre = pre ,
1084+ blocks = [
1085+ Block (
1086+ txs = [tx ],
1087+ header_verify = Header (gas_used = worst_case_state_gas ),
1088+ ),
1089+ ],
1090+ post = {},
1091+ )
1092+
1093+
1094+ @pytest .mark .parametrize (
1095+ "num_existing,num_new" ,
1096+ [
1097+ pytest .param (1 , 1 , id = "one_existing_one_new" ),
1098+ pytest .param (2 , 2 , id = "two_existing_two_new" ),
1099+ ],
1100+ )
1101+ @pytest .mark .valid_from ("EIP8037" )
1102+ def test_mixed_auths_header_gas_used_uses_worst_case (
1103+ blockchain_test : BlockchainTestFiller ,
1104+ pre : Alloc ,
1105+ fork : Fork ,
1106+ num_existing : int ,
1107+ num_new : int ,
1108+ ) -> None :
1109+ """
1110+ Verify the block header gas_used reflects the worst case intrinsic
1111+ state gas across a mix of existing and new account authorizations.
1112+
1113+ Refunds for the existing accounts go to the state gas reservoir,
1114+ and the intrinsic state gas carried into block accounting covers
1115+ the full authorization count as if every authority were a new
1116+ account.
1117+ """
1118+ gas_limit_cap = fork .transaction_gas_limit_cap ()
1119+ assert gas_limit_cap is not None
1120+ num_auths = num_existing + num_new
1121+ worst_case_state_gas = fork .transaction_intrinsic_state_gas (
1122+ authorization_count = num_auths ,
1123+ )
1124+
1125+ contract = pre .deploy_contract (code = Op .STOP )
1126+
1127+ authorization_list = []
1128+ for _ in range (num_existing ):
1129+ authorization_list .append (
1130+ AuthorizationTuple (
1131+ address = contract ,
1132+ nonce = 0 ,
1133+ signer = pre .fund_eoa (),
1134+ )
1135+ )
1136+ for _ in range (num_new ):
1137+ authorization_list .append (
1138+ AuthorizationTuple (
1139+ address = contract ,
1140+ nonce = 0 ,
1141+ signer = pre .fund_eoa (amount = 0 ),
1142+ )
1143+ )
1144+
1145+ tx = Transaction (
1146+ to = contract ,
1147+ gas_limit = gas_limit_cap + worst_case_state_gas ,
1148+ authorization_list = authorization_list ,
1149+ sender = pre .fund_eoa (),
1150+ )
1151+
1152+ blockchain_test (
1153+ pre = pre ,
1154+ blocks = [
1155+ Block (
1156+ txs = [tx ],
1157+ header_verify = Header (gas_used = worst_case_state_gas ),
1158+ ),
1159+ ],
1160+ post = {},
1161+ )
1162+
1163+
1164+ @pytest .mark .valid_from ("EIP8037" )
1165+ def test_existing_auth_with_reverted_execution_preserves_intrinsic (
1166+ blockchain_test : BlockchainTestFiller ,
1167+ pre : Alloc ,
1168+ fork : Fork ,
1169+ ) -> None :
1170+ """
1171+ Verify the worst case intrinsic state gas survives both the
1172+ existing account authorization refund and the top level failure
1173+ refund.
1174+
1175+ Scenario: a tx with a single authorization to an existing
1176+ account executes an SSTORE then REVERTs. `set_delegation` adds
1177+ the account creation portion to `state_gas_reservoir` without
1178+ mutating the intrinsic state gas. The top level revert refund
1179+ zeroes execution state gas. Block accounting reflects the worst
1180+ case intrinsic state gas unchanged. Under a mutating
1181+ implementation the intrinsic would be reduced and the block
1182+ header would fall back to the regular gas component.
1183+ """
1184+ gas_limit_cap = fork .transaction_gas_limit_cap ()
1185+ assert gas_limit_cap is not None
1186+ worst_case_state_gas = fork .transaction_intrinsic_state_gas (
1187+ authorization_count = 1 ,
1188+ )
1189+
1190+ contract = pre .deploy_contract (
1191+ code = Op .SSTORE (0 , 1 ) + Op .REVERT (0 , 0 ),
1192+ )
1193+
1194+ # Existing signer: the set_delegation refund is routed to the
1195+ # reservoir. Under the correct spec the intrinsic state gas is
1196+ # not mutated.
1197+ signer = pre .fund_eoa ()
1198+ authorization_list = [
1199+ AuthorizationTuple (address = contract , nonce = 0 , signer = signer ),
1200+ ]
1201+
1202+ tx = Transaction (
1203+ to = contract ,
1204+ gas_limit = gas_limit_cap + worst_case_state_gas ,
1205+ authorization_list = authorization_list ,
1206+ sender = pre .fund_eoa (),
1207+ )
1208+
1209+ blockchain_test (
1210+ pre = pre ,
1211+ blocks = [
1212+ Block (
1213+ txs = [tx ],
1214+ header_verify = Header (gas_used = worst_case_state_gas ),
1215+ ),
1216+ ],
1217+ post = {contract : Account (storage = {})},
1218+ )
0 commit comments