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

lightningnetwork / lnd / 8992481634

07 May 2024 09:20PM UTC coverage: 49.325% (-8.9%) from 58.246%
8992481634

push

github

web-flow
Merge pull request #8733 from lightningnetwork/0-18-branch-rc2

build: bump version to v0.18.0-beta.rc2

92557 of 187649 relevant lines covered (49.32%)

1.56 hits per line

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

89.06
/lnwallet/commitment.go
1
package lnwallet
2

3
import (
4
        "bytes"
5
        "fmt"
6

7
        "github.com/btcsuite/btcd/blockchain"
8
        "github.com/btcsuite/btcd/btcec/v2"
9
        "github.com/btcsuite/btcd/btcutil"
10
        "github.com/btcsuite/btcd/chaincfg/chainhash"
11
        "github.com/btcsuite/btcd/txscript"
12
        "github.com/btcsuite/btcd/wire"
13
        "github.com/lightningnetwork/lnd/channeldb"
14
        "github.com/lightningnetwork/lnd/input"
15
        "github.com/lightningnetwork/lnd/lnwallet/chainfee"
16
        "github.com/lightningnetwork/lnd/lnwire"
17
)
18

19
// anchorSize is the constant anchor output size.
20
const anchorSize = btcutil.Amount(330)
21

22
// DefaultAnchorsCommitMaxFeeRateSatPerVByte is the default max fee rate in
23
// sat/vbyte the initiator will use for anchor channels. This should be enough
24
// to ensure propagation before anchoring down the commitment transaction.
25
const DefaultAnchorsCommitMaxFeeRateSatPerVByte = 10
26

27
// CommitmentKeyRing holds all derived keys needed to construct commitment and
28
// HTLC transactions. The keys are derived differently depending whether the
29
// commitment transaction is ours or the remote peer's. Private keys associated
30
// with each key may belong to the commitment owner or the "other party" which
31
// is referred to in the field comments, regardless of which is local and which
32
// is remote.
33
type CommitmentKeyRing struct {
34
        // CommitPoint is the "per commitment point" used to derive the tweak
35
        // for each base point.
36
        CommitPoint *btcec.PublicKey
37

38
        // LocalCommitKeyTweak is the tweak used to derive the local public key
39
        // from the local payment base point or the local private key from the
40
        // base point secret. This may be included in a SignDescriptor to
41
        // generate signatures for the local payment key.
42
        //
43
        // NOTE: This will always refer to "our" local key, regardless of
44
        // whether this is our commit or not.
45
        LocalCommitKeyTweak []byte
46

47
        // TODO(roasbeef): need delay tweak as well?
48

49
        // LocalHtlcKeyTweak is the tweak used to derive the local HTLC key
50
        // from the local HTLC base point. This value is needed in order to
51
        // derive the final key used within the HTLC scripts in the commitment
52
        // transaction.
53
        //
54
        // NOTE: This will always refer to "our" local HTLC key, regardless of
55
        // whether this is our commit or not.
56
        LocalHtlcKeyTweak []byte
57

58
        // LocalHtlcKey is the key that will be used in any clause paying to
59
        // our node of any HTLC scripts within the commitment transaction for
60
        // this key ring set.
61
        //
62
        // NOTE: This will always refer to "our" local HTLC key, regardless of
63
        // whether this is our commit or not.
64
        LocalHtlcKey *btcec.PublicKey
65

66
        // RemoteHtlcKey is the key that will be used in clauses within the
67
        // HTLC script that send money to the remote party.
68
        //
69
        // NOTE: This will always refer to "their" remote HTLC key, regardless
70
        // of whether this is our commit or not.
71
        RemoteHtlcKey *btcec.PublicKey
72

73
        // ToLocalKey is the commitment transaction owner's key which is
74
        // included in HTLC success and timeout transaction scripts. This is
75
        // the public key used for the to_local output of the commitment
76
        // transaction.
77
        //
78
        // NOTE: Who's key this is depends on the current perspective. If this
79
        // is our commitment this will be our key.
80
        ToLocalKey *btcec.PublicKey
81

82
        // ToRemoteKey is the non-owner's payment key in the commitment tx.
83
        // This is the key used to generate the to_remote output within the
84
        // commitment transaction.
85
        //
86
        // NOTE: Who's key this is depends on the current perspective. If this
87
        // is our commitment this will be their key.
88
        ToRemoteKey *btcec.PublicKey
89

90
        // RevocationKey is the key that can be used by the other party to
91
        // redeem outputs from a revoked commitment transaction if it were to
92
        // be published.
93
        //
94
        // NOTE: Who can sign for this key depends on the current perspective.
95
        // If this is our commitment, it means the remote node can sign for
96
        // this key in case of a breach.
97
        RevocationKey *btcec.PublicKey
98
}
99

100
// DeriveCommitmentKeys generates a new commitment key set using the base points
101
// and commitment point. The keys are derived differently depending on the type
102
// of channel, and whether the commitment transaction is ours or the remote
103
// peer's.
104
func DeriveCommitmentKeys(commitPoint *btcec.PublicKey,
105
        isOurCommit bool, chanType channeldb.ChannelType,
106
        localChanCfg, remoteChanCfg *channeldb.ChannelConfig) *CommitmentKeyRing {
3✔
107

3✔
108
        tweaklessCommit := chanType.IsTweakless()
3✔
109

3✔
110
        // Depending on if this is our commit or not, we'll choose the correct
3✔
111
        // base point.
3✔
112
        localBasePoint := localChanCfg.PaymentBasePoint
3✔
113
        if isOurCommit {
6✔
114
                localBasePoint = localChanCfg.DelayBasePoint
3✔
115
        }
3✔
116

117
        // First, we'll derive all the keys that don't depend on the context of
118
        // whose commitment transaction this is.
119
        keyRing := &CommitmentKeyRing{
3✔
120
                CommitPoint: commitPoint,
3✔
121

3✔
122
                LocalCommitKeyTweak: input.SingleTweakBytes(
3✔
123
                        commitPoint, localBasePoint.PubKey,
3✔
124
                ),
3✔
125
                LocalHtlcKeyTweak: input.SingleTweakBytes(
3✔
126
                        commitPoint, localChanCfg.HtlcBasePoint.PubKey,
3✔
127
                ),
3✔
128
                LocalHtlcKey: input.TweakPubKey(
3✔
129
                        localChanCfg.HtlcBasePoint.PubKey, commitPoint,
3✔
130
                ),
3✔
131
                RemoteHtlcKey: input.TweakPubKey(
3✔
132
                        remoteChanCfg.HtlcBasePoint.PubKey, commitPoint,
3✔
133
                ),
3✔
134
        }
3✔
135

3✔
136
        // We'll now compute the to_local, to_remote, and revocation key based
3✔
137
        // on the current commitment point. All keys are tweaked each state in
3✔
138
        // order to ensure the keys from each state are unlinkable. To create
3✔
139
        // the revocation key, we take the opposite party's revocation base
3✔
140
        // point and combine that with the current commitment point.
3✔
141
        var (
3✔
142
                toLocalBasePoint    *btcec.PublicKey
3✔
143
                toRemoteBasePoint   *btcec.PublicKey
3✔
144
                revocationBasePoint *btcec.PublicKey
3✔
145
        )
3✔
146
        if isOurCommit {
6✔
147
                toLocalBasePoint = localChanCfg.DelayBasePoint.PubKey
3✔
148
                toRemoteBasePoint = remoteChanCfg.PaymentBasePoint.PubKey
3✔
149
                revocationBasePoint = remoteChanCfg.RevocationBasePoint.PubKey
3✔
150
        } else {
6✔
151
                toLocalBasePoint = remoteChanCfg.DelayBasePoint.PubKey
3✔
152
                toRemoteBasePoint = localChanCfg.PaymentBasePoint.PubKey
3✔
153
                revocationBasePoint = localChanCfg.RevocationBasePoint.PubKey
3✔
154
        }
3✔
155

156
        // With the base points assigned, we can now derive the actual keys
157
        // using the base point, and the current commitment tweak.
158
        keyRing.ToLocalKey = input.TweakPubKey(toLocalBasePoint, commitPoint)
3✔
159
        keyRing.RevocationKey = input.DeriveRevocationPubkey(
3✔
160
                revocationBasePoint, commitPoint,
3✔
161
        )
3✔
162

3✔
163
        // If this commitment should omit the tweak for the remote point, then
3✔
164
        // we'll use that directly, and ignore the commitPoint tweak.
3✔
165
        if tweaklessCommit {
6✔
166
                keyRing.ToRemoteKey = toRemoteBasePoint
3✔
167

3✔
168
                // If this is not our commitment, the above ToRemoteKey will be
3✔
169
                // ours, and we blank out the local commitment tweak to
3✔
170
                // indicate that the key should not be tweaked when signing.
3✔
171
                if !isOurCommit {
6✔
172
                        keyRing.LocalCommitKeyTweak = nil
3✔
173
                }
3✔
174
        } else {
3✔
175
                keyRing.ToRemoteKey = input.TweakPubKey(
3✔
176
                        toRemoteBasePoint, commitPoint,
3✔
177
                )
3✔
178
        }
3✔
179

180
        return keyRing
3✔
181
}
182

