mirror of
https://github.com/lightninglabs/loop.git
synced 2026-08-13 12:33:03 +02:00
loopout: use routerrpc to send payments
This commit is contained in:
parent
32d0cd90e3
commit
4039ba9b69
2 changed files with 120 additions and 11 deletions
112
loopout.go
112
loopout.go
|
|
@ -4,6 +4,7 @@ import (
|
|||
"context"
|
||||
"crypto/rand"
|
||||
"crypto/sha256"
|
||||
"errors"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
|
|
@ -14,6 +15,8 @@ import (
|
|||
"github.com/lightninglabs/loop/swap"
|
||||
"github.com/lightninglabs/loop/sweep"
|
||||
"github.com/lightningnetwork/lnd/chainntnfs"
|
||||
"github.com/lightningnetwork/lnd/channeldb"
|
||||
"github.com/lightningnetwork/lnd/lnrpc"
|
||||
"github.com/lightningnetwork/lnd/lntypes"
|
||||
)
|
||||
|
||||
|
|
@ -32,6 +35,10 @@ var (
|
|||
//
|
||||
// TODO(wilmer): tune?
|
||||
DefaultSweepConfTargetDelta = DefaultSweepConfTarget * 2
|
||||
|
||||
// paymentTimeout is the timeout for the loop out payment loop as
|
||||
// communicated to lnd.
|
||||
paymentTimeout = time.Minute
|
||||
)
|
||||
|
||||
// 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 {
|
|||
func (s *loopOutSwap) payInvoices(ctx context.Context) {
|
||||
// Pay the swap invoice.
|
||||
s.log.Infof("Sending swap payment %v", s.SwapInvoice)
|
||||
s.swapPaymentChan = s.lnd.Client.PayInvoice(
|
||||
s.swapPaymentChan = s.payInvoice(
|
||||
ctx, s.SwapInvoice, s.MaxSwapRoutingFee,
|
||||
s.LoopOutContract.UnchargeChannel,
|
||||
)
|
||||
|
||||
// Pay the prepay invoice.
|
||||
s.log.Infof("Sending prepayment %v", s.PrepayInvoice)
|
||||
s.prePaymentChan = s.lnd.Client.PayInvoice(
|
||||
s.prePaymentChan = s.payInvoice(
|
||||
ctx, s.PrepayInvoice, s.MaxPrepayRoutingFee,
|
||||
nil,
|
||||
)
|
||||
}
|
||||
|
||||
// payInvoice pays a single invoice.
|
||||
func (s *loopOutSwap) payInvoice(ctx context.Context, invoice string,
|
||||
maxFee btcutil.Amount,
|
||||
outgoingChannel *uint64) chan lndclient.PaymentResult {
|
||||
|
||||
resultChan := make(chan lndclient.PaymentResult)
|
||||
|
||||
go func() {
|
||||
var result lndclient.PaymentResult
|
||||
|
||||
status, err := s.payInvoiceAsync(
|
||||
ctx, invoice, maxFee, outgoingChannel,
|
||||
)
|
||||
if err != nil {
|
||||
result.Err = err
|
||||
} else {
|
||||
result.Preimage = status.Preimage
|
||||
result.PaidFee = status.Fee.ToSatoshis()
|
||||
result.PaidAmt = status.Value.ToSatoshis()
|
||||
}
|
||||
|
||||
select {
|
||||
case resultChan <- result:
|
||||
case <-ctx.Done():
|
||||
}
|
||||
}()
|
||||
|
||||
return resultChan
|
||||
}
|
||||
|
||||
// payInvoiceAsync is the asynchronously executed part of paying an invoice.
|
||||
func (s *loopOutSwap) payInvoiceAsync(ctx context.Context,
|
||||
invoice string, maxFee btcutil.Amount, outgoingChannel *uint64) (
|
||||
*lndclient.PaymentStatus, error) {
|
||||
|
||||
// Extract hash from payment request. Unfortunately the request
|
||||
// components aren't available directly.
|
||||
chainParams := s.lnd.ChainParams
|
||||
hash, _, err := swap.DecodeInvoice(chainParams, invoice)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
req := lndclient.SendPaymentRequest{
|
||||
MaxFee: maxFee,
|
||||
Invoice: invoice,
|
||||
OutgoingChannel: outgoingChannel,
|
||||
Timeout: paymentTimeout,
|
||||
}
|
||||
|
||||
// Lookup state of the swap payment.
|
||||
paymentStateCtx, cancel := context.WithCancel(ctx)
|
||||
defer cancel()
|
||||
|
||||
payStatusChan, payErrChan, err := s.lnd.Router.SendPayment(
|
||||
paymentStateCtx, req,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for {
|
||||
select {
|
||||
// Payment advanced to the next state.
|
||||
case payState := <-payStatusChan:
|
||||
s.log.Infof("Payment %v: state=%v",
|
||||
hash, payState.State)
|
||||
|
||||
switch payState.State {
|
||||
case lnrpc.Payment_SUCCEEDED:
|
||||
return &payState, nil
|
||||
|
||||
case lnrpc.Payment_FAILED:
|
||||
return nil, errors.New("payment failed")
|
||||
|
||||
case lnrpc.Payment_IN_FLIGHT:
|
||||
// Continue waiting for final state.
|
||||
|
||||
default:
|
||||
return nil, errors.New("unknown payment state")
|
||||
}
|
||||
|
||||
// Abort the swap in case of an error. An unknown payment error
|
||||
// from TrackPayment is no longer expected here.
|
||||
case err := <-payErrChan:
|
||||
if err != channeldb.ErrAlreadyPaid {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
payStatusChan, payErrChan, err =
|
||||
s.lnd.Router.TrackPayment(paymentStateCtx, hash)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
case <-ctx.Done():
|
||||
return nil, ctx.Err()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// waitForConfirmedHtlc waits for a confirmed htlc to appear on the chain. In
|
||||
// case we haven't revealed the preimage yet, it also monitors block height and
|
||||
// off-chain payment failure.
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ import (
|
|||
"github.com/btcsuite/btcd/wire"
|
||||
"github.com/lightninglabs/loop/lndclient"
|
||||
"github.com/lightningnetwork/lnd/chainntnfs"
|
||||
"github.com/lightningnetwork/lnd/lnrpc"
|
||||
"github.com/lightningnetwork/lnd/lntypes"
|
||||
"github.com/lightningnetwork/lnd/zpay32"
|
||||
)
|
||||
|
|
@ -124,15 +125,15 @@ func (ctx *Context) AssertPaid(
|
|||
|
||||
// Assert that client pays swap invoice.
|
||||
for {
|
||||
var swapPayment PaymentChannelMessage
|
||||
var swapPayment RouterPaymentChannelMessage
|
||||
select {
|
||||
case swapPayment = <-ctx.Lnd.SendPaymentChannel:
|
||||
case swapPayment = <-ctx.Lnd.RouterSendPaymentChannel:
|
||||
case <-time.After(Timeout):
|
||||
ctx.T.Fatalf("no payment sent for invoice: %v",
|
||||
expectedMemo)
|
||||
}
|
||||
|
||||
payReq := ctx.DecodeInvoice(swapPayment.PaymentRequest)
|
||||
payReq := ctx.DecodeInvoice(swapPayment.Invoice)
|
||||
|
||||
if _, ok := ctx.PaidInvoices[*payReq.Description]; ok {
|
||||
ctx.T.Fatalf("duplicate invoice paid: %v",
|
||||
|
|
@ -140,12 +141,12 @@ func (ctx *Context) AssertPaid(
|
|||
}
|
||||
|
||||
done := func(result error) {
|
||||
select {
|
||||
case swapPayment.Done <- lndclient.PaymentResult{
|
||||
Err: result,
|
||||
}:
|
||||
case <-time.After(Timeout):
|
||||
ctx.T.Fatalf("payment result not consumed")
|
||||
if result != nil {
|
||||
swapPayment.Errors <- result
|
||||
return
|
||||
}
|
||||
swapPayment.Updates <- lndclient.PaymentStatus{
|
||||
State: lnrpc.Payment_SUCCEEDED,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue