@@ -4,7 +4,7 @@ use std::sync::{Arc, Mutex};
44use anyhow:: { anyhow, Context , Result } ;
55use payjoin:: bitcoin:: consensus:: encode:: serialize_hex;
66use payjoin:: bitcoin:: { Amount , FeeRate } ;
7- use payjoin:: persist:: OptionalTransitionOutcome ;
7+ use payjoin:: persist:: { OptionalTransitionOutcome , PersistedError } ;
88use payjoin:: receive:: v2:: {
99 replay_event_log as replay_receiver_event_log, HasReplyableError , Initialized ,
1010 MaybeInputsOwned , MaybeInputsSeen , Monitor , OutputsUnknown , PayjoinProposal ,
@@ -13,8 +13,8 @@ use payjoin::receive::v2::{
1313 WantsOutputs ,
1414} ;
1515use payjoin:: send:: v2:: {
16- replay_event_log as replay_sender_event_log, PollingForProposal , SendSession , Sender ,
17- SenderBuilder , SessionOutcome as SenderSessionOutcome , WithReplyKey ,
16+ replay_event_log as replay_sender_event_log, EncapsulationError , PollingForProposal ,
17+ SendSession , Sender , SenderBuilder , SessionOutcome as SenderSessionOutcome , WithReplyKey ,
1818} ;
1919use payjoin:: { ImplementationError , PjParam , Uri } ;
2020use tokio:: sync:: watch;
@@ -25,7 +25,7 @@ use super::App as AppTrait;
2525use crate :: app:: v2:: ohttp:: { unwrap_ohttp_keys_or_else_fetch, RelayManager } ;
2626use crate :: app:: { handle_interrupt, http_agent} ;
2727use crate :: db:: v2:: { ReceiverPersister , SenderPersister , SessionId } ;
28- use crate :: db:: Database ;
28+ use crate :: db:: { error as db_error , Database } ;
2929
3030mod ohttp;
3131
@@ -215,42 +215,47 @@ impl AppTrait for App {
215215 }
216216 PjParam :: V2 ( pj_param) => {
217217 let receiver_pubkey = pj_param. receiver_pubkey ( ) ;
218- let sender_state =
219- self . db . get_send_session_ids ( ) ?. into_iter ( ) . find_map ( |session_id| {
218+ let ( sender_state, persister , fallback_tx ) =
219+ match self . db . get_send_session_ids ( ) ?. into_iter ( ) . find_map ( |session_id| {
220220 let session_receiver_pubkey = self
221221 . db
222222 . get_send_session_receiver_pk ( & session_id)
223223 . expect ( "Receiver pubkey should exist if session id exists" ) ;
224224 if session_receiver_pubkey == * receiver_pubkey {
225225 let sender_persister =
226226 SenderPersister :: from_id ( self . db . clone ( ) , session_id) ;
227- let ( send_session, _) = replay_sender_event_log ( & sender_persister)
228- . map_err ( |e| anyhow ! ( "Failed to replay sender event log: {:?}" , e) )
229- . ok ( ) ?;
230-
231- Some ( ( send_session, sender_persister) )
227+ let ( send_session, history) =
228+ replay_sender_event_log ( & sender_persister)
229+ . map_err ( |e| {
230+ anyhow ! ( "Failed to replay sender event log: {:?}" , e)
231+ } )
232+ . ok ( ) ?;
233+
234+ Some ( ( send_session, sender_persister, history. fallback_tx ( ) ) )
232235 } else {
233236 None
234237 }
235- } ) ;
236-
237- let ( sender_state, persister) = match sender_state {
238- Some ( ( sender_state, persister) ) => ( sender_state, persister) ,
239- None => {
240- let persister =
241- SenderPersister :: new ( self . db . clone ( ) , receiver_pubkey. clone ( ) ) ?;
242- let psbt = self . create_original_psbt ( & address, amount, fee_rate) ?;
243- let sender =
244- SenderBuilder :: from_parts ( psbt, pj_param, & address, Some ( amount) )
245- . build_recommended ( fee_rate) ?
246- . save ( & persister) ?;
247-
248- ( SendSession :: WithReplyKey ( sender) , persister)
249- }
250- } ;
238+ } ) {
239+ Some ( ( sender_state, persister, fallback_tx) ) =>
240+ ( sender_state, persister, fallback_tx) ,
241+ None => {
242+ let persister =
243+ SenderPersister :: new ( self . db . clone ( ) , receiver_pubkey. clone ( ) ) ?;
244+ let psbt = self . create_original_psbt ( & address, amount, fee_rate) ?;
245+ let fallback_tx = psbt. clone ( ) . extract_tx ( ) . map_err ( |e| {
246+ anyhow ! ( "Failed to extract fallback transaction: {}" , e)
247+ } ) ?;
248+ let sender =
249+ SenderBuilder :: from_parts ( psbt, pj_param, & address, Some ( amount) )
250+ . build_recommended ( fee_rate) ?
251+ . save ( & persister) ?;
252+
253+ ( SendSession :: WithReplyKey ( sender) , persister, fallback_tx)
254+ }
255+ } ;
251256 let mut interrupt = self . interrupt . clone ( ) ;
252257 tokio:: select! {
253- _ = self . process_sender_session( sender_state, & persister) => return Ok ( ( ) ) ,
258+ _ = self . process_sender_session( sender_state, & persister, & fallback_tx ) => return Ok ( ( ) ) ,
254259 _ = interrupt. changed( ) => {
255260 println!( "Interrupted. Call `send` with the same arguments to resume this session or `resume` to resume all sessions." ) ;
256261 return Err ( anyhow!( "Interrupted" ) )
@@ -310,12 +315,14 @@ impl AppTrait for App {
310315
311316 for session_id in send_session_ids {
312317 let sender_persiter = SenderPersister :: from_id ( self . db . clone ( ) , session_id) ;
313- let sender_state = replay_sender_event_log ( & sender_persiter)
314- . map_err ( |e| anyhow ! ( "Failed to replay sender event log: {:?}" , e) ) ?
315- . 0 ;
318+ let ( sender_state, history ) = replay_sender_event_log ( & sender_persiter)
319+ . map_err ( |e| anyhow ! ( "Failed to replay sender event log: {:?}" , e) ) ?;
320+ let fallback_tx = history . fallback_tx ( ) ;
316321 let self_clone = self . clone ( ) ;
317322 tasks. push ( tokio:: spawn ( async move {
318- self_clone. process_sender_session ( sender_state, & sender_persiter) . await
323+ self_clone
324+ . process_sender_session ( sender_state, & sender_persiter, & fallback_tx)
325+ . await
319326 } ) ) ;
320327 }
321328
@@ -465,10 +472,33 @@ impl App {
465472 & self ,
466473 session : SendSession ,
467474 persister : & SenderPersister ,
475+ fallback_tx : & payjoin:: bitcoin:: Transaction ,
468476 ) -> Result < ( ) > {
469477 match session {
470- SendSession :: WithReplyKey ( context) =>
471- self . post_original_proposal ( context, persister) . await ?,
478+ SendSession :: WithReplyKey ( context) => {
479+ let response = self . post_original_proposal ( context, persister) . await ;
480+ match response {
481+ Ok ( _) => {
482+ return Ok ( ( ) ) ;
483+ }
484+ Err ( e) => {
485+ if let Some ( persisted_error) = e. downcast_ref :: < PersistedError <
486+ EncapsulationError ,
487+ db_error:: Error ,
488+ ( ) ,
489+ > > ( ) {
490+ if let Some ( api_error) = persisted_error. api_error_ref ( ) {
491+ println ! ( "Error posting original proposal: {api_error}" ) ;
492+ let txid = self . wallet ( ) . broadcast_tx ( & fallback_tx) ?;
493+ println ! ( "Fallback transaction broadcasted. TXID: {}" , txid) ;
494+ return Err ( anyhow ! (
495+ "Fallback transaction broadcasted due to: {api_error}"
496+ ) ) ;
497+ }
498+ }
499+ }
500+ }
501+ }
472502 SendSession :: PollingForProposal ( context) =>
473503 self . get_proposed_payjoin_psbt ( context, persister) . await ?,
474504 SendSession :: ProposalReceived ( proposal) => {
0 commit comments