|
|
|
@ -10,10 +10,12 @@ import (
|
|
|
|
|
"github.com/btcsuite/btcd/btcutil"
|
|
|
|
|
"github.com/btcsuite/btcd/chaincfg"
|
|
|
|
|
"github.com/btcsuite/btcd/chaincfg/chainhash"
|
|
|
|
|
"github.com/btcsuite/btcd/txscript"
|
|
|
|
|
"github.com/lightningnetwork/lnd/chanbackup"
|
|
|
|
|
"github.com/lightningnetwork/lnd/channeldb"
|
|
|
|
|
"github.com/lightningnetwork/lnd/input"
|
|
|
|
|
"github.com/lightningnetwork/lnd/keychain"
|
|
|
|
|
"github.com/lightningnetwork/lnd/lnwallet"
|
|
|
|
|
"github.com/lightningnetwork/lnd/lnwire"
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
@ -21,14 +23,14 @@ const (
|
|
|
|
|
lndInternalDerivationPath = "m/1017'/%d'/%d'/0/%d"
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
// BackupSingle is the information we want to dump from an lnd channel backup
|
|
|
|
|
// BackupMulti is the information we want to dump from a lnd channel backup
|
|
|
|
|
// multi file. See `chanbackup.Multi` for information about the fields.
|
|
|
|
|
type BackupMulti struct {
|
|
|
|
|
Version chanbackup.MultiBackupVersion
|
|
|
|
|
StaticBackups []BackupSingle
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// BackupSingle is the information we want to dump from an lnd channel backup.
|
|
|
|
|
// BackupSingle is the information we want to dump from a lnd channel backup.
|
|
|
|
|
// See `chanbackup.Single` for information about the fields.
|
|
|
|
|
type BackupSingle struct {
|
|
|
|
|
Version chanbackup.SingleBackupVersion
|
|
|
|
@ -57,6 +59,7 @@ type OpenChannel struct {
|
|
|
|
|
FundingBroadcastHeight uint32
|
|
|
|
|
NumConfsRequired uint16
|
|
|
|
|
ChannelFlags lnwire.FundingFlag
|
|
|
|
|
ThawHeight uint32
|
|
|
|
|
IdentityPub string
|
|
|
|
|
Capacity btcutil.Amount
|
|
|
|
|
TotalMSatSent lnwire.MilliSatoshi
|
|
|
|
@ -66,6 +69,8 @@ type OpenChannel struct {
|
|
|
|
|
RemoteChanCfg ChannelConfig
|
|
|
|
|
LocalCommitment channeldb.ChannelCommitment
|
|
|
|
|
RemoteCommitment channeldb.ChannelCommitment
|
|
|
|
|
LocalCommitmentDebug ChannelDebugInfo
|
|
|
|
|
RemoteCommitmentDebug ChannelDebugInfo
|
|
|
|
|
RemoteCurrentRevocation string
|
|
|
|
|
RemoteNextRevocation string
|
|
|
|
|
FundingTxn string
|
|
|
|
@ -73,24 +78,38 @@ type OpenChannel struct {
|
|
|
|
|
RemoteShutdownScript lnwire.DeliveryAddress
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ChannelDebugInfo is a struct that holds additional information about an open
|
|
|
|
|
// or pending channel that is useful for debugging.
|
|
|
|
|
type ChannelDebugInfo struct {
|
|
|
|
|
ToLocalScript string
|
|
|
|
|
ToLocalAddr string
|
|
|
|
|
ToRemoteScript string
|
|
|
|
|
ToRemoteAddr string
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ClosedChannel is the information we want to dump from a closed channel in
|
|
|
|
|
// lnd's channel DB. See `channeldb.ChannelCloseSummary` for information about
|
|
|
|
|
// the fields.
|
|
|
|
|
type ClosedChannel struct {
|
|
|
|
|
ChanPoint string
|
|
|
|
|
ShortChanID lnwire.ShortChannelID
|
|
|
|
|
ChainHash chainhash.Hash
|
|
|
|
|
ClosingTXID string
|
|
|
|
|
RemotePub string
|
|
|
|
|
Capacity btcutil.Amount
|
|
|
|
|
CloseHeight uint32
|
|
|
|
|
SettledBalance btcutil.Amount
|
|
|
|
|
TimeLockedBalance btcutil.Amount
|
|
|
|
|
CloseType string
|
|
|
|
|
IsPending bool
|
|
|
|
|
RemoteCurrentRevocation string
|
|
|
|
|
RemoteNextRevocation string
|
|
|
|
|
LocalChanConfig ChannelConfig
|
|
|
|
|
ChanPoint string
|
|
|
|
|
ShortChanID lnwire.ShortChannelID
|
|
|
|
|
ChainHash chainhash.Hash
|
|
|
|
|
ClosingTXID string
|
|
|
|
|
RemotePub string
|
|
|
|
|
Capacity btcutil.Amount
|
|
|
|
|
CloseHeight uint32
|
|
|
|
|
SettledBalance btcutil.Amount
|
|
|
|
|
TimeLockedBalance btcutil.Amount
|
|
|
|
|
CloseType string
|
|
|
|
|
IsPending bool
|
|
|
|
|
RemoteCurrentRevocation string
|
|
|
|
|
RemoteNextRevocation string
|
|
|
|
|
LocalChanConfig ChannelConfig
|
|
|
|
|
NextLocalCommitHeight uint64
|
|
|
|
|
RemoteCommitTailHeight uint64
|
|
|
|
|
LastRemoteCommitSecret string
|
|
|
|
|
LocalUnrevokedCommitPoint string
|
|
|
|
|
HistoricalChannel *OpenChannel
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ChannelConfig is the information we want to dump from a channel
|
|
|
|
@ -119,68 +138,194 @@ func OpenChannelDump(channels []*channeldb.OpenChannel,
|
|
|
|
|
|
|
|
|
|
dumpChannels := make([]OpenChannel, len(channels))
|
|
|
|
|
for idx, channel := range channels {
|
|
|
|
|
var buf bytes.Buffer
|
|
|
|
|
if channel.FundingTxn != nil {
|
|
|
|
|
err := channel.FundingTxn.Serialize(&buf)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
openChan, err := openChannelDump(channel, params)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, fmt.Errorf("error converting to dump "+
|
|
|
|
|
"format: %w", err)
|
|
|
|
|
}
|
|
|
|
|
revPreimage, err := channel.RevocationProducer.AtIndex(
|
|
|
|
|
channel.LocalCommitment.CommitHeight,
|
|
|
|
|
)
|
|
|
|
|
dumpChannels[idx] = *openChan
|
|
|
|
|
}
|
|
|
|
|
return dumpChannels, nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func openChannelDump(channel *channeldb.OpenChannel,
|
|
|
|
|
params *chaincfg.Params) (*OpenChannel, error) {
|
|
|
|
|
|
|
|
|
|
var buf bytes.Buffer
|
|
|
|
|
if channel.FundingTxn != nil {
|
|
|
|
|
err := channel.FundingTxn.Serialize(&buf)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
perCommitPoint := input.ComputeCommitmentPoint(revPreimage[:])
|
|
|
|
|
|
|
|
|
|
dumpChannels[idx] = OpenChannel{
|
|
|
|
|
ChanType: channel.ChanType,
|
|
|
|
|
ChainHash: channel.ChainHash,
|
|
|
|
|
FundingOutpoint: channel.FundingOutpoint.String(),
|
|
|
|
|
ShortChannelID: channel.ShortChannelID,
|
|
|
|
|
IsPending: channel.IsPending,
|
|
|
|
|
IsInitiator: channel.IsInitiator,
|
|
|
|
|
ChanStatus: channel.ChanStatus(),
|
|
|
|
|
FundingBroadcastHeight: channel.FundingBroadcastHeight,
|
|
|
|
|
NumConfsRequired: channel.NumConfsRequired,
|
|
|
|
|
ChannelFlags: channel.ChannelFlags,
|
|
|
|
|
IdentityPub: PubKeyToString(
|
|
|
|
|
channel.IdentityPub,
|
|
|
|
|
),
|
|
|
|
|
Capacity: channel.Capacity,
|
|
|
|
|
TotalMSatSent: channel.TotalMSatSent,
|
|
|
|
|
TotalMSatReceived: channel.TotalMSatReceived,
|
|
|
|
|
PerCommitPoint: PubKeyToString(perCommitPoint),
|
|
|
|
|
LocalChanCfg: ToChannelConfig(
|
|
|
|
|
params, channel.LocalChanCfg,
|
|
|
|
|
),
|
|
|
|
|
RemoteChanCfg: ToChannelConfig(
|
|
|
|
|
params, channel.RemoteChanCfg,
|
|
|
|
|
),
|
|
|
|
|
LocalCommitment: channel.LocalCommitment,
|
|
|
|
|
RemoteCommitment: channel.RemoteCommitment,
|
|
|
|
|
RemoteCurrentRevocation: PubKeyToString(
|
|
|
|
|
channel.RemoteCurrentRevocation,
|
|
|
|
|
),
|
|
|
|
|
RemoteNextRevocation: PubKeyToString(
|
|
|
|
|
channel.RemoteNextRevocation,
|
|
|
|
|
),
|
|
|
|
|
FundingTxn: hex.EncodeToString(buf.Bytes()),
|
|
|
|
|
LocalShutdownScript: channel.LocalShutdownScript,
|
|
|
|
|
RemoteShutdownScript: channel.RemoteShutdownScript,
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return dumpChannels, nil
|
|
|
|
|
revPreimage, err := channel.RevocationProducer.AtIndex(
|
|
|
|
|
channel.LocalCommitment.CommitHeight,
|
|
|
|
|
)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
perCommitPoint := input.ComputeCommitmentPoint(revPreimage[:])
|
|
|
|
|
|
|
|
|
|
openChan := &OpenChannel{
|
|
|
|
|
ChanType: channel.ChanType,
|
|
|
|
|
ChainHash: channel.ChainHash,
|
|
|
|
|
FundingOutpoint: channel.FundingOutpoint.String(),
|
|
|
|
|
ShortChannelID: channel.ShortChannelID,
|
|
|
|
|
IsPending: channel.IsPending,
|
|
|
|
|
IsInitiator: channel.IsInitiator,
|
|
|
|
|
ChanStatus: channel.ChanStatus(),
|
|
|
|
|
FundingBroadcastHeight: channel.FundingBroadcastHeight,
|
|
|
|
|
NumConfsRequired: channel.NumConfsRequired,
|
|
|
|
|
ChannelFlags: channel.ChannelFlags,
|
|
|
|
|
ThawHeight: channel.ThawHeight,
|
|
|
|
|
IdentityPub: PubKeyToString(
|
|
|
|
|
channel.IdentityPub,
|
|
|
|
|
),
|
|
|
|
|
Capacity: channel.Capacity,
|
|
|
|
|
TotalMSatSent: channel.TotalMSatSent,
|
|
|
|
|
TotalMSatReceived: channel.TotalMSatReceived,
|
|
|
|
|
PerCommitPoint: PubKeyToString(perCommitPoint),
|
|
|
|
|
LocalChanCfg: ToChannelConfig(
|
|
|
|
|
params, channel.LocalChanCfg,
|
|
|
|
|
),
|
|
|
|
|
RemoteChanCfg: ToChannelConfig(
|
|
|
|
|
params, channel.RemoteChanCfg,
|
|
|
|
|
),
|
|
|
|
|
LocalCommitment: channel.LocalCommitment,
|
|
|
|
|
RemoteCommitment: channel.RemoteCommitment,
|
|
|
|
|
RemoteCurrentRevocation: PubKeyToString(
|
|
|
|
|
channel.RemoteCurrentRevocation,
|
|
|
|
|
),
|
|
|
|
|
RemoteNextRevocation: PubKeyToString(
|
|
|
|
|
channel.RemoteNextRevocation,
|
|
|
|
|
),
|
|
|
|
|
FundingTxn: hex.EncodeToString(buf.Bytes()),
|
|
|
|
|
LocalShutdownScript: channel.LocalShutdownScript,
|
|
|
|
|
RemoteShutdownScript: channel.RemoteShutdownScript,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
localDebug, err := CollectDebugInfo(
|
|
|
|
|
channel, perCommitPoint, true, channel.IsInitiator, params,
|
|
|
|
|
)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, fmt.Errorf("error collecting local debug info: %w",
|
|
|
|
|
err)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
remoteDebug, err := CollectDebugInfo(
|
|
|
|
|
channel, channel.RemoteCurrentRevocation, false,
|
|
|
|
|
!channel.IsInitiator, params,
|
|
|
|
|
)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, fmt.Errorf("error collecting remote debug info: %w",
|
|
|
|
|
err)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
openChan.LocalCommitmentDebug = *localDebug
|
|
|
|
|
openChan.RemoteCommitmentDebug = *remoteDebug
|
|
|
|
|
|
|
|
|
|
return openChan, nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// CollectDebugInfo collects the additional debug information for the given
|
|
|
|
|
// channel.
|
|
|
|
|
func CollectDebugInfo(channel *channeldb.OpenChannel,
|
|
|
|
|
commitPoint *btcec.PublicKey, ourCommit, initiator bool,
|
|
|
|
|
params *chaincfg.Params) (*ChannelDebugInfo, error) {
|
|
|
|
|
|
|
|
|
|
chanType := channel.ChanType
|
|
|
|
|
ourChanCfg := &channel.LocalChanCfg
|
|
|
|
|
theirChanCfg := &channel.RemoteChanCfg
|
|
|
|
|
leaseExpiry := channel.ThawHeight
|
|
|
|
|
|
|
|
|
|
keyRing := lnwallet.DeriveCommitmentKeys(
|
|
|
|
|
commitPoint, ourCommit, chanType, ourChanCfg, theirChanCfg,
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
// First, we create the script for the delayed "pay-to-self" output.
|
|
|
|
|
// This output has 2 main redemption clauses: either we can redeem the
|
|
|
|
|
// output after a relative block delay, or the remote node can claim
|
|
|
|
|
// the funds with the revocation key if we broadcast a revoked
|
|
|
|
|
// commitment transaction.
|
|
|
|
|
toLocalScript, err := lnwallet.CommitScriptToSelf(
|
|
|
|
|
chanType, initiator, keyRing.ToLocalKey, keyRing.RevocationKey,
|
|
|
|
|
uint32(ourChanCfg.CsvDelay), leaseExpiry,
|
|
|
|
|
)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Next, we create the script paying to the remote.
|
|
|
|
|
toRemoteScript, _, err := lnwallet.CommitScriptToRemote(
|
|
|
|
|
chanType, initiator, keyRing.ToRemoteKey, leaseExpiry,
|
|
|
|
|
)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
toLocalPkScript, err := txscript.ParsePkScript(toLocalScript.PkScript)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
toLocalAddr, err := toLocalPkScript.Address(params)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
toRemotePkScript, err := txscript.ParsePkScript(toRemoteScript.PkScript)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
toRemoteAddr, err := toRemotePkScript.Address(params)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return &ChannelDebugInfo{
|
|
|
|
|
ToLocalScript: hex.EncodeToString(toLocalScript.WitnessScript),
|
|
|
|
|
ToLocalAddr: toLocalAddr.String(),
|
|
|
|
|
ToRemoteScript: hex.EncodeToString(
|
|
|
|
|
toRemoteScript.WitnessScript,
|
|
|
|
|
),
|
|
|
|
|
ToRemoteAddr: toRemoteAddr.String(),
|
|
|
|
|
}, nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ClosedChannelDump converts the closed channels in the given channel DB into a
|
|
|
|
|
// dumpable format.
|
|
|
|
|
func ClosedChannelDump(channels []*channeldb.ChannelCloseSummary,
|
|
|
|
|
historicalChannels []*channeldb.OpenChannel,
|
|
|
|
|
params *chaincfg.Params) ([]ClosedChannel, error) {
|
|
|
|
|
|
|
|
|
|
dumpChannels := make([]ClosedChannel, len(channels))
|
|
|
|
|
for idx, channel := range channels {
|
|
|
|
|
var (
|
|
|
|
|
nextLocalHeight, remoteTailHeight uint64
|
|
|
|
|
lastRemoteSecret string
|
|
|
|
|
localUnrevokedCommitPoint *btcec.PublicKey
|
|
|
|
|
historicalChannel *OpenChannel
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
if channel.LastChanSyncMsg != nil {
|
|
|
|
|
msg := channel.LastChanSyncMsg
|
|
|
|
|
nextLocalHeight = msg.NextLocalCommitHeight
|
|
|
|
|
remoteTailHeight = msg.RemoteCommitTailHeight
|
|
|
|
|
lastRemoteSecret = hex.EncodeToString(
|
|
|
|
|
msg.LastRemoteCommitSecret[:],
|
|
|
|
|
)
|
|
|
|
|
localUnrevokedCommitPoint = msg.LocalUnrevokedCommitPoint
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
histChan := historicalChannels[idx]
|
|
|
|
|
if histChan != nil {
|
|
|
|
|
openChan, err := openChannelDump(histChan, params)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return nil, fmt.Errorf("error converting to "+
|
|
|
|
|
"dump format: %w", err)
|
|
|
|
|
}
|
|
|
|
|
historicalChannel = openChan
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
dumpChannels[idx] = ClosedChannel{
|
|
|
|
|
ChanPoint: channel.ChanPoint.String(),
|
|
|
|
|
ShortChanID: channel.ShortChanID,
|
|
|
|
@ -204,6 +349,13 @@ func ClosedChannelDump(channels []*channeldb.ChannelCloseSummary,
|
|
|
|
|
LocalChanConfig: ToChannelConfig(
|
|
|
|
|
params, channel.LocalChanConfig,
|
|
|
|
|
),
|
|
|
|
|
NextLocalCommitHeight: nextLocalHeight,
|
|
|
|
|
RemoteCommitTailHeight: remoteTailHeight,
|
|
|
|
|
LastRemoteCommitSecret: lastRemoteSecret,
|
|
|
|
|
LocalUnrevokedCommitPoint: PubKeyToString(
|
|
|
|
|
localUnrevokedCommitPoint,
|
|
|
|
|
),
|
|
|
|
|
HistoricalChannel: historicalChannel,
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return dumpChannels, nil
|
|
|
|
|