Merge pull request #1274 from joostjager/closechannels-squashed

rpc+lnrpc: add new closechannels cli+rpc command
This commit is contained in:
Olaoluwa Osuntokun authored and GitHub committed 2018-06-13 17:35:35 -07:00
commit c1a1b3ba3d
8 files changed
+1075 -440

No files matched your search

+2
View File
@@ -25,7 +25,9 @@ _testmain.go
*.prof *.prof
lnd lnd
lnd-debug
lncli lncli
lncli-debug
output*.log output*.log
+56
View File
@@ -1581,6 +1581,62 @@ func listChannels(ctx *cli.Context) error {
return nil return nil
} }
var closedChannelsCommand = cli.Command{
Name: "closedchannels",
Category: "Channels",
Usage: "List all closed channels.",
Flags: []cli.Flag{
cli.BoolFlag{
Name: "cooperative",
Usage: "list channels that were closed cooperatively",
},
cli.BoolFlag{
Name: "local_force",
Usage: "list channels that were force-closed " +
"by the local node",
},
cli.BoolFlag{
Name: "remote_force",
Usage: "list channels that were force-closed " +
"by the remote node",
},
cli.BoolFlag{
Name: "breach",
Usage: "list channels for which the remote node " +
"attempted to broadcast a prior " +
"revoked channel state",
},
cli.BoolFlag{
Name: "funding_canceled",
Usage: "list channels that were never fully opened",
},
},
Action: actionDecorator(closedChannels),
}
func closedChannels(ctx *cli.Context) error {
ctxb := context.Background()
client, cleanUp := getClient(ctx)
defer cleanUp()
req := &lnrpc.ClosedChannelsRequest{
Cooperative: ctx.Bool("cooperative"),
LocalForce: ctx.Bool("local_force"),
RemoteForce: ctx.Bool("remote_force"),
Breach: ctx.Bool("breach"),
FundingCanceled: ctx.Bool("funding_cancelled"),
}
resp, err := client.ClosedChannels(ctxb, req)
if err != nil {
return err
}
printRespJSON(resp)
return nil
}
var sendPaymentCommand = cli.Command{ var sendPaymentCommand = cli.Command{
Name: "sendpayment", Name: "sendpayment",
Category: "Payments", Category: "Payments",
+1
View File
@@ -215,6 +215,7 @@ func main() {
lookupInvoiceCommand, lookupInvoiceCommand,
listInvoicesCommand, listInvoicesCommand,
listChannelsCommand, listChannelsCommand,
closedChannelsCommand,
listPaymentsCommand, listPaymentsCommand,
describeGraphCommand, describeGraphCommand,
getChanInfoCommand, getChanInfoCommand,
+699 -440
View File
File diff suppressed because it is too large. Load diff
+50
View File
@@ -217,6 +217,23 @@ func request_Lightning_ListChannels_0(ctx context.Context, marshaler runtime.Mar
} }
var (
filter_Lightning_ClosedChannels_0 = &utilities.DoubleArray{Encoding: map[string]int{}, Base: []int(nil), Check: []int(nil)}
)
func request_Lightning_ClosedChannels_0(ctx context.Context, marshaler runtime.Marshaler, client LightningClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq ClosedChannelsRequest
var metadata runtime.ServerMetadata
if err := runtime.PopulateQueryParameters(&protoReq, req.URL.Query(), filter_Lightning_ClosedChannels_0); err != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
msg, err := client.ClosedChannels(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
return msg, metadata, err
}
func request_Lightning_OpenChannelSync_0(ctx context.Context, marshaler runtime.Marshaler, client LightningClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) { func request_Lightning_OpenChannelSync_0(ctx context.Context, marshaler runtime.Marshaler, client LightningClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq OpenChannelRequest var protoReq OpenChannelRequest
var metadata runtime.ServerMetadata var metadata runtime.ServerMetadata
@@ -1108,6 +1125,35 @@ func RegisterLightningHandler(ctx context.Context, mux *runtime.ServeMux, conn *
}) })
mux.Handle("GET", pattern_Lightning_ClosedChannels_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(ctx)
defer cancel()
if cn, ok := w.(http.CloseNotifier); ok {
go func(done <-chan struct{}, closed <-chan bool) {
select {
case <-done:
case <-closed:
cancel()
}
}(ctx.Done(), cn.CloseNotify())
}
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
rctx, err := runtime.AnnotateContext(ctx, mux, req)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := request_Lightning_ClosedChannels_0(rctx, inboundMarshaler, client, req, pathParams)
ctx = runtime.NewServerMetadataContext(ctx, md)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
forward_Lightning_ClosedChannels_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
})
mux.Handle("POST", pattern_Lightning_OpenChannelSync_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) { mux.Handle("POST", pattern_Lightning_OpenChannelSync_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(ctx) ctx, cancel := context.WithCancel(ctx)
defer cancel() defer cancel()
@@ -1685,6 +1731,8 @@ var (
pattern_Lightning_ListChannels_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"v1", "channels"}, "")) pattern_Lightning_ListChannels_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"v1", "channels"}, ""))
pattern_Lightning_ClosedChannels_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"v1", "channels", "closed"}, ""))
pattern_Lightning_OpenChannelSync_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"v1", "channels"}, "")) pattern_Lightning_OpenChannelSync_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"v1", "channels"}, ""))
pattern_Lightning_CloseChannel_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 1, 0, 4, 1, 5, 2, 1, 0, 4, 1, 5, 3}, []string{"v1", "channels", "channel_point.funding_txid_str", "channel_point.output_index"}, "")) pattern_Lightning_CloseChannel_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 1, 0, 4, 1, 5, 2, 1, 0, 4, 1, 5, 3}, []string{"v1", "channels", "channel_point.funding_txid_str", "channel_point.output_index"}, ""))
@@ -1747,6 +1795,8 @@ var (
forward_Lightning_ListChannels_0 = runtime.ForwardResponseMessage forward_Lightning_ListChannels_0 = runtime.ForwardResponseMessage
forward_Lightning_ClosedChannels_0 = runtime.ForwardResponseMessage
forward_Lightning_OpenChannelSync_0 = runtime.ForwardResponseMessage forward_Lightning_OpenChannelSync_0 = runtime.ForwardResponseMessage
forward_Lightning_CloseChannel_0 = runtime.ForwardResponseStream forward_Lightning_CloseChannel_0 = runtime.ForwardResponseStream
+64
View File
@@ -341,6 +341,17 @@ service Lightning {
}; };
} }
/** lncli: `closedchannels`
ClosedChannels returns a description of all the closed channels that
this node was a participant in.
*/
rpc ClosedChannels (ClosedChannelsRequest) returns (ClosedChannelsResponse) {
option (google.api.http) = {
get: "/v1/channels/closed"
};
}
/** /**
OpenChannelSync is a synchronous version of the OpenChannel RPC call. This OpenChannelSync is a synchronous version of the OpenChannel RPC call. This
call is meant to be consumed by clients to the REST proxy. As with all call is meant to be consumed by clients to the REST proxy. As with all
@@ -920,6 +931,7 @@ message Channel {
bool private = 17 [json_name = "private"]; bool private = 17 [json_name = "private"];
} }
message ListChannelsRequest { message ListChannelsRequest {
bool active_only = 1; bool active_only = 1;
bool inactive_only = 2; bool inactive_only = 2;
@@ -931,6 +943,58 @@ message ListChannelsResponse {
repeated Channel channels = 11 [json_name = "channels"]; repeated Channel channels = 11 [json_name = "channels"];
} }
message ChannelCloseSummary {
/// The outpoint (txid:index) of the funding transaction.
string channel_point = 1 [json_name = "channel_point"];
/// The unique channel ID for the channel.
uint64 chan_id = 2 [json_name = "chan_id"];
/// The hash of the genesis block that this channel resides within.
string chain_hash = 3 [json_name = "chain_hash"];
/// The txid of the transaction which ultimately closed this channel.
string closing_tx_hash = 4 [json_name = "closing_tx_hash"];
/// Public key of the remote peer that we formerly had a channel with.
string remote_pubkey = 5 [json_name = "remote_pubkey"];
/// Total capacity of the channel.
int64 capacity = 6 [json_name = "capacity"];
/// Height at which the funding transaction was spent.
uint32 close_height = 7 [json_name = "close_height"];
/// Settled balance at the time of channel closure
int64 settled_balance = 8 [json_name = "settled_balance"];
/// The sum of all the time-locked outputs at the time of channel closure
int64 time_locked_balance = 9 [json_name = "time_locked_balance"];
enum ClosureType {
COOPERATIVE_CLOSE = 0;
LOCAL_FORCE_CLOSE = 1;
REMOTE_FORCE_CLOSE = 2;
BREACH_CLOSE = 3;
FUNDING_CANCELED = 4;
}
/// Details on how the channel was closed.
ClosureType close_type = 10 [json_name = "close_type"];
}
message ClosedChannelsRequest {
bool cooperative = 1;
bool local_force = 2;
bool remote_force = 3;
bool breach = 4;
bool funding_canceled = 5;
}
message ClosedChannelsResponse {
repeated ChannelCloseSummary channels = 1 [json_name = "channels"];
}
message Peer { message Peer {
/// The identity pubkey of the peer /// The identity pubkey of the peer
string pub_key = 1 [json_name = "pub_key"]; string pub_key = 1 [json_name = "pub_key"];
+126
View File
@@ -148,6 +148,60 @@
] ]
} }
}, },
"/v1/channels/closed": {
"get": {
"summary": "* lncli: `closedchannels`\nClosedChannels returns a description of all the closed channels that \nthis node was a participant in.",
"operationId": "ClosedChannels",
"responses": {
"200": {
"description": "",
"schema": {
"$ref": "#/definitions/lnrpcClosedChannelsResponse"
}
}
},
"parameters": [
{
"name": "cooperative",
"in": "query",
"required": false,
"type": "boolean",
"format": "boolean"
},
{
"name": "local_force",
"in": "query",
"required": false,
"type": "boolean",
"format": "boolean"
},
{
"name": "remote_force",
"in": "query",
"required": false,
"type": "boolean",
"format": "boolean"
},
{
"name": "breach",
"in": "query",
"required": false,
"type": "boolean",
"format": "boolean"
},
{
"name": "funding_canceled",
"in": "query",
"required": false,
"type": "boolean",
"format": "boolean"
}
],
"tags": [
"Lightning"
]
}
},
"/v1/channels/pending": { "/v1/channels/pending": {
"get": { "get": {
"summary": "* lncli: `pendingchannels`\nPendingChannels returns a list of all the channels that are currently\nconsidered \"pending\". A channel is pending if it has finished the funding\nworkflow and is waiting for confirmations for the funding txn, or is in the\nprocess of closure, either initiated cooperatively or non-cooperatively.", "summary": "* lncli: `pendingchannels`\nPendingChannels returns a list of all the channels that are currently\nconsidered \"pending\". A channel is pending if it has finished the funding\nworkflow and is waiting for confirmations for the funding txn, or is in the\nprocess of closure, either initiated cooperatively or non-cooperatively.",
@@ -867,6 +921,17 @@
} }
}, },
"definitions": { "definitions": {
"ChannelCloseSummaryClosureType": {
"type": "string",
"enum": [
"COOPERATIVE_CLOSE",
"LOCAL_FORCE_CLOSE",
"REMOTE_FORCE_CLOSE",
"BREACH_CLOSE",
"FUNDING_CANCELED"
],
"default": "COOPERATIVE_CLOSE"
},
"PendingChannelsResponseClosedChannel": { "PendingChannelsResponseClosedChannel": {
"type": "object", "type": "object",
"properties": { "properties": {
@@ -1121,6 +1186,56 @@
} }
} }
}, },
"lnrpcChannelCloseSummary": {
"type": "object",
"properties": {
"channel_point": {
"type": "string",
"description": "/ The outpoint (txid:index) of the funding transaction."
},
"chan_id": {
"type": "string",
"format": "uint64",
"description": "/ The unique channel ID for the channel."
},
"chain_hash": {
"type": "string",
"description": "/ The hash of the genesis block that this channel resides within."
},
"closing_tx_hash": {
"type": "string",
"description": "/ The txid of the transaction which ultimately closed this channel."
},
"remote_pubkey": {
"type": "string",
"description": "/ Public key of the remote peer that we formerly had a channel with."
},
"capacity": {
"type": "string",
"format": "int64",
"description": "/ Total capacity of the channel."
},
"close_height": {
"type": "integer",
"format": "int64",
"description": "/ Height at which the funding transaction was spent."
},
"settled_balance": {
"type": "string",
"format": "int64",
"title": "/ Settled balance at the time of channel closure"
},
"time_locked_balance": {
"type": "string",
"format": "int64",
"title": "/ The sum of all the time-locked outputs at the time of channel closure"
},
"close_type": {
"$ref": "#/definitions/ChannelCloseSummaryClosureType",
"description": "/ Details on how the channel was closed."
}
}
},
"lnrpcChannelCloseUpdate": { "lnrpcChannelCloseUpdate": {
"type": "object", "type": "object",
"properties": { "properties": {
@@ -1300,6 +1415,17 @@
} }
} }
}, },
"lnrpcClosedChannelsResponse": {
"type": "object",
"properties": {
"channels": {
"type": "array",
"items": {
"$ref": "#/definitions/lnrpcChannelCloseSummary"
}
}
}
},
"lnrpcConfirmationUpdate": { "lnrpcConfirmationUpdate": {
"type": "object", "type": "object",
"properties": { "properties": {
+77
View File
@@ -223,6 +223,10 @@ var (
Entity: "offchain", Entity: "offchain",
Action: "read", Action: "read",
}}, }},
"/lnrpc.Lightning/ClosedChannels": {{
Entity: "offchain",
Action: "read",
}},
"/lnrpc.Lightning/SendPayment": {{ "/lnrpc.Lightning/SendPayment": {{
Entity: "offchain", Entity: "offchain",
Action: "write", Action: "write",
@@ -1579,6 +1583,79 @@ func (r *rpcServer) PendingChannels(ctx context.Context,
return resp, nil return resp, nil
} }
// ClosedChannels returns a list of all the channels have been closed.
// This does not include channels that are still in the process of closing.
func (r *rpcServer) ClosedChannels(ctx context.Context,
in *lnrpc.ClosedChannelsRequest) (*lnrpc.ClosedChannelsResponse,
error) {
// Show all channels when no filter flags are set.
filterResults := in.Cooperative || in.LocalForce ||
in.RemoteForce || in.Breach || in.FundingCanceled
resp := &lnrpc.ClosedChannelsResponse{}
dbChannels, err := r.server.chanDB.FetchClosedChannels(false)
if err != nil {
return nil, err
}
for _, dbChannel := range dbChannels {
if dbChannel.IsPending {
continue
}
nodePub := dbChannel.RemotePub
nodeID := hex.EncodeToString(nodePub.SerializeCompressed())
var closeType lnrpc.ChannelCloseSummary_ClosureType
switch dbChannel.CloseType {
case channeldb.CooperativeClose:
if filterResults && !in.Cooperative {
continue
}
closeType = lnrpc.ChannelCloseSummary_COOPERATIVE_CLOSE
case channeldb.LocalForceClose:
if filterResults && !in.LocalForce {
continue
}
closeType = lnrpc.ChannelCloseSummary_LOCAL_FORCE_CLOSE
case channeldb.RemoteForceClose:
if filterResults && !in.RemoteForce {
continue
}
closeType = lnrpc.ChannelCloseSummary_REMOTE_FORCE_CLOSE
case channeldb.BreachClose:
if filterResults && !in.Breach {
continue
}
closeType = lnrpc.ChannelCloseSummary_BREACH_CLOSE
case channeldb.FundingCanceled:
if filterResults && !in.FundingCanceled {
continue
}
closeType = lnrpc.ChannelCloseSummary_FUNDING_CANCELED
}
channel := &lnrpc.ChannelCloseSummary{
Capacity: int64(dbChannel.Capacity),
RemotePubkey: nodeID,
CloseHeight: dbChannel.CloseHeight,
CloseType: closeType,
ChannelPoint: dbChannel.ChanPoint.String(),
ChanId: dbChannel.ShortChanID.ToUint64(),
SettledBalance: int64(dbChannel.SettledBalance),
TimeLockedBalance: int64(dbChannel.TimeLockedBalance),
ChainHash: dbChannel.ChainHash.String(),
ClosingTxHash: dbChannel.ClosingTXID.String(),
}
resp.Channels = append(resp.Channels, channel)
}
return resp, nil
}
// ListChannels returns a description of all the open channels that this node // ListChannels returns a description of all the open channels that this node
// is a participant in. // is a participant in.
func (r *rpcServer) ListChannels(ctx context.Context, func (r *rpcServer) ListChannels(ctx context.Context,