• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

lightningnetwork / lnd / 13523316608

25 Feb 2025 02:12PM UTC coverage: 49.351% (-9.5%) from 58.835%
13523316608

Pull #9549

github

yyforyongyu
routing/chainview: refactor `TestFilteredChainView`

So each test has its own miner and chainView.
Pull Request #9549: Fix unit test flake `TestHistoricalConfDetailsTxIndex`

0 of 120 new or added lines in 1 file covered. (0.0%)

27196 existing lines in 434 files now uncovered.

100945 of 204543 relevant lines covered (49.35%)

1.54 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

0.0
/channeldb/migration25/channel.go
1
package migration25
2

3
import (
4
        "bytes"
5
        "fmt"
6
        "io"
7
        "strconv"
8
        "strings"
9

10
        lnwire "github.com/lightningnetwork/lnd/channeldb/migration/lnwire21"
11
        mig24 "github.com/lightningnetwork/lnd/channeldb/migration24"
12
        mig "github.com/lightningnetwork/lnd/channeldb/migration_01_to_11"
13
        "github.com/lightningnetwork/lnd/keychain"
14
        "github.com/lightningnetwork/lnd/kvdb"
15
        "github.com/lightningnetwork/lnd/tlv"
16
)
17

18
const (
19
        // A tlv type definition used to serialize and deserialize a KeyLocator
20
        // from the database.
21
        keyLocType tlv.Type = 1
22
)
23

24
var (
25
        // chanCommitmentKey can be accessed within the sub-bucket for a
26
        // particular channel. This key stores the up to date commitment state
27
        // for a particular channel party. Appending a 0 to the end of this key
28
        // indicates it's the commitment for the local party, and appending a 1
29
        // to the end of this key indicates it's the commitment for the remote
30
        // party.
31
        chanCommitmentKey = []byte("chan-commitment-key")
32

33
        // revocationLogBucketLegacy is the legacy bucket where we store the
34
        // revocation log in old format.
35
        revocationLogBucketLegacy = []byte("revocation-log-key")
36

37
        // localUpfrontShutdownKey can be accessed within the bucket for a
38
        // channel (identified by its chanPoint). This key stores an optional
39
        // upfront shutdown script for the local peer.
40
        localUpfrontShutdownKey = []byte("local-upfront-shutdown-key")
41

42
        // remoteUpfrontShutdownKey can be accessed within the bucket for a
43
        // channel (identified by its chanPoint). This key stores an optional
44
        // upfront shutdown script for the remote peer.
45
        remoteUpfrontShutdownKey = []byte("remote-upfront-shutdown-key")
46

47
        // lastWasRevokeKey is a key that stores true when the last update we
48
        // sent was a revocation and false when it was a commitment signature.
49
        // This is nil in the case of new channels with no updates exchanged.
50
        lastWasRevokeKey = []byte("last-was-revoke")
51

52
        // ErrNoChanInfoFound is returned when a particular channel does not
53
        // have any channels state.
54
        ErrNoChanInfoFound = fmt.Errorf("no chan info found")
55

56
        // ErrNoPastDeltas is returned when the channel delta bucket hasn't been
57
        // created.
58
        ErrNoPastDeltas = fmt.Errorf("channel has no recorded deltas")
59

60
        // ErrLogEntryNotFound is returned when we cannot find a log entry at
61
        // the height requested in the revocation log.
62
        ErrLogEntryNotFound = fmt.Errorf("log entry not found")
63

64
        // ErrNoCommitmentsFound is returned when a channel has not set
65
        // commitment states.
66
        ErrNoCommitmentsFound = fmt.Errorf("no commitments found")
67
)
68

69
// ChannelType is an enum-like type that describes one of several possible
70
// channel types. Each open channel is associated with a particular type as the
71
// channel type may determine how higher level operations are conducted such as
72
// fee negotiation, channel closing, the format of HTLCs, etc. Structure-wise,
73
// a ChannelType is a bit field, with each bit denoting a modification from the
74
// base channel type of single funder.
75
type ChannelType uint8
76

