Merge pull request #679 from sputn1ck/listswaps_filter

Add list swaps filter
pull/683/head
Konstantin Nick 4 months ago committed by GitHub
commit 52135a4031
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -15,6 +15,13 @@ import (
"github.com/urfave/cli"
)
var (
channelFlag = cli.StringFlag{
Name: "channel",
Usage: "the comma-separated list of short " +
"channel IDs of the channels to loop out",
}
)
var loopOutCommand = cli.Command{
Name: "out",
Usage: "perform an off-chain to on-chain swap (looping out)",
@ -28,11 +35,6 @@ var loopOutCommand = cli.Command{
Optionally a BASE58/bech32 encoded bitcoin destination address may be
specified. If not specified, a new wallet address will be generated.`,
Flags: []cli.Flag{
cli.StringFlag{
Name: "channel",
Usage: "the comma-separated list of short " +
"channel IDs of the channels to loop out",
},
cli.StringFlag{
Name: "addr",
Usage: "the optional address that the looped out funds " +
@ -93,6 +95,7 @@ var loopOutCommand = cli.Command{
forceFlag,
labelFlag,
verboseFlag,
channelFlag,
},
Action: loopOut,
}

@ -4,9 +4,12 @@ import (
"context"
"encoding/hex"
"fmt"
"strconv"
"strings"
"github.com/lightninglabs/loop/looprpc"
"github.com/lightningnetwork/lnd/lntypes"
"github.com/lightningnetwork/lnd/routing/route"
"github.com/urfave/cli"
)
@ -16,6 +19,23 @@ var listSwapsCommand = cli.Command{
Description: "Allows the user to get a list of all swaps that are " +
"currently stored in the database",
Action: listSwaps,
Flags: []cli.Flag{
cli.BoolFlag{
Name: "loop_out_only",
Usage: "only list swaps that are loop out swaps",
},
cli.BoolFlag{
Name: "loop_in_only",
Usage: "only list swaps that are loop in swaps",
},
cli.BoolFlag{
Name: "pending_only",
Usage: "only list pending swaps",
},
labelFlag,
channelFlag,
lastHopFlag,
},
}
func listSwaps(ctx *cli.Context) error {
@ -25,8 +45,64 @@ func listSwaps(ctx *cli.Context) error {
}
defer cleanup()
if ctx.Bool("loop_out_only") && ctx.Bool("loop_in_only") {
return fmt.Errorf("only one of loop_out_only and loop_in_only " +
"can be set")
}
filter := &looprpc.ListSwapsFilter{}
// Set the swap type filter.
switch {
case ctx.Bool("loop_out_only"):
filter.SwapType = looprpc.ListSwapsFilter_LOOP_OUT
case ctx.Bool("loop_in_only"):
filter.SwapType = looprpc.ListSwapsFilter_LOOP_IN
}
// Set the pending only filter.
filter.PendingOnly = ctx.Bool("pending_only")
// Parse outgoing channel set. Don't string split if the flag is empty.
// Otherwise, strings.Split returns a slice of length one with an empty
// element.
var outgoingChanSet []uint64
if ctx.IsSet(channelFlag.Name) {
chanStrings := strings.Split(ctx.String(channelFlag.Name), ",")
for _, chanString := range chanStrings {
chanID, err := strconv.ParseUint(chanString, 10, 64)
if err != nil {
return fmt.Errorf("error parsing channel id "+
"\"%v\"", chanString)
}
outgoingChanSet = append(outgoingChanSet, chanID)
}
filter.OutgoingChanSet = outgoingChanSet
}
// Parse last hop.
var lastHop []byte
if ctx.IsSet(lastHopFlag.Name) {
lastHopVertex, err := route.NewVertexFromStr(
ctx.String(lastHopFlag.Name),
)
if err != nil {
return err
}
lastHop = lastHopVertex[:]
filter.LoopInLastHop = lastHop
}
// Parse label.
if ctx.IsSet(labelFlag.Name) {
filter.Label = ctx.String(labelFlag.Name)
}
resp, err := client.ListSwaps(
context.Background(), &looprpc.ListSwapsRequest{},
context.Background(), &looprpc.ListSwapsRequest{
ListSwapFilter: filter,
},
)
if err != nil {
return err

@ -6,7 +6,9 @@ import (
"encoding/hex"
"errors"
"fmt"
"reflect"
"sort"
"strings"
"sync"
"time"
@ -470,12 +472,11 @@ func (s *swapClientServer) Monitor(in *clientrpc.MonitorRequest,
// ListSwaps returns a list of all currently known swaps and their current
// status.
func (s *swapClientServer) ListSwaps(_ context.Context,
_ *clientrpc.ListSwapsRequest) (*clientrpc.ListSwapsResponse, error) {
req *clientrpc.ListSwapsRequest) (*clientrpc.ListSwapsResponse, error) {
var (
rpcSwaps = make([]*clientrpc.SwapStatus, len(s.swaps))
rpcSwaps = []*clientrpc.SwapStatus{}
idx = 0
err error
)
s.swapsLock.Lock()
@ -487,15 +488,93 @@ func (s *swapClientServer) ListSwaps(_ context.Context,
// additional index.
for _, swp := range s.swaps {
swp := swp
rpcSwaps[idx], err = s.marshallSwap(&swp)
// Filter the swap based on the provided filter.
if !filterSwap(&swp, req.ListSwapFilter) {
continue
}
rpcSwap, err := s.marshallSwap(&swp)
if err != nil {
return nil, err
}
rpcSwaps = append(rpcSwaps, rpcSwap)
idx++
}
return &clientrpc.ListSwapsResponse{Swaps: rpcSwaps}, nil
}
// filterSwap filters the given swap based on the provided filter.
func filterSwap(swapInfo *loop.SwapInfo, filter *clientrpc.ListSwapsFilter) bool {
if filter == nil {
return true
}
// If the swap type filter is set, we only return swaps that match the
// filter.
if filter.SwapType != clientrpc.ListSwapsFilter_ANY {
switch filter.SwapType {
case clientrpc.ListSwapsFilter_LOOP_IN:
if swapInfo.SwapType != swap.TypeIn {
return false
}
case clientrpc.ListSwapsFilter_LOOP_OUT:
if swapInfo.SwapType != swap.TypeOut {
return false
}
}
}
// If the pending only filter is set, we only return pending swaps.
if filter.PendingOnly && !swapInfo.State.IsPending() {
return false
}
// If the swap is of type loop out and the outgoing channel filter is
// set, we only return swaps that match the filter.
if swapInfo.SwapType == swap.TypeOut && filter.OutgoingChanSet != nil {
// First we sort both channel sets to make sure we can compare
// them.
sort.Slice(swapInfo.OutgoingChanSet, func(i, j int) bool {
return swapInfo.OutgoingChanSet[i] <
swapInfo.OutgoingChanSet[j]
})
sort.Slice(filter.OutgoingChanSet, func(i, j int) bool {
return filter.OutgoingChanSet[i] <
filter.OutgoingChanSet[j]
})
// Compare the outgoing channel set by using reflect.DeepEqual
// which compares the underlying arrays.
if !reflect.DeepEqual(swapInfo.OutgoingChanSet,
filter.OutgoingChanSet) {
return false
}
}
// If the swap is of type loop in and the last hop filter is set, we
// only return swaps that match the filter.
if swapInfo.SwapType == swap.TypeIn && filter.LoopInLastHop != nil {
// Compare the last hop by using reflect.DeepEqual which
// compares the underlying arrays.
if !reflect.DeepEqual(swapInfo.LastHop, filter.LoopInLastHop) {
return false
}
}
// If a label filter is set, we only return swaps that softly match the
// filter.
if filter.Label != "" {
if !strings.Contains(swapInfo.Label, filter.Label) {
return false
}
}
return true
}
// SwapInfo returns all known details about a single swap.
func (s *swapClientServer) SwapInfo(_ context.Context,
req *clientrpc.SwapInfoRequest) (*clientrpc.SwapStatus, error) {

File diff suppressed because it is too large Load Diff

@ -99,10 +99,21 @@ func local_request_SwapClient_LoopIn_0(ctx context.Context, marshaler runtime.Ma
}
var (
filter_SwapClient_ListSwaps_0 = &utilities.DoubleArray{Encoding: map[string]int{}, Base: []int(nil), Check: []int(nil)}
)
func request_SwapClient_ListSwaps_0(ctx context.Context, marshaler runtime.Marshaler, client SwapClientClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq ListSwapsRequest
var metadata runtime.ServerMetadata
if err := req.ParseForm(); err != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_SwapClient_ListSwaps_0); err != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
msg, err := client.ListSwaps(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
return msg, metadata, err
@ -112,6 +123,13 @@ func local_request_SwapClient_ListSwaps_0(ctx context.Context, marshaler runtime
var protoReq ListSwapsRequest
var metadata runtime.ServerMetadata
if err := req.ParseForm(); err != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_SwapClient_ListSwaps_0); err != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
msg, err := server.ListSwaps(ctx, &protoReq)
return msg, metadata, err

@ -544,6 +544,34 @@ enum FailureReason {
}
message ListSwapsRequest {
// Optional filter to only return swaps that match the filter.
ListSwapsFilter list_swap_filter = 1;
}
message ListSwapsFilter {
enum SwapTypeFilter {
// ANY indicates that no filter is applied.
ANY = 0;
// LOOP_OUT indicates an loop out swap (off-chain to on-chain).
LOOP_OUT = 1;
// LOOP_IN indicates a loop in swap (on-chain to off-chain).
LOOP_IN = 2;
}
// The type of the swap.
SwapTypeFilter swap_type = 1;
// If set, only pending swaps are returned.
bool pending_only = 2;
// If specified on creation, the outgoing channel set of the swap.
repeated uint64 outgoing_chan_set = 3;
// Label of swap to filter for.
string label = 4;
// If specified on creation, the last hop of the swap.
bytes loop_in_last_hop = 5;
}
message ListSwapsResponse {

@ -462,6 +462,55 @@
}
}
},
"parameters": [
{
"name": "list_swap_filter.swap_type",
"description": "The type of the swap.\n\n - ANY: ANY indicates that no filter is applied.\n - LOOP_OUT: LOOP_OUT indicates an loop out swap (off-chain to on-chain)\n - LOOP_IN: LOOP_IN indicates a loop in swap (on-chain to off-chain)",
"in": "query",
"required": false,
"type": "string",
"enum": [
"ANY",
"LOOP_OUT",
"LOOP_IN"
],
"default": "ANY"
},
{
"name": "list_swap_filter.pending_only",
"description": "If set, only pending swaps are returned.",
"in": "query",
"required": false,
"type": "boolean"
},
{
"name": "list_swap_filter.outgoing_chan_set",
"description": "If specified on creation, the outgoing channel set of the swap.",
"in": "query",
"required": false,
"type": "array",
"items": {
"type": "string",
"format": "uint64"
},
"collectionFormat": "multi"
},
{
"name": "list_swap_filter.label",
"description": "Label of swap to filter for.",
"in": "query",
"required": false,
"type": "string"
},
{
"name": "list_swap_filter.loop_in_last_hop",
"description": "If specified on creation, the last hop of the swap.",
"in": "query",
"required": false,
"type": "string",
"format": "byte"
}
],
"tags": [
"SwapClient"
]
@ -492,6 +541,16 @@
}
},
"definitions": {
"ListSwapsFilterSwapTypeFilter": {
"type": "string",
"enum": [
"ANY",
"LOOP_OUT",
"LOOP_IN"
],
"default": "ANY",
"title": "- ANY: ANY indicates that no filter is applied.\n - LOOP_OUT: LOOP_OUT indicates an loop out swap (off-chain to on-chain)\n - LOOP_IN: LOOP_IN indicates a loop in swap (on-chain to off-chain)"
},
"looprpcAbandonSwapResponse": {
"type": "object"
},
@ -830,6 +889,36 @@
],
"default": "UNKNOWN"
},
"looprpcListSwapsFilter": {
"type": "object",
"properties": {
"swap_type": {
"$ref": "#/definitions/ListSwapsFilterSwapTypeFilter",
"description": "The type of the swap."
},
"pending_only": {
"type": "boolean",
"description": "If set, only pending swaps are returned."
},
"outgoing_chan_set": {
"type": "array",
"items": {
"type": "string",
"format": "uint64"
},
"description": "If specified on creation, the outgoing channel set of the swap."
},
"label": {
"type": "string",
"description": "Label of swap to filter for."
},
"loop_in_last_hop": {
"type": "string",
"format": "byte",
"description": "If specified on creation, the last hop of the swap."
}
}
},
"looprpcListSwapsResponse": {
"type": "object",
"properties": {

Loading…
Cancel
Save