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

lightningnetwork / lnd / 13211764208

08 Feb 2025 03:08AM UTC coverage: 49.288% (-9.5%) from 58.815%
13211764208

Pull #9489

github

calvinrzachman
itest: verify switchrpc server enforces send then track

We prevent the rpc server from allowing onion dispatches for
attempt IDs which have already been tracked by rpc clients.

This helps protect the client from leaking a duplicate onion
attempt. NOTE: This is not the only method for solving this
issue! The issue could be addressed via careful client side
programming which accounts for the uncertainty and async
nature of dispatching onions to a remote process via RPC.
This would require some lnd ChannelRouter changes for how
we intend to use these RPCs though.
Pull Request #9489: multi: add BuildOnion, SendOnion, and TrackOnion RPCs

474 of 990 new or added lines in 11 files covered. (47.88%)

27321 existing lines in 435 files now uncovered.

101192 of 205306 relevant lines covered (49.29%)

1.54 hits per line

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

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

3
import (
4
        "errors"
5
        "fmt"
6
        "io"
7
        "strconv"
8
        "strings"
9
        "sync"
10

11
        "github.com/btcsuite/btcd/btcec/v2"
12
        "github.com/btcsuite/btcd/btcutil"
13
        "github.com/btcsuite/btcd/chaincfg/chainhash"
14
        "github.com/btcsuite/btcd/wire"
15
        lnwire "github.com/lightningnetwork/lnd/channeldb/migration/lnwire21"
16
        "github.com/lightningnetwork/lnd/keychain"
17
        "github.com/lightningnetwork/lnd/shachain"
18
)
19

20
var (
21
        // closedChannelBucket stores summarization information concerning
22
        // previously open, but now closed channels.
23
        closedChannelBucket = []byte("closed-chan-bucket")
24

25
        // openChanBucket stores all the currently open channels. This bucket
26
        // has a second, nested bucket which is keyed by a node's ID. Within
27
        // that node ID bucket, all attributes required to track, update, and
28
        // close a channel are stored.
29
        //
30
        // openChan -> nodeID -> chanPoint
31
        //
32
        // TODO(roasbeef): flesh out comment
33
        openChannelBucket = []byte("open-chan-bucket")
34
)
35

36
// ChannelType is an enum-like type that describes one of several possible
37
// channel types. Each open channel is associated with a particular type as the
38
// channel type may determine how higher level operations are conducted such as
39
// fee negotiation, channel closing, the format of HTLCs, etc.
40
// TODO(roasbeef): split up per-chain?
41
type ChannelType uint8
42

43
const (
44
        // NOTE: iota isn't used here for this enum needs to be stable
45
        // long-term as it will be persisted to the database.
46

47
        // SingleFunder represents a channel wherein one party solely funds the
48
        // entire capacity of the channel.
49
        SingleFunder ChannelType = 0
50
)
51

52
// ChannelConstraints represents a set of constraints meant to allow a node to
53
// limit their exposure, enact flow control and ensure that all HTLCs are
54
// economically relevant. This struct will be mirrored for both sides of the
55
// channel, as each side will enforce various constraints that MUST be adhered
56
// to for the life time of the channel. The parameters for each of these
57
// constraints are static for the duration of the channel, meaning the channel
58
// must be torn down for them to change.
59
type ChannelConstraints struct {
60
        // DustLimit is the threshold (in satoshis) below which any outputs
61
        // should be trimmed. When an output is trimmed, it isn't materialized
62
        // as an actual output, but is instead burned to miner's fees.
63
        DustLimit btcutil.Amount
64

65
        // ChanReserve is an absolute reservation on the channel for the
66
        // owner of this set of constraints. This means that the current
67
        // settled balance for this node CANNOT dip below the reservation
68
        // amount. This acts as a defense against costless attacks when
69
        // either side no longer has any skin in the game.
70
        ChanReserve btcutil.Amount
71

72
        // MaxPendingAmount is the maximum pending HTLC value that the
73
        // owner of these constraints can offer the remote node at a
74
        // particular time.
75
        MaxPendingAmount lnwire.MilliSatoshi
76

77
        // MinHTLC is the minimum HTLC value that the owner of these
78
        // constraints can offer the remote node. If any HTLCs below this
79
        // amount are offered, then the HTLC will be rejected. This, in
80
        // tandem with the dust limit allows a node to regulate the
81
        // smallest HTLC that it deems economically relevant.
82
        MinHTLC lnwire.MilliSatoshi
83

84
        // MaxAcceptedHtlcs is the maximum number of HTLCs that the owner of
85
        // this set of constraints can offer the remote node. This allows each
86
        // node to limit their over all exposure to HTLCs that may need to be
87
        // acted upon in the case of a unilateral channel closure or a contract
88
        // breach.
89
        MaxAcceptedHtlcs uint16
90

91
        // CsvDelay is the relative time lock delay expressed in blocks. Any
92
        // settled outputs that pay to the owner of this channel configuration
93
        // MUST ensure that the delay branch uses this value as the relative
94
        // time lock. Similarly, any HTLC's offered by this node should use
95
        // this value as well.
96
        CsvDelay uint16
97
}
98