183
// WitnessScriptDesc holds the output script and the witness script for p2wsh
184
// outputs.
185
type WitnessScriptDesc struct {
186
        // OutputScript is the output's PkScript.
187
        OutputScript []byte
188

189
        // WitnessScript is the full script required to properly redeem the
190
        // output. This field should be set to the full script if a p2wsh
191
        // output is being signed. For p2wkh it should be set equal to the
192
        // PkScript.
193
        WitnessScript []byte
194
}
195

196
// PkScript is the public key script that commits to the final
197
// contract.
198
func (w *WitnessScriptDesc) PkScript() []byte {
3✔
199
        return w.OutputScript
3✔
200
}
3✔
201

202
// WitnessScript returns the witness script that we'll use when signing for the
203
// remote party, and also verifying signatures on our transactions. As an
204
// example, when we create an outgoing HTLC for the remote party, we want to
205
// sign their success path.
206
func (w *WitnessScriptDesc) WitnessScriptToSign() []byte {
3✔
207
        return w.WitnessScript
3✔
208
}
3✔
209

210
// WitnessScriptForPath returns the witness script for the given spending path.
211
// An error is returned if the path is unknown. This is useful as when
212
// constructing a contrl block for a given path, one also needs witness script
213
// being signed.
214
func (w *WitnessScriptDesc) WitnessScriptForPath(_ input.ScriptPath,
215
) ([]byte, error) {
3✔
216

3✔
217
        return w.WitnessScript, nil
3✔
218
}
3✔
219

220
// CommitScriptToSelf constructs the public key script for the output on the
221
// commitment transaction paying to the "owner" of said commitment transaction.
222
// The `initiator` argument should correspond to the owner of the commitment
223
// transaction which we are generating the to_local script for. If the other
224
// party learns of the preimage to the revocation hash, then they can claim all
225
// the settled funds in the channel, plus the unsettled funds.
226
func CommitScriptToSelf(chanType channeldb.ChannelType, initiator bool,
227
        selfKey, revokeKey *btcec.PublicKey, csvDelay, leaseExpiry uint32,
228
) (
229
        input.ScriptDescriptor, error) {
3✔
230

3✔
231
        switch {
3✔
232
        // For taproot scripts, we'll need to make a slightly modified script
233
        // where a NUMS key is used to force a script path reveal of either the
234
        // revocation or the CSV timeout.
235
        //
236
        // Our "redeem" script here is just the taproot witness program.
237
        case chanType.IsTaproot():
3✔
238
                return input.NewLocalCommitScriptTree(
3✔
239
                        csvDelay, selfKey, revokeKey,
3✔
240
                )
3✔
241

242
        // If we are the initiator of a leased channel, then we have an
243
        // additional CLTV requirement in addition to the usual CSV
244
        // requirement.
245
        case initiator && chanType.HasLeaseExpiration():
3✔
246
                toLocalRedeemScript, err := input.LeaseCommitScriptToSelf(
3✔
247
                        selfKey, revokeKey, csvDelay, leaseExpiry,
3✔
248
                )
3✔
249
                if err != nil {
3✔
250
                        return nil, err
×
251
                }
×
252

253
                toLocalScriptHash, err := input.WitnessScriptHash(
3✔
254
                        toLocalRedeemScript,
3✔
255
                )
3✔
256
                if err != nil {
3✔
257
                        return nil, err
×
258
                }
×
259

260
                return &WitnessScriptDesc{
3✔
261
                        OutputScript:  toLocalScriptHash,
3✔
262
                        WitnessScript: toLocalRedeemScript,
3✔
263
                }, nil
3✔
264

265
        default:
3✔
266
                toLocalRedeemScript, err := input.CommitScriptToSelf(
3✔
267
                        csvDelay, selfKey, revokeKey,
3✔
268
                )
3✔
269
                if err != nil {
3✔
270
                        return nil, err
×
271
                }
×
272

273
                toLocalScriptHash, err := input.WitnessScriptHash(
3✔
274
                        toLocalRedeemScript,
3✔
275
                )
3✔
276
                if err != nil {
3✔
277
                        return nil, err
×
278
                }
×
279

280
                return &WitnessScriptDesc{
3✔
281
                        OutputScript:  toLocalScriptHash,
3✔
282
                        WitnessScript: toLocalRedeemScript,
3✔
283
                }, nil
3✔
284
        }
285
}
286

