Skip to content

Commit 4039ba9

Browse files
committed
loopout: use routerrpc to send payments
1 parent 32d0cd9 commit 4039ba9

File tree

2 files changed

+120
-11
lines changed

2 files changed

+120
-11
lines changed

loopout.go

Lines changed: 110 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import (
44
"context"
55
"crypto/rand"
66
"crypto/sha256"
7+
"errors"
78
"fmt"
89
"time"
910

@@ -14,6 +15,8 @@ import (
1415
"github.com/lightninglabs/loop/swap"
1516
"github.com/lightninglabs/loop/sweep"
1617
"github.com/lightningnetwork/lnd/chainntnfs"
18+
"github.com/lightningnetwork/lnd/channeldb"
19+
"github.com/lightningnetwork/lnd/lnrpc"
1720
"github.com/lightningnetwork/lnd/lntypes"
1821
)
1922

@@ -32,6 +35,10 @@ var (
3235
//
3336
// TODO(wilmer): tune?
3437
DefaultSweepConfTargetDelta = DefaultSweepConfTarget * 2
38+
39+
// paymentTimeout is the timeout for the loop out payment loop as
40+
// communicated to lnd.
41+
paymentTimeout = time.Minute
3542
)
3643

3744
// loopOutSwap contains all the in-memory state related to a pending loop out
@@ -384,19 +391,120 @@ func (s *loopOutSwap) persistState(ctx context.Context) error {
384391
func (s *loopOutSwap) payInvoices(ctx context.Context) {
385392
// Pay the swap invoice.
386393
s.log.Infof("Sending swap payment %v", s.SwapInvoice)
387-
s.swapPaymentChan = s.lnd.Client.PayInvoice(
394+
s.swapPaymentChan = s.payInvoice(
388395
ctx, s.SwapInvoice, s.MaxSwapRoutingFee,
389396
s.LoopOutContract.UnchargeChannel,
390397
)
391398

392399
// Pay the prepay invoice.
393400
s.log.Infof("Sending prepayment %v", s.PrepayInvoice)
394-
s.prePaymentChan = s.lnd.Client.PayInvoice(
401+
s.prePaymentChan = s.payInvoice(
395402
ctx, s.PrepayInvoice, s.MaxPrepayRoutingFee,
396403
nil,
397404
)
398405
}
399406

407+
// payInvoice pays a single invoice.
408+
func (s *loopOutSwap) payInvoice(ctx context.Context, invoice string,
409+
maxFee btcutil.Amount,
410+
outgoingChannel *uint64) chan lndclient.PaymentResult {
411+
412+
resultChan := make(chan lndclient.PaymentResult)
413+
414+
go func() {
415+
var result lndclient.PaymentResult
416+
417+
status, err := s.payInvoiceAsync(
418+
ctx, invoice, maxFee, outgoingChannel,
419+
)
420+
if err != nil {
421+
result.Err = err
422+
} else {
423+
result.Preimage = status.Preimage
424+
result.PaidFee = status.Fee.ToSatoshis()
425+
result.PaidAmt = status.Value.ToSatoshis()
426+
}
427+
428+
select {
429+
case resultChan <- result:
430+
case <-ctx.Done():
431+
}
432+
}()
433+
434+
return resultChan
435+
}
436+
437+
// payInvoiceAsync is the asynchronously executed part of paying an invoice.
438+
func (s *loopOutSwap) payInvoiceAsync(ctx context.Context,
439+
invoice string, maxFee btcutil.Amount, outgoingChannel *uint64) (
440+
*lndclient.PaymentStatus, error) {
441+
442+
// Extract hash from payment request. Unfortunately the request
443+
// components aren't available directly.
444+
chainParams := s.lnd.ChainParams
445+
hash, _, err := swap.DecodeInvoice(chainParams, invoice)
446+
if err != nil {
447+
return nil, err
448+
}
449+
450+
req := lndclient.SendPaymentRequest{
451+
MaxFee: maxFee,
452+
Invoice: invoice,
453+
OutgoingChannel: outgoingChannel,
454+
Timeout: paymentTimeout,
455+
}
456+
457+
// Lookup state of the swap payment.
458+
paymentStateCtx, cancel := context.WithCancel(ctx)
459+
defer cancel()
460+
461+
payStatusChan, payErrChan, err := s.lnd.Router.SendPayment(
462+
paymentStateCtx, req,
463+
)
464+
if err != nil {
465+
return nil, err
466+
}
467+
468+
for {
469+
select {
470+
// Payment advanced to the next state.
471+
case payState := <-payStatusChan:
472+
s.log.Infof("Payment %v: state=%v",
473+
hash, payState.State)
474+
475+
switch payState.State {
476+
case lnrpc.Payment_SUCCEEDED:
477+
return &payState, nil
478+
479+
case lnrpc.Payment_FAILED:
480+
return nil, errors.New("payment failed")
481+
482+
case lnrpc.Payment_IN_FLIGHT:
483+
// Continue waiting for final state.
484+
485+
default:
486+
return nil, errors.New("unknown payment state")
487+
}
488+
489+
// Abort the swap in case of an error. An unknown payment error
490+
// from TrackPayment is no longer expected here.
491+
case err := <-payErrChan:
492+
if err != channeldb.ErrAlreadyPaid {
493+
return nil, err
494+
}
495+
496+
payStatusChan, payErrChan, err =
497+
s.lnd.Router.TrackPayment(paymentStateCtx, hash)
498+
if err != nil {
499+
return nil, err
500+
}
501+
502+
case <-ctx.Done():
503+
return nil, ctx.Err()
504+
}
505+
}
506+
}
507+
400508
// waitForConfirmedHtlc waits for a confirmed htlc to appear on the chain. In
401509
// case we haven't revealed the preimage yet, it also monitors block height and
402510
// off-chain payment failure.

test/context.go

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import (
99
"github.com/btcsuite/btcd/wire"
1010
"github.com/lightninglabs/loop/lndclient"
1111
"github.com/lightningnetwork/lnd/chainntnfs"
12+
"github.com/lightningnetwork/lnd/lnrpc"
1213
"github.com/lightningnetwork/lnd/lntypes"
1314
"github.com/lightningnetwork/lnd/zpay32"
1415
)
@@ -124,28 +125,28 @@ func (ctx *Context) AssertPaid(
124125

125126
// Assert that client pays swap invoice.
126127
for {
127-
var swapPayment PaymentChannelMessage
128+
var swapPayment RouterPaymentChannelMessage
128129
select {
129-
case swapPayment = <-ctx.Lnd.SendPaymentChannel:
130+
case swapPayment = <-ctx.Lnd.RouterSendPaymentChannel:
130131
case <-time.After(Timeout):
131132
ctx.T.Fatalf("no payment sent for invoice: %v",
132133
expectedMemo)
133134
}
134135

135-
payReq := ctx.DecodeInvoice(swapPayment.PaymentRequest)
136+
payReq := ctx.DecodeInvoice(swapPayment.Invoice)
136137

137138
if _, ok := ctx.PaidInvoices[*payReq.Description]; ok {
138139
ctx.T.Fatalf("duplicate invoice paid: %v",
139140
*payReq.Description)
140141
}
141142

142143
done := func(result error) {
143-
select {
144-
case swapPayment.Done <- lndclient.PaymentResult{
145-
Err: result,
146-
}:
147-
case <-time.After(Timeout):
148-
ctx.T.Fatalf("payment result not consumed")
144+
if result != nil {
145+
swapPayment.Errors <- result
146+
return
147+
}
148+
swapPayment.Updates <- lndclient.PaymentStatus{
149+
State: lnrpc.Payment_SUCCEEDED,
149150
}
150151
}
151152

0 commit comments

Comments
 (0)