99
// ChannelConfig is a struct that houses the various configuration opens for
100
// channels. Each side maintains an instance of this configuration file as it
101
// governs: how the funding and commitment transaction to be created, the
102
// nature of HTLC's allotted, the keys to be used for delivery, and relative
103
// time lock parameters.
104
type ChannelConfig struct {
105
        // ChannelConstraints is the set of constraints that must be upheld for
106
        // the duration of the channel for the owner of this channel
107
        // configuration. Constraints govern a number of flow control related
108
        // parameters, also including the smallest HTLC that will be accepted
109
        // by a participant.
110
        ChannelConstraints
111

112
        // MultiSigKey is the key to be used within the 2-of-2 output script
113
        // for the owner of this channel config.
114
        MultiSigKey keychain.KeyDescriptor
115

116
        // RevocationBasePoint is the base public key to be used when deriving
117
        // revocation keys for the remote node's commitment transaction. This
118
        // will be combined along with a per commitment secret to derive a
119
        // unique revocation key for each state.
120
        RevocationBasePoint keychain.KeyDescriptor
121

122
        // PaymentBasePoint is the base public key to be used when deriving
123
        // the key used within the non-delayed pay-to-self output on the
124
        // commitment transaction for a node. This will be combined with a
125
        // tweak derived from the per-commitment point to ensure unique keys
126
        // for each commitment transaction.
127
        PaymentBasePoint keychain.KeyDescriptor
128

129
        // DelayBasePoint is the base public key to be used when deriving the
130
        // key used within the delayed pay-to-self output on the commitment
131
        // transaction for a node. This will be combined with a tweak derived
132
        // from the per-commitment point to ensure unique keys for each
133
        // commitment transaction.
134
        DelayBasePoint keychain.KeyDescriptor
135

136
        // HtlcBasePoint is the base public key to be used when deriving the
137
        // local HTLC key. The derived key (combined with the tweak derived
138
        // from the per-commitment point) is used within the "to self" clause
139
        // within any HTLC output scripts.
140
        HtlcBasePoint keychain.KeyDescriptor
141
}
142

143
// ChannelCommitment is a snapshot of the commitment state at a particular
144
// point in the commitment chain. With each state transition, a snapshot of the
145
// current state along with all non-settled HTLCs are recorded. These snapshots
146
// detail the state of the _remote_ party's commitment at a particular state
147
// number.  For ourselves (the local node) we ONLY store our most recent
148
// (unrevoked) state for safety purposes.
149
type ChannelCommitment struct {
150
        // CommitHeight is the update number that this ChannelDelta represents
151
        // the total number of commitment updates to this point. This can be
152
        // viewed as sort of a "commitment height" as this number is
153
        // monotonically increasing.
154
        CommitHeight uint64
155

156
        // LocalLogIndex is the cumulative log index index of the local node at
157
        // this point in the commitment chain. This value will be incremented
158
        // for each _update_ added to the local update log.
159
        LocalLogIndex uint64
160

161
        // LocalHtlcIndex is the current local running HTLC index. This value
162
        // will be incremented for each outgoing HTLC the local node offers.
163
        LocalHtlcIndex uint64
164

165
        // RemoteLogIndex is the cumulative log index index of the remote node
166
        // at this point in the commitment chain. This value will be
167
        // incremented for each _update_ added to the remote update log.
168
        RemoteLogIndex uint64
169

170
        // RemoteHtlcIndex is the current remote running HTLC index. This value
171
        // will be incremented for each outgoing HTLC the remote node offers.
172
        RemoteHtlcIndex uint64
173

174
        // LocalBalance is the current available settled balance within the
175
        // channel directly spendable by us.
176
        LocalBalance lnwire.MilliSatoshi
177

178
        // RemoteBalance is the current available settled balance within the
179
        // channel directly spendable by the remote node.
180
        RemoteBalance lnwire.MilliSatoshi
181

182
        // CommitFee is the amount calculated to be paid in fees for the
183
        // current set of commitment transactions. The fee amount is persisted
184
        // with the channel in order to allow the fee amount to be removed and
185
        // recalculated with each channel state update, including updates that
186
        // happen after a system restart.
187
        CommitFee btcutil.Amount
188

189
        // FeePerKw is the min satoshis/kilo-weight that should be paid within
190
        // the commitment transaction for the entire duration of the channel's
191
        // lifetime. This field may be updated during normal operation of the
192
        // channel as on-chain conditions change.
193
        //
194
        // TODO(halseth): make this SatPerKWeight. Cannot be done atm because
195
        // this will cause the import cycle lnwallet<->channeldb. Fee
196
        // estimation stuff should be in its own package.
197
        FeePerKw btcutil.Amount
198

199
        // CommitTx is the latest version of the commitment state, broadcast
200
        // able by us.
201
        CommitTx *wire.MsgTx
202

203
        // CommitSig is one half of the signature required to fully complete
204
        // the script for the commitment transaction above. This is the
205
        // signature signed by the remote party for our version of the
206
        // commitment transactions.
207
        CommitSig []byte
208

209
        // Htlcs is the set of HTLC's that are pending at this particular
210
        // commitment height.
211
        Htlcs []HTLC
212

213
        // TODO(roasbeef): pending commit pointer?
214
        //  * lets just walk through
215
}
216

