Skip to content

Commit 52135a4

Browse files
authored
Merge pull request #679 from sputn1ck/listswaps_filter
Add list swaps filter
2 parents 9f2bf5c + c8172ad commit 52135a4

File tree

7 files changed

+1090
-612
lines changed

7 files changed

+1090
-612
lines changed

cmd/loop/loopout.go

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,13 @@ import (
1515
"github.com/urfave/cli"
1616
)
1717

18+
var (
19+
channelFlag = cli.StringFlag{
20+
Name: "channel",
21+
Usage: "the comma-separated list of short " +
22+
"channel IDs of the channels to loop out",
23+
}
24+
)
1825
var loopOutCommand = cli.Command{
1926
Name: "out",
2027
Usage: "perform an off-chain to on-chain swap (looping out)",
@@ -28,11 +35,6 @@ var loopOutCommand = cli.Command{
2835
Optionally a BASE58/bech32 encoded bitcoin destination address may be
2936
specified. If not specified, a new wallet address will be generated.`,
3037
Flags: []cli.Flag{
31-
cli.StringFlag{
32-
Name: "channel",
33-
Usage: "the comma-separated list of short " +
34-
"channel IDs of the channels to loop out",
35-
},
3638
cli.StringFlag{
3739
Name: "addr",
3840
Usage: "the optional address that the looped out funds " +
@@ -93,6 +95,7 @@ var loopOutCommand = cli.Command{
9395
forceFlag,
9496
labelFlag,
9597
verboseFlag,
98+
channelFlag,
9699
},
97100
Action: loopOut,
98101
}

cmd/loop/swaps.go

Lines changed: 77 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,12 @@ import (
44
"context"
55
"encoding/hex"
66
"fmt"
7+
"strconv"
8+
"strings"
79

810
"github.com/lightninglabs/loop/looprpc"
911
"github.com/lightningnetwork/lnd/lntypes"
12+
"github.com/lightningnetwork/lnd/routing/route"
1013
"github.com/urfave/cli"
1114
)
1215

@@ -16,6 +19,23 @@ var listSwapsCommand = cli.Command{
1619
Description: "Allows the user to get a list of all swaps that are " +
1720
"currently stored in the database",
1821
Action: listSwaps,
22+
Flags: []cli.Flag{
23+
cli.BoolFlag{
24+
Name: "loop_out_only",
25+
Usage: "only list swaps that are loop out swaps",
26+
},
27+
cli.BoolFlag{
28+
Name: "loop_in_only",
29+
Usage: "only list swaps that are loop in swaps",
30+
},
31+
cli.BoolFlag{
32+
Name: "pending_only",
33+
Usage: "only list pending swaps",
34+
},
35+
labelFlag,
36+
channelFlag,
37+
lastHopFlag,
38+
},
1939
}
2040

2141
func listSwaps(ctx *cli.Context) error {
@@ -25,8 +45,64 @@ func listSwaps(ctx *cli.Context) error {
2545
}
2646
defer cleanup()
2747

48+
if ctx.Bool("loop_out_only") && ctx.Bool("loop_in_only") {
49+
return fmt.Errorf("only one of loop_out_only and loop_in_only " +
50+
"can be set")
51+
}
52+
53+
filter := &looprpc.ListSwapsFilter{}
54+
55+
// Set the swap type filter.
56+
switch {
57+
case ctx.Bool("loop_out_only"):
58+
filter.SwapType = looprpc.ListSwapsFilter_LOOP_OUT
59+
case ctx.Bool("loop_in_only"):
60+
filter.SwapType = looprpc.ListSwapsFilter_LOOP_IN
61+
}
62+
63+
// Set the pending only filter.
64+
filter.PendingOnly = ctx.Bool("pending_only")
65+
66+
// Parse outgoing channel set. Don't string split if the flag is empty.
67+
// Otherwise, strings.Split returns a slice of length one with an empty
68+
// element.
69+
var outgoingChanSet []uint64
70+
if ctx.IsSet(channelFlag.Name) {
71+
chanStrings := strings.Split(ctx.String(channelFlag.Name), ",")
72+
for _, chanString := range chanStrings {
73+
chanID, err := strconv.ParseUint(chanString, 10, 64)
74+
if err != nil {
75+
return fmt.Errorf("error parsing channel id "+
76+
"\"%v\"", chanString)
77+
}
78+
outgoingChanSet = append(outgoingChanSet, chanID)
79+
}
80+
filter.OutgoingChanSet = outgoingChanSet
81+
}
82+
83+
// Parse last hop.
84+
var lastHop []byte
85+
if ctx.IsSet(lastHopFlag.Name) {
86+
lastHopVertex, err := route.NewVertexFromStr(
87+
ctx.String(lastHopFlag.Name),
88+
)
89+
if err != nil {
90+
return err
91+
}
92+
93+
lastHop = lastHopVertex[:]
94+
filter.LoopInLastHop = lastHop
95+
}
96+
97+
// Parse label.
98+
if ctx.IsSet(labelFlag.Name) {
99+
filter.Label = ctx.String(labelFlag.Name)
100+
}
101+
28102
resp, err := client.ListSwaps(
29-
context.Background(), &looprpc.ListSwapsRequest{},
103+
context.Background(), &looprpc.ListSwapsRequest{
104+
ListSwapFilter: filter,
105+
},
30106
)
31107
if err != nil {
32108
return err

loopd/swapclient_server.go

Lines changed: 83 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,9 @@ import (
66
"encoding/hex"
77
"errors"
88
"fmt"
9+
"reflect"
910
"sort"
11+
"strings"
1012
"sync"
1113
"time"
1214

@@ -470,12 +472,11 @@ func (s *swapClientServer) Monitor(in *clientrpc.MonitorRequest,
470472
// ListSwaps returns a list of all currently known swaps and their current
471473
// status.
472474
func (s *swapClientServer) ListSwaps(_ context.Context,
473-
_ *clientrpc.ListSwapsRequest) (*clientrpc.ListSwapsResponse, error) {
475+
req *clientrpc.ListSwapsRequest) (*clientrpc.ListSwapsResponse, error) {
474476

475477
var (
476-
rpcSwaps = make([]*clientrpc.SwapStatus, len(s.swaps))
478+
rpcSwaps = []*clientrpc.SwapStatus{}
477479
idx = 0
478-
err error
479480
)
480481

481482
s.swapsLock.Lock()
@@ -487,15 +488,93 @@ func (s *swapClientServer) ListSwaps(_ context.Context,
487488
// additional index.
488489
for _, swp := range s.swaps {
489490
swp := swp
490-
rpcSwaps[idx], err = s.marshallSwap(&swp)
491+
492+
// Filter the swap based on the provided filter.
493+
if !filterSwap(&swp, req.ListSwapFilter) {
494+
continue
495+
}
496+
497+
rpcSwap, err := s.marshallSwap(&swp)
491498
if err != nil {
492499
return nil, err
493500
}
501+
rpcSwaps = append(rpcSwaps, rpcSwap)
494502
idx++
495503
}
496504
return &clientrpc.ListSwapsResponse{Swaps: rpcSwaps}, nil
497505
}
498506

507+
// filterSwap filters the given swap based on the provided filter.
508+
func filterSwap(swapInfo *loop.SwapInfo, filter *clientrpc.ListSwapsFilter) bool {
509+
if filter == nil {
510+
return true
511+
}
512+
513+
// If the swap type filter is set, we only return swaps that match the
514+
// filter.
515+
if filter.SwapType != clientrpc.ListSwapsFilter_ANY {
516+
switch filter.SwapType {
517+
case clientrpc.ListSwapsFilter_LOOP_IN:
518+
if swapInfo.SwapType != swap.TypeIn {
519+
return false
520+
}
521+
522+
case clientrpc.ListSwapsFilter_LOOP_OUT:
523+
if swapInfo.SwapType != swap.TypeOut {
524+
return false
525+
}
526+
}
527+
}
528+
529+
// If the pending only filter is set, we only return pending swaps.
530+
if filter.PendingOnly && !swapInfo.State.IsPending() {
531+
return false
532+
}
533+
534+
// If the swap is of type loop out and the outgoing channel filter is
535+
// set, we only return swaps that match the filter.
536+
if swapInfo.SwapType == swap.TypeOut && filter.OutgoingChanSet != nil {
537+
// First we sort both channel sets to make sure we can compare
538+
// them.
539+
sort.Slice(swapInfo.OutgoingChanSet, func(i, j int) bool {
540+
return swapInfo.OutgoingChanSet[i] <
541+
swapInfo.OutgoingChanSet[j]
542+
})
543+
sort.Slice(filter.OutgoingChanSet, func(i, j int) bool {
544+
return filter.OutgoingChanSet[i] <
545+
filter.OutgoingChanSet[j]
546+
})
547+
548+
// Compare the outgoing channel set by using reflect.DeepEqual
549+
// which compares the underlying arrays.
550+
if !reflect.DeepEqual(swapInfo.OutgoingChanSet,
551+
filter.OutgoingChanSet) {
552+
553+
return false
554+
}
555+
}
556+
557+
// If the swap is of type loop in and the last hop filter is set, we
558+
// only return swaps that match the filter.
559+
if swapInfo.SwapType == swap.TypeIn && filter.LoopInLastHop != nil {
560+
// Compare the last hop by using reflect.DeepEqual which
561+
// compares the underlying arrays.
562+
if !reflect.DeepEqual(swapInfo.LastHop, filter.LoopInLastHop) {
563+
return false
564+
}
565+
}
566+
567+
// If a label filter is set, we only return swaps that softly match the
568+
// filter.
569+
if filter.Label != "" {
570+
if !strings.Contains(swapInfo.Label, filter.Label) {
571+
return false
572+
}
573+
}
574+
575+
return true
576+
}
577+
499578
// SwapInfo returns all known details about a single swap.
500579
func (s *swapClientServer) SwapInfo(_ context.Context,
501580
req *clientrpc.SwapInfoRequest) (*clientrpc.SwapStatus, error) {

0 commit comments

Comments
 (0)