4444 calculate_gas_extend_memory ,
4545 calculate_message_call_gas ,
4646 charge_gas ,
47+ check_gas ,
4748 max_message_call_gas ,
4849)
4950from ..memory import memory_read_bytes , memory_write
@@ -64,14 +65,15 @@ def generic_create(
6465 # if it's not moved inside this method
6566 from ...vm .interpreter import STACK_DEPTH_LIMIT , process_create_message
6667
68+ if evm .message .is_static :
69+ raise WriteInStaticContext
70+
6771 call_data = memory_read_bytes (
6872 evm .memory , memory_start_position , memory_size
6973 )
7074
7175 create_message_gas = max_message_call_gas (Uint (evm .gas_left ))
7276 evm .gas_left -= create_message_gas
73- if evm .message .is_static :
74- raise WriteInStaticContext
7577 evm .return_data = b""
7678
7779 sender_address = evm .message .current_target
@@ -333,6 +335,9 @@ def call(evm: Evm) -> None:
333335 memory_output_start_position = pop (evm .stack )
334336 memory_output_size = pop (evm .stack )
335337
338+ if evm .message .is_static and value != U256 (0 ):
339+ raise WriteInStaticContext
340+
336341 # GAS
337342 extend_memory = calculate_gas_extend_memory (
338343 evm .memory ,
@@ -342,32 +347,45 @@ def call(evm: Evm) -> None:
342347 ],
343348 )
344349
345- if to in evm .accessed_addresses :
346- access_gas_cost = GasCosts .WARM_ACCESS
350+ is_cold_access = to not in evm .accessed_addresses
351+ if is_cold_access :
352+ access_gas_cost = GasCosts .COLD_ACCOUNT_ACCESS
347353 else :
354+ access_gas_cost = GasCosts .WARM_ACCESS
355+
356+ transfer_gas_cost = Uint (0 ) if value == 0 else GasCosts .CALL_VALUE
357+
358+ # check static gas before state access
359+ check_gas (
360+ evm ,
361+ access_gas_cost + transfer_gas_cost + extend_memory .cost ,
362+ )
363+
364+ # STATE ACCESS
365+ tx_state = evm .message .tx_env .state
366+ if is_cold_access :
348367 evm .accessed_addresses .add (to )
349- access_gas_cost = GasCosts .COLD_ACCOUNT_ACCESS
350368
351369 code_address = to
352370
353371 create_gas_cost = GasCosts .NEW_ACCOUNT
354- if value == 0 or is_account_alive (evm . message . tx_env . state , to ):
372+ if value == 0 or is_account_alive (tx_state , to ):
355373 create_gas_cost = Uint (0 )
356- transfer_gas_cost = Uint (0 ) if value == 0 else GasCosts .CALL_VALUE
374+
375+ extra_gas = access_gas_cost + transfer_gas_cost + create_gas_cost
376+
357377 message_call_gas = calculate_message_call_gas (
358378 value ,
359379 gas ,
360380 Uint (evm .gas_left ),
361381 extend_memory .cost ,
362- access_gas_cost + create_gas_cost + transfer_gas_cost ,
382+ extra_gas ,
363383 )
364384 charge_gas (evm , message_call_gas .cost + extend_memory .cost )
365- if evm . message . is_static and value != U256 ( 0 ):
366- raise WriteInStaticContext
385+
386+ # OPERATION
367387 evm .memory += b"\x00 " * extend_memory .expand_by
368- sender_balance = get_account (
369- evm .message .tx_env .state , evm .message .current_target
370- ).balance
388+ sender_balance = get_account (tx_state , evm .message .current_target ).balance
371389 if sender_balance < value :
372390 push (evm .stack , U256 (0 ))
373391 evm .return_data = b""
@@ -422,13 +440,25 @@ def callcode(evm: Evm) -> None:
422440 ],
423441 )
424442
425- if code_address in evm .accessed_addresses :
426- access_gas_cost = GasCosts .WARM_ACCESS
427- else :
428- evm .accessed_addresses .add (code_address )
443+ is_cold_access = code_address not in evm .accessed_addresses
444+ if is_cold_access :
429445 access_gas_cost = GasCosts .COLD_ACCOUNT_ACCESS
446+ else :
447+ access_gas_cost = GasCosts .WARM_ACCESS
430448
431449 transfer_gas_cost = Uint (0 ) if value == 0 else GasCosts .CALL_VALUE
450+
451+ # check static gas before state access
452+ check_gas (
453+ evm ,
454+ access_gas_cost + extend_memory .cost + transfer_gas_cost ,
455+ )
456+
457+ # STATE ACCESS
458+ tx_state = evm .message .tx_env .state
459+ if is_cold_access :
460+ evm .accessed_addresses .add (code_address )
461+
432462 message_call_gas = calculate_message_call_gas (
433463 value ,
434464 gas ,
@@ -440,9 +470,7 @@ def callcode(evm: Evm) -> None:
440470
441471 # OPERATION
442472 evm .memory += b"\x00 " * extend_memory .expand_by
443- sender_balance = get_account (
444- evm .message .tx_env .state , evm .message .current_target
445- ).balance
473+ sender_balance = get_account (tx_state , evm .message .current_target ).balance
446474 if sender_balance < value :
447475 push (evm .stack , U256 (0 ))
448476 evm .return_data = b""
@@ -477,52 +505,55 @@ def selfdestruct(evm: Evm) -> None:
477505 The current EVM frame.
478506
479507 """
508+ if evm .message .is_static :
509+ raise WriteInStaticContext
510+
480511 # STACK
481512 beneficiary = to_address_masked (pop (evm .stack ))
482513
483514 # GAS
484515 gas_cost = GasCosts .OPCODE_SELFDESTRUCT_BASE
485- if beneficiary not in evm .accessed_addresses :
486- evm .accessed_addresses .add (beneficiary )
516+
517+ is_cold_access = beneficiary not in evm .accessed_addresses
518+ if is_cold_access :
487519 gas_cost += GasCosts .COLD_ACCOUNT_ACCESS
488520
521+ # check access gas cost before state access
522+ check_gas (evm , gas_cost )
523+
524+ # STATE ACCESS
525+ tx_state = evm .message .tx_env .state
526+ if is_cold_access :
527+ evm .accessed_addresses .add (beneficiary )
528+
489529 if (
490- not is_account_alive (evm .message .tx_env .state , beneficiary )
491- and get_account (
492- evm .message .tx_env .state , evm .message .current_target
493- ).balance
494- != 0
530+ not is_account_alive (tx_state , beneficiary )
531+ and get_account (tx_state , evm .message .current_target ).balance != 0
495532 ):
496533 gas_cost += GasCosts .OPCODE_SELFDESTRUCT_NEW_ACCOUNT
497534
498535 charge_gas (evm , gas_cost )
499- if evm .message .is_static :
500- raise WriteInStaticContext
501536
502537 originator = evm .message .current_target
503- beneficiary_balance = get_account (
504- evm .message .tx_env .state , beneficiary
505- ).balance
506- originator_balance = get_account (
507- evm .message .tx_env .state , originator
508- ).balance
538+ beneficiary_balance = get_account (tx_state , beneficiary ).balance
539+ originator_balance = get_account (tx_state , originator ).balance
509540
510541 # First Transfer to beneficiary
511542 set_account_balance (
512- evm . message . tx_env . state ,
543+ tx_state ,
513544 beneficiary ,
514545 beneficiary_balance + originator_balance ,
515546 )
516547 # Next, Zero the balance of the address being deleted (must come after
517548 # sending to beneficiary in case the contract named itself as the
518549 # beneficiary).
519- set_account_balance (evm . message . tx_env . state , originator , U256 (0 ))
550+ set_account_balance (tx_state , originator , U256 (0 ))
520551
521552 # register account for deletion
522553 evm .accounts_to_delete .add (originator )
523554
524555 # mark beneficiary as touched
525- if account_exists_and_is_empty (evm . message . tx_env . state , beneficiary ):
556+ if account_exists_and_is_empty (tx_state , beneficiary ):
526557 evm .touched_accounts .add (beneficiary )
527558
528559 # HALT the execution
@@ -559,11 +590,18 @@ def delegatecall(evm: Evm) -> None:
559590 ],
560591 )
561592
562- if code_address in evm .accessed_addresses :
563- access_gas_cost = GasCosts .WARM_ACCESS
593+ is_cold_access = code_address not in evm .accessed_addresses
594+ if is_cold_access :
595+ access_gas_cost = GasCosts .COLD_ACCOUNT_ACCESS
564596 else :
597+ access_gas_cost = GasCosts .WARM_ACCESS
598+
599+ # check static gas before state access
600+ check_gas (evm , access_gas_cost + extend_memory .cost )
601+
602+ # STATE ACCESS
603+ if is_cold_access :
565604 evm .accessed_addresses .add (code_address )
566- access_gas_cost = GasCosts .COLD_ACCOUNT_ACCESS
567605
568606 message_call_gas = calculate_message_call_gas (
569607 U256 (0 ),
@@ -622,11 +660,18 @@ def staticcall(evm: Evm) -> None:
622660 ],
623661 )
624662
625- if to in evm .accessed_addresses :
626- access_gas_cost = GasCosts .WARM_ACCESS
663+ is_cold_access = to not in evm .accessed_addresses
664+ if is_cold_access :
665+ access_gas_cost = GasCosts .COLD_ACCOUNT_ACCESS
627666 else :
667+ access_gas_cost = GasCosts .WARM_ACCESS
668+
669+ # check static gas before state access
670+ check_gas (evm , access_gas_cost + extend_memory .cost )
671+
672+ # STATE ACCESS
673+ if is_cold_access :
628674 evm .accessed_addresses .add (to )
629- access_gas_cost = GasCosts .COLD_ACCOUNT_ACCESS
630675
631676 code_address = to
632677
0 commit comments