217
// ChannelStatus is a bit vector used to indicate whether an OpenChannel is in
218
// the default usable state, or a state where it shouldn't be used.
219
type ChannelStatus uint8
220

221
var (
222
        // ChanStatusDefault is the normal state of an open channel.
223
        ChanStatusDefault ChannelStatus
224

225
        // ChanStatusBorked indicates that the channel has entered an
226
        // irreconcilable state, triggered by a state desynchronization or
227
        // channel breach.  Channels in this state should never be added to the
228
        // htlc switch.
229
        ChanStatusBorked ChannelStatus = 1
230

231
        // ChanStatusCommitBroadcasted indicates that a commitment for this
232
        // channel has been broadcasted.
233
        ChanStatusCommitBroadcasted ChannelStatus = 1 << 1
234

235
        // ChanStatusLocalDataLoss indicates that we have lost channel state
236
        // for this channel, and broadcasting our latest commitment might be
237
        // considered a breach.
238
        //
239
        // TODO(halseh): actually enforce that we are not force closing such a
240
        // channel.
241
        ChanStatusLocalDataLoss ChannelStatus = 1 << 2
242

243
        // ChanStatusRestored is a status flag that signals that the channel
244
        // has been restored, and doesn't have all the fields a typical channel
245
        // will have.
246
        ChanStatusRestored ChannelStatus = 1 << 3
247
)
248

249
// chanStatusStrings maps a ChannelStatus to a human friendly string that
250
// describes that status.
251
var chanStatusStrings = map[ChannelStatus]string{
252
        ChanStatusDefault:           "ChanStatusDefault",
253
        ChanStatusBorked:            "ChanStatusBorked",
254
        ChanStatusCommitBroadcasted: "ChanStatusCommitBroadcasted",
255
        ChanStatusLocalDataLoss:     "ChanStatusLocalDataLoss",
256
        ChanStatusRestored:          "ChanStatusRestored",
257
}
258

259
// orderedChanStatusFlags is an in-order list of all that channel status flags.
260
var orderedChanStatusFlags = []ChannelStatus{
261
        ChanStatusDefault,
262
        ChanStatusBorked,
263
        ChanStatusCommitBroadcasted,
264
        ChanStatusLocalDataLoss,
265
        ChanStatusRestored,
266
}
267

268
// String returns a human-readable representation of the ChannelStatus.
269
func (c ChannelStatus) String() string {
×
270
        // If no flags are set, then this is the default case.
×
271
        if c == 0 {
×
272
                return chanStatusStrings[ChanStatusDefault]
×
273
        }
×
274

275
        // Add individual bit flags.
276
        statusStr := ""
×
277
        for _, flag := range orderedChanStatusFlags {
×
278
                if c&flag == flag {
×
279
                        statusStr += chanStatusStrings[flag] + "|"
×
280
                        c -= flag
×
281
                }
×
282
        }
283

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

×
287
        // Add any remaining flags which aren't accounted for as hex.
×
288
        if c != 0 {
×
289
                statusStr += "|0x" + strconv.FormatUint(uint64(c), 16)
×
290
        }
×
291

292
        // If this was purely an unknown flag, then remove the extra bar at the
293
        // start of the string.
294
        statusStr = strings.TrimLeft(statusStr, "|")
×
295

×
296
        return statusStr
×
297
}
298

