@@ -298,15 +298,10 @@ def generic_call(
298298 """
299299 Perform the core logic of the `CALL*` family of opcodes.
300300 """
301- from ...vm .interpreter import STACK_DEPTH_LIMIT , process_message
301+ from ...vm .interpreter import process_message
302302
303303 evm .return_data = b""
304304
305- if evm .message .depth + Uint (1 ) > STACK_DEPTH_LIMIT :
306- evm .gas_left += gas
307- push (evm .stack , U256 (0 ))
308- return
309-
310305 tx_state = evm .message .tx_env .state
311306 code_hash = get_account (tx_state , code_address ).code_hash
312307 code = get_code (tx_state , code_hash )
@@ -386,37 +381,47 @@ def call(evm: Evm) -> None:
386381 )
387382
388383 is_cold_access = to not in evm .accessed_addresses
389- if is_cold_access :
390- access_gas_cost = GasCosts .COLD_ACCOUNT_ACCESS
391- else :
392- access_gas_cost = GasCosts .WARM_ACCESS
393-
394384 transfer_gas_cost = Uint (0 ) if value == 0 else GasCosts .CALL_VALUE
395385
396- # check static gas before state access
397- check_gas (
398- evm ,
399- access_gas_cost + transfer_gas_cost + extend_memory .cost ,
400- )
386+ # Pre-state extra gas (warm-equivalent access cost only; cold surcharge
387+ # is deferred to post-state).
388+ extra_gas = GasCosts .WARM_ACCESS + transfer_gas_cost
389+ check_gas (evm , extra_gas + extend_memory .cost )
401390
402- # STATE ACCESS
391+ # Pre-state preconditions: stack depth and (if value > 0) sender balance.
392+ from ...vm .interpreter import STACK_DEPTH_LIMIT
403393 tx_state = evm .message .tx_env .state
394+ sender_balance = get_account (
395+ tx_state , evm .message .current_target
396+ ).balance
397+ if (
398+ evm .message .depth + Uint (1 ) > STACK_DEPTH_LIMIT
399+ or (value > 0 and sender_balance < value )
400+ ):
401+ charge_gas (evm , extra_gas + extend_memory .cost )
402+ evm .memory += b"\x00 " * extend_memory .expand_by
403+ push (evm .stack , U256 (0 ))
404+ evm .return_data = b""
405+ evm .pc += Uint (1 )
406+ return
407+
408+ # Post-state: cold surcharge paired with warming and BAL insertion.
404409 if is_cold_access :
410+ extra_gas += GasCosts .COLD_ACCOUNT_ACCESS - GasCosts .WARM_ACCESS
411+ check_gas (evm , extra_gas + extend_memory .cost )
405412 evm .accessed_addresses .add (to )
406413
407- create_gas_cost = GasCosts . NEW_ACCOUNT
408- if value == 0 or is_account_alive ( tx_state , to ):
409- create_gas_cost = Uint ( 0 )
414+ if value > 0 and not is_account_alive ( tx_state , to ):
415+ extra_gas += GasCosts . NEW_ACCOUNT
416+ check_gas ( evm , extra_gas + extend_memory . cost )
410417
411- extra_gas = access_gas_cost + transfer_gas_cost + create_gas_cost
412418 (
413419 is_delegated ,
414420 code_address ,
415421 delegation_access_cost ,
416422 ) = calculate_delegation_cost (evm , to )
417423
418424 if is_delegated :
419- # check enough gas for delegation access
420425 extra_gas += delegation_access_cost
421426 check_gas (evm , extra_gas + extend_memory .cost )
422427 if code_address not in evm .accessed_addresses :
@@ -433,27 +438,21 @@ def call(evm: Evm) -> None:
433438
434439 # OPERATION
435440 evm .memory += b"\x00 " * extend_memory .expand_by
436- sender_balance = get_account (tx_state , evm .message .current_target ).balance
437- if sender_balance < value :
438- push (evm .stack , U256 (0 ))
439- evm .return_data = b""
440- evm .gas_left += message_call_gas .sub_call
441- else :
442- generic_call (
443- evm ,
444- message_call_gas .sub_call ,
445- value ,
446- evm .message .current_target ,
447- to ,
448- code_address ,
449- True ,
450- False ,
451- memory_input_start_position ,
452- memory_input_size ,
453- memory_output_start_position ,
454- memory_output_size ,
455- is_delegated ,
456- )
441+ generic_call (
442+ evm ,
443+ message_call_gas .sub_call ,
444+ value ,
445+ evm .message .current_target ,
446+ to ,
447+ code_address ,
448+ True ,
449+ False ,
450+ memory_input_start_position ,
451+ memory_input_size ,
452+ memory_output_start_position ,
453+ memory_output_size ,
454+ is_delegated ,
455+ )
457456
458457 # PROGRAM COUNTER
459458 evm .pc += Uint (1 )
@@ -490,33 +489,43 @@ def callcode(evm: Evm) -> None:
490489 )
491490
492491 is_cold_access = code_address not in evm .accessed_addresses
493- if is_cold_access :
494- access_gas_cost = GasCosts .COLD_ACCOUNT_ACCESS
495- else :
496- access_gas_cost = GasCosts .WARM_ACCESS
497-
498492 transfer_gas_cost = Uint (0 ) if value == 0 else GasCosts .CALL_VALUE
499493
500- # check static gas before state access
501- check_gas (
502- evm ,
503- access_gas_cost + extend_memory .cost + transfer_gas_cost ,
504- )
494+ # Pre-state extra gas (warm-equivalent access cost only; cold surcharge
495+ # is deferred to post-state).
496+ extra_gas = GasCosts .WARM_ACCESS + transfer_gas_cost
497+ check_gas (evm , extra_gas + extend_memory .cost )
505498
506- # STATE ACCESS
499+ # Pre-state preconditions: stack depth and (if value > 0) sender balance.
500+ from ...vm .interpreter import STACK_DEPTH_LIMIT
507501 tx_state = evm .message .tx_env .state
502+ sender_balance = get_account (
503+ tx_state , evm .message .current_target
504+ ).balance
505+ if (
506+ evm .message .depth + Uint (1 ) > STACK_DEPTH_LIMIT
507+ or (value > 0 and sender_balance < value )
508+ ):
509+ charge_gas (evm , extra_gas + extend_memory .cost )
510+ evm .memory += b"\x00 " * extend_memory .expand_by
511+ push (evm .stack , U256 (0 ))
512+ evm .return_data = b""
513+ evm .pc += Uint (1 )
514+ return
515+
516+ # Post-state: cold surcharge paired with warming and BAL insertion.
508517 if is_cold_access :
518+ extra_gas += GasCosts .COLD_ACCOUNT_ACCESS - GasCosts .WARM_ACCESS
519+ check_gas (evm , extra_gas + extend_memory .cost )
509520 evm .accessed_addresses .add (code_address )
510521
511- extra_gas = access_gas_cost + transfer_gas_cost
512522 (
513523 is_delegated ,
514524 code_address ,
515525 delegation_access_cost ,
516526 ) = calculate_delegation_cost (evm , code_address )
517527
518528 if is_delegated :
519- # check enough gas for delegation access
520529 extra_gas += delegation_access_cost
521530 check_gas (evm , extra_gas + extend_memory .cost )
522531 if code_address not in evm .accessed_addresses :
@@ -533,28 +542,21 @@ def callcode(evm: Evm) -> None:
533542
534543 # OPERATION
535544 evm .memory += b"\x00 " * extend_memory .expand_by
536- sender_balance = get_account (tx_state , evm .message .current_target ).balance
537-
538- if sender_balance < value :
539- push (evm .stack , U256 (0 ))
540- evm .return_data = b""
541- evm .gas_left += message_call_gas .sub_call
542- else :
543- generic_call (
544- evm ,
545- message_call_gas .sub_call ,
546- value ,
547- evm .message .current_target ,
548- to ,
549- code_address ,
550- True ,
551- False ,
552- memory_input_start_position ,
553- memory_input_size ,
554- memory_output_start_position ,
555- memory_output_size ,
556- is_delegated ,
557- )
545+ generic_call (
546+ evm ,
547+ message_call_gas .sub_call ,
548+ value ,
549+ evm .message .current_target ,
550+ to ,
551+ code_address ,
552+ True ,
553+ False ,
554+ memory_input_start_position ,
555+ memory_input_size ,
556+ memory_output_start_position ,
557+ memory_output_size ,
558+ is_delegated ,
559+ )
558560
559561 # PROGRAM COUNTER
560562 evm .pc += Uint (1 )
@@ -652,27 +654,35 @@ def delegatecall(evm: Evm) -> None:
652654 )
653655
654656 is_cold_access = code_address not in evm .accessed_addresses
655- if is_cold_access :
656- access_gas_cost = GasCosts .COLD_ACCOUNT_ACCESS
657- else :
658- access_gas_cost = GasCosts .WARM_ACCESS
659657
660- # check static gas before state access
661- check_gas (evm , access_gas_cost + extend_memory .cost )
658+ # Pre-state extra gas (warm-equivalent access cost only; cold surcharge
659+ # is deferred to post-state).
660+ extra_gas = GasCosts .WARM_ACCESS
661+ check_gas (evm , extra_gas + extend_memory .cost )
662662
663- # STATE ACCESS
663+ # Pre-state precondition: stack depth.
664+ from ...vm .interpreter import STACK_DEPTH_LIMIT
665+ if evm .message .depth + Uint (1 ) > STACK_DEPTH_LIMIT :
666+ charge_gas (evm , extra_gas + extend_memory .cost )
667+ evm .memory += b"\x00 " * extend_memory .expand_by
668+ push (evm .stack , U256 (0 ))
669+ evm .return_data = b""
670+ evm .pc += Uint (1 )
671+ return
672+
673+ # Post-state: cold surcharge paired with warming and BAL insertion.
664674 if is_cold_access :
675+ extra_gas += GasCosts .COLD_ACCOUNT_ACCESS - GasCosts .WARM_ACCESS
676+ check_gas (evm , extra_gas + extend_memory .cost )
665677 evm .accessed_addresses .add (code_address )
666678
667- extra_gas = access_gas_cost
668679 (
669680 is_delegated ,
670681 code_address ,
671682 delegation_access_cost ,
672683 ) = calculate_delegation_cost (evm , code_address )
673684
674685 if is_delegated :
675- # check enough gas for delegation access
676686 extra_gas += delegation_access_cost
677687 check_gas (evm , extra_gas + extend_memory .cost )
678688 if code_address not in evm .accessed_addresses :
@@ -737,27 +747,35 @@ def staticcall(evm: Evm) -> None:
737747 )
738748
739749 is_cold_access = to not in evm .accessed_addresses
740- if is_cold_access :
741- access_gas_cost = GasCosts .COLD_ACCOUNT_ACCESS
742- else :
743- access_gas_cost = GasCosts .WARM_ACCESS
744750
745- # check static gas before state access
746- check_gas (evm , access_gas_cost + extend_memory .cost )
751+ # Pre-state extra gas (warm-equivalent access cost only; cold surcharge
752+ # is deferred to post-state).
753+ extra_gas = GasCosts .WARM_ACCESS
754+ check_gas (evm , extra_gas + extend_memory .cost )
747755
748- # STATE ACCESS
756+ # Pre-state precondition: stack depth.
757+ from ...vm .interpreter import STACK_DEPTH_LIMIT
758+ if evm .message .depth + Uint (1 ) > STACK_DEPTH_LIMIT :
759+ charge_gas (evm , extra_gas + extend_memory .cost )
760+ evm .memory += b"\x00 " * extend_memory .expand_by
761+ push (evm .stack , U256 (0 ))
762+ evm .return_data = b""
763+ evm .pc += Uint (1 )
764+ return
765+
766+ # Post-state: cold surcharge paired with warming and BAL insertion.
749767 if is_cold_access :
768+ extra_gas += GasCosts .COLD_ACCOUNT_ACCESS - GasCosts .WARM_ACCESS
769+ check_gas (evm , extra_gas + extend_memory .cost )
750770 evm .accessed_addresses .add (to )
751771
752- extra_gas = access_gas_cost
753772 (
754773 is_delegated ,
755774 code_address ,
756775 delegation_access_cost ,
757776 ) = calculate_delegation_cost (evm , to )
758777
759778 if is_delegated :
760- # check enough gas for delegation access
761779 extra_gas += delegation_access_cost
762780 check_gas (evm , extra_gas + extend_memory .cost )
763781 if code_address not in evm .accessed_addresses :
0 commit comments