287
// CommitScriptToRemote derives the appropriate to_remote script based on the
288
// channel's commitment type. The `initiator` argument should correspond to the
289
// owner of the commitment transaction which we are generating the to_remote
290
// script for. The second return value is the CSV delay of the output script,
291
// what must be satisfied in order to spend the output.
292
func CommitScriptToRemote(chanType channeldb.ChannelType, initiator bool,
293
        remoteKey *btcec.PublicKey,
294
        leaseExpiry uint32) (input.ScriptDescriptor, uint32, error) {
3✔
295

3✔
296
        switch {
3✔
297
        // If we are not the initiator of a leased channel, then the remote
298
        // party has an additional CLTV requirement in addition to the 1 block
299
        // CSV requirement.
300
        case chanType.HasLeaseExpiration() && !initiator:
3✔
301
                script, err := input.LeaseCommitScriptToRemoteConfirmed(
3✔
302
                        remoteKey, leaseExpiry,
3✔
303
                )
3✔
304
                if err != nil {
3✔
305
                        return nil, 0, err
×
306
                }
×
307

308
                p2wsh, err := input.WitnessScriptHash(script)
3✔
309
                if err != nil {
3✔
310
                        return nil, 0, err
×
311
                }
×
312

313
                return &WitnessScriptDesc{
3✔
314
                        OutputScript:  p2wsh,
3✔
315
                        WitnessScript: script,
3✔
316
                }, 1, nil
3✔
317

318
        // For taproot channels, we'll use a slightly different format, where
319
        // we use a NUMS key to force the remote party to take a script path,
320
        // with the sole tap leaf enforcing the 1 CSV delay.
321
        case chanType.IsTaproot():
3✔
322
                toRemoteScriptTree, err := input.NewRemoteCommitScriptTree(
3✔
323
                        remoteKey,
3✔
324
                )
3✔
325
                if err != nil {
3✔
326
                        return nil, 0, err
×
327
                }
×
328

329
                return toRemoteScriptTree, 1, nil
3✔
330

331
        // If this channel type has anchors, we derive the delayed to_remote
332
        // script.
333
        case chanType.HasAnchors():
3✔
334
                script, err := input.CommitScriptToRemoteConfirmed(remoteKey)
3✔
335
                if err != nil {
3✔
336
                        return nil, 0, err
×
337
                }
×
338

339
                p2wsh, err := input.WitnessScriptHash(script)
3✔
340
                if err != nil {
3✔
341
                        return nil, 0, err
×
342
                }
×
343

344
                return &WitnessScriptDesc{
3✔
345
                        OutputScript:  p2wsh,
3✔
346
                        WitnessScript: script,
3✔
347
                }, 1, nil
3✔
348

349
        default:
3✔
350
                // Otherwise the to_remote will be a simple p2wkh.
3✔
351
                p2wkh, err := input.CommitScriptUnencumbered(remoteKey)
3✔
352
                if err != nil {
3✔
353
                        return nil, 0, err
×
354
                }
×
355

356
                // Since this is a regular P2WKH, the WitnessScipt and PkScript
357
                // should both be set to the script hash.
358
                return &WitnessScriptDesc{
3✔
359
                        OutputScript:  p2wkh,
3✔
360
                        WitnessScript: p2wkh,
3✔
361
                }, 0, nil
3✔
362
        }
363
}
364

365
// HtlcSigHashType returns the sighash type to use for HTLC success and timeout
366
// transactions given the channel type.
367
func HtlcSigHashType(chanType channeldb.ChannelType) txscript.SigHashType {
3✔
368
        if chanType.HasAnchors() {
6✔
369
                return txscript.SigHashSingle | txscript.SigHashAnyOneCanPay
3✔
370
        }
3✔
371

372
        return txscript.SigHashAll
3✔
373
}
374

375
// HtlcSignDetails converts the passed parameters to a SignDetails valid for
376
// this channel type. For non-anchor channels this will return nil.
377
func HtlcSignDetails(chanType channeldb.ChannelType, signDesc input.SignDescriptor,
378
        sigHash txscript.SigHashType, peerSig input.Signature) *input.SignDetails {
3✔
379

3✔
380
        // Non-anchor channels don't need sign details, as the HTLC second
3✔
381
        // level cannot be altered.
3✔
382
        if !chanType.HasAnchors() {
6✔
383
                return nil
3✔
384
        }
3✔
385

386
        return &input.SignDetails{
3✔
387
                SignDesc:    signDesc,
3✔
388
                SigHashType: sigHash,
3✔
389
                PeerSig:     peerSig,
3✔
390
        }
3✔
391
}
392

393
// HtlcSecondLevelInputSequence dictates the sequence number we must use on the
394
// input to a second level HTLC transaction.
395
func HtlcSecondLevelInputSequence(chanType channeldb.ChannelType) uint32 {
3✔
396
        if chanType.HasAnchors() {
6✔
397
                return 1
3✔
398
        }
3✔
399

400
        return 0
3✔
401
}
402

403
// sweepSigHash returns the sign descriptor to use when signing a sweep
404
// transaction. For taproot channels, we'll use this to always sweep with
405
// sighash default.
406
func sweepSigHash(chanType channeldb.ChannelType) txscript.SigHashType {
3✔
407
        if chanType.IsTaproot() {
6✔
408
                return txscript.SigHashDefault
3✔
409
        }
3✔
410

411
        return txscript.SigHashAll
3✔
412
}
413

414
// SecondLevelHtlcScript derives the appropriate second level HTLC script based
415
// on the channel's commitment type. It is the uniform script that's used as the
416
// output for the second-level HTLC transactions. The second level transaction
417
// act as a sort of covenant, ensuring that a 2-of-2 multi-sig output can only
418
// be spent in a particular way, and to a particular output. The `initiator`
419
// argument should correspond to the owner of the commitment transaction which
420
// we are generating the to_local script for.
421
func SecondLevelHtlcScript(chanType channeldb.ChannelType, initiator bool,
422
        revocationKey, delayKey *btcec.PublicKey,
423
        csvDelay, leaseExpiry uint32) (input.ScriptDescriptor, error) {
3✔
424

3✔
425
        switch {
3✔
426
        // For taproot channels, the pkScript is a segwit v1 p2tr output.
427
        case chanType.IsTaproot():
3✔
428
                return input.TaprootSecondLevelScriptTree(
3✔
429
                        revocationKey, delayKey, csvDelay,
3✔
430
                )
3✔
431

432
        // If we are the initiator of a leased channel, then we have an
433
        // additional CLTV requirement in addition to the usual CSV
434
        // requirement.
435
        case initiator && chanType.HasLeaseExpiration():
3✔
436
                witnessScript, err := input.LeaseSecondLevelHtlcScript(
3✔
437
                        revocationKey, delayKey, csvDelay, leaseExpiry,
3✔
438
                )
3✔
439
                if err != nil {
3✔
440
                        return nil, err
×
441
                }
×
442

443
                pkScript, err := input.WitnessScriptHash(witnessScript)
3✔
444
                if err != nil {
3✔
445
                        return nil, err
×
446
                }
×
447

448
                return &WitnessScriptDesc{
3✔
449
                        OutputScript:  pkScript,
3✔
450
                        WitnessScript: witnessScript,
3✔
451
                }, nil
3✔
452

453
        default:
3✔
454
                witnessScript, err := input.SecondLevelHtlcScript(
3✔
455
                        revocationKey, delayKey, csvDelay,
3✔
456
                )
3✔
457
                if err != nil {
3✔
458
                        return nil, err
×
459
                }
×
460

461
                pkScript, err := input.WitnessScriptHash(witnessScript)
3✔
462
                if err != nil {
3✔
463
                        return nil, err
×
464
                }
×
465

466
                return &WitnessScriptDesc{
3✔
467
                        OutputScript:  pkScript,
3✔
468
                        WitnessScript: witnessScript,
3✔
469
                }, nil
3✔
470
        }
471
}
472

473
// CommitWeight returns the base commitment weight before adding HTLCs.
474
func CommitWeight(chanType channeldb.ChannelType) int64 {
3✔
475
        switch {
3✔
476
        case chanType.IsTaproot():
3✔
477
                return input.TaprootCommitWeight
3✔
478

479
        // If this commitment has anchors, it will be slightly heavier.
480
        case chanType.HasAnchors():
3✔
481
                return input.AnchorCommitWeight
3✔
482

483
        default:
3✔
484
                return input.CommitWeight
3✔
485
        }
486
}
487

