dump+dumpchannels: add additional debug info to channels

pull/79/head
Oliver Gugger 8 months ago
parent 4926ae2db8
commit bae1bff7e2
No known key found for this signature in database
GPG Key ID: 8E4256593F177720

@ -107,7 +107,30 @@ func dumpClosedChannelInfo(chanDb *channeldb.ChannelStateDB) error {
return err
}
dumpChannels, err := dump.ClosedChannelDump(channels, chainParams)
historicalChannels := make([]*channeldb.OpenChannel, len(channels))
for idx := range channels {
closedChan := channels[idx]
histChan, err := chanDb.FetchHistoricalChannel(
&closedChan.ChanPoint,
)
switch err {
// The channel was closed in a pre-historic version of lnd.
// Ignore the error.
case channeldb.ErrNoHistoricalBucket:
case channeldb.ErrChannelNotFound:
case nil:
historicalChannels[idx] = histChan
// Non-nil error not due to older versions of lnd.
default:
return err
}
}
dumpChannels, err := dump.ClosedChannelDump(
channels, historicalChannels, chainParams,
)
if err != nil {
return fmt.Errorf("error converting to dump format: %w", err)
}

@ -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

Loading…
Cancel
Save