Merge pull request #1274 from joostjager/closechannels-squashed

rpc+lnrpc: add new closechannels cli+rpc command
This commit is contained in:
Olaoluwa Osuntokun 2018-06-13 17:35:35 -07:00 committed by GitHub
commit c1a1b3ba3d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 1075 additions and 440 deletions

2
.gitignore vendored
View File

@ -25,7 +25,9 @@ _testmain.go
*.prof
lnd
lnd-debug
lncli
lncli-debug
output*.log

View File

@ -1581,6 +1581,62 @@ func listChannels(ctx *cli.Context) error {
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{
Name: "sendpayment",
Category: "Payments",

View File

@ -215,6 +215,7 @@ func main() {
lookupInvoiceCommand,
listInvoicesCommand,
listChannelsCommand,
closedChannelsCommand,
listPaymentsCommand,
describeGraphCommand,
getChanInfoCommand,

File diff suppressed because it is too large Load Diff

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) {
var protoReq OpenChannelRequest
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) {
ctx, cancel := context.WithCancel(ctx)
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_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_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_ClosedChannels_0 = runtime.ForwardResponseMessage
forward_Lightning_OpenChannelSync_0 = runtime.ForwardResponseMessage
forward_Lightning_CloseChannel_0 = runtime.ForwardResponseStream

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
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"];
}
message ListChannelsRequest {
bool active_only = 1;
bool inactive_only = 2;
@ -931,6 +943,58 @@ message ListChannelsResponse {
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 {
/// The identity pubkey of the peer
string pub_key = 1 [json_name = "pub_key"];

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": {
"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.",
@ -867,6 +921,17 @@
}
},
"definitions": {
"ChannelCloseSummaryClosureType": {
"type": "string",
"enum": [
"COOPERATIVE_CLOSE",
"LOCAL_FORCE_CLOSE",
"REMOTE_FORCE_CLOSE",
"BREACH_CLOSE",
"FUNDING_CANCELED"
],
"default": "COOPERATIVE_CLOSE"
},
"PendingChannelsResponseClosedChannel": {
"type": "object",
"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": {
"type": "object",
"properties": {
@ -1300,6 +1415,17 @@
}
}
},
"lnrpcClosedChannelsResponse": {
"type": "object",
"properties": {
"channels": {
"type": "array",
"items": {
"$ref": "#/definitions/lnrpcChannelCloseSummary"
}
}
}
},
"lnrpcConfirmationUpdate": {
"type": "object",
"properties": {

View File

@ -223,6 +223,10 @@ var (
Entity: "offchain",
Action: "read",
}},
"/lnrpc.Lightning/ClosedChannels": {{
Entity: "offchain",
Action: "read",
}},
"/lnrpc.Lightning/SendPayment": {{
Entity: "offchain",
Action: "write",
@ -1579,6 +1583,79 @@ func (r *rpcServer) PendingChannels(ctx context.Context,
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
// is a participant in.
func (r *rpcServer) ListChannels(ctx context.Context,