mirror of
https://github.com/lightninglabs/loop.git
synced 2026-08-16 13:00:37 +02:00
lndclient: add closed channels to lnd client
This commit is contained in:
parent
11a04e65ff
commit
c1a9889e4d
3 changed files with 268 additions and 1 deletions
|
|
@ -50,6 +50,9 @@ type LightningClient interface {
|
|||
// ListChannels retrieves all channels of the backing lnd node.
|
||||
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
|
||||
// backup is returned as an encrypted chanbackup.Single payload.
|
||||
ChannelBackup(context.Context, wire.OutPoint) ([]byte, error)
|
||||
|
|
@ -109,6 +112,138 @@ type ChannelInfo struct {
|
|||
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 (
|
||||
// ErrMalformedServerResponse is returned when the swap and/or prepay
|
||||
// invoice is malformed.
|
||||
|
|
@ -583,6 +718,130 @@ func (s *lightningClient) ListChannels(ctx context.Context) (
|
|||
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
|
||||
// returned as an encrypted chanbackup.Single payload.
|
||||
func (s *lightningClient) ChannelBackup(ctx context.Context,
|
||||
|
|
|
|||
|
|
@ -175,6 +175,13 @@ func (h *mockLightningClient) ListChannels(ctx context.Context) (
|
|||
return h.lnd.Channels, nil
|
||||
}
|
||||
|
||||
// ClosedChannels returns a list of our closed channels.
|
||||
func (h *mockLightningClient) ClosedChannels(_ context.Context) ([]lndclient.ClosedChannel,
|
||||
error) {
|
||||
|
||||
return h.lnd.ClosedChannels, nil
|
||||
}
|
||||
|
||||
// ChannelBackup retrieves the backup for a particular channel. The
|
||||
// backup is returned as an encrypted chanbackup.Single payload.
|
||||
func (h *mockLightningClient) ChannelBackup(context.Context, wire.OutPoint) ([]byte, error) {
|
||||
|
|
|
|||
|
|
@ -163,7 +163,8 @@ type LndMockServices struct {
|
|||
// keyed by hash string.
|
||||
Invoices map[lntypes.Hash]*lndclient.Invoice
|
||||
|
||||
Channels []lndclient.ChannelInfo
|
||||
Channels []lndclient.ChannelInfo
|
||||
ClosedChannels []lndclient.ClosedChannel
|
||||
|
||||
WaitForFinished func()
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue