@@ -10,10 +10,10 @@ use crate::{
1010 ADDITIONAL_SUBMISSION_GAS_COST_PER_PROOF , CONSTANT_GAS_COST ,
1111 MAX_FEE_BATCH_PROOF_NUMBER , MAX_FEE_DEFAULT_PROOF_NUMBER ,
1212 } ,
13- errors:: { self , GetNonceError } ,
13+ errors:: { self , GetFirstNonceFromQueueError , GetNonceError } ,
1414 types:: {
15- AlignedVerificationData , ClientMessage , GetNonceResponseMessage , Network ,
16- PriceEstimate , ProvingSystemId , VerificationData ,
15+ AlignedVerificationData , ClientMessage , GetFirstNonceInQueueResponseMessage ,
16+ GetNonceResponseMessage , Network , PriceEstimate , ProvingSystemId , VerificationData ,
1717 } ,
1818 } ,
1919 eth:: {
@@ -653,6 +653,79 @@ pub async fn get_nonce_from_ethereum(
653653 }
654654}
655655
656+ /// Returns the nonce of the proof with the lowest nonce inside the batcher queue for a given address.
657+ /// This might be useful when you proofs are stuck in the batcher due to a low fee and you need to bump them
658+ /// # Arguments
659+ /// * `batcher_url` - The batcher websocket url.
660+ /// * `address` - The user address for which the nonce will be retrieved.
661+ /// # Returns
662+ /// * The nonce of the oldest proof inside the batcher queue.
663+ /// # Errors
664+ /// * `NoProofsInQueue` if the address did not have proofs in the batcher queue.
665+ pub async fn get_first_nonce_in_queue_from_batcher (
666+ batcher_ws_url : & str ,
667+ address : Address ,
668+ ) -> Result < U256 , GetFirstNonceFromQueueError > {
669+ let ( ws_stream, _) = connect_async ( batcher_ws_url) . await . map_err ( |_| {
670+ GetFirstNonceFromQueueError :: ConnectionFailed ( "Ws connection to batcher failed" . to_string ( ) )
671+ } ) ?;
672+
673+ debug ! ( "WebSocket handshake has been successfully completed" ) ;
674+ let ( mut ws_write, mut ws_read) = ws_stream. split ( ) ;
675+ check_protocol_version ( & mut ws_read)
676+ . map_err ( |e| match e {
677+ errors:: SubmitError :: ProtocolVersionMismatch { current, expected } => {
678+ GetFirstNonceFromQueueError :: ProtocolMismatch { current, expected }
679+ }
680+ _ => GetFirstNonceFromQueueError :: UnexpectedResponse (
681+ "Unexpected response, expected protocol version" . to_string ( ) ,
682+ ) ,
683+ } )
684+ . await ?;
685+
686+ let msg = ClientMessage :: GetNonceForAddress ( address) ;
687+
688+ let msg_bin = cbor_serialize ( & msg) . map_err ( |_| {
689+ GetFirstNonceFromQueueError :: SerializationError ( "Failed to serialize msg" . to_string ( ) )
690+ } ) ?;
691+ ws_write
692+ . send ( Message :: Binary ( msg_bin. clone ( ) ) )
693+ . await
694+ . map_err ( |_| {
695+ GetFirstNonceFromQueueError :: ConnectionFailed (
696+ "Ws connection failed to send message to batcher" . to_string ( ) ,
697+ )
698+ } ) ?;
699+
700+ let mut response_stream: ResponseStream =
701+ ws_read. try_filter ( |msg| futures_util:: future:: ready ( msg. is_binary ( ) ) ) ;
702+
703+ let msg = match response_stream. next ( ) . await {
704+ Some ( Ok ( msg) ) => msg,
705+ _ => {
706+ return Err ( GetFirstNonceFromQueueError :: ConnectionFailed (
707+ "Connection was closed without close message before receiving all messages"
708+ . to_string ( ) ,
709+ ) ) ;
710+ }
711+ } ;
712+
713+ let _ = ws_write. close ( ) . await ;
714+
715+ match cbor_deserialize ( msg. into_data ( ) . as_slice ( ) ) {
716+ Ok ( GetFirstNonceInQueueResponseMessage :: Nonce ( nonce) ) => Ok ( nonce) ,
717+ Ok ( GetFirstNonceInQueueResponseMessage :: InvalidRequest ( e) ) => {
718+ Err ( GetFirstNonceFromQueueError :: InvalidRequest ( e) )
719+ }
720+ Ok ( GetFirstNonceInQueueResponseMessage :: NoProofsInQueue ) => {
721+ Err ( GetFirstNonceFromQueueError :: NoProofsInQueue )
722+ }
723+ Err ( _) => Err ( GetFirstNonceFromQueueError :: SerializationError (
724+ "Failed to deserialize batcher message" . to_string ( ) ,
725+ ) ) ,
726+ }
727+ }
728+
656729/// Returns the chain ID of the Ethereum network.
657730/// # Arguments
658731/// * `eth_rpc_url` - The URL of the Ethereum RPC node.
0 commit comments