@@ -8,13 +8,14 @@ use payjoin::persist::{OptionalTransitionOutcome, SessionPersister};
88use payjoin:: receive:: v2:: {
99 replay_event_log as replay_receiver_event_log, HasReplyableError , Initialized ,
1010 MaybeInputsOwned , MaybeInputsSeen , Monitor , OutputsUnknown , PayjoinProposal ,
11- ProvisionalProposal , ReceiveSession , Receiver , ReceiverBuilder ,
12- SessionOutcome as ReceiverSessionOutcome , UncheckedOriginalPayload , WantsFeeRange , WantsInputs ,
13- WantsOutputs ,
11+ PendingFallback as ReceiverPendingFallback , ProvisionalProposal , ReceiveSession , Receiver ,
12+ ReceiverBuilder , SessionOutcome as ReceiverSessionOutcome , UncheckedOriginalPayload ,
13+ WantsFeeRange , WantsInputs , WantsOutputs ,
1414} ;
1515use payjoin:: send:: v2:: {
16- replay_event_log as replay_sender_event_log, PendingFallback , PollingForProposal , SendSession ,
17- Sender , SenderBuilder , SessionOutcome as SenderSessionOutcome , WithReplyKey ,
16+ replay_event_log as replay_sender_event_log, PendingFallback as SenderPendingFallback ,
17+ PollingForProposal , SendSession , Sender , SenderBuilder , SessionOutcome as SenderSessionOutcome ,
18+ WithReplyKey ,
1819} ;
1920use payjoin:: { ImplementationError , PjParam , Uri } ;
2021use tokio:: sync:: watch;
@@ -24,6 +25,7 @@ use super::wallet::BitcoindWallet;
2425use super :: App as AppTrait ;
2526use crate :: app:: v2:: ohttp:: { unwrap_ohttp_keys_or_else_fetch, RelayManager } ;
2627use crate :: app:: { handle_interrupt, http_agent} ;
28+ use crate :: cli:: Role as CliRole ;
2729use crate :: db:: v2:: { ReceiverPersister , SenderPersister , SessionId } ;
2830use crate :: db:: Database ;
2931
@@ -486,11 +488,42 @@ impl AppTrait for App {
486488 Ok ( ( ) )
487489 }
488490
489- async fn cancel_sender ( & self , session_id : SessionId , no_broadcast : bool ) -> Result < ( ) > {
491+ async fn cancel (
492+ & self ,
493+ session_id : SessionId ,
494+ no_broadcast : bool ,
495+ role : Option < CliRole > ,
496+ ) -> Result < ( ) > {
497+ if let Some ( role) = role {
498+ return match role {
499+ CliRole :: Sender => self . cancel_sender_session ( session_id, no_broadcast) ,
500+ CliRole :: Receiver => self . cancel_receiver_session ( session_id, no_broadcast) ,
501+ } ;
502+ }
503+
504+ let send_ids = self . db . get_send_session_ids ( ) ?;
505+ let recv_ids = self . db . get_recv_session_ids ( ) ?;
506+ let is_sender = send_ids. iter ( ) . any ( |id| id. 0 == session_id. 0 ) ;
507+ let is_receiver = recv_ids. iter ( ) . any ( |id| id. 0 == session_id. 0 ) ;
508+
509+ match ( is_sender, is_receiver) {
510+ ( true , false ) => self . cancel_sender_session ( session_id, no_broadcast) ,
511+ ( false , true ) => self . cancel_receiver_session ( session_id, no_broadcast) ,
512+ ( true , true ) => anyhow:: bail!(
513+ "Session {session_id} exists as both a sender and receiver session. \
514+ Pass `--role sender` or `--role receiver`."
515+ ) ,
516+ ( false , false ) => anyhow:: bail!( "Session {session_id} not found" ) ,
517+ }
518+ }
519+ }
520+
521+ impl App {
522+ fn cancel_sender_session ( & self , session_id : SessionId , no_broadcast : bool ) -> Result < ( ) > {
490523 let persister = SenderPersister :: from_id ( self . db . clone ( ) , session_id. clone ( ) ) ;
491524 let ( session, _history) = replay_sender_event_log ( & persister) ?;
492525
493- let pending: Sender < PendingFallback > = match session {
526+ let pending: Sender < SenderPendingFallback > = match session {
494527 SendSession :: WithReplyKey ( sender) => sender. cancel ( ) . save ( & persister) ?,
495528 SendSession :: PollingForProposal ( sender) => sender. cancel ( ) . save ( & persister) ?,
496529 SendSession :: PendingFallback ( sender) => sender,
@@ -523,9 +556,72 @@ impl AppTrait for App {
523556 pending. close ( ) . save ( & persister) ?;
524557 Ok ( ( ) )
525558 }
526- }
527559
528- impl App {
560+ fn cancel_receiver_session ( & self , session_id : SessionId , no_broadcast : bool ) -> Result < ( ) > {
561+ let persister = ReceiverPersister :: from_id ( self . db . clone ( ) , session_id. clone ( ) ) ;
562+ let ( session, _history) = replay_receiver_event_log ( & persister) ?;
563+
564+ let pending: Receiver < ReceiverPendingFallback > = match session {
565+ ReceiveSession :: Initialized ( receiver) => {
566+ receiver. cancel ( ) . save ( & persister) ?;
567+ println ! ( "Session {session_id} cancelled. No fallback transaction to broadcast." ) ;
568+ return Ok ( ( ) ) ;
569+ }
570+ ReceiveSession :: UncheckedOriginalPayload ( receiver) => {
571+ receiver. cancel ( ) . save ( & persister) ?;
572+ println ! ( "Session {session_id} cancelled. No fallback transaction to broadcast." ) ;
573+ return Ok ( ( ) ) ;
574+ }
575+ ReceiveSession :: MaybeInputsOwned ( receiver) => receiver. cancel ( ) . save ( & persister) ?,
576+ ReceiveSession :: MaybeInputsSeen ( receiver) => receiver. cancel ( ) . save ( & persister) ?,
577+ ReceiveSession :: OutputsUnknown ( receiver) => receiver. cancel ( ) . save ( & persister) ?,
578+ ReceiveSession :: WantsOutputs ( receiver) => receiver. cancel ( ) . save ( & persister) ?,
579+ ReceiveSession :: WantsInputs ( receiver) => receiver. cancel ( ) . save ( & persister) ?,
580+ ReceiveSession :: WantsFeeRange ( receiver) => receiver. cancel ( ) . save ( & persister) ?,
581+ ReceiveSession :: ProvisionalProposal ( receiver) => receiver. cancel ( ) . save ( & persister) ?,
582+ ReceiveSession :: PayjoinProposal ( receiver) => receiver. cancel ( ) . save ( & persister) ?,
583+ ReceiveSession :: Monitor ( receiver) => receiver. cancel ( ) . save ( & persister) ?,
584+ ReceiveSession :: HasReplyableError ( receiver) => match receiver
585+ . cancel ( )
586+ . save ( & persister) ?
587+ {
588+ Some ( pending) => pending,
589+ None => {
590+ println ! ( "Session {session_id} cancelled. No fallback transaction available." ) ;
591+ return Ok ( ( ) ) ;
592+ }
593+ } ,
594+ ReceiveSession :: PendingFallback ( receiver) => receiver,
595+ ReceiveSession :: Closed (
596+ ReceiverSessionOutcome :: Success ( _)
597+ | ReceiverSessionOutcome :: FallbackBroadcasted
598+ | ReceiverSessionOutcome :: PayjoinProposalSent ,
599+ ) => {
600+ println ! ( "Session {session_id} already completed successfully. Cannot cancel." ) ;
601+ return Ok ( ( ) ) ;
602+ }
603+ ReceiveSession :: Closed ( _) => {
604+ println ! ( "Session {session_id} is already closed. Nothing left to do." ) ;
605+ return Ok ( ( ) ) ;
606+ }
607+ } ;
608+
609+ if no_broadcast {
610+ println ! (
611+ "Session {session_id} cancelled. Broadcast the fallback transaction manually:\n {}" ,
612+ serialize_hex( pending. fallback_tx( ) )
613+ ) ;
614+ } else {
615+ self . wallet ( ) . broadcast_tx ( pending. fallback_tx ( ) ) ?;
616+ println ! (
617+ "Broadcasted fallback transaction txid: {}" ,
618+ pending. fallback_tx( ) . compute_txid( )
619+ ) ;
620+ }
621+ pending. close ( ) . save ( & persister) ?;
622+ Ok ( ( ) )
623+ }
624+
529625 fn close_failed_session < P > ( persister : & P , session_id : & SessionId , role : & str )
530626 where
531627 P : SessionPersister ,
@@ -559,7 +655,7 @@ impl App {
559655 SendSession :: PendingFallback ( _) => {
560656 let id = persister. session_id ( ) ;
561657 println ! (
562- "Session {id} was cancelled. Run `payjoin-cli cancel {id}` to cancel and broadcast the original transaction."
658+ "Session {id} was cancelled. Run `payjoin-cli cancel {id}` to cancel and broadcast the fallback transaction."
563659 ) ;
564660 return Ok ( ( ) ) ;
565661 }
@@ -674,8 +770,13 @@ impl App {
674770 self . handle_error ( error, persister) . await ,
675771 ReceiveSession :: Monitor ( proposal) =>
676772 self . monitor_payjoin_proposal ( proposal, persister) . await ,
677- ReceiveSession :: PendingFallback ( _) =>
678- return Err ( anyhow ! ( "PendingFallback session handling not yet implemented" ) ) ,
773+ ReceiveSession :: PendingFallback ( _) => {
774+ let id = persister. session_id ( ) ;
775+ println ! (
776+ "Session {id} was cancelled. Run `payjoin-cli cancel {id}` to cancel and broadcast the fallback transaction."
777+ ) ;
778+ return Ok ( ( ) ) ;
779+ }
679780 ReceiveSession :: Closed ( _) => return Err ( anyhow ! ( "Session closed" ) ) ,
680781 }
681782 } ;
0 commit comments