@@ -22,7 +22,7 @@ use alloy::{
2222 consensus:: { BlobTransactionSidecar , EnvKzgSettings , EthereumTxEnvelope , TxEip4844WithSidecar } ,
2323 eips:: { eip4844:: BYTES_PER_BLOB , eip7594:: BlobTransactionSidecarEip7594 , Encodable2718 } ,
2424 hex,
25- network:: EthereumWallet ,
25+ network:: { EthereumWallet , TransactionBuilder } ,
2626 primitives:: { utils:: parse_ether, Address , U256 } ,
2727 providers:: { PendingTransactionError , Provider , ProviderBuilder } ,
2828 rpc:: types:: TransactionReceipt ,
@@ -334,90 +334,170 @@ impl ProofAggregator {
334334
335335 info ! ( "Sending proof to ProofAggregationService contract..." ) ;
336336
337- let tx_req = match aggregated_proof {
338- AlignedProof :: SP1 ( proof) => self
339- . proof_aggregation_service
340- . verifyAggregationSP1 (
341- blob_versioned_hash. into ( ) ,
342- proof. proof_with_pub_values . public_values . to_vec ( ) . into ( ) ,
343- proof. proof_with_pub_values . bytes ( ) . into ( ) ,
344- self . sp1_chunk_aggregator_vk_hash_bytes . into ( ) ,
345- )
346- . sidecar ( blob)
347- . into_transaction_request ( ) ,
348- AlignedProof :: Risc0 ( proof) => {
349- let encoded_seal = encode_seal ( & proof. receipt )
350- . map_err ( |e| AggregatedProofSubmissionError :: Risc0EncodingSeal ( e. to_string ( ) ) )
351- . map_err ( RetryError :: Permanent ) ?;
352- self . proof_aggregation_service
353- . verifyAggregationRisc0 (
337+ // TODO: Read from config
338+ let max_retries = 5 ;
339+ let retry_interval = Duration :: from_secs ( 120 ) ;
340+ let fee_multiplier: f64 = 1.2 ;
341+
342+ for attempt in 0 ..max_retries {
343+ let mut tx_req = match aggregated_proof {
344+ AlignedProof :: SP1 ( proof) => self
345+ . proof_aggregation_service
346+ . verifyAggregationSP1 (
354347 blob_versioned_hash. into ( ) ,
355- encoded_seal . into ( ) ,
356- proof. receipt . journal . bytes . clone ( ) . into ( ) ,
357- self . risc0_chunk_aggregator_image_id_bytes . into ( ) ,
348+ proof . proof_with_pub_values . public_values . to_vec ( ) . into ( ) ,
349+ proof. proof_with_pub_values . bytes ( ) . into ( ) ,
350+ self . sp1_chunk_aggregator_vk_hash_bytes . into ( ) ,
358351 )
359- . sidecar ( blob)
360- . into_transaction_request ( )
361- }
362- } ;
363-
364- let provider = self . proof_aggregation_service . provider ( ) ;
365- let envelope = provider
366- . fill ( tx_req)
367- . await
368- . map_err ( |err| {
369- AggregatedProofSubmissionError :: SendVerifyAggregatedProofTransaction (
370- err. to_string ( ) ,
371- )
372- } )
373- . map_err ( RetryError :: Transient ) ?
374- . try_into_envelope ( )
375- . map_err ( |err| {
376- AggregatedProofSubmissionError :: SendVerifyAggregatedProofTransaction (
377- err. to_string ( ) ,
378- )
379- } )
380- . map_err ( RetryError :: Transient ) ?;
381- let tx: EthereumTxEnvelope < TxEip4844WithSidecar < BlobTransactionSidecarEip7594 > > = envelope
382- . try_into_pooled ( )
383- . map_err ( |err| {
384- AggregatedProofSubmissionError :: SendVerifyAggregatedProofTransaction (
385- err. to_string ( ) ,
386- )
387- } )
388- . map_err ( RetryError :: Transient ) ?
389- . try_map_eip4844 ( |tx| {
390- tx. try_map_sidecar ( |sidecar| sidecar. try_into_7594 ( EnvKzgSettings :: Default . get ( ) ) )
391- } )
392- . map_err ( |err| {
393- AggregatedProofSubmissionError :: SendVerifyAggregatedProofTransaction (
394- err. to_string ( ) ,
395- )
396- } )
397- . map_err ( RetryError :: Transient ) ?;
352+ . sidecar ( blob. clone ( ) )
353+ . into_transaction_request ( ) ,
354+ AlignedProof :: Risc0 ( proof) => {
355+ let encoded_seal = encode_seal ( & proof. receipt )
356+ . map_err ( |e| {
357+ AggregatedProofSubmissionError :: Risc0EncodingSeal ( e. to_string ( ) )
358+ } )
359+ . map_err ( RetryError :: Permanent ) ?;
360+ self . proof_aggregation_service
361+ . verifyAggregationRisc0 (
362+ blob_versioned_hash. into ( ) ,
363+ encoded_seal. into ( ) ,
364+ proof. receipt . journal . bytes . clone ( ) . into ( ) ,
365+ self . risc0_chunk_aggregator_image_id_bytes . into ( ) ,
366+ )
367+ . sidecar ( blob. clone ( ) )
368+ . into_transaction_request ( )
369+ }
370+ } ;
398371
399- let encoded_tx = tx. encoded_2718 ( ) ;
400- let pending_tx = provider
401- . send_raw_transaction ( & encoded_tx)
402- . await
403- . map_err ( |err| {
404- AggregatedProofSubmissionError :: SendVerifyAggregatedProofTransaction (
405- err. to_string ( ) ,
406- )
407- } )
408- . map_err ( RetryError :: Transient ) ?;
372+ let provider = self . proof_aggregation_service . provider ( ) ;
373+
374+ // TODO: Move this to a separate method reset_gas_fees()
375+ // Increase gas price/fees for retries before filling
376+ if attempt > 0 {
377+ let multiplier = fee_multiplier. powi ( attempt as i32 ) ;
378+
379+ info ! (
380+ "Retry attempt {} with increased fee ({}x)" ,
381+ attempt, multiplier
382+ ) ;
383+
384+ // Obtain the current gas price if not set
385+ if tx_req. max_fee_per_gas . is_none ( ) {
386+ let current_gas_price = provider. get_gas_price ( ) . await . map_err ( |e| {
387+ RetryError :: Transient ( AggregatedProofSubmissionError :: GasPriceError (
388+ e. to_string ( ) ,
389+ ) )
390+ } ) ?;
391+
392+ let new_max_fee = ( current_gas_price as f64 * multiplier) as u128 ;
393+ let new_priority_fee = ( current_gas_price as f64 * multiplier * 0.1 ) as u128 ;
394+
395+ tx_req = tx_req
396+ . with_max_fee_per_gas ( new_max_fee)
397+ . with_max_priority_fee_per_gas ( new_priority_fee) ;
398+ } else {
399+ // If set, multiplicate the current ones
400+ if let Some ( max_fee) = tx_req. max_fee_per_gas {
401+ let new_max_fee = ( max_fee as f64 * multiplier) as u128 ;
402+ tx_req = tx_req. with_max_fee_per_gas ( new_max_fee) ;
403+ }
404+ if let Some ( priority_fee) = tx_req. max_priority_fee_per_gas {
405+ let new_priority_fee = ( priority_fee as f64 * multiplier * 0.1 ) as u128 ;
406+ tx_req = tx_req. with_max_priority_fee_per_gas ( new_priority_fee) ;
407+ }
408+ }
409+ }
409410
410- let receipt = pending_tx
411- . get_receipt ( )
412- . await
413- . map_err ( |err| {
414- AggregatedProofSubmissionError :: SendVerifyAggregatedProofTransaction (
415- err. to_string ( ) ,
416- )
417- } )
418- . map_err ( RetryError :: Transient ) ?;
411+ let envelope = provider
412+ . fill ( tx_req)
413+ . await
414+ . map_err ( |err| {
415+ AggregatedProofSubmissionError :: SendVerifyAggregatedProofTransaction (
416+ err. to_string ( ) ,
417+ )
418+ } )
419+ . map_err ( RetryError :: Transient ) ?
420+ . try_into_envelope ( )
421+ . map_err ( |err| {
422+ AggregatedProofSubmissionError :: SendVerifyAggregatedProofTransaction (
423+ err. to_string ( ) ,
424+ )
425+ } )
426+ . map_err ( RetryError :: Transient ) ?;
427+
428+ let tx: EthereumTxEnvelope < TxEip4844WithSidecar < BlobTransactionSidecarEip7594 > > =
429+ envelope
430+ . try_into_pooled ( )
431+ . map_err ( |err| {
432+ AggregatedProofSubmissionError :: SendVerifyAggregatedProofTransaction (
433+ err. to_string ( ) ,
434+ )
435+ } )
436+ . map_err ( RetryError :: Transient ) ?
437+ . try_map_eip4844 ( |tx| {
438+ tx. try_map_sidecar ( |sidecar| {
439+ sidecar. try_into_7594 ( EnvKzgSettings :: Default . get ( ) )
440+ } )
441+ } )
442+ . map_err ( |err| {
443+ AggregatedProofSubmissionError :: SendVerifyAggregatedProofTransaction (
444+ err. to_string ( ) ,
445+ )
446+ } )
447+ . map_err ( RetryError :: Transient ) ?;
448+
449+ let encoded_tx = tx. encoded_2718 ( ) ;
450+ let pending_tx = provider
451+ . send_raw_transaction ( & encoded_tx)
452+ . await
453+ . map_err ( |err| {
454+ AggregatedProofSubmissionError :: SendVerifyAggregatedProofTransaction (
455+ err. to_string ( ) ,
456+ )
457+ } )
458+ . map_err ( RetryError :: Transient ) ?;
459+
460+ // Wait for the receipt with timeout
461+ let receipt_result =
462+ tokio:: time:: timeout ( retry_interval, pending_tx. get_receipt ( ) ) . await ;
463+
464+ match receipt_result {
465+ Ok ( Ok ( receipt) ) => {
466+ info ! (
467+ "Transaction confirmed successfully on attempt {}" ,
468+ attempt + 1
469+ ) ;
470+ return Ok ( receipt) ;
471+ }
472+ Ok ( Err ( err) ) => {
473+ warn ! ( "Error getting receipt on attempt {}: {}" , attempt + 1 , err) ;
474+ if attempt == max_retries - 1 {
475+ return Err ( RetryError :: Transient (
476+ AggregatedProofSubmissionError :: SendVerifyAggregatedProofTransaction (
477+ err. to_string ( ) ,
478+ ) ,
479+ ) ) ;
480+ }
481+ }
482+ Err ( _) => {
483+ warn ! ( "Transaction not confirmed after {} seconds on attempt {}, retrying with higher fee..." ,
484+ retry_interval. as_secs( ) , attempt + 1 ) ;
485+ if attempt == max_retries - 1 {
486+ return Err ( RetryError :: Transient (
487+ AggregatedProofSubmissionError :: SendVerifyAggregatedProofTransaction (
488+ "Transaction timeout after all retries" . to_string ( ) ,
489+ ) ,
490+ ) ) ;
491+ }
492+ }
493+ }
494+ }
419495
420- Ok ( receipt)
496+ Err ( RetryError :: Transient (
497+ AggregatedProofSubmissionError :: SendVerifyAggregatedProofTransaction (
498+ "Max retries exceeded" . to_string ( ) ,
499+ ) ,
500+ ) )
421501 }
422502
423503 async fn wait_until_can_submit_aggregated_proof (
0 commit comments