488
// HtlcTimeoutFee returns the fee in satoshis required for an HTLC timeout
489
// transaction based on the current fee rate.
490
func HtlcTimeoutFee(chanType channeldb.ChannelType,
491
        feePerKw chainfee.SatPerKWeight) btcutil.Amount {
3✔
492

3✔
493
        switch {
3✔
494
        // For zero-fee HTLC channels, this will always be zero, regardless of
495
        // feerate.
496
        case chanType.ZeroHtlcTxFee() || chanType.IsTaproot():
3✔
497
                return 0
3✔
498

499
        case chanType.HasAnchors():
×
500
                return feePerKw.FeeForWeight(input.HtlcTimeoutWeightConfirmed)
×
501

502
        default:
3✔
503
                return feePerKw.FeeForWeight(input.HtlcTimeoutWeight)
3✔
504
        }
505
}
506

507
// HtlcSuccessFee returns the fee in satoshis required for an HTLC success
508
// transaction based on the current fee rate.
509
func HtlcSuccessFee(chanType channeldb.ChannelType,
510
        feePerKw chainfee.SatPerKWeight) btcutil.Amount {
3✔
511

3✔
512
        switch {
3✔
513
        // For zero-fee HTLC channels, this will always be zero, regardless of
514
        // feerate.
515
        case chanType.ZeroHtlcTxFee() || chanType.IsTaproot():
3✔
516
                return 0
3✔
517

518
        case chanType.HasAnchors():
×
519
                return feePerKw.FeeForWeight(input.HtlcSuccessWeightConfirmed)
×
520

521
        default:
3✔
522
                return feePerKw.FeeForWeight(input.HtlcSuccessWeight)
3✔
523
        }
524
}
525

526
// CommitScriptAnchors return the scripts to use for the local and remote
527
// anchor.
528
func CommitScriptAnchors(chanType channeldb.ChannelType,
529
        localChanCfg, remoteChanCfg *channeldb.ChannelConfig,
530
        keyRing *CommitmentKeyRing) (
531
        input.ScriptDescriptor, input.ScriptDescriptor, error) {
3✔
532

3✔
533
        var (
3✔
534
                anchorScript func(key *btcec.PublicKey) (
3✔
535
                        input.ScriptDescriptor, error)
3✔
536

3✔
537
                keySelector func(*channeldb.ChannelConfig,
3✔
538
                        bool) *btcec.PublicKey
3✔
539
        )
3✔
540

3✔
541
        switch {
3✔
542
        // For taproot channels, the anchor is slightly different: the top
543
        // level key is now the (relative) local delay and remote public key,
544
        // since these are fully revealed once the commitment hits the chain.
545
        case chanType.IsTaproot():
3✔
546
                anchorScript = func(key *btcec.PublicKey,
3✔
547
                ) (input.ScriptDescriptor, error) {
6✔
548

3✔
549
                        return input.NewAnchorScriptTree(
3✔
550
                                key,
3✔
551
                        )
3✔
552
                }
3✔
553

554
                keySelector = func(cfg *channeldb.ChannelConfig,
3✔
555
                        local bool) *btcec.PublicKey {
6✔
556

3✔
557
                        if local {
6✔
558
                                return keyRing.ToLocalKey
3✔
559
                        }
3✔
560

561
                        return keyRing.ToRemoteKey
3✔
562
                }
563

564
        // For normal channels we'll use the multi-sig keys since those are
565
        // revealed when the channel closes
566
        default:
3✔
567
                // For normal channels, we'll create a p2wsh script based on
3✔
568
                // the target key.
3✔
569
                anchorScript = func(key *btcec.PublicKey,
3✔
570
                ) (input.ScriptDescriptor, error) {
6✔
571

3✔
572
                        script, err := input.CommitScriptAnchor(key)
3✔
573
                        if err != nil {
3✔
574
                                return nil, err
×
575
                        }
×
576

577
                        scriptHash, err := input.WitnessScriptHash(script)
3✔
578
                        if err != nil {
3✔
579
                                return nil, err
×
580
                        }
×
581

582
                        return &WitnessScriptDesc{
3✔
583
                                OutputScript:  scriptHash,
3✔
584
                                WitnessScript: script,
3✔
585
                        }, nil
3✔
586
                }
587

588
                // For the existing channels, we'll always select the multi-sig
589
                // key from the party's channel config.
590
                keySelector = func(cfg *channeldb.ChannelConfig,
3✔
591
                        _ bool) *btcec.PublicKey {
6✔
592

3✔
593
                        return cfg.MultiSigKey.PubKey
3✔
594
                }
3✔
595
        }
596

597
        // Get the script used for the anchor output spendable by the local
598
        // node.
599
        localAnchor, err := anchorScript(keySelector(localChanCfg, true))
3✔
600
        if err != nil {
3✔
601
                return nil, nil, err
×
602
        }
×
603

604
        // And the anchor spendable by the remote node.
605
        remoteAnchor, err := anchorScript(keySelector(remoteChanCfg, false))
3✔
606
        if err != nil {
3✔
607
                return nil, nil, err
×
608
        }
×
609

610
        return localAnchor, remoteAnchor, nil
3✔
611
}
612

613
// CommitmentBuilder is a type that wraps the type of channel we are dealing
614
// with, and abstracts the various ways of constructing commitment
615
// transactions.
616
type CommitmentBuilder struct {
617
        // chanState is the underlying channels's state struct, used to
618
        // determine the type of channel we are dealing with, and relevant
619
        // parameters.
620
        chanState *channeldb.OpenChannel
621

622
        // obfuscator is a 48-bit state hint that's used to obfuscate the
623
        // current state number on the commitment transactions.
624
        obfuscator [StateHintSize]byte
625
}
626

627
// NewCommitmentBuilder creates a new CommitmentBuilder from chanState.
628
func NewCommitmentBuilder(chanState *channeldb.OpenChannel) *CommitmentBuilder {
3✔
629
        // The anchor channel type MUST be tweakless.
3✔
630
        if chanState.ChanType.HasAnchors() && !chanState.ChanType.IsTweakless() {
3✔
631
                panic("invalid channel type combination")
×
632
        }
633

634
        return &CommitmentBuilder{
3✔
635
                chanState:  chanState,
3✔
636
                obfuscator: createStateHintObfuscator(chanState),
3✔
637
        }
3✔
638
}
639

640
// createStateHintObfuscator derives and assigns the state hint obfuscator for
641
// the channel, which is used to encode the commitment height in the sequence
642
// number of commitment transaction inputs.
643
func createStateHintObfuscator(state *channeldb.OpenChannel) [StateHintSize]byte {
3✔
644
        if state.IsInitiator {
6✔
645
                return DeriveStateHintObfuscator(
3✔
646
                        state.LocalChanCfg.PaymentBasePoint.PubKey,
3✔
647
                        state.RemoteChanCfg.PaymentBasePoint.PubKey,
3✔
648
                )
3✔
649
        }
3✔
650

651
        return DeriveStateHintObfuscator(
3✔
652
                state.RemoteChanCfg.PaymentBasePoint.PubKey,
3✔
653
                state.LocalChanCfg.PaymentBasePoint.PubKey,
3✔
654
        )
3✔
655
}
656

657
// unsignedCommitmentTx is the final commitment created from evaluating an HTLC
658
// view at a given height, along with some meta data.
659
type unsignedCommitmentTx struct {
660
        // txn is the final, unsigned commitment transaction for this view.
661
        txn *wire.MsgTx
662

663
        // fee is the total fee of the commitment transaction.
664
        fee btcutil.Amount
665

666
        // ourBalance is our balance on this commitment *after* subtracting
667
        // commitment fees and anchor outputs. This can be different than the
668
        // balances before creating the commitment transaction as one party must
669
        // pay the commitment fee.
670
        ourBalance lnwire.MilliSatoshi
671

672
        // theirBalance is their balance of this commitment *after* subtracting
673
        // commitment fees and anchor outputs. This can be different than the
674
        // balances before creating the commitment transaction as one party must
675
        // pay the commitment fee.
676
        theirBalance lnwire.MilliSatoshi
677

678
        // cltvs is a sorted list of CLTV deltas for each HTLC on the commitment
679
        // transaction. Any non-htlc outputs will have a CLTV delay of zero.
680
        cltvs []uint32
681
}
682