77
const (
78
        // NOTE: iota isn't used here for this enum needs to be stable
79
        // long-term as it will be persisted to the database.
80

81
        // SingleFunderBit represents a channel wherein one party solely funds
82
        // the entire capacity of the channel.
83
        SingleFunderBit ChannelType = 0
84

85
        // DualFunderBit represents a channel wherein both parties contribute
86
        // funds towards the total capacity of the channel. The channel may be
87
        // funded symmetrically or asymmetrically.
88
        DualFunderBit ChannelType = 1 << 0
89

90
        // SingleFunderTweaklessBit is similar to the basic SingleFunder channel
91
        // type, but it omits the tweak for one's key in the commitment
92
        // transaction of the remote party.
93
        SingleFunderTweaklessBit ChannelType = 1 << 1
94

95
        // NoFundingTxBit denotes if we have the funding transaction locally on
96
        // disk. This bit may be on if the funding transaction was crafted by a
97
        // wallet external to the primary daemon.
98
        NoFundingTxBit ChannelType = 1 << 2
99

100
        // AnchorOutputsBit indicates that the channel makes use of anchor
101
        // outputs to bump the commitment transaction's effective feerate. This
102
        // channel type also uses a delayed to_remote output script.
103
        AnchorOutputsBit ChannelType = 1 << 3
104

105
        // FrozenBit indicates that the channel is a frozen channel, meaning
106
        // that only the responder can decide to cooperatively close the
107
        // channel.
108
        FrozenBit ChannelType = 1 << 4
109

110
        // ZeroHtlcTxFeeBit indicates that the channel should use zero-fee
111
        // second-level HTLC transactions.
112
        ZeroHtlcTxFeeBit ChannelType = 1 << 5
113

114
        // LeaseExpirationBit indicates that the channel has been leased for a
115
        // period of time, constraining every output that pays to the channel
116
        // initiator with an additional CLTV of the lease maturity.
117
        LeaseExpirationBit ChannelType = 1 << 6
118
)
119

120
// IsSingleFunder returns true if the channel type if one of the known single
121
// funder variants.
UNCOV
122
func (c ChannelType) IsSingleFunder() bool {
×
UNCOV
123
        return c&DualFunderBit == 0
×
UNCOV
124
}
×
125

126
// IsDualFunder returns true if the ChannelType has the DualFunderBit set.
127
func (c ChannelType) IsDualFunder() bool {
×
128
        return c&DualFunderBit == DualFunderBit
×
129
}
×
130

131
// IsTweakless returns true if the target channel uses a commitment that
132
// doesn't tweak the key for the remote party.
UNCOV
133
func (c ChannelType) IsTweakless() bool {
×
UNCOV
134
        return c&SingleFunderTweaklessBit == SingleFunderTweaklessBit
×
UNCOV
135
}
×
136

137
// HasFundingTx returns true if this channel type is one that has a funding
138
// transaction stored locally.
UNCOV
139
func (c ChannelType) HasFundingTx() bool {
×
UNCOV
140
        return c&NoFundingTxBit == 0
×
UNCOV
141
}
×
142

143
// HasAnchors returns true if this channel type has anchor outputs on its
144
// commitment.
UNCOV
145
func (c ChannelType) HasAnchors() bool {
×
UNCOV
146
        return c&AnchorOutputsBit == AnchorOutputsBit
×
UNCOV
147
}
×
148

149
// ZeroHtlcTxFee returns true if this channel type uses second-level HTLC
150
// transactions signed with zero-fee.
151
func (c ChannelType) ZeroHtlcTxFee() bool {
×
152
        return c&ZeroHtlcTxFeeBit == ZeroHtlcTxFeeBit
×
153
}
×
154

155
// IsFrozen returns true if the channel is considered to be "frozen". A frozen
156
// channel means that only the responder can initiate a cooperative channel
157
// closure.
158
func (c ChannelType) IsFrozen() bool {
×
159
        return c&FrozenBit == FrozenBit
×
160
}
×
161

162
// HasLeaseExpiration returns true if the channel originated from a lease.
UNCOV
163
func (c ChannelType) HasLeaseExpiration() bool {
×
UNCOV
164
        return c&LeaseExpirationBit == LeaseExpirationBit
×
UNCOV
165
}
×
166

167
// ChannelStatus is a bit vector used to indicate whether an OpenChannel is in
168
// the default usable state, or a state where it shouldn't be used.
169
type ChannelStatus uint8
170