299
// OpenChannel encapsulates the persistent and dynamic state of an open channel
300
// with a remote node. An open channel supports several options for on-disk
301
// serialization depending on the exact context. Full (upon channel creation)
302
// state commitments, and partial (due to a commitment update) writes are
303
// supported. Each partial write due to a state update appends the new update
304
// to an on-disk log, which can then subsequently be queried in order to
305
// "time-travel" to a prior state.
306
type OpenChannel struct {
307
        // ChanType denotes which type of channel this is.
308
        ChanType ChannelType
309

310
        // ChainHash is a hash which represents the blockchain that this
311
        // channel will be opened within. This value is typically the genesis
312
        // hash. In the case that the original chain went through a contentious
313
        // hard-fork, then this value will be tweaked using the unique fork
314
        // point on each branch.
315
        ChainHash chainhash.Hash
316

317
        // FundingOutpoint is the outpoint of the final funding transaction.
318
        // This value uniquely and globally identifies the channel within the
319
        // target blockchain as specified by the chain hash parameter.
320
        FundingOutpoint wire.OutPoint
321

322
        // ShortChannelID encodes the exact location in the chain in which the
323
        // channel was initially confirmed. This includes: the block height,
324
        // transaction index, and the output within the target transaction.
325
        ShortChannelID lnwire.ShortChannelID
326

327
        // IsPending indicates whether a channel's funding transaction has been
328
        // confirmed.
329
        IsPending bool
330

331
        // IsInitiator is a bool which indicates if we were the original
332
        // initiator for the channel. This value may affect how higher levels
333
        // negotiate fees, or close the channel.
334
        IsInitiator bool
335

336
        // FundingBroadcastHeight is the height in which the funding
337
        // transaction was broadcast. This value can be used by higher level
338
        // sub-systems to determine if a channel is stale and/or should have
339
        // been confirmed before a certain height.
340
        FundingBroadcastHeight uint32
341

342
        // NumConfsRequired is the number of confirmations a channel's funding
343
        // transaction must have received in order to be considered available
344
        // for normal transactional use.
345
        NumConfsRequired uint16
346

347
        // ChannelFlags holds the flags that were sent as part of the
348
        // open_channel message.
349
        ChannelFlags lnwire.FundingFlag
350

351
        // IdentityPub is the identity public key of the remote node this
352
        // channel has been established with.
353
        IdentityPub *btcec.PublicKey
354

355
        // Capacity is the total capacity of this channel.
356
        Capacity btcutil.Amount
357

358
        // TotalMSatSent is the total number of milli-satoshis we've sent
359
        // within this channel.
360
        TotalMSatSent lnwire.MilliSatoshi
361

362
        // TotalMSatReceived is the total number of milli-satoshis we've
363
        // received within this channel.
364
        TotalMSatReceived lnwire.MilliSatoshi
365

366
        // LocalChanCfg is the channel configuration for the local node.
367
        LocalChanCfg ChannelConfig
368

369
        // RemoteChanCfg is the channel configuration for the remote node.
370
        RemoteChanCfg ChannelConfig
371

372
        // LocalCommitment is the current local commitment state for the local
373
        // party. This is stored distinct from the state of the remote party
374
        // as there are certain asymmetric parameters which affect the
375
        // structure of each commitment.
376
        LocalCommitment ChannelCommitment
377

378
        // RemoteCommitment is the current remote commitment state for the
379
        // remote party. This is stored distinct from the state of the local
380
        // party as there are certain asymmetric parameters which affect the
381
        // structure of each commitment.
382
        RemoteCommitment ChannelCommitment
383

384
        // RemoteCurrentRevocation is the current revocation for their
385
        // commitment transaction. However, since this the derived public key,
386
        // we don't yet have the private key so we aren't yet able to verify
387
        // that it's actually in the hash chain.
388
        RemoteCurrentRevocation *btcec.PublicKey
389

390
        // RemoteNextRevocation is the revocation key to be used for the *next*
391
        // commitment transaction we create for the local node. Within the
392
        // specification, this value is referred to as the
393
        // per-commitment-point.
394
        RemoteNextRevocation *btcec.PublicKey
395

396
        // RevocationProducer is used to generate the revocation in such a way
397
        // that remote side might store it efficiently and have the ability to
398
        // restore the revocation by index if needed. Current implementation of
399
        // secret producer is shachain producer.
400
        RevocationProducer shachain.Producer
401

402
        // RevocationStore is used to efficiently store the revocations for
403
        // previous channels states sent to us by remote side. Current
404
        // implementation of secret store is shachain store.
405
        RevocationStore shachain.Store
406

407
        // FundingTxn is the transaction containing this channel's funding
408
        // outpoint. Upon restarts, this txn will be rebroadcast if the channel
409
        // is found to be pending.
410
        //
411
        // NOTE: This value will only be populated for single-funder channels
412
        // for which we are the initiator.
413
        FundingTxn *wire.MsgTx
414

415
        // TODO(roasbeef): eww
416
        Db *DB
417

418
        // TODO(roasbeef): just need to store local and remote HTLC's?
419

420
        sync.RWMutex
421
}
422

423
// ShortChanID returns the current ShortChannelID of this channel.
UNCOV
424
func (c *OpenChannel) ShortChanID() lnwire.ShortChannelID {
×
UNCOV
425
        c.RLock()
×
UNCOV
426
        defer c.RUnlock()
×
UNCOV
427

×
UNCOV
428
        return c.ShortChannelID
×
UNCOV
429
}
×
430

