@@ -62,8 +62,8 @@ type loopOutSwap struct {
62
62
// htlcTxHash is the confirmed htlc tx id.
63
63
htlcTxHash * chainhash.Hash
64
64
65
- swapPaymentChan chan lndclient. PaymentResult
66
- prePaymentChan chan lndclient. PaymentResult
65
+ swapPaymentChan chan paymentResult
66
+ prePaymentChan chan paymentResult
67
67
68
68
wg sync.WaitGroup
69
69
}
@@ -340,27 +340,35 @@ func (s *loopOutSwap) executeAndFinalize(globalCtx context.Context) error {
340
340
select {
341
341
case result := <- s .swapPaymentChan :
342
342
s .swapPaymentChan = nil
343
- if result .Err != nil {
343
+
344
+ err := s .handlePaymentResult (result )
345
+ if err != nil {
346
+ return err
347
+ }
348
+
349
+ if result .failure () != nil {
344
350
// Server didn't pull the swap payment.
345
351
s .log .Infof ("Swap payment failed: %v" ,
346
- result .Err )
352
+ result .failure () )
347
353
348
354
continue
349
355
}
350
- s .cost .Server += result .PaidAmt
351
- s .cost .Offchain += result .PaidFee
352
356
353
357
case result := <- s .prePaymentChan :
354
358
s .prePaymentChan = nil
355
- if result .Err != nil {
359
+
360
+ err := s .handlePaymentResult (result )
361
+ if err != nil {
362
+ return err
363
+ }
364
+
365
+ if result .failure () != nil {
356
366
// Server didn't pull the prepayment.
357
367
s .log .Infof ("Prepayment failed: %v" ,
358
- result .Err )
368
+ result .failure () )
359
369
360
370
continue
361
371
}
362
- s .cost .Server += result .PaidAmt
363
- s .cost .Offchain += result .PaidFee
364
372
365
373
case <- globalCtx .Done ():
366
374
return globalCtx .Err ()
@@ -379,6 +387,27 @@ func (s *loopOutSwap) executeAndFinalize(globalCtx context.Context) error {
379
387
return s .persistState (globalCtx )
380
388
}
381
389
390
+ func (s * loopOutSwap ) handlePaymentResult (result paymentResult ) error {
391
+ switch {
392
+ // If our result has a non-nil error, our status will be nil. In this
393
+ // case the payment failed so we do not need to take any action.
394
+ case result .err != nil :
395
+ return nil
396
+
397
+ case result .status .State == lnrpc .Payment_SUCCEEDED :
398
+ s .cost .Server += result .status .Value .ToSatoshis ()
399
+ s .cost .Offchain += result .status .Fee .ToSatoshis ()
400
+
401
+ return nil
402
+
403
+ case result .status .State == lnrpc .Payment_FAILED :
404
+ return nil
405
+
406
+ default :
407
+ return fmt .Errorf ("unexpected state: %v" , result .status .State )
408
+ }
409
+ }
410
+
382
411
// executeSwap executes the swap, but returns as soon as the swap outcome is
383
412
// final. At that point, there may still be pending off-chain payment(s).
384
413
func (s * loopOutSwap ) executeSwap (globalCtx context.Context ) error {
@@ -510,31 +539,64 @@ func (s *loopOutSwap) payInvoices(ctx context.Context) {
510
539
)
511
540
}
512
541
542
+ // paymentResult contains the response for a failed or settled payment, and
543
+ // any errors that occurred if the payment unexpectedly failed.
544
+ type paymentResult struct {
545
+ status lndclient.PaymentStatus
546
+ err error
547
+ }
548
+
549
+ // failure returns the error we encountered trying to dispatch a payment result,
550
+ // if any.
551
+ func (p paymentResult ) failure () error {
552
+ if p .err != nil {
553
+ return p .err
554
+ }
555
+
556
+ if p .status .State == lnrpc .Payment_SUCCEEDED {
557
+ return nil
558
+ }
559
+
560
+ return fmt .Errorf ("payment failed: %v" , p .status .FailureReason )
561
+ }
562
+
513
563
// payInvoice pays a single invoice.
514
564
func (s * loopOutSwap ) payInvoice (ctx context.Context , invoice string ,
515
565
maxFee btcutil.Amount ,
516
- outgoingChanIds loopdb.ChannelSet ) chan lndclient. PaymentResult {
566
+ outgoingChanIds loopdb.ChannelSet ) chan paymentResult {
517
567
518
- resultChan := make (chan lndclient.PaymentResult )
568
+ resultChan := make (chan paymentResult )
569
+ sendResult := func (result paymentResult ) {
570
+ select {
571
+ case resultChan <- result :
572
+ case <- ctx .Done ():
573
+ }
574
+ }
519
575
520
576
go func () {
521
- var result lndclient. PaymentResult
577
+ var result paymentResult
522
578
523
579
status , err := s .payInvoiceAsync (
524
580
ctx , invoice , maxFee , outgoingChanIds ,
525
581
)
526
582
if err != nil {
527
- result .Err = err
528
- } else {
529
- result .Preimage = status .Preimage
530
- result .PaidFee = status .Fee .ToSatoshis ()
531
- result .PaidAmt = status .Value .ToSatoshis ()
583
+ result .err = err
584
+ sendResult (result )
585
+ return
532
586
}
533
587
534
- select {
535
- case resultChan <- result :
536
- case <- ctx .Done ():
588
+ // If our payment failed or succeeded, our status should be
589
+ // non-nil.
590
+ switch status .State {
591
+ case lnrpc .Payment_FAILED , lnrpc .Payment_SUCCEEDED :
592
+ result .status = * status
593
+
594
+ default :
595
+ result .err = fmt .Errorf ("unexpected payment state: %v" ,
596
+ status .State )
537
597
}
598
+
599
+ sendResult (result )
538
600
}()
539
601
540
602
return resultChan
@@ -583,7 +645,7 @@ func (s *loopOutSwap) payInvoiceAsync(ctx context.Context,
583
645
return & payState , nil
584
646
585
647
case lnrpc .Payment_FAILED :
586
- return nil , errors . New ( "payment failed" )
648
+ return & payState , nil
587
649
588
650
case lnrpc .Payment_IN_FLIGHT :
589
651
// Continue waiting for final state.
@@ -686,30 +748,38 @@ func (s *loopOutSwap) waitForConfirmedHtlc(globalCtx context.Context) (
686
748
// have lost the prepayment.
687
749
case result := <- s .swapPaymentChan :
688
750
s .swapPaymentChan = nil
689
- if result .Err != nil {
690
- s .state = loopdb .StateFailOffchainPayments
751
+
752
+ err := s .handlePaymentResult (result )
753
+ if err != nil {
754
+ return nil , err
755
+ }
756
+
757
+ if result .failure () != nil {
691
758
s .log .Infof ("Failed swap payment: %v" ,
692
- result .Err )
759
+ result .failure () )
693
760
761
+ s .state = loopdb .StateFailOffchainPayments
694
762
return nil , nil
695
763
}
696
- s .cost .Server += result .PaidAmt
697
- s .cost .Offchain += result .PaidFee
698
764
699
765
// If the prepay fails, abandon the swap. Because we
700
766
// didn't reveal the preimage, the swap payment will be
701
767
// canceled or time out.
702
768
case result := <- s .prePaymentChan :
703
769
s .prePaymentChan = nil
704
- if result .Err != nil {
705
- s .state = loopdb .StateFailOffchainPayments
770
+
771
+ err := s .handlePaymentResult (result )
772
+ if err != nil {
773
+ return nil , err
774
+ }
775
+
776
+ if result .failure () != nil {
706
777
s .log .Infof ("Failed prepayment: %v" ,
707
- result .Err )
778
+ result .failure () )
708
779
780
+ s .state = loopdb .StateFailOffchainPayments
709
781
return nil , nil
710
782
}
711
- s .cost .Server += result .PaidAmt
712
- s .cost .Offchain += result .PaidFee
713
783
714
784
// Unexpected error on the confirm channel happened,
715
785
// abandon the swap.
0 commit comments