171
var (
172
        // ChanStatusDefault is the normal state of an open channel.
173
        ChanStatusDefault ChannelStatus
174

175
        // ChanStatusBorked indicates that the channel has entered an
176
        // irreconcilable state, triggered by a state desynchronization or
177
        // channel breach.  Channels in this state should never be added to the
178
        // htlc switch.
179
        ChanStatusBorked ChannelStatus = 1
180

181
        // ChanStatusCommitBroadcasted indicates that a commitment for this
182
        // channel has been broadcasted.
183
        ChanStatusCommitBroadcasted ChannelStatus = 1 << 1
184

185
        // ChanStatusLocalDataLoss indicates that we have lost channel state
186
        // for this channel, and broadcasting our latest commitment might be
187
        // considered a breach.
188
        //
189
        // TODO(halseh): actually enforce that we are not force closing such a
190
        // channel.
191
        ChanStatusLocalDataLoss ChannelStatus = 1 << 2
192

193
        // ChanStatusRestored is a status flag that signals that the channel
194
        // has been restored, and doesn't have all the fields a typical channel
195
        // will have.
196
        ChanStatusRestored ChannelStatus = 1 << 3
197

198
        // ChanStatusCoopBroadcasted indicates that a cooperative close for
199
        // this channel has been broadcasted. Older cooperatively closed
200
        // channels will only have this status set. Newer ones will also have
201
        // close initiator information stored using the local/remote initiator
202
        // status. This status is set in conjunction with the initiator status
203
        // so that we do not need to check multiple channel statues for
204
        // cooperative closes.
205
        ChanStatusCoopBroadcasted ChannelStatus = 1 << 4
206

207
        // ChanStatusLocalCloseInitiator indicates that we initiated closing
208
        // the channel.
209
        ChanStatusLocalCloseInitiator ChannelStatus = 1 << 5
210

211
        // ChanStatusRemoteCloseInitiator indicates that the remote node
212
        // initiated closing the channel.
213
        ChanStatusRemoteCloseInitiator ChannelStatus = 1 << 6
214
)
215

216
// chanStatusStrings maps a ChannelStatus to a human friendly string that
217
// describes that status.
218
var chanStatusStrings = map[ChannelStatus]string{
219
        ChanStatusDefault:              "ChanStatusDefault",
220
        ChanStatusBorked:               "ChanStatusBorked",
221
        ChanStatusCommitBroadcasted:    "ChanStatusCommitBroadcasted",
222
        ChanStatusLocalDataLoss:        "ChanStatusLocalDataLoss",
223
        ChanStatusRestored:             "ChanStatusRestored",
224
        ChanStatusCoopBroadcasted:      "ChanStatusCoopBroadcasted",
225
        ChanStatusLocalCloseInitiator:  "ChanStatusLocalCloseInitiator",
226
        ChanStatusRemoteCloseInitiator: "ChanStatusRemoteCloseInitiator",
227
}
228

229
// orderedChanStatusFlags is an in-order list of all that channel status flags.
230
var orderedChanStatusFlags = []ChannelStatus{
231
        ChanStatusBorked,
232
        ChanStatusCommitBroadcasted,
233
        ChanStatusLocalDataLoss,
234
        ChanStatusRestored,
235
        ChanStatusCoopBroadcasted,
236
        ChanStatusLocalCloseInitiator,
237
        ChanStatusRemoteCloseInitiator,
238
}
239

240
// String returns a human-readable representation of the ChannelStatus.
241
func (c ChannelStatus) String() string {
×
242
        // If no flags are set, then this is the default case.
×
243
        if c == ChanStatusDefault {
×
244
                return chanStatusStrings[ChanStatusDefault]
×
245
        }
×
246

247
        // Add individual bit flags.
248
        statusStr := ""
×
249
        for _, flag := range orderedChanStatusFlags {
×
250
                if c&flag == flag {
×
251
                        statusStr += chanStatusStrings[flag] + "|"
×
252
                        c -= flag
×
253
                }
×
254
        }
255

256
        // Remove anything to the right of the final bar, including it as well.
257
        statusStr = strings.TrimRight(statusStr, "|")
×
258

×
259
        // Add any remaining flags which aren't accounted for as hex.
×
260
        if c != 0 {
×
261
                statusStr += "|0x" + strconv.FormatUint(uint64(c), 16)
×
262
        }
×
263

264
        // If this was purely an unknown flag, then remove the extra bar at the
265
        // start of the string.
266
        statusStr = strings.TrimLeft(statusStr, "|")
×
267

×
268
        return statusStr
×
269
}
270

