@@ -10,25 +10,27 @@ import (
1010 "github.com/btcsuite/btcd/btcutil"
1111 "github.com/btcsuite/btcd/chaincfg"
1212 "github.com/btcsuite/btcd/chaincfg/chainhash"
13+ "github.com/btcsuite/btcd/txscript"
1314 "github.com/lightningnetwork/lnd/chanbackup"
1415 "github.com/lightningnetwork/lnd/channeldb"
1516 "github.com/lightningnetwork/lnd/input"
1617 "github.com/lightningnetwork/lnd/keychain"
18+ "github.com/lightningnetwork/lnd/lnwallet"
1719 "github.com/lightningnetwork/lnd/lnwire"
1820)
1921
2022const (
2123 lndInternalDerivationPath = "m/1017'/%d'/%d'/0/%d"
2224)
2325
24- // BackupSingle is the information we want to dump from an lnd channel backup
26+ // BackupMulti is the information we want to dump from a lnd channel backup
2527// multi file. See `chanbackup.Multi` for information about the fields.
2628type BackupMulti struct {
2729 Version chanbackup.MultiBackupVersion
2830 StaticBackups []BackupSingle
2931}
3032
31- // BackupSingle is the information we want to dump from an lnd channel backup.
33+ // BackupSingle is the information we want to dump from a lnd channel backup.
3234// See `chanbackup.Single` for information about the fields.
3335type BackupSingle struct {
3436 Version chanbackup.SingleBackupVersion
@@ -57,6 +59,7 @@ type OpenChannel struct {
5759 FundingBroadcastHeight uint32
5860 NumConfsRequired uint16
5961 ChannelFlags lnwire.FundingFlag
62+ ThawHeight uint32
6063 IdentityPub string
6164 Capacity btcutil.Amount
6265 TotalMSatSent lnwire.MilliSatoshi
@@ -66,31 +69,47 @@ type OpenChannel struct {
6669 RemoteChanCfg ChannelConfig
6770 LocalCommitment channeldb.ChannelCommitment
6871 RemoteCommitment channeldb.ChannelCommitment
72+ LocalCommitmentDebug ChannelDebugInfo
73+ RemoteCommitmentDebug ChannelDebugInfo
6974 RemoteCurrentRevocation string
7075 RemoteNextRevocation string
7176 FundingTxn string
7277 LocalShutdownScript lnwire.DeliveryAddress
7378 RemoteShutdownScript lnwire.DeliveryAddress
7479}
7580
81+ // ChannelDebugInfo is a struct that holds additional information about an open
82+ // or pending channel that is useful for debugging.
83+ type ChannelDebugInfo struct {
84+ ToLocalScript string
85+ ToLocalAddr string
86+ ToRemoteScript string
87+ ToRemoteAddr string
88+ }
89+
7690// ClosedChannel is the information we want to dump from a closed channel in
7791// lnd's channel DB. See `channeldb.ChannelCloseSummary` for information about
7892// the fields.
7993type ClosedChannel struct {
80- ChanPoint string
81- ShortChanID lnwire.ShortChannelID
82- ChainHash chainhash.Hash
83- ClosingTXID string
84- RemotePub string
85- Capacity btcutil.Amount
86- CloseHeight uint32
87- SettledBalance btcutil.Amount
88- TimeLockedBalance btcutil.Amount
89- CloseType string
90- IsPending bool
91- RemoteCurrentRevocation string
92- RemoteNextRevocation string
93- LocalChanConfig ChannelConfig
94+ ChanPoint string
95+ ShortChanID lnwire.ShortChannelID
96+ ChainHash chainhash.Hash
97+ ClosingTXID string
98+ RemotePub string
99+ Capacity btcutil.Amount
100+ CloseHeight uint32
101+ SettledBalance btcutil.Amount
102+ TimeLockedBalance btcutil.Amount
103+ CloseType string
104+ IsPending bool
105+ RemoteCurrentRevocation string
106+ RemoteNextRevocation string
107+ LocalChanConfig ChannelConfig
108+ NextLocalCommitHeight uint64
109+ RemoteCommitTailHeight uint64
110+ LastRemoteCommitSecret string
111+ LocalUnrevokedCommitPoint string
112+ HistoricalChannel * OpenChannel
94113}
95114
96115// ChannelConfig is the information we want to dump from a channel
@@ -119,68 +138,194 @@ func OpenChannelDump(channels []*channeldb.OpenChannel,
119138
120139 dumpChannels := make ([]OpenChannel , len (channels ))
121140 for idx , channel := range channels {
122- var buf bytes.Buffer
123- if channel .FundingTxn != nil {
124- err := channel .FundingTxn .Serialize (& buf )
125- if err != nil {
126- return nil , err
127- }
141+ openChan , err := openChannelDump (channel , params )
142+ if err != nil {
143+ return nil , fmt .Errorf ("error converting to dump " +
144+ "format: %w" , err )
128145 }
129- revPreimage , err := channel .RevocationProducer .AtIndex (
130- channel .LocalCommitment .CommitHeight ,
131- )
146+ dumpChannels [idx ] = * openChan
147+ }
148+ return dumpChannels , nil
149+ }
150+
151+ func openChannelDump (channel * channeldb.OpenChannel ,
152+ params * chaincfg.Params ) (* OpenChannel , error ) {
153+
154+ var buf bytes.Buffer
155+ if channel .FundingTxn != nil {
156+ err := channel .FundingTxn .Serialize (& buf )
132157 if err != nil {
133158 return nil , err
134159 }
135- perCommitPoint := input .ComputeCommitmentPoint (revPreimage [:])
136-
137- dumpChannels [idx ] = OpenChannel {
138- ChanType : channel .ChanType ,
139- ChainHash : channel .ChainHash ,
140- FundingOutpoint : channel .FundingOutpoint .String (),
141- ShortChannelID : channel .ShortChannelID ,
142- IsPending : channel .IsPending ,
143- IsInitiator : channel .IsInitiator ,
144- ChanStatus : channel .ChanStatus (),
145- FundingBroadcastHeight : channel .FundingBroadcastHeight ,
146- NumConfsRequired : channel .NumConfsRequired ,
147- ChannelFlags : channel .ChannelFlags ,
148- IdentityPub : PubKeyToString (
149- channel .IdentityPub ,
150- ),
151- Capacity : channel .Capacity ,
152- TotalMSatSent : channel .TotalMSatSent ,
153- TotalMSatReceived : channel .TotalMSatReceived ,
154- PerCommitPoint : PubKeyToString (perCommitPoint ),
155- LocalChanCfg : ToChannelConfig (
156- params , channel .LocalChanCfg ,
157- ),
158- RemoteChanCfg : ToChannelConfig (
159- params , channel .RemoteChanCfg ,
160- ),
161- LocalCommitment : channel .LocalCommitment ,
162- RemoteCommitment : channel .RemoteCommitment ,
163- RemoteCurrentRevocation : PubKeyToString (
164- channel .RemoteCurrentRevocation ,
165- ),
166- RemoteNextRevocation : PubKeyToString (
167- channel .RemoteNextRevocation ,
168- ),
169- FundingTxn : hex .EncodeToString (buf .Bytes ()),
170- LocalShutdownScript : channel .LocalShutdownScript ,
171- RemoteShutdownScript : channel .RemoteShutdownScript ,
172- }
173160 }
174- return dumpChannels , nil
161+ revPreimage , err := channel .RevocationProducer .AtIndex (
162+ channel .LocalCommitment .CommitHeight ,
163+ )
164+ if err != nil {
165+ return nil , err
166+ }
167+ perCommitPoint := input .ComputeCommitmentPoint (revPreimage [:])
168+
169+ openChan := & OpenChannel {
170+ ChanType : channel .ChanType ,
171+ ChainHash : channel .ChainHash ,
172+ FundingOutpoint : channel .FundingOutpoint .String (),
173+ ShortChannelID : channel .ShortChannelID ,
174+ IsPending : channel .IsPending ,
175+ IsInitiator : channel .IsInitiator ,
176+ ChanStatus : channel .ChanStatus (),
177+ FundingBroadcastHeight : channel .FundingBroadcastHeight ,
178+ NumConfsRequired : channel .NumConfsRequired ,
179+ ChannelFlags : channel .ChannelFlags ,
180+ ThawHeight : channel .ThawHeight ,
181+ IdentityPub : PubKeyToString (
182+ channel .IdentityPub ,
183+ ),
184+ Capacity : channel .Capacity ,
185+ TotalMSatSent : channel .TotalMSatSent ,
186+ TotalMSatReceived : channel .TotalMSatReceived ,
187+ PerCommitPoint : PubKeyToString (perCommitPoint ),
188+ LocalChanCfg : ToChannelConfig (
189+ params , channel .LocalChanCfg ,
190+ ),
191+ RemoteChanCfg : ToChannelConfig (
192+ params , channel .RemoteChanCfg ,
193+ ),
194+ LocalCommitment : channel .LocalCommitment ,
195+ RemoteCommitment : channel .RemoteCommitment ,
196+ RemoteCurrentRevocation : PubKeyToString (
197+ channel .RemoteCurrentRevocation ,
198+ ),
199+ RemoteNextRevocation : PubKeyToString (
200+ channel .RemoteNextRevocation ,
201+ ),
202+ FundingTxn : hex .EncodeToString (buf .Bytes ()),
203+ LocalShutdownScript : channel .LocalShutdownScript ,
204+ RemoteShutdownScript : channel .RemoteShutdownScript ,
205+ }
206+
207+ localDebug , err := CollectDebugInfo (
208+ channel , perCommitPoint , true , channel .IsInitiator , params ,
209+ )
210+ if err != nil {
211+ return nil , fmt .Errorf ("error collecting local debug info: %w" ,
212+ err )
213+ }
214+
215+ remoteDebug , err := CollectDebugInfo (
216+ channel , channel .RemoteCurrentRevocation , false ,
217+ ! channel .IsInitiator , params ,
218+ )
219+ if err != nil {
220+ return nil , fmt .Errorf ("error collecting remote debug info: %w" ,
221+ err )
222+ }
223+
224+ openChan .LocalCommitmentDebug = * localDebug
225+ openChan .RemoteCommitmentDebug = * remoteDebug
226+
227+ return openChan , nil
228+ }
229+
230+ // CollectDebugInfo collects the additional debug information for the given
231+ // channel.
232+ func CollectDebugInfo (channel * channeldb.OpenChannel ,
233+ commitPoint * btcec.PublicKey , ourCommit , initiator bool ,
234+ params * chaincfg.Params ) (* ChannelDebugInfo , error ) {
235+
236+ chanType := channel .ChanType
237+ ourChanCfg := & channel .LocalChanCfg
238+ theirChanCfg := & channel .RemoteChanCfg
239+ leaseExpiry := channel .ThawHeight
240+
241+ keyRing := lnwallet .DeriveCommitmentKeys (
242+ commitPoint , ourCommit , chanType , ourChanCfg , theirChanCfg ,
243+ )
244+
245+ // First, we create the script for the delayed "pay-to-self" output.
246+ // This output has 2 main redemption clauses: either we can redeem the
247+ // output after a relative block delay, or the remote node can claim
248+ // the funds with the revocation key if we broadcast a revoked
249+ // commitment transaction.
250+ toLocalScript , err := lnwallet .CommitScriptToSelf (
251+ chanType , initiator , keyRing .ToLocalKey , keyRing .RevocationKey ,
252+ uint32 (ourChanCfg .CsvDelay ), leaseExpiry ,
253+ )
254+ if err != nil {
255+ return nil , err
256+ }
257+
258+ // Next, we create the script paying to the remote.
259+ toRemoteScript , _ , err := lnwallet .CommitScriptToRemote (
260+ chanType , initiator , keyRing .ToRemoteKey , leaseExpiry ,
261+ )
262+ if err != nil {
263+ return nil , err
264+ }
265+
266+ toLocalPkScript , err := txscript .ParsePkScript (toLocalScript .PkScript )
267+ if err != nil {
268+ return nil , err
269+ }
270+ toLocalAddr , err := toLocalPkScript .Address (params )
271+ if err != nil {
272+ return nil , err
273+ }
274+
275+ toRemotePkScript , err := txscript .ParsePkScript (toRemoteScript .PkScript )
276+ if err != nil {
277+ return nil , err
278+ }
279+ toRemoteAddr , err := toRemotePkScript .Address (params )
280+ if err != nil {
281+ return nil , err
282+ }
283+
284+ return & ChannelDebugInfo {
285+ ToLocalScript : hex .EncodeToString (toLocalScript .WitnessScript ),
286+ ToLocalAddr : toLocalAddr .String (),
287+ ToRemoteScript : hex .EncodeToString (
288+ toRemoteScript .WitnessScript ,
289+ ),
290+ ToRemoteAddr : toRemoteAddr .String (),
291+ }, nil
175292}
176293
177294// ClosedChannelDump converts the closed channels in the given channel DB into a
178295// dumpable format.
179296func ClosedChannelDump (channels []* channeldb.ChannelCloseSummary ,
297+ historicalChannels []* channeldb.OpenChannel ,
180298 params * chaincfg.Params ) ([]ClosedChannel , error ) {
181299
182300 dumpChannels := make ([]ClosedChannel , len (channels ))
183301 for idx , channel := range channels {
302+ var (
303+ nextLocalHeight , remoteTailHeight uint64
304+ lastRemoteSecret string
305+ localUnrevokedCommitPoint * btcec.PublicKey
306+ historicalChannel * OpenChannel
307+ )
308+
309+ if channel .LastChanSyncMsg != nil {
310+ msg := channel .LastChanSyncMsg
311+ nextLocalHeight = msg .NextLocalCommitHeight
312+ remoteTailHeight = msg .RemoteCommitTailHeight
313+ lastRemoteSecret = hex .EncodeToString (
314+ msg .LastRemoteCommitSecret [:],
315+ )
316+ localUnrevokedCommitPoint = msg .LocalUnrevokedCommitPoint
317+ }
318+
319+ histChan := historicalChannels [idx ]
320+ if histChan != nil {
321+ openChan , err := openChannelDump (histChan , params )
322+ if err != nil {
323+ return nil , fmt .Errorf ("error converting to " +
324+ "dump format: %w" , err )
325+ }
326+ historicalChannel = openChan
327+ }
328+
184329 dumpChannels [idx ] = ClosedChannel {
185330 ChanPoint : channel .ChanPoint .String (),
186331 ShortChanID : channel .ShortChanID ,
@@ -204,6 +349,13 @@ func ClosedChannelDump(channels []*channeldb.ChannelCloseSummary,
204349 LocalChanConfig : ToChannelConfig (
205350 params , channel .LocalChanConfig ,
206351 ),
352+ NextLocalCommitHeight : nextLocalHeight ,
353+ RemoteCommitTailHeight : remoteTailHeight ,
354+ LastRemoteCommitSecret : lastRemoteSecret ,
355+ LocalUnrevokedCommitPoint : PubKeyToString (
356+ localUnrevokedCommitPoint ,
357+ ),
358+ HistoricalChannel : historicalChannel ,
207359 }
208360 }
209361 return dumpChannels , nil
0 commit comments