Skip to content

Commit 45f1b6f

Browse files
committed
all coinselect changes
1 parent a710bb9 commit 45f1b6f

File tree

10 files changed

+1210
-1062
lines changed

10 files changed

+1210
-1062
lines changed

cmd/loop/staticaddr.go

Lines changed: 16 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ import (
55
"encoding/hex"
66
"errors"
77
"fmt"
8-
"sort"
98
"strconv"
109
"strings"
1110

@@ -15,8 +14,6 @@ import (
1514
"github.com/lightninglabs/loop/staticaddr/deposit"
1615
"github.com/lightninglabs/loop/staticaddr/loopin"
1716
"github.com/lightninglabs/loop/swapserverrpc"
18-
"github.com/lightningnetwork/lnd/input"
19-
"github.com/lightningnetwork/lnd/lnwallet"
2017
"github.com/lightningnetwork/lnd/routing/route"
2118
"github.com/urfave/cli"
2219
)
@@ -509,17 +506,16 @@ func staticAddressLoopIn(ctx *cli.Context) error {
509506
defer cleanup()
510507

511508
var (
512-
ctxb = context.Background()
513-
isAllSelected = ctx.IsSet("all")
514-
isUtxoSelected = ctx.IsSet("utxo")
515-
isAmountSelected bool
516-
selectedAmount = ctx.Int64("amount")
517-
label = ctx.String("static-loop-in")
518-
hints []*swapserverrpc.RouteHint
519-
lastHop []byte
520-
paymentTimeoutSeconds = uint32(loopin.DefaultPaymentTimeoutSeconds)
509+
ctxb = context.Background()
510+
isAllSelected = ctx.IsSet("all")
511+
isUtxoSelected = ctx.IsSet("utxo")
512+
selectedAmount = ctx.Int64("amount")
513+
selectDepositsForQuote bool
514+
label = ctx.String("static-loop-in")
515+
hints []*swapserverrpc.RouteHint
516+
lastHop []byte
517+
paymentTimeoutSeconds = uint32(loopin.DefaultPaymentTimeoutSeconds)
521518
)
522-
isAmountSelected = selectedAmount > 0
523519

524520
// Validate our label early so that we can fail before getting a quote.
525521
if err := labels.Validate(label); err != nil {
@@ -575,15 +571,8 @@ func staticAddressLoopIn(ctx *cli.Context) error {
575571
case isUtxoSelected:
576572
depositOutpoints = ctx.StringSlice("utxo")
577573

578-
case isAmountSelected:
579-
// If there's only a swap amount specified we'll coin-select
580-
// deposits to cover the swap amount.
581-
depositOutpoints, err = selectDeposits(
582-
allDeposits, selectedAmount,
583-
)
584-
if err != nil {
585-
return err
586-
}
574+
case selectedAmount > 0:
575+
// If only an amount is selected we will trigger coin selection.
587576

588577
default:
589578
return fmt.Errorf("unknown quote request")
@@ -593,12 +582,17 @@ func staticAddressLoopIn(ctx *cli.Context) error {
593582
return errors.New("duplicate outpoints detected")
594583
}
595584

585+
if len(depositOutpoints) == 0 && selectedAmount > 0 {
586+
selectDepositsForQuote = true
587+
}
588+
596589
quoteReq := &looprpc.QuoteRequest{
597590
Amt: selectedAmount,
598591
LoopInRouteHints: hints,
599592
LoopInLastHop: lastHop,
600593
Private: ctx.Bool(privateFlag.Name),
601594
DepositOutpoints: depositOutpoints,
595+
SelectDeposits: selectDepositsForQuote,
602596
}
603597
quote, err := client.GetLoopInQuote(ctxb, quoteReq)
604598
if err != nil {
@@ -640,47 +634,6 @@ func staticAddressLoopIn(ctx *cli.Context) error {
640634
return nil
641635
}
642636

643-
// selectDeposits sorts the deposits by amount in descending order, then by
644-
// blocks-until-expiry in ascending order. It then selects the deposits that
645-
// are needed to cover the amount requested without leaving a dust change. It
646-
// returns an error if the sum of deposits minus dust is less than the requested
647-
// amount.
648-
func selectDeposits(deposits []*looprpc.Deposit, targetAmount int64) ([]string,
649-
error) {
650-
651-
// Sort the deposits by amount in descending order, then by
652-
// blocks-until-expiry in ascending order.
653-
sort.Slice(deposits, func(i, j int) bool {
654-
if deposits[i].Value == deposits[j].Value {
655-
return deposits[i].BlocksUntilExpiry <
656-
deposits[j].BlocksUntilExpiry
657-
}
658-
return deposits[i].Value > deposits[j].Value
659-
})
660-
661-
// Select the deposits that are needed to cover the swap amount without
662-
// leaving a dust change.
663-
var selectedDeposits []string
664-
var selectedAmount int64
665-
dustLimit := lnwallet.DustLimitForSize(input.P2TRSize)
666-
for _, deposit := range deposits {
667-
selectedDeposits = append(selectedDeposits, deposit.Outpoint)
668-
selectedAmount += deposit.Value
669-
if selectedAmount == targetAmount {
670-
return selectedDeposits, nil
671-
}
672-
if selectedAmount > targetAmount {
673-
if selectedAmount-targetAmount >= int64(dustLimit) {
674-
return selectedDeposits, nil
675-
}
676-
}
677-
}
678-
679-
return nil, fmt.Errorf("not enough deposits to cover "+
680-
"requested amount, selected %d but need %d",
681-
selectedAmount, targetAmount)
682-
}
683-
684637
func containsDuplicates(outpoints []string) bool {
685638
found := make(map[string]struct{})
686639
for _, outpoint := range outpoints {

cmd/loop/staticaddr_test.go

Lines changed: 0 additions & 104 deletions
This file was deleted.

loopd/swapclient_server.go

Lines changed: 70 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -895,25 +895,60 @@ func (s *swapClientServer) GetLoopInQuote(ctx context.Context,
895895
var (
896896
selectedAmount = btcutil.Amount(req.Amt)
897897
totalDepositAmount btcutil.Amount
898-
numDeposits = len(req.DepositOutpoints)
898+
autoSelectDeposits = req.SelectDeposits
899899
err error
900900
)
901901

902902
htlcConfTarget, err := validateLoopInRequest(
903-
req.ConfTarget, req.ExternalHtlc, uint32(numDeposits),
904-
int64(selectedAmount),
903+
req.ConfTarget, req.ExternalHtlc,
904+
uint32(len(req.DepositOutpoints)), int64(selectedAmount),
905+
autoSelectDeposits,
905906
)
906907
if err != nil {
907908
return nil, err
908909
}
909910

910-
// Retrieve deposits to calculate their total value.
911-
var depositList *looprpc.ListStaticAddressDepositsResponse
911+
// If deposits should be automatically selected we do so and count the
912+
// number of deposits to quote for.
913+
numDeposits := 0
914+
if autoSelectDeposits {
915+
deposits, err := s.depositManager.GetActiveDepositsInState(
916+
deposit.Deposited,
917+
)
918+
if err != nil {
919+
return nil, fmt.Errorf("unable to retrieve all "+
920+
"deposits: %w", err)
921+
}
922+
923+
// TODO(hieblmi): add params to deposit for multi-address
924+
// support.
925+
params, err := s.staticAddressManager.GetStaticAddressParameters(
926+
ctx,
927+
)
928+
if err != nil {
929+
return nil, fmt.Errorf("unable to retrieve static "+
930+
"address parameters: %w", err)
931+
}
932+
933+
info, err := s.lnd.Client.GetInfo(ctx)
934+
if err != nil {
935+
return nil, fmt.Errorf("unable to get lnd info: %w",
936+
err)
937+
}
938+
selectedDeposits, err := loopin.SelectDeposits(
939+
selectedAmount, deposits, params.Expiry,
940+
info.BlockHeight,
941+
)
942+
if err != nil {
943+
return nil, fmt.Errorf("unable to select deposits: %w",
944+
err)
945+
}
912946

913-
// If deposits are selected, we need to retrieve them to calculate the
914-
// total value which we request a quote for.
915-
if numDeposits > 0 {
916-
depositList, err = s.ListStaticAddressDeposits(
947+
numDeposits = len(selectedDeposits)
948+
} else if len(req.DepositOutpoints) > 0 {
949+
// If deposits are selected, we need to retrieve them to
950+
// calculate the total value which we request a quote for.
951+
depositList, err := s.ListStaticAddressDeposits(
917952
ctx, &looprpc.ListStaticAddressDepositsRequest{
918953
Outpoints: req.DepositOutpoints,
919954
},
@@ -927,9 +962,13 @@ func (s *swapClientServer) GetLoopInQuote(ctx context.Context,
927962
"deposit outpoints")
928963
}
929964

930-
if numDeposits != len(depositList.FilteredDeposits) {
965+
if len(req.DepositOutpoints) !=
966+
len(depositList.FilteredDeposits) {
967+
931968
return nil, fmt.Errorf("expected %d deposits, got %d",
932969
numDeposits, len(depositList.FilteredDeposits))
970+
} else {
971+
numDeposits = len(depositList.FilteredDeposits)
933972
}
934973

935974
// In case we quote for deposits we send the server both the
@@ -942,12 +981,15 @@ func (s *swapClientServer) GetLoopInQuote(ctx context.Context,
942981
)
943982
}
944983

945-
selectedAmount, err = s.staticLoopInManager.SwapAmountFromSelectedAmount(
946-
selectedAmount, totalDepositAmount,
984+
// If a fractional amount is also selected, we check if it would
985+
// lead to a dust change output.
986+
selectedAmount, err = loopin.SwapAmountFromSelectedAmount(
987+
totalDepositAmount, selectedAmount,
947988
)
948989
if err != nil {
949-
return nil, fmt.Errorf("error calculating swap "+
950-
"amount from selected amount: %v", err)
990+
return nil, fmt.Errorf("error calculating "+
991+
"swap amount from selected amount: %v",
992+
err)
951993
}
952994
}
953995

@@ -1077,8 +1119,11 @@ func (s *swapClientServer) LoopIn(ctx context.Context,
10771119

10781120
infof("Loop in request received")
10791121

1122+
selectDeposits := false
1123+
numDeposits := uint32(0)
10801124
htlcConfTarget, err := validateLoopInRequest(
1081-
in.HtlcConfTarget, in.ExternalHtlc, 0, in.Amt,
1125+
in.HtlcConfTarget, in.ExternalHtlc, numDeposits, in.Amt,
1126+
selectDeposits,
10821127
)
10831128
if err != nil {
10841129
return nil, err
@@ -2184,10 +2229,17 @@ func validateConfTarget(target, defaultTarget int32) (int32, error) {
21842229
// validateLoopInRequest fails if the mutually exclusive conf target and
21852230
// external parameters are both set.
21862231
func validateLoopInRequest(htlcConfTarget int32, external bool,
2187-
numDeposits uint32, amount int64) (int32, error) {
2232+
numDeposits uint32, amount int64, autoSelectDeposits bool) (int32,
2233+
error) {
21882234

21892235
if amount == 0 && numDeposits == 0 {
2190-
return 0, errors.New("either amount or deposits must be set")
2236+
return 0, errors.New("either amount, or deposits or both " +
2237+
"must be set")
2238+
}
2239+
2240+
if autoSelectDeposits && numDeposits > 0 {
2241+
return 0, errors.New("cannot auto-select deposits while " +
2242+
"providing deposits at the same time")
21912243
}
21922244

21932245
// If the htlc is going to be externally set, the htlcConfTarget should
@@ -2205,7 +2257,7 @@ func validateLoopInRequest(htlcConfTarget int32, external bool,
22052257

22062258
// If the loop in uses static address deposits, we do not need to set a
22072259
// confirmation target since the HTLC won't be published by the client.
2208-
if numDeposits > 0 {
2260+
if numDeposits > 0 || autoSelectDeposits {
22092261
return 0, nil
22102262
}
22112263

0 commit comments

Comments
 (0)