271
// OpenChannel embeds a mig.OpenChannel with the extra update-to-date fields.
272
//
273
// NOTE: doesn't have the Packager field as it's not used in current migration.
274
type OpenChannel struct {
275
        mig.OpenChannel
276

277
        // ChanType denotes which type of channel this is.
278
        ChanType ChannelType
279

280
        // ChanStatus is the current status of this channel. If it is not in
281
        // the state Default, it should not be used for forwarding payments.
282
        //
283
        // NOTE: In `channeldb.OpenChannel`, this field is private. We choose
284
        // to export this private field such that following migrations can
285
        // access this field directly.
286
        ChanStatus ChannelStatus
287

288
        // InitialLocalBalance is the balance we have during the channel
289
        // opening. When we are not the initiator, this value represents the
290
        // push amount.
291
        InitialLocalBalance lnwire.MilliSatoshi
292

293
        // InitialRemoteBalance is the balance they have during the channel
294
        // opening.
295
        InitialRemoteBalance lnwire.MilliSatoshi
296

297
        // LocalShutdownScript is set to a pre-set script if the channel was
298
        // opened by the local node with option_upfront_shutdown_script set. If
299
        // the option was not set, the field is empty.
300
        LocalShutdownScript lnwire.DeliveryAddress
301

302
        // RemoteShutdownScript is set to a pre-set script if the channel was
303
        // opened by the remote node with option_upfront_shutdown_script set.
304
        // If the option was not set, the field is empty.
305
        RemoteShutdownScript lnwire.DeliveryAddress
306

307
        // ThawHeight is the height when a frozen channel once again becomes a
308
        // normal channel. If this is zero, then there're no restrictions on
309
        // this channel. If the value is lower than 500,000, then it's
310
        // interpreted as a relative height, or an absolute height otherwise.
311
        ThawHeight uint32
312

313
        // LastWasRevoke is a boolean that determines if the last update we
314
        // sent was a revocation (true) or a commitment signature (false).
315
        LastWasRevoke bool
316

317
        // RevocationKeyLocator stores the KeyLocator information that we will
318
        // need to derive the shachain root for this channel. This allows us to
319
        // have private key isolation from lnd.
320
        RevocationKeyLocator keychain.KeyLocator
321
}
322

UNCOV
323
func (c *OpenChannel) hasChanStatus(status ChannelStatus) bool {
×
UNCOV
324
        // Special case ChanStatusDefualt since it isn't actually flag, but a
×
UNCOV
325
        // particular combination (or lack-there-of) of flags.
×
UNCOV
326
        if status == ChanStatusDefault {
×
327
                return c.ChanStatus == ChanStatusDefault
×
328
        }
×
329

UNCOV
330
        return c.ChanStatus&status == status
×
331
}
332

333
// FundingTxPresent returns true if expect the funding transcation to be found
334
// on disk or already populated within the passed open channel struct.
UNCOV
335
func (c *OpenChannel) FundingTxPresent() bool {
×
UNCOV
336
        chanType := c.ChanType
×
UNCOV
337

×
UNCOV
338
        return chanType.IsSingleFunder() && chanType.HasFundingTx() &&
×
UNCOV
339
                c.IsInitiator &&
×
UNCOV
340
                !c.hasChanStatus(ChanStatusRestored)
×
UNCOV
341
}
×
342