683
// createUnsignedCommitmentTx generates the unsigned commitment transaction for
684
// a commitment view and returns it as part of the unsignedCommitmentTx. The
685
// passed in balances should be balances *before* subtracting any commitment
686
// fees, but after anchor outputs.
687
func (cb *CommitmentBuilder) createUnsignedCommitmentTx(ourBalance,
688
        theirBalance lnwire.MilliSatoshi, isOurs bool,
689
        feePerKw chainfee.SatPerKWeight, height uint64,
690
        filteredHTLCView *htlcView,
691
        keyRing *CommitmentKeyRing) (*unsignedCommitmentTx, error) {
3✔
692

3✔
693
        dustLimit := cb.chanState.LocalChanCfg.DustLimit
3✔
694
        if !isOurs {
6✔
695
                dustLimit = cb.chanState.RemoteChanCfg.DustLimit
3✔
696
        }
3✔
697

698
        numHTLCs := int64(0)
3✔
699
        for _, htlc := range filteredHTLCView.ourUpdates {
6✔
700
                if HtlcIsDust(
3✔
701
                        cb.chanState.ChanType, false, isOurs, feePerKw,
3✔
702
                        htlc.Amount.ToSatoshis(), dustLimit,
3✔
703
                ) {
6✔
704

3✔
705
                        continue
3✔
706
                }
707

708
                numHTLCs++
3✔
709
        }
710
        for _, htlc := range filteredHTLCView.theirUpdates {
6✔
711
                if HtlcIsDust(
3✔
712
                        cb.chanState.ChanType, true, isOurs, feePerKw,
3✔
713
                        htlc.Amount.ToSatoshis(), dustLimit,
3✔
714
                ) {
6✔
715

3✔
716
                        continue
3✔
717
                }
718

719
                numHTLCs++
3✔
720
        }
721

722
        // Next, we'll calculate the fee for the commitment transaction based
723
        // on its total weight. Once we have the total weight, we'll multiply
724
        // by the current fee-per-kw, then divide by 1000 to get the proper
725
        // fee.
726
        totalCommitWeight := CommitWeight(cb.chanState.ChanType) +
3✔
727
                input.HTLCWeight*numHTLCs
3✔
728

3✔
729
        // With the weight known, we can now calculate the commitment fee,
3✔
730
        // ensuring that we account for any dust outputs trimmed above.
3✔
731
        commitFee := feePerKw.FeeForWeight(totalCommitWeight)
3✔
732
        commitFeeMSat := lnwire.NewMSatFromSatoshis(commitFee)
3✔
733

3✔
734
        // Currently, within the protocol, the initiator always pays the fees.
3✔
735
        // So we'll subtract the fee amount from the balance of the current
3✔
736
        // initiator. If the initiator is unable to pay the fee fully, then
3✔
737
        // their entire output is consumed.
3✔
738
        switch {
3✔
739
        case cb.chanState.IsInitiator && commitFee > ourBalance.ToSatoshis():
×
740
                ourBalance = 0
×
741

742
        case cb.chanState.IsInitiator:
3✔
743
                ourBalance -= commitFeeMSat
3✔
744

745
        case !cb.chanState.IsInitiator && commitFee > theirBalance.ToSatoshis():
×
746
                theirBalance = 0
×
747

748
        case !cb.chanState.IsInitiator:
3✔
749
                theirBalance -= commitFeeMSat
3✔
750
        }
751

752
        var (
3✔
753
                commitTx *wire.MsgTx
3✔
754
                err      error
3✔
755
        )
3✔
756

3✔
757
        // Depending on whether the transaction is ours or not, we call
3✔
758
        // CreateCommitTx with parameters matching the perspective, to generate
3✔
759
        // a new commitment transaction with all the latest unsettled/un-timed
3✔
760
        // out HTLCs.
3✔
761
        var leaseExpiry uint32
3✔
762
        if cb.chanState.ChanType.HasLeaseExpiration() {
6✔
763
                leaseExpiry = cb.chanState.ThawHeight
3✔
764
        }
3✔
765
        if isOurs {
6✔
766
                commitTx, err = CreateCommitTx(
3✔
767
                        cb.chanState.ChanType, fundingTxIn(cb.chanState), keyRing,
3✔
768
                        &cb.chanState.LocalChanCfg, &cb.chanState.RemoteChanCfg,
3✔
769
                        ourBalance.ToSatoshis(), theirBalance.ToSatoshis(),
3✔
770
                        numHTLCs, cb.chanState.IsInitiator, leaseExpiry,
3✔
771
                )
3✔
772
        } else {
6✔
773
                commitTx, err = CreateCommitTx(
3✔
774
                        cb.chanState.ChanType, fundingTxIn(cb.chanState), keyRing,
3✔
775
                        &cb.chanState.RemoteChanCfg, &cb.chanState.LocalChanCfg,
3✔
776
                        theirBalance.ToSatoshis(), ourBalance.ToSatoshis(),
3✔
777
                        numHTLCs, !cb.chanState.IsInitiator, leaseExpiry,
3✔
778
                )
3✔
779
        }
3✔
780
        if err != nil {
3✔
781
                return nil, err
×
782
        }
×
783

784
        // We'll now add all the HTLC outputs to the commitment transaction.
785
        // Each output includes an off-chain 2-of-2 covenant clause, so we'll
786
        // need the objective local/remote keys for this particular commitment
787
        // as well. For any non-dust HTLCs that are manifested on the commitment
788
        // transaction, we'll also record its CLTV which is required to sort the
789
        // commitment transaction below. The slice is initially sized to the
790
        // number of existing outputs, since any outputs already added are
791
        // commitment outputs and should correspond to zero values for the
792
        // purposes of sorting.
793
        cltvs := make([]uint32, len(commitTx.TxOut))
3✔
794
        for _, htlc := range filteredHTLCView.ourUpdates {
6✔
795
                if HtlcIsDust(
3✔
796
                        cb.chanState.ChanType, false, isOurs, feePerKw,
3✔
797
                        htlc.Amount.ToSatoshis(), dustLimit,
3✔
798
                ) {
6✔
799

3✔
800
                        continue
3✔
801
                }
802

803
                err := addHTLC(
3✔
804
                        commitTx, isOurs, false, htlc, keyRing,
3✔
805
                        cb.chanState.ChanType,
3✔
806
                )
3✔
807
                if err != nil {
3✔
808
                        return nil, err
×
809
                }
×
810
                cltvs = append(cltvs, htlc.Timeout) // nolint:makezero
3✔
811
        }
812
        for _, htlc := range filteredHTLCView.theirUpdates {
6✔
813
                if HtlcIsDust(
3✔
814
                        cb.chanState.ChanType, true, isOurs, feePerKw,
3✔
815
                        htlc.Amount.ToSatoshis(), dustLimit,
3✔
816
                ) {
6✔
817

3✔
818
                        continue
3✔
819
                }
820

821
                err := addHTLC(
3✔
822
                        commitTx, isOurs, true, htlc, keyRing,
3✔
823
                        cb.chanState.ChanType,
3✔
824
                )
3✔
825
                if err != nil {
3✔
826
                        return nil, err
×
827
                }
×
828
                cltvs = append(cltvs, htlc.Timeout) // nolint:makezero
3✔
829
        }
830

831
        // Set the state hint of the commitment transaction to facilitate
832
        // quickly recovering the necessary penalty state in the case of an
833
        // uncooperative broadcast.
834
        err = SetStateNumHint(commitTx, height, cb.obfuscator)
3✔
835
        if err != nil {
3✔
836
                return nil, err
×
837
        }
×
838

839
        // Sort the transactions according to the agreed upon canonical
840
        // ordering. This lets us skip sending the entire transaction over,
841
        // instead we'll just send signatures.
842
        InPlaceCommitSort(commitTx, cltvs)
3✔
843

3✔
844
        // Next, we'll ensure that we don't accidentally create a commitment
3✔
845
        // transaction which would be invalid by consensus.
3✔
846
        uTx := btcutil.NewTx(commitTx)
3✔
847
        if err := blockchain.CheckTransactionSanity(uTx); err != nil {
3✔
848
                return nil, err
×
849
        }
×
850

851
        // Finally, we'll assert that were not attempting to draw more out of
852
        // the channel that was originally placed within it.
853
        var totalOut btcutil.Amount
3✔
854
        for _, txOut := range commitTx.TxOut {
6✔
855
                totalOut += btcutil.Amount(txOut.Value)
3✔
856
        }
3✔
857
        if totalOut+commitFee > cb.chanState.Capacity {
3✔
858
                return nil, fmt.Errorf("height=%v, for ChannelPoint(%v) "+
×
859
                        "attempts to consume %v while channel capacity is %v",
×
860
                        height, cb.chanState.FundingOutpoint,
×
861
                        totalOut+commitFee, cb.chanState.Capacity)
×
862
        }
×
863

864
        return &unsignedCommitmentTx{
3✔
865
                txn:          commitTx,
3✔
866
                fee:          commitFee,
3✔
867
                ourBalance:   ourBalance,
3✔
868
                theirBalance: theirBalance,
3✔
869
                cltvs:        cltvs,
3✔
870
        }, nil
3✔
871
}
872