431
// HTLC is the on-disk representation of a hash time-locked contract. HTLCs are
432
// contained within ChannelDeltas which encode the current state of the
433
// commitment between state updates.
434
//
435
// TODO(roasbeef): save space by using smaller ints at tail end?
436
type HTLC struct {
437
        // Signature is the signature for the second level covenant transaction
438
        // for this HTLC. The second level transaction is a timeout tx in the
439
        // case that this is an outgoing HTLC, and a success tx in the case
440
        // that this is an incoming HTLC.
441
        //
442
        // TODO(roasbeef): make [64]byte instead?
443
        Signature []byte
444

445
        // RHash is the payment hash of the HTLC.
446
        RHash [32]byte
447

448
        // Amt is the amount of milli-satoshis this HTLC escrows.
449
        Amt lnwire.MilliSatoshi
450

451
        // RefundTimeout is the absolute timeout on the HTLC that the sender
452
        // must wait before reclaiming the funds in limbo.
453
        RefundTimeout uint32
454

455
        // OutputIndex is the output index for this particular HTLC output
456
        // within the commitment transaction.
457
        OutputIndex int32
458

459
        // Incoming denotes whether we're the receiver or the sender of this
460
        // HTLC.
461
        Incoming bool
462

463
        // OnionBlob is an opaque blob which is used to complete multi-hop
464
        // routing.
465
        OnionBlob []byte
466

467
        // HtlcIndex is the HTLC counter index of this active, outstanding
468
        // HTLC. This differs from the LogIndex, as the HtlcIndex is only
469
        // incremented for each offered HTLC, while they LogIndex is
470
        // incremented for each update (includes settle+fail).
471
        HtlcIndex uint64
472

473
        // LogIndex is the cumulative log index of this HTLC. This differs
474
        // from the HtlcIndex as this will be incremented for each new log
475
        // update added.
476
        LogIndex uint64
477
}
478

479
// CircuitKey is used by a channel to uniquely identify the HTLCs it receives
480
// from the switch, and is used to purge our in-memory state of HTLCs that have
481
// already been processed by a link. Two list of CircuitKeys are included in
482
// each CommitDiff to allow a link to determine which in-memory htlcs directed
483
// the opening and closing of circuits in the switch's circuit map.
484
type CircuitKey struct {
485
        // ChanID is the short chanid indicating the HTLC's origin.
486
        //
487
        // NOTE: It is fine for this value to be blank, as this indicates a
488
        // locally-sourced payment.
489
        ChanID lnwire.ShortChannelID
490

491
        // HtlcID is the unique htlc index predominately assigned by links,
492
        // though can also be assigned by switch in the case of locally-sourced
493
        // payments.
494
        HtlcID uint64
495
}
496

497
// String returns a string representation of the CircuitKey.
498
func (k CircuitKey) String() string {
×
499
        return fmt.Sprintf("(Chan ID=%s, HTLC ID=%d)", k.ChanID, k.HtlcID)
×
500
}
×
501

502
// ClosureType is an enum like structure that details exactly _how_ a channel
503
// was closed. Three closure types are currently possible: none, cooperative,
504
// local force close, remote force close, and (remote) breach.
505
type ClosureType uint8
506

507
const (
508
        // RemoteForceClose indicates that the remote peer has unilaterally
509
        // broadcast their current commitment state on-chain.
510
        RemoteForceClose ClosureType = 4
511
)
512