343
// fetchChanInfo deserializes the channel info based on the legacy boolean.
UNCOV
344
func fetchChanInfo(chanBucket kvdb.RBucket, c *OpenChannel, legacy bool) error {
×
UNCOV
345
        infoBytes := chanBucket.Get(chanInfoKey)
×
UNCOV
346
        if infoBytes == nil {
×
347
                return ErrNoChanInfoFound
×
348
        }
×
UNCOV
349
        r := bytes.NewReader(infoBytes)
×
UNCOV
350

×
UNCOV
351
        var (
×
UNCOV
352
                chanType   mig.ChannelType
×
UNCOV
353
                chanStatus mig.ChannelStatus
×
UNCOV
354
        )
×
UNCOV
355

×
UNCOV
356
        if err := mig.ReadElements(r,
×
UNCOV
357
                &chanType, &c.ChainHash, &c.FundingOutpoint,
×
UNCOV
358
                &c.ShortChannelID, &c.IsPending, &c.IsInitiator,
×
UNCOV
359
                &chanStatus, &c.FundingBroadcastHeight,
×
UNCOV
360
                &c.NumConfsRequired, &c.ChannelFlags,
×
UNCOV
361
                &c.IdentityPub, &c.Capacity, &c.TotalMSatSent,
×
UNCOV
362
                &c.TotalMSatReceived,
×
UNCOV
363
        ); err != nil {
×
364
                return err
×
365
        }
×
366

UNCOV
367
        c.ChanType = ChannelType(chanType)
×
UNCOV
368
        c.ChanStatus = ChannelStatus(chanStatus)
×
UNCOV
369

×
UNCOV
370
        // If this is not the legacy format, we need to read the extra two new
×
UNCOV
371
        // fields.
×
UNCOV
372
        if !legacy {
×
UNCOV
373
                if err := mig.ReadElements(r,
×
UNCOV
374
                        &c.InitialLocalBalance, &c.InitialRemoteBalance,
×
UNCOV
375
                ); err != nil {
×
376
                        return err
×
377
                }
×
378
        }
379

380
        // For single funder channels that we initiated and have the funding
381
        // transaction to, read the funding txn.
UNCOV
382
        if c.FundingTxPresent() {
×
383
                if err := mig.ReadElement(r, &c.FundingTxn); err != nil {
×
384
                        return err
×
385
                }
×
386
        }
387

UNCOV
388
        if err := mig.ReadChanConfig(r, &c.LocalChanCfg); err != nil {
×
389
                return err
×
390
        }
×
UNCOV
391
        if err := mig.ReadChanConfig(r, &c.RemoteChanCfg); err != nil {
×
392
                return err
×
393
        }
×
394

395
        // Retrieve the boolean stored under lastWasRevokeKey.
UNCOV
396
        lastWasRevokeBytes := chanBucket.Get(lastWasRevokeKey)
×
UNCOV
397
        if lastWasRevokeBytes == nil {
×
UNCOV
398
                // If nothing has been stored under this key, we store false in
×
UNCOV
399
                // the OpenChannel struct.
×
UNCOV
400
                c.LastWasRevoke = false
×
UNCOV
401
        } else {
×
402
                // Otherwise, read the value into the LastWasRevoke field.
×
403
                revokeReader := bytes.NewReader(lastWasRevokeBytes)
×
404
                err := mig.ReadElements(revokeReader, &c.LastWasRevoke)
×
405
                if err != nil {
×
406
                        return err
×
407
                }
×
408
        }
409

UNCOV
410
        keyLocRecord := MakeKeyLocRecord(keyLocType, &c.RevocationKeyLocator)
×
UNCOV
411
        tlvStream, err := tlv.NewStream(keyLocRecord)
×
UNCOV
412
        if err != nil {
×
413
                return err
×
414
        }
×
415

UNCOV
416
        if err := tlvStream.Decode(r); err != nil {
×
417
                return err
×
418
        }
×
419

420
        // Finally, read the optional shutdown scripts.
UNCOV
421
        if err := GetOptionalUpfrontShutdownScript(
×
UNCOV
422
                chanBucket, localUpfrontShutdownKey, &c.LocalShutdownScript,
×
UNCOV
423
        ); err != nil {
×
424
                return err
×
425
        }
×
426

UNCOV
427
        return GetOptionalUpfrontShutdownScript(
×
UNCOV
428
                chanBucket, remoteUpfrontShutdownKey, &c.RemoteShutdownScript,
×
UNCOV
429
        )
×
430
}
431

432
// fetchChanInfo serializes the channel info based on the legacy boolean and
433
// saves it to disk.
UNCOV
434
func putChanInfo(chanBucket kvdb.RwBucket, c *OpenChannel, legacy bool) error {
×
UNCOV
435
        var w bytes.Buffer
×
UNCOV
436
        if err := mig.WriteElements(&w,
×
UNCOV
437
                mig.ChannelType(c.ChanType), c.ChainHash, c.FundingOutpoint,
×
UNCOV
438
                c.ShortChannelID, c.IsPending, c.IsInitiator,
×
UNCOV
439
                mig.ChannelStatus(c.ChanStatus), c.FundingBroadcastHeight,
×
UNCOV
440
                c.NumConfsRequired, c.ChannelFlags,
×
UNCOV
441
                c.IdentityPub, c.Capacity, c.TotalMSatSent,
×
UNCOV
442
                c.TotalMSatReceived,
×
UNCOV
443
        ); err != nil {
×
444
                return err
×
445
        }
×
446

447
        // If this is not legacy format, we need to write the extra two fields.
UNCOV
448
        if !legacy {
×
UNCOV
449
                if err := mig.WriteElements(&w,
×
UNCOV
450
                        c.InitialLocalBalance, c.InitialRemoteBalance,
×
UNCOV
451
                ); err != nil {
×
452
                        return err
×
453
                }
×
454
        }
455

456
        // For single funder channels that we initiated, and we have the
457
        // funding transaction, then write the funding txn.
UNCOV
458
        if c.FundingTxPresent() {
×
459
                if err := mig.WriteElement(&w, c.FundingTxn); err != nil {
×
460
                        return err
×
461
                }
×
462
        }
463

UNCOV
464
        if err := mig.WriteChanConfig(&w, &c.LocalChanCfg); err != nil {
×
465
                return err
×
466
        }
×
UNCOV
467
        if err := mig.WriteChanConfig(&w, &c.RemoteChanCfg); err != nil {
×
468
                return err
×
469
        }
×
470

471
        // Write the RevocationKeyLocator as the first entry in a tlv stream.
UNCOV
472
        keyLocRecord := MakeKeyLocRecord(
×
UNCOV
473
                keyLocType, &c.RevocationKeyLocator,
×
UNCOV
474
        )
×
UNCOV
475

×
UNCOV
476
        tlvStream, err := tlv.NewStream(keyLocRecord)
×
UNCOV
477
        if err != nil {
×
478
                return err
×
479
        }
×
480

UNCOV
481
        if err := tlvStream.Encode(&w); err != nil {
×
482
                return err
×
483
        }
×
484

UNCOV
485
        if err := chanBucket.Put(chanInfoKey, w.Bytes()); err != nil {
×
486
                return err
×
487
        }
×
488

489
        // Finally, add optional shutdown scripts for the local and remote peer
490
        // if they are present.
UNCOV
491
        if err := PutOptionalUpfrontShutdownScript(
×
UNCOV
492
                chanBucket, localUpfrontShutdownKey, c.LocalShutdownScript,
×
UNCOV
493
        ); err != nil {
×
494
                return err
×
495
        }
×
496

UNCOV
497
        return PutOptionalUpfrontShutdownScript(
×
UNCOV
498
                chanBucket, remoteUpfrontShutdownKey, c.RemoteShutdownScript,
×
UNCOV
499
        )
×
500
}
501

