@@ -1393,41 +1393,59 @@ def test_callcode_value_no_new_account_state_gas(
13931393 sender = pre .fund_eoa (),
13941394 )
13951395
1396- post = {contract : Account (storage = storage )}
1396+ post = {
1397+ contract : Account (storage = storage ),
1398+ target : Account .NONEXISTENT ,
1399+ }
13971400 state_test (pre = pre , post = post , tx = tx )
13981401
13991402
1403+ @pytest .mark .with_all_create_opcodes ()
14001404@pytest .mark .valid_from ("EIP8037" )
14011405def test_create_oog_during_state_gas_charge (
14021406 state_test : StateTestFiller ,
14031407 pre : Alloc ,
14041408 fork : Fork ,
1409+ create_opcode : Op ,
14051410) -> None :
14061411 """
14071412 Verify the parent reservoir is refunded when a child's CREATE
1408- OOGs while charging account-creation state gas.
1413+ OOGs while charging account-creation state gas. The grandchild
1414+ SSTORE is forwarded only its regular stipend, so it succeeds
1415+ only if the refund landed in the reservoir (not in `gas_left`).
14091416 """
14101417 gas_limit_cap = fork .transaction_gas_limit_cap ()
14111418 assert gas_limit_cap is not None
1419+ gas_costs = fork .gas_costs ()
14121420 sstore_state_gas = fork .sstore_state_gas ()
14131421
14141422 init_code = Op .STOP
1423+ inner_create_call = (
1424+ create_opcode (value = 0 , offset = 31 , size = 1 , salt = 0 )
1425+ if create_opcode == Op .CREATE2
1426+ else create_opcode (value = 0 , offset = 31 , size = 1 )
1427+ )
14151428
14161429 inner = pre .deploy_contract (
14171430 code = (
14181431 Op .MSTORE (
14191432 0 ,
14201433 int .from_bytes (bytes (init_code ), "big" ) << 248 ,
14211434 )
1422- + Op .POP (Op . CREATE ( 0 , 31 , 1 ) )
1435+ + Op .POP (inner_create_call )
14231436 ),
14241437 )
14251438
1426- storage = Storage ()
1439+ grandchild = pre .deploy_contract (code = Op .SSTORE (0 , 1 ))
1440+
1441+ push_cost = 2 * gas_costs .GAS_VERY_LOW
1442+ sstore_regular = gas_costs .GAS_COLD_STORAGE_WRITE
1443+ grandchild_stipend = push_cost + sstore_regular
1444+
14271445 parent = pre .deploy_contract (
14281446 code = (
14291447 Op .POP (Op .CALL (gas = 20_000 , address = inner ))
1430- + Op .SSTORE ( storage . store_next ( 1 ), 1 )
1448+ + Op .POP ( Op . CALL ( gas = grandchild_stipend , address = grandchild ) )
14311449 ),
14321450 )
14331451
@@ -1437,8 +1455,11 @@ def test_create_oog_during_state_gas_charge(
14371455 sender = pre .fund_eoa (),
14381456 )
14391457
1440- post = {parent : Account (storage = storage )}
1441- state_test (pre = pre , post = post , tx = tx )
1458+ state_test (
1459+ pre = pre ,
1460+ post = {grandchild : Account (storage = {0 : 1 })},
1461+ tx = tx ,
1462+ )
14421463
14431464
14441465@pytest .mark .valid_from ("EIP8037" )
@@ -1477,16 +1498,26 @@ def test_call_new_account_no_regular_account_creation_cost(
14771498 state_test (pre = pre , post = {target : Account (balance = 1 )}, tx = tx )
14781499
14791500
1501+ @pytest .mark .parametrize (
1502+ "call_opcode" ,
1503+ [
1504+ pytest .param (Op .CALL , id = "call" ),
1505+ pytest .param (Op .DELEGATECALL , id = "delegatecall" ),
1506+ ],
1507+ )
14801508@pytest .mark .valid_from ("EIP8037" )
14811509def test_child_failure_refunds_state_gas_to_reservoir_not_gas_left (
14821510 state_test : StateTestFiller ,
14831511 pre : Alloc ,
14841512 fork : Fork ,
1513+ call_opcode : Op ,
14851514) -> None :
14861515 """
14871516 Verify state gas from a failing child is restored to the
14881517 reservoir (not regular gas), so a grandchild SSTORE can draw
1489- from it under a tight regular stipend.
1518+ from it under a tight regular stipend. Parametrized across CALL
1519+ (grandchild writes to its own storage) and DELEGATECALL
1520+ (grandchild writes to the parent's storage via shared context).
14901521 """
14911522 gas_limit_cap = fork .transaction_gas_limit_cap ()
14921523 assert gas_limit_cap is not None
@@ -1506,8 +1537,8 @@ def test_child_failure_refunds_state_gas_to_reservoir_not_gas_left(
15061537
15071538 parent = pre .deploy_contract (
15081539 code = (
1509- Op .POP (Op . CALL (gas = Op .GAS , address = child ))
1510- + Op .POP (Op . CALL (gas = grandchild_stipend , address = grandchild ))
1540+ Op .POP (call_opcode (gas = Op .GAS , address = child ))
1541+ + Op .POP (call_opcode (gas = grandchild_stipend , address = grandchild ))
15111542 ),
15121543 )
15131544
@@ -1517,8 +1548,12 @@ def test_child_failure_refunds_state_gas_to_reservoir_not_gas_left(
15171548 sender = pre .fund_eoa (),
15181549 )
15191550
1520- state_test (
1521- pre = pre ,
1522- post = {grandchild : Account (storage = {0 : 1 })},
1523- tx = tx ,
1524- )
1551+ # DELEGATECALL executes the callee in the caller's storage
1552+ # context, so grandchild's SSTORE lands on `parent` instead of
1553+ # `grandchild`.
1554+ if call_opcode == Op .DELEGATECALL :
1555+ post : dict = {parent : Account (storage = {0 : 1 })}
1556+ else :
1557+ post = {grandchild : Account (storage = {0 : 1 })}
1558+
1559+ state_test (pre = pre , post = post , tx = tx )
0 commit comments