@@ -26,12 +26,15 @@ use apollo_proc_macros::sequencer_latency_histogram;
2626use apollo_state_sync_types:: communication:: SharedStateSyncClient ;
2727use axum:: async_trait;
2828use blockifier:: context:: ChainInfo ;
29+ use num_rational:: Ratio ;
30+ use starknet_api:: block:: NonzeroGasPrice ;
2931use starknet_api:: executable_transaction:: ValidateCompiledClassHashError ;
3032use starknet_api:: rpc_transaction:: {
3133 InternalRpcTransaction ,
3234 InternalRpcTransactionWithoutTxHash ,
3335 RpcTransaction ,
3436} ;
37+ use starknet_api:: transaction:: fields:: ValidResourceBounds ;
3538use tracing:: { debug, error, info, instrument, warn, Span } ;
3639
3740use crate :: config:: GatewayConfig ;
@@ -46,6 +49,10 @@ use crate::sync_state_reader::SyncStateReaderFactory;
4649#[ path = "gateway_test.rs" ]
4750pub mod gateway_test;
4851
52+ // TODO(Arni): Move to a config.
53+ // Minimum gas price as percentage of threshold to accept transactions.
54+ const MIN_GAS_PRICE_PRECENTAGE : u8 = 80 ; // E.g., 80 to require 80% of threshold.
55+
4956#[ derive( Clone ) ]
5057pub struct Gateway {
5158 pub config : Arc < GatewayConfig > ,
@@ -203,10 +210,17 @@ impl ProcessTxBlockingTask {
203210 let mut validator = self
204211 . stateful_tx_validator
205212 . instantiate_validator ( self . state_reader_factory . as_ref ( ) , & self . chain_info ) ?;
206- // TODO(Arni): Use the _l2_gas_price reject transactions that do not pass the gas price
207- // threshold.
208- let _l2_gas_price =
209- validator. block_context ( ) . block_info ( ) . gas_prices . strk_gas_prices . l2_gas_price ;
213+
214+ // Skip this validation during the systems bootstrap phase.
215+ if self . stateless_tx_validator . config . validate_non_zero_resource_bounds {
216+ let l2_gas_price =
217+ validator. block_context ( ) . block_info ( ) . gas_prices . strk_gas_prices . l2_gas_price ;
218+ validate_tx_l2_gas_price_within_threshold (
219+ executable_tx. resource_bounds ( ) ,
220+ l2_gas_price,
221+ ) ?;
222+ }
223+
210224 let address = executable_tx. contract_address ( ) ;
211225 let nonce = validator. get_nonce ( address) . map_err ( |e| {
212226 error ! ( "Failed to get nonce for sender address {}: {}" , address, e) ;
@@ -226,6 +240,36 @@ impl ProcessTxBlockingTask {
226240 }
227241}
228242
243+ // TODO(Arni): Consider running this validation for all gas prices.
244+ fn validate_tx_l2_gas_price_within_threshold (
245+ tx_resource_bounds : ValidResourceBounds ,
246+ previous_block_l2_gas_price : NonzeroGasPrice ,
247+ ) -> GatewayResult < ( ) > {
248+ match tx_resource_bounds {
249+ ValidResourceBounds :: AllResources ( tx_resource_bounds) => {
250+ let tx_l2_gas_price = tx_resource_bounds. l2_gas . max_price_per_unit ;
251+ let gas_price_threshold_multiplier =
252+ Ratio :: new ( MIN_GAS_PRICE_PRECENTAGE . into ( ) , 100_u128 ) ;
253+ let threshold =
254+ ( gas_price_threshold_multiplier * previous_block_l2_gas_price. get ( ) . 0 ) . to_integer ( ) ;
255+ if tx_l2_gas_price. 0 < threshold {
256+ return Err ( StarknetError {
257+ code : StarknetErrorCode :: KnownErrorCode ( KnownStarknetErrorCode :: GasPriceTooLow ) ,
258+ message : format ! (
259+ "Transaction gas price {} is below the required threshold {}." ,
260+ tx_l2_gas_price, threshold
261+ ) ,
262+ } ) ;
263+ }
264+ }
265+ ValidResourceBounds :: L1Gas ( _) => {
266+ // No validation required for legacy transactions.
267+ }
268+ }
269+
270+ Ok ( ( ) )
271+ }
272+
229273fn convert_compiled_class_hash_error ( error : ValidateCompiledClassHashError ) -> StarknetError {
230274 let ValidateCompiledClassHashError :: CompiledClassHashMismatch {
231275 computed_class_hash,
0 commit comments