502
// EKeyLocator is an encoder for keychain.KeyLocator.
UNCOV
503
func EKeyLocator(w io.Writer, val interface{}, buf *[8]byte) error {
×
UNCOV
504
        if v, ok := val.(*keychain.KeyLocator); ok {
×
UNCOV
505
                err := tlv.EUint32T(w, uint32(v.Family), buf)
×
UNCOV
506
                if err != nil {
×
507
                        return err
×
508
                }
×
509

UNCOV
510
                return tlv.EUint32T(w, v.Index, buf)
×
511
        }
512
        return tlv.NewTypeForEncodingErr(val, "keychain.KeyLocator")
×
513
}
514

515
// DKeyLocator is a decoder for keychain.KeyLocator.
UNCOV
516
func DKeyLocator(r io.Reader, val interface{}, buf *[8]byte, l uint64) error {
×
UNCOV
517
        if v, ok := val.(*keychain.KeyLocator); ok {
×
UNCOV
518
                var family uint32
×
UNCOV
519
                err := tlv.DUint32(r, &family, buf, 4)
×
UNCOV
520
                if err != nil {
×
521
                        return err
×
522
                }
×
UNCOV
523
                v.Family = keychain.KeyFamily(family)
×
UNCOV
524

×
UNCOV
525
                return tlv.DUint32(r, &v.Index, buf, 4)
×
526
        }
527
        return tlv.NewTypeForDecodingErr(val, "keychain.KeyLocator", l, 8)
×
528
}
529

530
// MakeKeyLocRecord creates a Record out of a KeyLocator using the passed
531
// Type and the EKeyLocator and DKeyLocator functions. The size will always be
532
// 8 as KeyFamily is uint32 and the Index is uint32.
UNCOV
533
func MakeKeyLocRecord(typ tlv.Type, keyLoc *keychain.KeyLocator) tlv.Record {
×
UNCOV
534
        return tlv.MakeStaticRecord(typ, keyLoc, 8, EKeyLocator, DKeyLocator)
×
UNCOV
535
}
×
536

537
// PutOptionalUpfrontShutdownScript adds a shutdown script under the key
538
// provided if it has a non-zero length.
539
func PutOptionalUpfrontShutdownScript(chanBucket kvdb.RwBucket, key []byte,
UNCOV
540
        script []byte) error {
×
UNCOV
541
        // If the script is empty, we do not need to add anything.
×
UNCOV
542
        if len(script) == 0 {
×
UNCOV
543
                return nil
×
UNCOV
544
        }
×
545

546
        var w bytes.Buffer
×
547
        if err := mig.WriteElement(&w, script); err != nil {
×
548
                return err
×
549
        }
×
550

551
        return chanBucket.Put(key, w.Bytes())
×
552
}
553

554
// GetOptionalUpfrontShutdownScript reads the shutdown script stored under the
555
// key provided if it is present. Upfront shutdown scripts are optional, so the
556
// function returns with no error if the key is not present.
557
func GetOptionalUpfrontShutdownScript(chanBucket kvdb.RBucket, key []byte,
UNCOV
558
        script *lnwire.DeliveryAddress) error {
×
UNCOV
559

×
UNCOV
560
        // Return early if the bucket does not exit, a shutdown script was not
×
UNCOV
561
        // set.
×
UNCOV
562
        bs := chanBucket.Get(key)
×
UNCOV
563
        if bs == nil {
×
UNCOV
564
                return nil
×
UNCOV
565
        }
×
566

567
        var tempScript []byte
×
568
        r := bytes.NewReader(bs)
×
569
        if err := mig.ReadElement(r, &tempScript); err != nil {
×
570
                return err
×
571
        }
×
572
        *script = tempScript
×
573

×
574
        return nil
×
575
}
576

