33use std:: {
44 collections:: HashMap ,
55 str:: FromStr ,
6- sync:: { Arc , RwLock } ,
6+ sync:: { atomic :: AtomicBool , Arc , RwLock } ,
77 time:: { SystemTime , UNIX_EPOCH } ,
88} ;
99
1010use alloy:: { dyn_abi:: Eip712Domain , primitives:: Address , signers:: local:: PrivateKeySigner } ;
11+ use anyhow:: anyhow;
1112use rstest:: * ;
1213
1314fn get_current_timestamp_u64_ns ( ) -> anyhow:: Result < u64 > {
@@ -24,8 +25,9 @@ use tap_core::{
2425 } ,
2526 rav:: ReceiptAggregateVoucher ,
2627 receipt:: {
27- checks:: { CheckList , StatefulTimestampCheck } ,
28- Receipt ,
28+ checks:: { Check , CheckError , CheckList , StatefulTimestampCheck } ,
29+ state:: Checking ,
30+ Receipt , ReceiptWithState ,
2931 } ,
3032 signed_message:: EIP712SignedMessage ,
3133 tap_eip712_domain,
@@ -530,3 +532,79 @@ async fn manager_create_rav_and_ignore_invalid_receipts(
530532 //Rav Value corresponds only to value of one receipt
531533 assert_eq ! ( expected_rav. valueAggregate, 20 ) ;
532534}
535+
536+ #[ rstest]
537+ #[ tokio:: test]
538+ async fn test_retryable_checks (
539+ allocation_ids : Vec < Address > ,
540+ domain_separator : Eip712Domain ,
541+ context : ContextFixture ,
542+ ) {
543+ struct RetryableCheck ( Arc < AtomicBool > ) ;
544+
545+ #[ async_trait:: async_trait]
546+ impl Check for RetryableCheck {
547+ async fn check ( & self , receipt : & ReceiptWithState < Checking > ) -> Result < ( ) , CheckError > {
548+ // we want to fail only if nonce is 5 and if is create rav step
549+ if self . 0 . load ( std:: sync:: atomic:: Ordering :: SeqCst )
550+ && receipt. signed_receipt ( ) . message . nonce == 5
551+ {
552+ Err ( CheckError :: Retryable ( anyhow ! ( "Retryable error" ) ) )
553+ } else {
554+ Ok ( ( ) )
555+ }
556+ }
557+ }
558+
559+ let ContextFixture {
560+ context,
561+ checks,
562+ escrow_storage,
563+ signer,
564+ ..
565+ } = context;
566+
567+ let is_create_rav = Arc :: new ( AtomicBool :: new ( false ) ) ;
568+
569+ let mut checks: Vec < Arc < dyn Check + Send + Sync > > = checks. iter ( ) . cloned ( ) . collect ( ) ;
570+ checks. push ( Arc :: new ( RetryableCheck ( is_create_rav. clone ( ) ) ) ) ;
571+
572+ let manager = Manager :: new (
573+ domain_separator. clone ( ) ,
574+ context. clone ( ) ,
575+ CheckList :: new ( checks) ,
576+ ) ;
577+
578+ escrow_storage
579+ . write ( )
580+ . unwrap ( )
581+ . insert ( signer. address ( ) , 999999 ) ;
582+
583+ let mut stored_signed_receipts = Vec :: new ( ) ;
584+ for i in 0 ..10 {
585+ let receipt = Receipt {
586+ allocation_id : allocation_ids[ 0 ] ,
587+ timestamp_ns : i + 1 ,
588+ nonce : i,
589+ value : 20u128 ,
590+ } ;
591+ let signed_receipt = EIP712SignedMessage :: new ( & domain_separator, receipt, & signer) . unwrap ( ) ;
592+ stored_signed_receipts. push ( signed_receipt. clone ( ) ) ;
593+ manager
594+ . verify_and_store_receipt ( signed_receipt)
595+ . await
596+ . unwrap ( ) ;
597+ }
598+
599+ is_create_rav. store ( true , std:: sync:: atomic:: Ordering :: SeqCst ) ;
600+
601+ let rav_request = manager. create_rav_request ( 0 , None ) . await ;
602+
603+ assert_eq ! (
604+ rav_request. expect_err( "Didn't fail" ) . to_string( ) ,
605+ tap_core:: Error :: ReceiptError ( tap_core:: receipt:: ReceiptError :: RetryableCheck (
606+ "Retryable error" . to_string( )
607+ ) )
608+ . to_string( )
609+ ) ;
610+ }
0 commit comments