package dump import ( "bytes" "encoding/hex" "fmt" "github.com/lightningnetwork/lnd/input" "net" "github.com/btcsuite/btcd/btcec" "github.com/btcsuite/btcd/chaincfg" "github.com/btcsuite/btcd/chaincfg/chainhash" "github.com/btcsuite/btcutil" "github.com/lightningnetwork/lnd/chanbackup" "github.com/lightningnetwork/lnd/channeldb" "github.com/lightningnetwork/lnd/keychain" "github.com/lightningnetwork/lnd/lnwire" ) const ( lndInternalDerivationPath = "m/1017'/%d'/%d'/0/%d" ) // BackupSingle is the information we want to dump from an 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. // See `chanbackup.Single` for information about the fields. type BackupSingle struct { Version chanbackup.SingleBackupVersion IsInitiator bool ChainHash string FundingOutpoint string ShortChannelID lnwire.ShortChannelID RemoteNodePub string Addresses []net.Addr Capacity btcutil.Amount LocalChanCfg ChannelConfig RemoteChanCfg ChannelConfig ShaChainRootDesc KeyDescriptor } // OpenChannel is the information we want to dump from an open channel in lnd's // channel DB. See `channeldb.OpenChannel` for information about the fields. type OpenChannel struct { ChanType channeldb.ChannelType ChainHash chainhash.Hash FundingOutpoint string ShortChannelID lnwire.ShortChannelID IsPending bool IsInitiator bool ChanStatus channeldb.ChannelStatus FundingBroadcastHeight uint32 NumConfsRequired uint16 ChannelFlags lnwire.FundingFlag IdentityPub string Capacity btcutil.Amount TotalMSatSent lnwire.MilliSatoshi TotalMSatReceived lnwire.MilliSatoshi PerCommitPoint string LocalChanCfg ChannelConfig RemoteChanCfg ChannelConfig LocalCommitment channeldb.ChannelCommitment RemoteCommitment channeldb.ChannelCommitment RemoteCurrentRevocation string RemoteNextRevocation string FundingTxn string LocalShutdownScript lnwire.DeliveryAddress RemoteShutdownScript lnwire.DeliveryAddress } // ChannelConfig is the information we want to dump from a channel // configuration. See `channeldb.ChannelConfig` for more information about the // fields. type ChannelConfig struct { channeldb.ChannelConstraints MultiSigKey KeyDescriptor RevocationBasePoint KeyDescriptor PaymentBasePoint KeyDescriptor DelayBasePoint KeyDescriptor HtlcBasePoint KeyDescriptor } // KeyDescriptor is the information we want to dump from a key descriptor. See // `keychain.KeyDescriptor` for more information about the fields. type KeyDescriptor struct { Path string PubKey string } // ChannelDump converts the channels in the given channel DB into a dumpable // format. func ChannelDump(channels []*channeldb.OpenChannel, params *chaincfg.Params) ( []OpenChannel, error) { 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 } } revPreimage, err := channel.RevocationProducer.AtIndex( channel.LocalCommitment.CommitHeight, ) 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 } // BackupDump converts the given multi backup into a dumpable format. func BackupDump(multi *chanbackup.Multi, params *chaincfg.Params) []BackupSingle { dumpSingles := make([]BackupSingle, len(multi.StaticBackups)) for idx, single := range multi.StaticBackups { dumpSingles[idx] = BackupSingle{ Version: single.Version, IsInitiator: single.IsInitiator, ChainHash: single.ChainHash.String(), FundingOutpoint: single.FundingOutpoint.String(), ShortChannelID: single.ShortChannelID, RemoteNodePub: PubKeyToString( single.RemoteNodePub, ), Addresses: single.Addresses, Capacity: single.Capacity, LocalChanCfg: ToChannelConfig( params, single.LocalChanCfg, ), RemoteChanCfg: ToChannelConfig( params, single.RemoteChanCfg, ), ShaChainRootDesc: ToKeyDescriptor( params, single.ShaChainRootDesc, ), } } return dumpSingles } func ToChannelConfig(params *chaincfg.Params, cfg channeldb.ChannelConfig) ChannelConfig { return ChannelConfig{ ChannelConstraints: cfg.ChannelConstraints, MultiSigKey: ToKeyDescriptor(params, cfg.MultiSigKey), RevocationBasePoint: ToKeyDescriptor( params, cfg.RevocationBasePoint, ), PaymentBasePoint: ToKeyDescriptor( params, cfg.PaymentBasePoint, ), DelayBasePoint: ToKeyDescriptor( params, cfg.DelayBasePoint, ), HtlcBasePoint: ToKeyDescriptor(params, cfg.HtlcBasePoint), } } func ToKeyDescriptor(params *chaincfg.Params, desc keychain.KeyDescriptor) KeyDescriptor { return KeyDescriptor{ Path: fmt.Sprintf( lndInternalDerivationPath, params.HDCoinType, desc.Family, desc.Index, ), PubKey: PubKeyToString(desc.PubKey), } } func PubKeyToString(pubkey *btcec.PublicKey) string { if pubkey == nil { return "" } return hex.EncodeToString(pubkey.SerializeCompressed()) }