577
// FetchChanCommitments fetches both the local and remote commitments. This
578
// function is exported so it can be used by later migrations.
UNCOV
579
func FetchChanCommitments(chanBucket kvdb.RBucket, channel *OpenChannel) error {
×
UNCOV
580
        var err error
×
UNCOV
581

×
UNCOV
582
        // If this is a restored channel, then we don't have any commitments to
×
UNCOV
583
        // read.
×
UNCOV
584
        if channel.hasChanStatus(ChanStatusRestored) {
×
585
                return nil
×
586
        }
×
587

UNCOV
588
        channel.LocalCommitment, err = FetchChanCommitment(chanBucket, true)
×
UNCOV
589
        if err != nil {
×
590
                return err
×
591
        }
×
UNCOV
592
        channel.RemoteCommitment, err = FetchChanCommitment(chanBucket, false)
×
UNCOV
593
        if err != nil {
×
594
                return err
×
595
        }
×
596

UNCOV
597
        return nil
×
598
}
599

600
// FetchChanCommitment fetches a channel commitment. This function is exported
601
// so it can be used by later migrations.
602
func FetchChanCommitment(chanBucket kvdb.RBucket,
UNCOV
603
        local bool) (mig.ChannelCommitment, error) {
×
UNCOV
604

×
UNCOV
605
        commitKey := chanCommitmentKey
×
UNCOV
606
        if local {
×
UNCOV
607
                commitKey = append(commitKey, byte(0x00))
×
UNCOV
608
        } else {
×
UNCOV
609
                commitKey = append(commitKey, byte(0x01))
×
UNCOV
610
        }
×
611

UNCOV
612
        commitBytes := chanBucket.Get(commitKey)
×
UNCOV
613
        if commitBytes == nil {
×
614
                return mig.ChannelCommitment{}, ErrNoCommitmentsFound
×
615
        }
×
616

UNCOV
617
        r := bytes.NewReader(commitBytes)
×
UNCOV
618
        return mig.DeserializeChanCommit(r)
×
619
}
620

621
func PutChanCommitment(chanBucket kvdb.RwBucket, c *mig.ChannelCommitment,
UNCOV
622
        local bool) error {
×
UNCOV
623

×
UNCOV
624
        commitKey := chanCommitmentKey
×
UNCOV
625
        if local {
×
UNCOV
626
                commitKey = append(commitKey, byte(0x00))
×
UNCOV
627
        } else {
×
UNCOV
628
                commitKey = append(commitKey, byte(0x01))
×
UNCOV
629
        }
×
630

UNCOV
631
        var b bytes.Buffer
×
UNCOV
632
        if err := mig.SerializeChanCommit(&b, c); err != nil {
×
633
                return err
×
634
        }
×
635

UNCOV
636
        return chanBucket.Put(commitKey, b.Bytes())
×
637
}
638

UNCOV
639
func PutChanCommitments(chanBucket kvdb.RwBucket, channel *OpenChannel) error {
×
UNCOV
640
        // If this is a restored channel, then we don't have any commitments to
×
UNCOV
641
        // write.
×
UNCOV
642
        if channel.hasChanStatus(ChanStatusRestored) {
×
643
                return nil
×
644
        }
×
645

UNCOV
646
        err := PutChanCommitment(
×
UNCOV
647
                chanBucket, &channel.LocalCommitment, true,
×
UNCOV
648
        )
×
UNCOV
649
        if err != nil {
×
650
                return err
×
651
        }
×
652

UNCOV
653
        return PutChanCommitment(
×
UNCOV
654
                chanBucket, &channel.RemoteCommitment, false,
×
UNCOV
655
        )
×
656
}
657