513
// ChannelCloseSummary contains the final state of a channel at the point it
514
// was closed. Once a channel is closed, all the information pertaining to that
515
// channel within the openChannelBucket is deleted, and a compact summary is
516
// put in place instead.
517
type ChannelCloseSummary struct {
518
        // ChanPoint is the outpoint for this channel's funding transaction,
519
        // and is used as a unique identifier for the channel.
520
        ChanPoint wire.OutPoint
521

522
        // ShortChanID encodes the exact location in the chain in which the
523
        // channel was initially confirmed. This includes: the block height,
524
        // transaction index, and the output within the target transaction.
525
        ShortChanID lnwire.ShortChannelID
526

527
        // ChainHash is the hash of the genesis block that this channel resides
528
        // within.
529
        ChainHash chainhash.Hash
530

531
        // ClosingTXID is the txid of the transaction which ultimately closed
532
        // this channel.
533
        ClosingTXID chainhash.Hash
534

535
        // RemotePub is the public key of the remote peer that we formerly had
536
        // a channel with.
537
        RemotePub *btcec.PublicKey
538

539
        // Capacity was the total capacity of the channel.
540
        Capacity btcutil.Amount
541

542
        // CloseHeight is the height at which the funding transaction was
543
        // spent.
544
        CloseHeight uint32
545

546
        // SettledBalance is our total balance settled balance at the time of
547
        // channel closure. This _does not_ include the sum of any outputs that
548
        // have been time-locked as a result of the unilateral channel closure.
549
        SettledBalance btcutil.Amount
550

551
        // TimeLockedBalance is the sum of all the time-locked outputs at the
552
        // time of channel closure. If we triggered the force closure of this
553
        // channel, then this value will be non-zero if our settled output is
554
        // above the dust limit. If we were on the receiving side of a channel
555
        // force closure, then this value will be non-zero if we had any
556
        // outstanding outgoing HTLC's at the time of channel closure.
557
        TimeLockedBalance btcutil.Amount
558

559
        // CloseType details exactly _how_ the channel was closed. Five closure
560
        // types are possible: cooperative, local force, remote force, breach
561
        // and funding canceled.
562
        CloseType ClosureType
563

564
        // IsPending indicates whether this channel is in the 'pending close'
565
        // state, which means the channel closing transaction has been
566
        // confirmed, but not yet been fully resolved. In the case of a channel
567
        // that has been cooperatively closed, it will go straight into the
568
        // fully resolved state as soon as the closing transaction has been
569
        // confirmed. However, for channels that have been force closed, they'll
570
        // stay marked as "pending" until _all_ the pending funds have been
571
        // swept.
572
        IsPending bool
573

574
        // RemoteCurrentRevocation is the current revocation for their
575
        // commitment transaction. However, since this is the derived public key,
576
        // we don't yet have the private key so we aren't yet able to verify
577
        // that it's actually in the hash chain.
578
        RemoteCurrentRevocation *btcec.PublicKey
579

580
        // RemoteNextRevocation is the revocation key to be used for the *next*
581
        // commitment transaction we create for the local node. Within the
582
        // specification, this value is referred to as the
583
        // per-commitment-point.
584
        RemoteNextRevocation *btcec.PublicKey
585

586
        // LocalChanConfig is the channel configuration for the local node.
587
        LocalChanConfig ChannelConfig
588

589
        // LastChanSyncMsg is the ChannelReestablish message for this channel
590
        // for the state at the point where it was closed.
591
        LastChanSyncMsg *lnwire.ChannelReestablish
592
}
593

UNCOV
594
func serializeChannelCloseSummary(w io.Writer, cs *ChannelCloseSummary) error {
×
UNCOV
595
        err := WriteElements(w,
×
UNCOV
596
                cs.ChanPoint, cs.ShortChanID, cs.ChainHash, cs.ClosingTXID,
×
UNCOV
597
                cs.CloseHeight, cs.RemotePub, cs.Capacity, cs.SettledBalance,
×
UNCOV
598
                cs.TimeLockedBalance, cs.CloseType, cs.IsPending,
×
UNCOV
599
        )
×
UNCOV
600
        if err != nil {
×
601
                return err
×
602
        }
×
603

604
        // If this is a close channel summary created before the addition of
605
        // the new fields, then we can exit here.
UNCOV
606
        if cs.RemoteCurrentRevocation == nil {
×
UNCOV
607
                return WriteElements(w, false)
×
UNCOV
608
        }
×
609

610
        // If fields are present, write boolean to indicate this, and continue.
UNCOV
611
        if err := WriteElements(w, true); err != nil {
×
612
                return err
×
613
        }
×
614

UNCOV
615
        if err := WriteElements(w, cs.RemoteCurrentRevocation); err != nil {
×
616
                return err
×
617
        }
×
618

UNCOV
619
        if err := WriteChanConfig(w, &cs.LocalChanConfig); err != nil {
×
620
                return err
×
621
        }
×
622

623
        // The RemoteNextRevocation field is optional, as it's possible for a
624
        // channel to be closed before we learn of the next unrevoked
625
        // revocation point for the remote party. Write a boolean indicating
626
        // whether this field is present or not.
UNCOV
627
        if err := WriteElements(w, cs.RemoteNextRevocation != nil); err != nil {
×
628
                return err
×
629
        }
×
630

631
        // Write the field, if present.
UNCOV
632
        if cs.RemoteNextRevocation != nil {
×
UNCOV
633
                if err = WriteElements(w, cs.RemoteNextRevocation); err != nil {
×
634
                        return err
×
635
                }
×
636
        }
637

638
        // Write whether the channel sync message is present.
UNCOV
639
        if err := WriteElements(w, cs.LastChanSyncMsg != nil); err != nil {
×
640
                return err
×
641
        }
×
642

643
        // Write the channel sync message, if present.
UNCOV
644
        if cs.LastChanSyncMsg != nil {
×
645
                if err := WriteElements(w, cs.LastChanSyncMsg); err != nil {
×
646
                        return err
×
647
                }
×
648
        }
649

UNCOV
650
        return nil
×
651
}
652

