mirror of
https://github.com/lightninglabs/loop.git
synced 2026-08-16 13:00:37 +02:00
Merge pull request #679 from sputn1ck/listswaps_filter
Add list swaps filter
This commit is contained in:
commit
52135a4031
7 changed files with 1090 additions and 612 deletions
|
|
@ -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) {
|
||||
|
|
|
|||
1389
looprpc/client.pb.go
1389
looprpc/client.pb.go
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…
Add table
Add a link
Reference in a new issue