@@ -19,7 +19,11 @@ use apollo_gateway_types::gateway_types::{
1919 InvokeGatewayOutput ,
2020} ;
2121use apollo_infra:: component_definitions:: ComponentStarter ;
22- use apollo_mempool_types:: communication:: { AddTransactionArgsWrapper , SharedMempoolClient } ;
22+ use apollo_mempool_types:: communication:: {
23+ AddTransactionArgsWrapper ,
24+ MempoolClientError ,
25+ SharedMempoolClient ,
26+ } ;
2327use apollo_mempool_types:: mempool_types:: AddTransactionArgs ;
2428use apollo_network_types:: network_types:: BroadcastedMessageMetadata ;
2529use apollo_proc_macros:: sequencer_latency_histogram;
@@ -33,6 +37,7 @@ use starknet_api::rpc_transaction::{
3337 RpcDeclareTransaction ,
3438 RpcTransaction ,
3539} ;
40+ use starknet_types_core:: felt:: Felt ;
3641use tracing:: { debug, info, warn, Span } ;
3742
3843use crate :: errors:: {
@@ -151,32 +156,49 @@ impl Gateway {
151156 transaction_converter_err_to_deprecated_gw_err ( & tx_signature, e)
152157 } ) ?;
153158
154- let mut blocking_task =
155- ProcessTxBlockingTask :: new ( self , executable_tx, tokio:: runtime:: Handle :: current ( ) )
156- . await
157- . map_err ( |e| {
158- info ! (
159- "Gateway validation failed for tx with signature: {:?} with error: {}" ,
160- & tx_signature, e
161- ) ;
162- metric_counters. record_add_tx_failure ( & e) ;
163- e
164- } ) ?;
159+ let mut blocking_task = ProcessTxBlockingTask :: new (
160+ self ,
161+ executable_tx. clone ( ) ,
162+ tokio:: runtime:: Handle :: current ( ) ,
163+ )
164+ . await
165+ . map_err ( |e| {
166+ info ! (
167+ "Gateway validation failed for tx with signature: {:?} with error: {}" ,
168+ & tx_signature, e
169+ ) ;
170+ metric_counters. record_add_tx_failure ( & e) ;
171+ e
172+ } ) ?;
165173
166174 let state_reader = blocking_task. get_state_reader ( ) . await ?;
167175
168176 let account_address = blocking_task. executable_tx . contract_address ( ) ;
169- let account_nonce =
170- state_reader. get_account_nonce ( account_address) . await . map_err ( |e| {
171- StarknetError :: internal_with_logging ( "Failed to get account nonce" , e)
172- } ) ?;
177+ let account_nonce = state_reader
178+ . get_account_nonce ( account_address)
179+ . await
180+ . map_err ( |e| StarknetError :: internal_with_logging ( "Failed to get account nonce" , e) ) ?;
181+
182+ let is_account_tx_in_mempool =
183+ if should_query_mempool_for_account_tx ( & executable_tx, account_nonce) {
184+ self . mempool_client
185+ . account_tx_in_pool_or_recent_block ( executable_tx. contract_address ( ) )
186+ . await
187+ } else {
188+ Ok ( false )
189+ } ;
173190
174191 let stateful_tx_validator = blocking_task. create_stateful_validator ( state_reader) . await ?;
175192
176- // Run the blocking task in the current span.
177193 let curr_span = Span :: current ( ) ;
178194 let handle = tokio:: task:: spawn_blocking ( move || {
179- curr_span. in_scope ( || blocking_task. process_tx ( account_nonce, stateful_tx_validator) )
195+ curr_span. in_scope ( || {
196+ blocking_task. process_tx (
197+ account_nonce,
198+ stateful_tx_validator,
199+ is_account_tx_in_mempool,
200+ )
201+ } )
180202 } ) ;
181203 let handle_result = handle. await ;
182204 let nonce = match handle_result {
@@ -249,12 +271,22 @@ impl Gateway {
249271 }
250272}
251273
274+ // Returns true if we should prefetch mempool data to potentially skip stateful validations:
275+ // applies only to Invoke with nonce == 1 and when the account nonce is zero (pre-deploy state).
276+ fn should_query_mempool_for_account_tx (
277+ executable_tx : & AccountTransaction ,
278+ account_nonce : Nonce ,
279+ ) -> bool {
280+ matches ! ( executable_tx, AccountTransaction :: Invoke ( _) )
281+ && executable_tx. nonce ( ) == Nonce ( Felt :: ONE )
282+ && account_nonce == Nonce ( Felt :: ZERO )
283+ }
284+
252285/// CPU-intensive transaction processing, spawned in a blocking thread to avoid blocking other tasks
253286/// from running.
254287struct ProcessTxBlockingTask {
255288 state_reader_factory : Arc < dyn StateReaderFactory > ,
256289 stateful_tx_validator_factory : Arc < dyn StatefulTransactionValidatorFactoryTrait > ,
257- mempool_client : SharedMempoolClient ,
258290 executable_tx : AccountTransaction ,
259291 runtime : tokio:: runtime:: Handle ,
260292}
@@ -268,23 +300,22 @@ impl ProcessTxBlockingTask {
268300 Ok ( Self {
269301 state_reader_factory : gateway. state_reader_factory . clone ( ) ,
270302 stateful_tx_validator_factory : gateway. stateful_tx_validator_factory . clone ( ) ,
271- mempool_client : gateway. mempool_client . clone ( ) ,
272303 executable_tx,
273304 runtime,
274305 } )
275306 }
276307
277308 pub async fn get_state_reader ( & self ) -> GatewayResult < Box < dyn MempoolStateReader > > {
278309 let state_reader = self
279- . stateful_tx_validator_factory
280- . get_state_reader_for_validation ( self . state_reader_factory . as_ref ( ) )
281- . await
282- . map_err ( |e| {
283- StarknetError :: internal_with_logging (
284- "Failed to get state reader from latest block" ,
285- e,
286- )
287- } ) ?;
310+ . stateful_tx_validator_factory
311+ . get_state_reader_for_validation ( self . state_reader_factory . as_ref ( ) )
312+ . await
313+ . map_err ( |e| {
314+ StarknetError :: internal_with_logging (
315+ "Failed to get state reader from latest block" ,
316+ e,
317+ )
318+ } ) ?;
288319 Ok ( state_reader)
289320 }
290321
@@ -307,12 +338,12 @@ impl ProcessTxBlockingTask {
307338 self ,
308339 account_nonce : Nonce ,
309340 mut stateful_tx_validator : Box < dyn StatefulTransactionValidatorTrait > ,
341+ is_account_tx_in_mempool : Result < bool , MempoolClientError > ,
310342 ) -> GatewayResult < Nonce > {
311343 let nonce = stateful_tx_validator. extract_state_nonce_and_run_validations (
312344 & self . executable_tx ,
313345 account_nonce,
314- self . mempool_client ,
315- self . runtime ,
346+ is_account_tx_in_mempool,
316347 ) ?;
317348
318349 Ok ( nonce)
0 commit comments