873
// CreateCommitTx creates a commitment transaction, spending from specified
874
// funding output. The commitment transaction contains two outputs: one local
875
// output paying to the "owner" of the commitment transaction which can be
876
// spent after a relative block delay or revocation event, and a remote output
877
// paying the counterparty within the channel, which can be spent immediately
878
// or after a delay depending on the commitment type. The `initiator` argument
879
// should correspond to the owner of the commitment transaction we are creating.
880
func CreateCommitTx(chanType channeldb.ChannelType,
881
        fundingOutput wire.TxIn, keyRing *CommitmentKeyRing,
882
        localChanCfg, remoteChanCfg *channeldb.ChannelConfig,
883
        amountToLocal, amountToRemote btcutil.Amount,
884
        numHTLCs int64, initiator bool, leaseExpiry uint32) (*wire.MsgTx, error) {
3✔
885

3✔
886
        // First, we create the script for the delayed "pay-to-self" output.
3✔
887
        // This output has 2 main redemption clauses: either we can redeem the
3✔
888
        // output after a relative block delay, or the remote node can claim
3✔
889
        // the funds with the revocation key if we broadcast a revoked
3✔
890
        // commitment transaction.
3✔
891
        toLocalScript, err := CommitScriptToSelf(
3✔
892
                chanType, initiator, keyRing.ToLocalKey, keyRing.RevocationKey,
3✔
893
                uint32(localChanCfg.CsvDelay), leaseExpiry,
3✔
894
        )
3✔
895
        if err != nil {
3✔
896
                return nil, err
×
897
        }
×
898

899
        // Next, we create the script paying to the remote.
900
        toRemoteScript, _, err := CommitScriptToRemote(
3✔
901
                chanType, initiator, keyRing.ToRemoteKey, leaseExpiry,
3✔
902
        )
3✔
903
        if err != nil {
3✔
904
                return nil, err
×
905
        }
×
906

907
        // Now that both output scripts have been created, we can finally create
908
        // the transaction itself. We use a transaction version of 2 since CSV
909
        // will fail unless the tx version is >= 2.
910
        commitTx := wire.NewMsgTx(2)
3✔
911
        commitTx.AddTxIn(&fundingOutput)
3✔
912

3✔
913
        // Avoid creating dust outputs within the commitment transaction.
3✔
914
        localOutput := amountToLocal >= localChanCfg.DustLimit
3✔
915
        if localOutput {
6✔
916
                commitTx.AddTxOut(&wire.TxOut{
3✔
917
                        PkScript: toLocalScript.PkScript(),
3✔
918
                        Value:    int64(amountToLocal),
3✔
919
                })
3✔
920
        }
3✔
921

922
        remoteOutput := amountToRemote >= localChanCfg.DustLimit
3✔
923
        if remoteOutput {
6✔
924
                commitTx.AddTxOut(&wire.TxOut{
3✔
925
                        PkScript: toRemoteScript.PkScript(),
3✔
926
                        Value:    int64(amountToRemote),
3✔
927
                })
3✔
928
        }
3✔
929

930
        // If this channel type has anchors, we'll also add those.
931
        if chanType.HasAnchors() {
6✔
932
                localAnchor, remoteAnchor, err := CommitScriptAnchors(
3✔
933
                        chanType, localChanCfg, remoteChanCfg, keyRing,
3✔
934
                )
3✔
935
                if err != nil {
3✔
936
                        return nil, err
×
937
                }
×
938

939
                // Add local anchor output only if we have a commitment output
940
                // or there are HTLCs.
941
                if localOutput || numHTLCs > 0 {
6✔
942
                        commitTx.AddTxOut(&wire.TxOut{
3✔
943
                                PkScript: localAnchor.PkScript(),
3✔
944
                                Value:    int64(anchorSize),
3✔
945
                        })
3✔
946
                }
3✔
947

948
                // Add anchor output to remote only if they have a commitment
949
                // output or there are HTLCs.
950
                if remoteOutput || numHTLCs > 0 {
6✔
951
                        commitTx.AddTxOut(&wire.TxOut{
3✔
952
                                PkScript: remoteAnchor.PkScript(),
3✔
953
                                Value:    int64(anchorSize),
3✔
954
                        })
3✔
955
                }
3✔
956
        }
957

958
        return commitTx, nil
3✔
959
}
960

961
// CoopCloseBalance returns the final balances that should be used to create
962
// the cooperative close tx, given the channel type and transaction fee.
963
func CoopCloseBalance(chanType channeldb.ChannelType, isInitiator bool,
964
        coopCloseFee btcutil.Amount, localCommit channeldb.ChannelCommitment) (
965
        btcutil.Amount, btcutil.Amount, error) {
3✔
966

3✔
967
        // Get both parties' balances from the latest commitment.
3✔
968
        ourBalance := localCommit.LocalBalance.ToSatoshis()
3✔
969
        theirBalance := localCommit.RemoteBalance.ToSatoshis()
3✔
970

3✔
971
        // We'll make sure we account for the complete balance by adding the
3✔
972
        // current dangling commitment fee to the balance of the initiator.
3✔
973
        initiatorDelta := localCommit.CommitFee
3✔
974

3✔
975
        // Since the initiator's balance also is stored after subtracting the
3✔
976
        // anchor values, add that back in case this was an anchor commitment.
3✔
977
        if chanType.HasAnchors() {
6✔
978
                initiatorDelta += 2 * anchorSize
3✔
979
        }
3✔
980

981
        // The initiator will pay the full coop close fee, subtract that value
982
        // from their balance.
983
        initiatorDelta -= coopCloseFee
3✔
984

3✔
985
        if isInitiator {
6✔
986
                ourBalance += initiatorDelta
3✔
987
        } else {
6✔
988
                theirBalance += initiatorDelta
3✔
989
        }
3✔
990

991
        // During fee negotiation it should always be verified that the
992
        // initiator can pay the proposed fee, but we do a sanity check just to
993
        // be sure here.
994
        if ourBalance < 0 || theirBalance < 0 {
3✔
995
                return 0, 0, fmt.Errorf("initiator cannot afford proposed " +
×
996
                        "coop close fee")
×
997
        }
×
998

999
        return ourBalance, theirBalance, nil
3✔
1000
}
1001