UNCOV
653
func deserializeCloseChannelSummary(r io.Reader) (*ChannelCloseSummary, error) {
×
UNCOV
654
        c := &ChannelCloseSummary{}
×
UNCOV
655

×
UNCOV
656
        err := ReadElements(r,
×
UNCOV
657
                &c.ChanPoint, &c.ShortChanID, &c.ChainHash, &c.ClosingTXID,
×
UNCOV
658
                &c.CloseHeight, &c.RemotePub, &c.Capacity, &c.SettledBalance,
×
UNCOV
659
                &c.TimeLockedBalance, &c.CloseType, &c.IsPending,
×
UNCOV
660
        )
×
UNCOV
661
        if err != nil {
×
662
                return nil, err
×
663
        }
×
664

665
        // We'll now check to see if the channel close summary was encoded with
666
        // any of the additional optional fields.
UNCOV
667
        var hasNewFields bool
×
UNCOV
668
        err = ReadElements(r, &hasNewFields)
×
UNCOV
669
        if err != nil {
×
670
                return nil, err
×
671
        }
×
672

673
        // If fields are not present, we can return.
UNCOV
674
        if !hasNewFields {
×
UNCOV
675
                return c, nil
×
UNCOV
676
        }
×
677

678
        // Otherwise read the new fields.
UNCOV
679
        if err := ReadElements(r, &c.RemoteCurrentRevocation); err != nil {
×
680
                return nil, err
×
681
        }
×
682

UNCOV
683
        if err := ReadChanConfig(r, &c.LocalChanConfig); err != nil {
×
684
                return nil, err
×
685
        }
×
686

687
        // Finally, we'll attempt to read the next unrevoked commitment point
688
        // for the remote party. If we closed the channel before receiving a
689
        // funding locked message then this might not be present. A boolean
690
        // indicating whether the field is present will come first.
UNCOV
691
        var hasRemoteNextRevocation bool
×
UNCOV
692
        err = ReadElements(r, &hasRemoteNextRevocation)
×
UNCOV
693
        if err != nil {
×
694
                return nil, err
×
695
        }
×
696

697
        // If this field was written, read it.
UNCOV
698
        if hasRemoteNextRevocation {
×
UNCOV
699
                err = ReadElements(r, &c.RemoteNextRevocation)
×
UNCOV
700
                if err != nil {
×
701
                        return nil, err
×
702
                }
×
703
        }
704

705
        // Check if we have a channel sync message to read.
UNCOV
706
        var hasChanSyncMsg bool
×
UNCOV
707
        err = ReadElements(r, &hasChanSyncMsg)
×
UNCOV
708
        if err == io.EOF {
×
709
                return c, nil
×
UNCOV
710
        } else if err != nil {
×
711
                return nil, err
×
712
        }
×
713

714
        // If a chan sync message is present, read it.
UNCOV
715
        if hasChanSyncMsg {
×
716
                // We must pass in reference to a lnwire.Message for the codec
×
717
                // to support it.
×
718
                var msg lnwire.Message
×
719
                if err := ReadElements(r, &msg); err != nil {
×
720
                        return nil, err
×
721
                }
×
722

723
                chanSync, ok := msg.(*lnwire.ChannelReestablish)
×
724
                if !ok {
×
725
                        return nil, errors.New("unable cast db Message to " +
×
726
                                "ChannelReestablish")
×
727
                }
×
728
                c.LastChanSyncMsg = chanSync
×
729
        }
730

UNCOV
731
        return c, nil
×
732
}
733

UNCOV
734
func WriteChanConfig(b io.Writer, c *ChannelConfig) error {
×
UNCOV
735
        return WriteElements(b,
×
UNCOV
736
                c.DustLimit, c.MaxPendingAmount, c.ChanReserve, c.MinHTLC,
×
UNCOV
737
                c.MaxAcceptedHtlcs, c.CsvDelay, c.MultiSigKey,
×
UNCOV
738
                c.RevocationBasePoint, c.PaymentBasePoint, c.DelayBasePoint,
×
UNCOV
739
                c.HtlcBasePoint,
×
UNCOV
740
        )
×
UNCOV
741
}
×
742

UNCOV
743
func ReadChanConfig(b io.Reader, c *ChannelConfig) error {
×
UNCOV
744
        return ReadElements(b,
×
UNCOV
745
                &c.DustLimit, &c.MaxPendingAmount, &c.ChanReserve,
×
UNCOV
746
                &c.MinHTLC, &c.MaxAcceptedHtlcs, &c.CsvDelay,
×
UNCOV
747
                &c.MultiSigKey, &c.RevocationBasePoint,
×
UNCOV
748
                &c.PaymentBasePoint, &c.DelayBasePoint,
×
UNCOV
749
                &c.HtlcBasePoint,
×
UNCOV
750
        )
×
UNCOV
751
}
×
752

