@@ -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,11 +210,18 @@ 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- // TODO(Arni): get next_l2_gas_price from the block header.
209- let _l2_gas_price =
210- 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+ // TODO(Arni): get next_l2_gas_price from the block header.
217+ let previous_block_l2_gas_price =
218+ validator. block_context ( ) . block_info ( ) . gas_prices . strk_gas_prices . l2_gas_price ;
219+ validate_tx_l2_gas_price_within_threshold (
220+ executable_tx. resource_bounds ( ) ,
221+ previous_block_l2_gas_price,
222+ ) ?;
223+ }
224+
211225 let address = executable_tx. contract_address ( ) ;
212226 let nonce = validator. get_nonce ( address) . map_err ( |e| {
213227 error ! ( "Failed to get nonce for sender address {}: {}" , address, e) ;
@@ -227,6 +241,39 @@ impl ProcessTxBlockingTask {
227241 }
228242}
229243
244+ // TODO(Arni): Consider running this validation for all gas prices.
245+ fn validate_tx_l2_gas_price_within_threshold (
246+ tx_resource_bounds : ValidResourceBounds ,
247+ previous_block_l2_gas_price : NonzeroGasPrice ,
248+ ) -> GatewayResult < ( ) > {
249+ match tx_resource_bounds {
250+ ValidResourceBounds :: AllResources ( tx_resource_bounds) => {
251+ let tx_l2_gas_price = tx_resource_bounds. l2_gas . max_price_per_unit ;
252+ let gas_price_threshold_multiplier =
253+ Ratio :: new ( MIN_GAS_PRICE_PRECENTAGE . into ( ) , 100_u128 ) ;
254+ let threshold =
255+ ( gas_price_threshold_multiplier * previous_block_l2_gas_price. get ( ) . 0 ) . to_integer ( ) ;
256+ if tx_l2_gas_price. 0 < threshold {
257+ return Err ( StarknetError {
258+ // We didn't have this kind of an error.
259+ code : StarknetErrorCode :: UnknownErrorCode (
260+ "StarknetErrorCode.GAS_PRICE_TOO_LOW" . to_string ( ) ,
261+ ) ,
262+ message : format ! (
263+ "Transaction L2 gas price {} is below the required threshold {}." ,
264+ tx_l2_gas_price, threshold
265+ ) ,
266+ } ) ;
267+ }
268+ }
269+ ValidResourceBounds :: L1Gas ( _) => {
270+ // No validation required for legacy transactions.
271+ }
272+ }
273+
274+ Ok ( ( ) )
275+ }
276+
230277fn convert_compiled_class_hash_error ( error : ValidateCompiledClassHashError ) -> StarknetError {
231278 let ValidateCompiledClassHashError :: CompiledClassHashMismatch {
232279 computed_class_hash,
0 commit comments