1002
// genSegwitV0HtlcScript generates the HTLC scripts for a normal segwit v0
1003
// channel.
1004
func genSegwitV0HtlcScript(chanType channeldb.ChannelType,
1005
        isIncoming, ourCommit bool, timeout uint32, rHash [32]byte,
1006
        keyRing *CommitmentKeyRing) (*WitnessScriptDesc, error) {
3✔
1007

3✔
1008
        var (
3✔
1009
                witnessScript []byte
3✔
1010
                err           error
3✔
1011
        )
3✔
1012

3✔
1013
        // Choose scripts based on channel type.
3✔
1014
        confirmedHtlcSpends := false
3✔
1015
        if chanType.HasAnchors() {
6✔
1016
                confirmedHtlcSpends = true
3✔
1017
        }
3✔
1018

1019
        // Generate the proper redeem scripts for the HTLC output modified by
1020
        // two-bits denoting if this is an incoming HTLC, and if the HTLC is
1021
        // being applied to their commitment transaction or ours.
1022
        switch {
3✔
1023
        // The HTLC is paying to us, and being applied to our commitment
1024
        // transaction. So we need to use the receiver's version of the HTLC
1025
        // script.
1026
        case isIncoming && ourCommit:
3✔
1027
                witnessScript, err = input.ReceiverHTLCScript(
3✔
1028
                        timeout, keyRing.RemoteHtlcKey, keyRing.LocalHtlcKey,
3✔
1029
                        keyRing.RevocationKey, rHash[:], confirmedHtlcSpends,
3✔
1030
                )
3✔
1031

1032
        // We're being paid via an HTLC by the remote party, and the HTLC is
1033
        // being added to their commitment transaction, so we use the sender's
1034
        // version of the HTLC script.
1035
        case isIncoming && !ourCommit:
3✔
1036
                witnessScript, err = input.SenderHTLCScript(
3✔
1037
                        keyRing.RemoteHtlcKey, keyRing.LocalHtlcKey,
3✔
1038
                        keyRing.RevocationKey, rHash[:], confirmedHtlcSpends,
3✔
1039
                )
3✔
1040

1041
        // We're sending an HTLC which is being added to our commitment
1042
        // transaction. Therefore, we need to use the sender's version of the
1043
        // HTLC script.
1044
        case !isIncoming && ourCommit:
3✔
1045
                witnessScript, err = input.SenderHTLCScript(
3✔
1046
                        keyRing.LocalHtlcKey, keyRing.RemoteHtlcKey,
3✔
1047
                        keyRing.RevocationKey, rHash[:], confirmedHtlcSpends,
3✔
1048
                )
3✔
1049

1050
        // Finally, we're paying the remote party via an HTLC, which is being
1051
        // added to their commitment transaction. Therefore, we use the
1052
        // receiver's version of the HTLC script.
1053
        case !isIncoming && !ourCommit:
3✔
1054
                witnessScript, err = input.ReceiverHTLCScript(
3✔
1055
                        timeout, keyRing.LocalHtlcKey, keyRing.RemoteHtlcKey,
3✔
1056
                        keyRing.RevocationKey, rHash[:], confirmedHtlcSpends,
3✔
1057
                )
3✔
1058
        }
1059
        if err != nil {
3✔
1060
                return nil, err
×
1061
        }
×
1062

1063
        // Now that we have the redeem scripts, create the P2WSH public key
1064
        // script for the output itself.
1065
        htlcP2WSH, err := input.WitnessScriptHash(witnessScript)
3✔
1066
        if err != nil {
3✔
1067
                return nil, err
×
1068
        }
×
1069

1070
        return &WitnessScriptDesc{
3✔
1071
                OutputScript:  htlcP2WSH,
3✔
1072
                WitnessScript: witnessScript,
3✔
1073
        }, nil
3✔
1074
}
1075

1076
// genTaprootHtlcScript generates the HTLC scripts for a taproot+musig2
1077
// channel.
1078
func genTaprootHtlcScript(isIncoming, ourCommit bool, timeout uint32,
1079
        rHash [32]byte,
1080
        keyRing *CommitmentKeyRing) (*input.HtlcScriptTree, error) {
3✔
1081

3✔
1082
        var (
3✔
1083
                htlcScriptTree *input.HtlcScriptTree
3✔
1084
                err            error
3✔
1085
        )
3✔
1086

3✔
1087
        // Generate the proper redeem scripts for the HTLC output modified by
3✔
1088
        // two-bits denoting if this is an incoming HTLC, and if the HTLC is
3✔
1089
        // being applied to their commitment transaction or ours.
3✔
1090
        switch {
3✔
1091
        // The HTLC is paying to us, and being applied to our commitment
1092
        // transaction. So we need to use the receiver's version of HTLC the
1093
        // script.
1094
        case isIncoming && ourCommit:
3✔
1095
                htlcScriptTree, err = input.ReceiverHTLCScriptTaproot(
3✔
1096
                        timeout, keyRing.RemoteHtlcKey, keyRing.LocalHtlcKey,
3✔
1097
                        keyRing.RevocationKey, rHash[:], ourCommit,
3✔
1098
                )
3✔
1099

1100
        // We're being paid via an HTLC by the remote party, and the HTLC is
1101
        // being added to their commitment transaction, so we use the sender's
1102
        // version of the HTLC script.
1103
        case isIncoming && !ourCommit:
3✔
1104
                htlcScriptTree, err = input.SenderHTLCScriptTaproot(
3✔
1105
                        keyRing.RemoteHtlcKey, keyRing.LocalHtlcKey,
3✔
1106
                        keyRing.RevocationKey, rHash[:], ourCommit,
3✔
1107
                )
3✔
1108

1109
        // We're sending an HTLC which is being added to our commitment
1110
        // transaction. Therefore, we need to use the sender's version of the
1111
        // HTLC script.
1112
        case !isIncoming && ourCommit:
3✔
1113
                htlcScriptTree, err = input.SenderHTLCScriptTaproot(
3✔
1114
                        keyRing.LocalHtlcKey, keyRing.RemoteHtlcKey,
3✔
1115
                        keyRing.RevocationKey, rHash[:], ourCommit,
3✔
1116
                )
3✔
1117

1118
        // Finally, we're paying the remote party via an HTLC, which is being
1119
        // added to their commitment transaction. Therefore, we use the
1120
        // receiver's version of the HTLC script.
1121
        case !isIncoming && !ourCommit:
3✔
1122
                htlcScriptTree, err = input.ReceiverHTLCScriptTaproot(
3✔
1123
                        timeout, keyRing.LocalHtlcKey, keyRing.RemoteHtlcKey,
3✔
1124
                        keyRing.RevocationKey, rHash[:], ourCommit,
3✔
1125
                )
3✔
1126
        }
1127

1128
        return htlcScriptTree, err
3✔
1129
}
1130