658
// balancesAtHeight returns the local and remote balances on our commitment
659
// transactions as of a given height. This function is not exported as it's
660
// deprecated.
661
//
662
// NOTE: these are our balances *after* subtracting the commitment fee and
663
// anchor outputs.
664
func (c *OpenChannel) balancesAtHeight(chanBucket kvdb.RBucket,
UNCOV
665
        height uint64) (lnwire.MilliSatoshi, lnwire.MilliSatoshi, error) {
×
UNCOV
666

×
UNCOV
667
        // If our current commit is as the desired height, we can return our
×
UNCOV
668
        // current balances.
×
UNCOV
669
        if c.LocalCommitment.CommitHeight == height {
×
UNCOV
670
                return c.LocalCommitment.LocalBalance,
×
UNCOV
671
                        c.LocalCommitment.RemoteBalance, nil
×
UNCOV
672
        }
×
673

674
        // If our current remote commit is at the desired height, we can return
675
        // the current balances.
UNCOV
676
        if c.RemoteCommitment.CommitHeight == height {
×
677
                return c.RemoteCommitment.LocalBalance,
×
678
                        c.RemoteCommitment.RemoteBalance, nil
×
679
        }
×
680

681
        // If we are not currently on the height requested, we need to look up
682
        // the previous height to obtain our balances at the given height.
UNCOV
683
        commit, err := c.FindPreviousStateLegacy(chanBucket, height)
×
UNCOV
684
        if err != nil {
×
UNCOV
685
                return 0, 0, err
×
UNCOV
686
        }
×
687

UNCOV
688
        return commit.LocalBalance, commit.RemoteBalance, nil
×
689
}
690

691
// FindPreviousStateLegacy scans through the append-only log in an attempt to
692
// recover the previous channel state indicated by the update number. This
693
// method is intended to be used for obtaining the relevant data needed to
694
// claim all funds rightfully spendable in the case of an on-chain broadcast of
695
// the commitment transaction.
696
func (c *OpenChannel) FindPreviousStateLegacy(chanBucket kvdb.RBucket,
UNCOV
697
        updateNum uint64) (*mig.ChannelCommitment, error) {
×
UNCOV
698

×
UNCOV
699
        c.RLock()
×
UNCOV
700
        defer c.RUnlock()
×
UNCOV
701

×
UNCOV
702
        logBucket := chanBucket.NestedReadBucket(revocationLogBucketLegacy)
×
UNCOV
703
        if logBucket == nil {
×
UNCOV
704
                return nil, ErrNoPastDeltas
×
UNCOV
705
        }
×
706

UNCOV
707
        commit, err := fetchChannelLogEntry(logBucket, updateNum)
×
UNCOV
708
        if err != nil {
×
UNCOV
709
                return nil, err
×
UNCOV
710
        }
×
711

UNCOV
712
        return &commit, nil
×
713
}
714

715
func fetchChannelLogEntry(log kvdb.RBucket,
UNCOV
716
        updateNum uint64) (mig.ChannelCommitment, error) {
×
UNCOV
717

×
UNCOV
718
        logEntrykey := mig24.MakeLogKey(updateNum)
×
UNCOV
719
        commitBytes := log.Get(logEntrykey[:])
×
UNCOV
720
        if commitBytes == nil {
×
UNCOV
721
                return mig.ChannelCommitment{}, ErrLogEntryNotFound
×
UNCOV
722
        }
×
723

UNCOV
724
        commitReader := bytes.NewReader(commitBytes)
×
UNCOV
725
        return mig.DeserializeChanCommit(commitReader)
×
726
}
727

UNCOV
728
func CreateChanBucket(tx kvdb.RwTx, c *OpenChannel) (kvdb.RwBucket, error) {
×
UNCOV
729
        // First fetch the top level bucket which stores all data related to
×
UNCOV
730
        // current, active channels.
×
UNCOV
731
        openChanBucket, err := tx.CreateTopLevelBucket(openChannelBucket)
×
UNCOV
732
        if err != nil {
×
733
                return nil, err
×
734
        }
×
735

736
        // Within this top level bucket, fetch the bucket dedicated to storing
737
        // open channel data specific to the remote node.
UNCOV
738
        nodePub := c.IdentityPub.SerializeCompressed()
×
UNCOV
739
        nodeChanBucket, err := openChanBucket.CreateBucketIfNotExists(nodePub)
×
UNCOV
740
        if err != nil {
×
741
                return nil, err
×
742
        }
×
743

744
        // We'll then recurse down an additional layer in order to fetch the
745
        // bucket for this particular chain.
UNCOV
746
        chainBucket, err := nodeChanBucket.CreateBucketIfNotExists(
×
UNCOV
747
                c.ChainHash[:],
×
UNCOV
748
        )
×
UNCOV
749
        if err != nil {
×
750
                return nil, err
×
751
        }
×
752

UNCOV
753
        var chanPointBuf bytes.Buffer
×
UNCOV
754
        err = mig.WriteOutpoint(&chanPointBuf, &c.FundingOutpoint)
×
UNCOV
755
        if err != nil {
×
756
                return nil, err
×
757
        }
×
758

759
        // With the bucket for the node fetched, we can now go down another
760
        // level, creating the bucket for this channel itself.
UNCOV
761
        return chainBucket.CreateBucketIfNotExists(chanPointBuf.Bytes())
×
762
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc