@@ -3,7 +3,7 @@ mod costs;
33mod utils;
44
55use alloc:: vec:: Vec ;
6- use core:: cmp:: { max, min } ;
6+ use core:: cmp:: max;
77
88use evm_interpreter:: {
99 Control , ExitError , ExitException , Machine , Opcode , Stack ,
@@ -19,6 +19,7 @@ pub struct GasometerState {
1919 gas_limit : u64 ,
2020 memory_gas : u64 ,
2121 used_gas : u64 ,
22+ floor_gas : u64 ,
2223 refunded_gas : i64 ,
2324 /// Whether the gasometer is in static context.
2425 pub is_static : bool ,
@@ -78,6 +79,13 @@ impl GasometerState {
7879 Ok ( ( ) )
7980 }
8081
82+ /// Record used and floor costs of a transaction.
83+ pub fn records_transaction_cost ( & mut self , cost : TransactionGas ) -> Result < ( ) , ExitError > {
84+ self . record_gas64 ( cost. used ) ?;
85+ self . floor_gas = cost. floor ;
86+ Ok ( ( ) )
87+ }
88+
8189 /// Set memory gas usage.
8290 pub fn set_memory_gas ( & mut self , memory_cost : u64 ) -> Result < ( ) , ExitError > {
8391 let all_gas_cost = self . used_gas . checked_add ( memory_cost) ;
@@ -99,6 +107,7 @@ impl GasometerState {
99107 gas_limit,
100108 memory_gas : 0 ,
101109 used_gas : 0 ,
110+ floor_gas : 0 ,
102111 refunded_gas : 0 ,
103112 is_static,
104113 }
@@ -117,10 +126,15 @@ impl GasometerState {
117126 gas_limit. as_u64 ( )
118127 } ;
119128
120- let mut s = Self :: new ( gas_limit, false ) ;
121- let transaction_cost = TransactionCost :: call ( data, access_list) . cost ( config) ;
129+ let cost = TransactionCost :: call ( data, access_list) . cost ( config) ;
130+
131+ // EIP-7623: Check if gas limit meets the floor requirement
132+ if config. eip7623_calldata_floor && gas_limit < cost. floor {
133+ return Err ( ExitException :: OutOfGas . into ( ) ) ;
134+ }
122135
123- s. record_gas64 ( transaction_cost) ?;
136+ let mut s = Self :: new ( gas_limit, false ) ;
137+ s. records_transaction_cost ( cost) ?;
124138 Ok ( s)
125139 }
126140
@@ -137,33 +151,38 @@ impl GasometerState {
137151 gas_limit. as_u64 ( )
138152 } ;
139153
140- let mut s = Self :: new ( gas_limit, false ) ;
141- let transaction_cost = TransactionCost :: create ( code, access_list) . cost ( config) ;
154+ let cost = TransactionCost :: create ( code, access_list) . cost ( config) ;
155+
156+ // EIP-7623: Check if gas limit meets the floor requirement
157+ if config. eip7623_calldata_floor && gas_limit < cost. floor {
158+ return Err ( ExitException :: OutOfGas . into ( ) ) ;
159+ }
142160
143- s. record_gas64 ( transaction_cost) ?;
161+ let mut s = Self :: new ( gas_limit, false ) ;
162+ s. records_transaction_cost ( cost) ?;
144163 Ok ( s)
145164 }
146165
147166 /// The effective used gas at the end of the transaction.
148167 ///
149168 /// In case of revert, refunded gas are not taken into account.
150169 pub fn effective_gas ( & self , with_refund : bool , config : & Config ) -> U256 {
151- let refunded_gas = if self . refunded_gas >= 0 {
152- self . refunded_gas as u64
170+ let refunded_gas = self . refunded_gas . max ( 0 ) as u64 ;
171+
172+ let used_gas = if with_refund {
173+ let max_refund = self . total_used_gas ( ) / config. max_refund_quotient ( ) ;
174+ self . total_used_gas ( ) - refunded_gas. min ( max_refund)
153175 } else {
154- 0
176+ self . total_used_gas ( )
155177 } ;
156178
157- U256 :: from ( if with_refund {
158- self . gas_limit
159- - ( self . total_used_gas ( )
160- - min (
161- self . total_used_gas ( ) / config. max_refund_quotient ( ) ,
162- refunded_gas,
163- ) )
179+ let used_gas = if config. eip7623_calldata_floor {
180+ used_gas. max ( self . floor_gas )
164181 } else {
165- self . gas_limit - self . total_used_gas ( )
166- } )
182+ used_gas
183+ } ;
184+
185+ U256 :: from ( self . gas_limit - used_gas)
167186 }
168187
169188 /// Create a submeter.
@@ -940,6 +959,11 @@ enum TransactionCost {
940959 } ,
941960}
942961
962+ pub struct TransactionGas {
963+ used : u64 ,
964+ floor : u64 ,
965+ }
966+
943967impl TransactionCost {
944968 pub fn call ( data : & [ u8 ] , access_list : & [ ( H160 , Vec < H256 > ) ] ) -> TransactionCost {
945969 let zero_data_len = data. iter ( ) . filter ( |v| * * v == 0 ) . count ( ) ;
@@ -969,22 +993,32 @@ impl TransactionCost {
969993 }
970994 }
971995
972- pub fn cost ( & self , config : & Config ) -> u64 {
996+ pub fn cost ( & self , config : & Config ) -> TransactionGas {
973997 match self {
974998 TransactionCost :: Call {
975999 zero_data_len,
9761000 non_zero_data_len,
9771001 access_list_address_len,
9781002 access_list_storage_len,
9791003 } => {
980- #[ deny( clippy:: let_and_return) ]
981- let cost = config. gas_transaction_call ( )
1004+ let used = config. gas_transaction_call ( )
9821005 + * zero_data_len as u64 * config. gas_transaction_zero_data ( )
9831006 + * non_zero_data_len as u64 * config. gas_transaction_non_zero_data ( )
9841007 + * access_list_address_len as u64 * config. gas_access_list_address ( )
9851008 + * access_list_storage_len as u64 * config. gas_access_list_storage_key ( ) ;
9861009
987- cost
1010+ let floor = config
1011+ . gas_transaction_call ( )
1012+ . saturating_add (
1013+ ( * zero_data_len as u64 )
1014+ . saturating_mul ( config. gas_floor_transaction_zero_data ( ) ) ,
1015+ )
1016+ . saturating_add (
1017+ ( * non_zero_data_len as u64 )
1018+ . saturating_mul ( config. gas_floor_transaction_non_zero_data ( ) ) ,
1019+ ) ;
1020+
1021+ TransactionGas { used, floor }
9881022 }
9891023 TransactionCost :: Create {
9901024 zero_data_len,
@@ -993,16 +1027,28 @@ impl TransactionCost {
9931027 access_list_storage_len,
9941028 initcode_cost,
9951029 } => {
996- let mut cost = config. gas_transaction_create ( )
1030+ let mut used = config. gas_transaction_create ( )
9971031 + * zero_data_len as u64 * config. gas_transaction_zero_data ( )
9981032 + * non_zero_data_len as u64 * config. gas_transaction_non_zero_data ( )
9991033 + * access_list_address_len as u64 * config. gas_access_list_address ( )
10001034 + * access_list_storage_len as u64 * config. gas_access_list_storage_key ( ) ;
1035+
10011036 if config. max_initcode_size ( ) . is_some ( ) {
1002- cost += initcode_cost;
1037+ used += initcode_cost;
10031038 }
10041039
1005- cost
1040+ let floor = config
1041+ . gas_transaction_call ( )
1042+ . saturating_add (
1043+ ( * zero_data_len as u64 )
1044+ . saturating_mul ( config. gas_floor_transaction_zero_data ( ) ) ,
1045+ )
1046+ . saturating_add (
1047+ ( * non_zero_data_len as u64 )
1048+ . saturating_mul ( config. gas_floor_transaction_non_zero_data ( ) ) ,
1049+ ) ;
1050+
1051+ TransactionGas { used, floor }
10061052 }
10071053 }
10081054 }
0 commit comments