1131
// genHtlcScript generates the proper P2WSH public key scripts for the HTLC
1132
// output modified by two-bits denoting if this is an incoming HTLC, and if the
1133
// HTLC is being applied to their commitment transaction or ours. A script
1134
// multiplexer for the various spending paths is returned. The script path that
1135
// we need to sign for the remote party (2nd level HTLCs) is also returned
1136
// along side the multiplexer.
1137
func genHtlcScript(chanType channeldb.ChannelType, isIncoming, ourCommit bool,
1138
        timeout uint32, rHash [32]byte, keyRing *CommitmentKeyRing,
1139
) (input.ScriptDescriptor, error) {
3✔
1140

3✔
1141
        if !chanType.IsTaproot() {
6✔
1142
                return genSegwitV0HtlcScript(
3✔
1143
                        chanType, isIncoming, ourCommit, timeout, rHash,
3✔
1144
                        keyRing,
3✔
1145
                )
3✔
1146
        }
3✔
1147

1148
        return genTaprootHtlcScript(
3✔
1149
                isIncoming, ourCommit, timeout, rHash, keyRing,
3✔
1150
        )
3✔
1151
}
1152

1153
// addHTLC adds a new HTLC to the passed commitment transaction. One of four
1154
// full scripts will be generated for the HTLC output depending on if the HTLC
1155
// is incoming and if it's being applied to our commitment transaction or that
1156
// of the remote node's. Additionally, in order to be able to efficiently
1157
// locate the added HTLC on the commitment transaction from the
1158
// PaymentDescriptor that generated it, the generated script is stored within
1159
// the descriptor itself.
1160
func addHTLC(commitTx *wire.MsgTx, ourCommit bool,
1161
        isIncoming bool, paymentDesc *PaymentDescriptor,
1162
        keyRing *CommitmentKeyRing, chanType channeldb.ChannelType) error {
3✔
1163

3✔
1164
        timeout := paymentDesc.Timeout
3✔
1165
        rHash := paymentDesc.RHash
3✔
1166

3✔
1167
        scriptInfo, err := genHtlcScript(
3✔
1168
                chanType, isIncoming, ourCommit, timeout, rHash, keyRing,
3✔
1169
        )
3✔
1170
        if err != nil {
3✔
1171
                return err
×
1172
        }
×
1173

1174
        pkScript := scriptInfo.PkScript()
3✔
1175

3✔
1176
        // Add the new HTLC outputs to the respective commitment transactions.
3✔
1177
        amountPending := int64(paymentDesc.Amount.ToSatoshis())
3✔
1178
        commitTx.AddTxOut(wire.NewTxOut(amountPending, pkScript))
3✔
1179

3✔
1180
        // Store the pkScript of this particular PaymentDescriptor so we can
3✔
1181
        // quickly locate it within the commitment transaction later.
3✔
1182
        if ourCommit {
6✔
1183
                paymentDesc.ourPkScript = pkScript
3✔
1184

3✔
1185
                paymentDesc.ourWitnessScript = scriptInfo.WitnessScriptToSign()
3✔
1186
        } else {
6✔
1187
                paymentDesc.theirPkScript = pkScript
3✔
1188

3✔
1189
                //nolint:lll
3✔
1190
                paymentDesc.theirWitnessScript = scriptInfo.WitnessScriptToSign()
3✔
1191
        }
3✔
1192

1193
        return nil
3✔
1194
}
1195

1196
// findOutputIndexesFromRemote finds the index of our and their outputs from
1197
// the remote commitment transaction. It derives the key ring to compute the
1198
// output scripts and compares them against the outputs inside the commitment
1199
// to find the match.
1200
func findOutputIndexesFromRemote(revocationPreimage *chainhash.Hash,
1201
        chanState *channeldb.OpenChannel) (uint32, uint32, error) {
3✔
1202

3✔
1203
        // Init the output indexes as empty.
3✔
1204
        ourIndex := uint32(channeldb.OutputIndexEmpty)
3✔
1205
        theirIndex := uint32(channeldb.OutputIndexEmpty)
3✔
1206

3✔
1207
        chanCommit := chanState.RemoteCommitment
3✔
1208
        _, commitmentPoint := btcec.PrivKeyFromBytes(revocationPreimage[:])
3✔
1209

3✔
1210
        // With the commitment point generated, we can now derive the king ring
3✔
1211
        // which will be used to generate the output scripts.
3✔
1212
        keyRing := DeriveCommitmentKeys(
3✔
1213
                commitmentPoint, false, chanState.ChanType,
3✔
1214
                &chanState.LocalChanCfg, &chanState.RemoteChanCfg,
3✔
1215
        )
3✔
1216

3✔
1217
        // Since it's remote commitment chain, we'd used the mirrored values.
3✔
1218
        //
3✔
1219
        // We use the remote's channel config for the csv delay.
3✔
1220
        theirDelay := uint32(chanState.RemoteChanCfg.CsvDelay)
3✔
1221

3✔
1222
        // If we are the initiator of this channel, then it's be false from the
3✔
1223
        // remote's PoV.
3✔
1224
        isRemoteInitiator := !chanState.IsInitiator
3✔
1225

3✔
1226
        var leaseExpiry uint32
3✔
1227
        if chanState.ChanType.HasLeaseExpiration() {
6✔
1228
                leaseExpiry = chanState.ThawHeight
3✔
1229
        }
3✔
1230

1231
        // Map the scripts from our PoV. When facing a local commitment, the to
1232
        // local output belongs to us and the to remote output belongs to them.
1233
        // When facing a remote commitment, the to local output belongs to them
1234
        // and the to remote output belongs to us.
1235

1236
        // Compute the to local script. From our PoV, when facing a remote
1237
        // commitment, the to local output belongs to them.
1238
        theirScript, err := CommitScriptToSelf(
3✔
1239
                chanState.ChanType, isRemoteInitiator, keyRing.ToLocalKey,
3✔
1240
                keyRing.RevocationKey, theirDelay, leaseExpiry,
3✔
1241
        )
3✔
1242
        if err != nil {
3✔
1243
                return ourIndex, theirIndex, err
×
1244
        }
×
1245

1246
        // Compute the to remote script. From our PoV, when facing a remote
1247
        // commitment, the to remote output belongs to us.
1248
        ourScript, _, err := CommitScriptToRemote(
3✔
1249
                chanState.ChanType, isRemoteInitiator, keyRing.ToRemoteKey,
3✔
1250
                leaseExpiry,
3✔
1251
        )
3✔
1252
        if err != nil {
3✔
1253
                return ourIndex, theirIndex, err
×
1254
        }
×
1255

1256
        // Now compare the scripts to find our/their output index.
1257
        for i, txOut := range chanCommit.CommitTx.TxOut {
6✔
1258
                switch {
3✔
1259
                case bytes.Equal(txOut.PkScript, ourScript.PkScript()):
3✔
1260
                        ourIndex = uint32(i)
3✔
1261
                case bytes.Equal(txOut.PkScript, theirScript.PkScript()):
3✔
1262
                        theirIndex = uint32(i)
3✔
1263
                }
1264
        }
1265

1266
        return ourIndex, theirIndex, nil
3✔
1267
}
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

© 2026 Coveralls, Inc