|
|
@ -50,6 +50,9 @@ type LightningClient interface {
|
|
|
|
// ListChannels retrieves all channels of the backing lnd node.
|
|
|
|
// ListChannels retrieves all channels of the backing lnd node.
|
|
|
|
ListChannels(ctx context.Context) ([]ChannelInfo, error)
|
|
|
|
ListChannels(ctx context.Context) ([]ChannelInfo, error)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// ClosedChannels returns all closed channels of the backing lnd node.
|
|
|
|
|
|
|
|
ClosedChannels(ctx context.Context) ([]ClosedChannel, error)
|
|
|
|
|
|
|
|
|
|
|
|
// ChannelBackup retrieves the backup for a particular channel. The
|
|
|
|
// ChannelBackup retrieves the backup for a particular channel. The
|
|
|
|
// backup is returned as an encrypted chanbackup.Single payload.
|
|
|
|
// backup is returned as an encrypted chanbackup.Single payload.
|
|
|
|
ChannelBackup(context.Context, wire.OutPoint) ([]byte, error)
|
|
|
|
ChannelBackup(context.Context, wire.OutPoint) ([]byte, error)
|
|
|
@ -109,6 +112,138 @@ type ChannelInfo struct {
|
|
|
|
Uptime time.Duration
|
|
|
|
Uptime time.Duration
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// ClosedChannel represents a channel that has been closed.
|
|
|
|
|
|
|
|
type ClosedChannel struct {
|
|
|
|
|
|
|
|
// ChannelPoint is the funding outpoint of the channel.
|
|
|
|
|
|
|
|
ChannelPoint string
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// ChannelID holds the unique channel ID for the channel. The first 3
|
|
|
|
|
|
|
|
// bytes are the block height, the next 3 the index within the block,
|
|
|
|
|
|
|
|
// and the last 2 bytes are the output index for the channel.
|
|
|
|
|
|
|
|
ChannelID uint64
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// ClosingTxHash is the tx hash of the close transaction for the channel.
|
|
|
|
|
|
|
|
ClosingTxHash string
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// CloseType is the type of channel closure.
|
|
|
|
|
|
|
|
CloseType CloseType
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// OpenInitiator is true if we opened the channel. This value is not
|
|
|
|
|
|
|
|
// always available (older channels do not have it).
|
|
|
|
|
|
|
|
OpenInitiator Initiator
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Initiator indicates which party initiated the channel close. Since
|
|
|
|
|
|
|
|
// this value is not always set in the rpc response, we also make a best
|
|
|
|
|
|
|
|
// effort attempt to set it based on CloseType.
|
|
|
|
|
|
|
|
CloseInitiator Initiator
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// PubKeyBytes is the raw bytes of the public key of the remote node.
|
|
|
|
|
|
|
|
PubKeyBytes route.Vertex
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Capacity is the total amount of funds held in this channel.
|
|
|
|
|
|
|
|
Capacity btcutil.Amount
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// SettledBalance is the amount we were paid out directly in this
|
|
|
|
|
|
|
|
// channel close. Note that this does not include cases where we need to
|
|
|
|
|
|
|
|
// sweep our commitment or htlcs.
|
|
|
|
|
|
|
|
SettledBalance btcutil.Amount
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// CloseType is an enum which represents the types of closes our channels may
|
|
|
|
|
|
|
|
// have. This type maps to the rpc value.
|
|
|
|
|
|
|
|
type CloseType uint8
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const (
|
|
|
|
|
|
|
|
// CloseTypeCooperative represents cooperative closes.
|
|
|
|
|
|
|
|
CloseTypeCooperative CloseType = iota
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// CloseTypeLocalForce represents force closes that we initiated.
|
|
|
|
|
|
|
|
CloseTypeLocalForce
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// CloseTypeRemoteForce represents force closes that our peer initiated.
|
|
|
|
|
|
|
|
CloseTypeRemoteForce
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// CloseTypeBreach represents breach closes from our peer.
|
|
|
|
|
|
|
|
CloseTypeBreach
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// CloseTypeFundingCancelled represents channels which were never
|
|
|
|
|
|
|
|
// created because their funding transaction was cancelled.
|
|
|
|
|
|
|
|
CloseTypeFundingCancelled
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// CloseTypeAbandoned represents a channel that was abandoned.
|
|
|
|
|
|
|
|
CloseTypeAbandoned
|
|
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// String returns the string representation of a close type.
|
|
|
|
|
|
|
|
func (c CloseType) String() string {
|
|
|
|
|
|
|
|
switch c {
|
|
|
|
|
|
|
|
case CloseTypeCooperative:
|
|
|
|
|
|
|
|
return "Cooperative"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
case CloseTypeLocalForce:
|
|
|
|
|
|
|
|
return "Local Force"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
case CloseTypeRemoteForce:
|
|
|
|
|
|
|
|
return "Remote Force"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
case CloseTypeBreach:
|
|
|
|
|
|
|
|
return "Breach"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
case CloseTypeFundingCancelled:
|
|
|
|
|
|
|
|
return "Funding Cancelled"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
case CloseTypeAbandoned:
|
|
|
|
|
|
|
|
return "Abandoned"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
|
|
|
return "Unknown"
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Initiator indicates the party that opened or closed a channel. This enum is
|
|
|
|
|
|
|
|
// used for cases where we may not have a full set of initiator information
|
|
|
|
|
|
|
|
// available over rpc (this is the case for older channels).
|
|
|
|
|
|
|
|
type Initiator uint8
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const (
|
|
|
|
|
|
|
|
// InitiatorUnrecorded is set when we do not know the open/close
|
|
|
|
|
|
|
|
// initiator for a channel, this is the case when the channel was
|
|
|
|
|
|
|
|
// closed before lnd started tracking initiators.
|
|
|
|
|
|
|
|
InitiatorUnrecorded Initiator = iota
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// InitiatorLocal is set when we initiated a channel open or close.
|
|
|
|
|
|
|
|
InitiatorLocal
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// InitiatorRemote is set when the remote party initiated a chanel open
|
|
|
|
|
|
|
|
// or close.
|
|
|
|
|
|
|
|
InitiatorRemote
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// InitiatorBoth is set in the case where both parties initiated a
|
|
|
|
|
|
|
|
// cooperative close (this is possible with multiple rounds of
|
|
|
|
|
|
|
|
// negotiation).
|
|
|
|
|
|
|
|
InitiatorBoth
|
|
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// String provides the string represenetation of a close initiator.
|
|
|
|
|
|
|
|
func (c Initiator) String() string {
|
|
|
|
|
|
|
|
switch c {
|
|
|
|
|
|
|
|
case InitiatorUnrecorded:
|
|
|
|
|
|
|
|
return "Unrecorded"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
case InitiatorLocal:
|
|
|
|
|
|
|
|
return "Local"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
case InitiatorRemote:
|
|
|
|
|
|
|
|
return "Remote"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
case InitiatorBoth:
|
|
|
|
|
|
|
|
return "Both"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
|
|
|
return fmt.Sprintf("unknown initiator: %d", c)
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
var (
|
|
|
|
var (
|
|
|
|
// ErrMalformedServerResponse is returned when the swap and/or prepay
|
|
|
|
// ErrMalformedServerResponse is returned when the swap and/or prepay
|
|
|
|
// invoice is malformed.
|
|
|
|
// invoice is malformed.
|
|
|
@ -583,6 +718,130 @@ func (s *lightningClient) ListChannels(ctx context.Context) (
|
|
|
|
return result, nil
|
|
|
|
return result, nil
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// ClosedChannels returns a list of our closed channels.
|
|
|
|
|
|
|
|
func (s *lightningClient) ClosedChannels(ctx context.Context) ([]ClosedChannel,
|
|
|
|
|
|
|
|
error) {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
rpcCtx, cancel := context.WithTimeout(ctx, rpcTimeout)
|
|
|
|
|
|
|
|
defer cancel()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
response, err := s.client.ClosedChannels(
|
|
|
|
|
|
|
|
s.adminMac.WithMacaroonAuth(rpcCtx),
|
|
|
|
|
|
|
|
&lnrpc.ClosedChannelsRequest{},
|
|
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
|
|
return nil, err
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
channels := make([]ClosedChannel, len(response.Channels))
|
|
|
|
|
|
|
|
for i, channel := range response.Channels {
|
|
|
|
|
|
|
|
remote, err := route.NewVertexFromStr(channel.RemotePubkey)
|
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
|
|
return nil, err
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
closeType, err := rpcCloseType(channel.CloseType)
|
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
|
|
return nil, err
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
openInitiator, err := getInitiator(channel.OpenInitiator)
|
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
|
|
return nil, err
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
closeInitiator, err := rpcCloseInitiator(
|
|
|
|
|
|
|
|
channel.CloseInitiator, closeType,
|
|
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
|
|
return nil, err
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
channels[i] = ClosedChannel{
|
|
|
|
|
|
|
|
ChannelPoint: channel.ChannelPoint,
|
|
|
|
|
|
|
|
ChannelID: channel.ChanId,
|
|
|
|
|
|
|
|
ClosingTxHash: channel.ClosingTxHash,
|
|
|
|
|
|
|
|
CloseType: closeType,
|
|
|
|
|
|
|
|
OpenInitiator: openInitiator,
|
|
|
|
|
|
|
|
CloseInitiator: closeInitiator,
|
|
|
|
|
|
|
|
PubKeyBytes: remote,
|
|
|
|
|
|
|
|
Capacity: btcutil.Amount(channel.Capacity),
|
|
|
|
|
|
|
|
SettledBalance: btcutil.Amount(channel.SettledBalance),
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return channels, nil
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// rpcCloseType maps a rpc close type to our local enum.
|
|
|
|
|
|
|
|
func rpcCloseType(t lnrpc.ChannelCloseSummary_ClosureType) (CloseType, error) {
|
|
|
|
|
|
|
|
switch t {
|
|
|
|
|
|
|
|
case lnrpc.ChannelCloseSummary_COOPERATIVE_CLOSE:
|
|
|
|
|
|
|
|
return CloseTypeCooperative, nil
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
case lnrpc.ChannelCloseSummary_LOCAL_FORCE_CLOSE:
|
|
|
|
|
|
|
|
return CloseTypeLocalForce, nil
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
case lnrpc.ChannelCloseSummary_REMOTE_FORCE_CLOSE:
|
|
|
|
|
|
|
|
return CloseTypeRemoteForce, nil
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
case lnrpc.ChannelCloseSummary_BREACH_CLOSE:
|
|
|
|
|
|
|
|
return CloseTypeBreach, nil
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
case lnrpc.ChannelCloseSummary_FUNDING_CANCELED:
|
|
|
|
|
|
|
|
return CloseTypeFundingCancelled, nil
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
case lnrpc.ChannelCloseSummary_ABANDONED:
|
|
|
|
|
|
|
|
return CloseTypeAbandoned, nil
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
|
|
|
return 0, fmt.Errorf("unknown close type: %v", t)
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// rpcCloseInitiator maps a close initiator to our local type. Since this field
|
|
|
|
|
|
|
|
// is not always set in lnd for older channels, also use our close type to infer
|
|
|
|
|
|
|
|
// who initiated the close when we have force closes.
|
|
|
|
|
|
|
|
func rpcCloseInitiator(initiator lnrpc.Initiator,
|
|
|
|
|
|
|
|
closeType CloseType) (Initiator, error) {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Since our close type is always set on the rpc, we first check whether
|
|
|
|
|
|
|
|
// we can figure out the close initiator from this value. This is only
|
|
|
|
|
|
|
|
// possible for force closes/breaches.
|
|
|
|
|
|
|
|
switch closeType {
|
|
|
|
|
|
|
|
case CloseTypeLocalForce:
|
|
|
|
|
|
|
|
return InitiatorLocal, nil
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
case CloseTypeRemoteForce, CloseTypeBreach:
|
|
|
|
|
|
|
|
return InitiatorRemote, nil
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Otherwise, we check whether our initiator field is set, and fail only
|
|
|
|
|
|
|
|
// if we have an unknown type.
|
|
|
|
|
|
|
|
return getInitiator(initiator)
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// getInitiator maps a rpc initiator value to our initiator enum.
|
|
|
|
|
|
|
|
func getInitiator(initiator lnrpc.Initiator) (Initiator, error) {
|
|
|
|
|
|
|
|
switch initiator {
|
|
|
|
|
|
|
|
case lnrpc.Initiator_INITIATOR_LOCAL:
|
|
|
|
|
|
|
|
return InitiatorLocal, nil
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
case lnrpc.Initiator_INITIATOR_REMOTE:
|
|
|
|
|
|
|
|
return InitiatorRemote, nil
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
case lnrpc.Initiator_INITIATOR_BOTH:
|
|
|
|
|
|
|
|
return InitiatorBoth, nil
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
case lnrpc.Initiator_INITIATOR_UNKNOWN:
|
|
|
|
|
|
|
|
return InitiatorUnrecorded, nil
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
|
|
|
return InitiatorUnrecorded, fmt.Errorf("unknown "+
|
|
|
|
|
|
|
|
"initiator: %v", initiator)
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// ChannelBackup retrieves the backup for a particular channel. The backup is
|
|
|
|
// ChannelBackup retrieves the backup for a particular channel. The backup is
|
|
|
|
// returned as an encrypted chanbackup.Single payload.
|
|
|
|
// returned as an encrypted chanbackup.Single payload.
|
|
|
|
func (s *lightningClient) ChannelBackup(ctx context.Context,
|
|
|
|
func (s *lightningClient) ChannelBackup(ctx context.Context,
|
|
|
|