@@ -581,8 +581,8 @@ def validate_transaction(tx: Transaction) -> Tuple[Uint, Uint]:
581581 """
582582 from .vm .interpreter import MAX_INIT_CODE_SIZE
583583
584- intrinsic_gas , calldata_floor_gas_cost = calculate_intrinsic_cost (tx )
585- if max (intrinsic_gas , calldata_floor_gas_cost ) > tx .gas :
584+ intrinsic_gas , data_floor_gas_cost = calculate_intrinsic_cost (tx )
585+ if max (intrinsic_gas , data_floor_gas_cost ) > tx .gas :
586586 raise InsufficientTransactionGasError ("Insufficient gas" )
587587 if U256 (tx .nonce ) >= U256 (U64 .MAX_VALUE ):
588588 raise NonceOverflowError ("Nonce too high" )
@@ -591,7 +591,7 @@ def validate_transaction(tx: Transaction) -> Tuple[Uint, Uint]:
591591 if tx .gas > TX_MAX_GAS_LIMIT :
592592 raise TransactionGasLimitExceededError ("Gas limit too high" )
593593
594- return intrinsic_gas , calldata_floor_gas_cost
594+ return intrinsic_gas , data_floor_gas_cost
595595
596596
597597def calculate_intrinsic_cost (tx : Transaction ) -> Tuple [Uint , Uint ]:
@@ -622,14 +622,7 @@ def calculate_intrinsic_cost(tx: Transaction) -> Tuple[Uint, Uint]:
622622 from .vm .eoa_delegation import GAS_AUTH_PER_EMPTY_ACCOUNT
623623 from .vm .gas import init_code_cost
624624
625- num_zeros = Uint (tx .data .count (0 ))
626- num_non_zeros = ulen (tx .data ) - num_zeros
627-
628- tokens_in_calldata = num_zeros + num_non_zeros * Uint (4 )
629- # EIP-7623 floor price (note: no EVM costs)
630- calldata_floor_gas_cost = (
631- tokens_in_calldata * GAS_TX_DATA_TOKEN_FLOOR + GAS_TX_BASE
632- )
625+ tokens_in_calldata = count_tokens_in_data (tx .data )
633626
634627 data_cost = tokens_in_calldata * GAS_TX_DATA_TOKEN_STANDARD
635628
@@ -639,17 +632,32 @@ def calculate_intrinsic_cost(tx: Transaction) -> Tuple[Uint, Uint]:
639632 create_cost = Uint (0 )
640633
641634 access_list_cost = Uint (0 )
635+ tokens_in_access_list = Uint (0 )
642636 if has_access_list (tx ):
643637 for access in tx .access_list :
644638 access_list_cost += GAS_TX_ACCESS_LIST_ADDRESS
645639 access_list_cost += (
646640 ulen (access .slots ) * GAS_TX_ACCESS_LIST_STORAGE_KEY
647641 )
648642
643+ # Data token floor cost for access list bytes.
644+ access_list_cost += tokens_in_access_list * GAS_TX_DATA_TOKEN_FLOOR
645+
649646 auth_cost = Uint (0 )
650647 if isinstance (tx , SetCodeTransaction ):
651648 auth_cost += Uint (GAS_AUTH_PER_EMPTY_ACCOUNT * len (tx .authorizations ))
652649
650+ # Floor tokens from calldata.
651+ floor_tokens_in_calldata = tokens_in_calldata
652+
653+ # Total floor tokens.
654+ total_floor_tokens = floor_tokens_in_calldata + tokens_in_access_list
655+
656+ # Floor gas cost (EIP-7623: minimum gas for data-heavy transactions).
657+ data_floor_gas_cost = (
658+ total_floor_tokens * GAS_TX_DATA_TOKEN_FLOOR + GAS_TX_BASE
659+ )
660+
653661 return (
654662 Uint (
655663 GAS_TX_BASE
@@ -658,10 +666,22 @@ def calculate_intrinsic_cost(tx: Transaction) -> Tuple[Uint, Uint]:
658666 + access_list_cost
659667 + auth_cost
660668 ),
661- calldata_floor_gas_cost ,
669+ data_floor_gas_cost ,
662670 )
663671
664672
673+ def count_tokens_in_data (data : bytes ) -> Uint :
674+ """
675+ Count the data tokens in arbitrary input bytes.
676+
677+ Zero bytes count as 1 token; non-zero bytes count as 4 tokens.
678+ """
679+ num_zeros = Uint (data .count (0 ))
680+ num_non_zeros = ulen (data ) - num_zeros
681+
682+ return num_zeros + num_non_zeros * Uint (4 )
683+
684+
665685def recover_sender (chain_id : U64 , tx : Transaction ) -> Address :
666686 """
667687 Extracts the sender address from a transaction.
0 commit comments