UNCOV
753
func DeserializeChanCommit(r io.Reader) (ChannelCommitment, error) {
×
UNCOV
754
        var c ChannelCommitment
×
UNCOV
755

×
UNCOV
756
        err := ReadElements(r,
×
UNCOV
757
                &c.CommitHeight, &c.LocalLogIndex, &c.LocalHtlcIndex, &c.RemoteLogIndex,
×
UNCOV
758
                &c.RemoteHtlcIndex, &c.LocalBalance, &c.RemoteBalance,
×
UNCOV
759
                &c.CommitFee, &c.FeePerKw, &c.CommitTx, &c.CommitSig,
×
UNCOV
760
        )
×
UNCOV
761
        if err != nil {
×
762
                return c, err
×
763
        }
×
764

UNCOV
765
        c.Htlcs, err = DeserializeHtlcs(r)
×
UNCOV
766
        if err != nil {
×
767
                return c, err
×
768
        }
×
769

UNCOV
770
        return c, nil
×
771
}
772

773
// DeserializeHtlcs attempts to read out a slice of HTLC's from the passed
774
// io.Reader. The bytes within the passed reader MUST have been previously
775
// written to using the SerializeHtlcs function.
776
//
777
// NOTE: This API is NOT stable, the on-disk format will likely change in the
778
// future.
UNCOV
779
func DeserializeHtlcs(r io.Reader) ([]HTLC, error) {
×
UNCOV
780
        var numHtlcs uint16
×
UNCOV
781
        if err := ReadElement(r, &numHtlcs); err != nil {
×
782
                return nil, err
×
783
        }
×
784

UNCOV
785
        var htlcs []HTLC
×
UNCOV
786
        if numHtlcs == 0 {
×
UNCOV
787
                return htlcs, nil
×
UNCOV
788
        }
×
789

UNCOV
790
        htlcs = make([]HTLC, numHtlcs)
×
UNCOV
791
        for i := uint16(0); i < numHtlcs; i++ {
×
UNCOV
792
                if err := ReadElements(r,
×
UNCOV
793
                        &htlcs[i].Signature, &htlcs[i].RHash, &htlcs[i].Amt,
×
UNCOV
794
                        &htlcs[i].RefundTimeout, &htlcs[i].OutputIndex,
×
UNCOV
795
                        &htlcs[i].Incoming, &htlcs[i].OnionBlob,
×
UNCOV
796
                        &htlcs[i].HtlcIndex, &htlcs[i].LogIndex,
×
UNCOV
797
                ); err != nil {
×
798
                        return htlcs, err
×
799
                }
×
800
        }
801

UNCOV
802
        return htlcs, nil
×
803
}
804

UNCOV
805
func SerializeChanCommit(w io.Writer, c *ChannelCommitment) error {
×
UNCOV
806
        if err := WriteElements(w,
×
UNCOV
807
                c.CommitHeight, c.LocalLogIndex, c.LocalHtlcIndex,
×
UNCOV
808
                c.RemoteLogIndex, c.RemoteHtlcIndex, c.LocalBalance,
×
UNCOV
809
                c.RemoteBalance, c.CommitFee, c.FeePerKw, c.CommitTx,
×
UNCOV
810
                c.CommitSig,
×
UNCOV
811
        ); err != nil {
×
812
                return err
×
813
        }
×
814

UNCOV
815
        return SerializeHtlcs(w, c.Htlcs...)
×
816
}
817

818
// SerializeHtlcs writes out the passed set of HTLC's into the passed writer
819
// using the current default on-disk serialization format.
820
//
821
// NOTE: This API is NOT stable, the on-disk format will likely change in the
822
// future.
UNCOV
823
func SerializeHtlcs(b io.Writer, htlcs ...HTLC) error {
×
UNCOV
824
        numHtlcs := uint16(len(htlcs))
×
UNCOV
825
        if err := WriteElement(b, numHtlcs); err != nil {
×
826
                return err
×
827
        }
×
828

UNCOV
829
        for _, htlc := range htlcs {
×
UNCOV
830
                if err := WriteElements(b,
×
UNCOV
831
                        htlc.Signature, htlc.RHash, htlc.Amt, htlc.RefundTimeout,
×
UNCOV
832
                        htlc.OutputIndex, htlc.Incoming, htlc.OnionBlob[:],
×
UNCOV
833
                        htlc.HtlcIndex, htlc.LogIndex,
×
UNCOV
834
                ); err != nil {
×
835
                        return err
×
836
                }
×
837
        }
838

UNCOV
839
        return nil
×
840
}
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