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

lightningnetwork / lnd / 13035292482

29 Jan 2025 03:59PM UTC coverage: 49.3% (-9.5%) from 58.777%
13035292482

Pull #9456

github

mohamedawnallah
docs: update release-notes-0.19.0.md

In this commit, we warn users about the removal
of RPCs `SendToRoute`, `SendToRouteSync`, `SendPayment`,
and `SendPaymentSync` in the next release 0.20.
Pull Request #9456: lnrpc+docs: deprecate warning `SendToRoute`, `SendToRouteSync`, `SendPayment`, and `SendPaymentSync` in Release 0.19

100634 of 204126 relevant lines covered (49.3%)

1.54 hits per line

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

76.61
/lnwallet/wallet.go
1
package lnwallet
2

3
import (
4
        "bytes"
5
        "crypto/sha256"
6
        "errors"
7
        "fmt"
8
        "math"
9
        "net"
10
        "sync"
11
        "sync/atomic"
12

13
        "github.com/btcsuite/btcd/blockchain"
14
        "github.com/btcsuite/btcd/btcec/v2"
15
        "github.com/btcsuite/btcd/btcec/v2/schnorr/musig2"
16
        "github.com/btcsuite/btcd/btcutil"
17
        "github.com/btcsuite/btcd/btcutil/psbt"
18
        "github.com/btcsuite/btcd/btcutil/txsort"
19
        "github.com/btcsuite/btcd/chaincfg"
20
        "github.com/btcsuite/btcd/chaincfg/chainhash"
21
        "github.com/btcsuite/btcd/txscript"
22
        "github.com/btcsuite/btcd/wire"
23
        "github.com/btcsuite/btcwallet/wallet"
24
        "github.com/davecgh/go-spew/spew"
25
        "github.com/lightningnetwork/lnd/channeldb"
26
        "github.com/lightningnetwork/lnd/fn/v2"
27
        "github.com/lightningnetwork/lnd/input"
28
        "github.com/lightningnetwork/lnd/keychain"
29
        "github.com/lightningnetwork/lnd/lntypes"
30
        "github.com/lightningnetwork/lnd/lnwallet/chainfee"
31
        "github.com/lightningnetwork/lnd/lnwallet/chanfunding"
32
        "github.com/lightningnetwork/lnd/lnwallet/chanvalidate"
33
        "github.com/lightningnetwork/lnd/lnwire"
34
        "github.com/lightningnetwork/lnd/shachain"
35
        "github.com/lightningnetwork/lnd/tlv"
36
)
37

38
const (
39
        // The size of the buffered queue of requests to the wallet from the
40
        // outside word.
41
        msgBufferSize = 100
42

43
        // AnchorChanReservedValue is the amount we'll keep around in the
44
        // wallet in case we have to fee bump anchor channels on force close.
45
        // TODO(halseth): update constant to target a specific commit size at
46
        // set fee rate.
47
        AnchorChanReservedValue = btcutil.Amount(10_000)
48

49
        // MaxAnchorChanReservedValue is the maximum value we'll reserve for
50
        // anchor channel fee bumping. We cap it at 10 times the per-channel
51
        // amount such that nodes with a high number of channels don't have to
52
        // keep around a very large amount for the unlikely scenario that they
53
        // all close at the same time.
54
        MaxAnchorChanReservedValue = 10 * AnchorChanReservedValue
55
)
56

57
var (
58
        // ErrPsbtFundingRequired is the error that is returned during the
59
        // contribution handling process if the process should be paused for
60
        // the construction of a PSBT outside of lnd's wallet.
61
        ErrPsbtFundingRequired = errors.New("PSBT funding required")
62

63
        // ErrReservedValueInvalidated is returned if we try to publish a
64
        // transaction that would take the walletbalance below what we require
65
        // to keep around to fee bump our open anchor channels.
66
        ErrReservedValueInvalidated = errors.New("reserved wallet balance " +
67
                "invalidated: transaction would leave insufficient funds for " +
68
                "fee bumping anchor channel closings (see debug log for details)")
69

70
        // ErrEmptyPendingChanID is returned when an empty value is used for
71
        // the pending channel ID.
72
        ErrEmptyPendingChanID = errors.New("pending channel ID is empty")
73

74
        // ErrDuplicatePendingChanID is returned when an existing pending
75
        // channel ID is registered again.
76
        ErrDuplicatePendingChanID = errors.New("duplicate pending channel ID")
77
)
78

79
// PsbtFundingRequired is a type that implements the error interface and
80
// contains the information needed to construct a PSBT.
81
type PsbtFundingRequired struct {
82
        // Intent is the pending PSBT funding intent that needs to be funded
83
        // if the wrapping error is returned.
84
        Intent *chanfunding.PsbtIntent
85
}
86

87
// Error returns the underlying error.
88
//
89
// NOTE: This method is part of the error interface.
90
func (p *PsbtFundingRequired) Error() string {
×
91
        return ErrPsbtFundingRequired.Error()
×
92
}
×
93

94
// AuxFundingDesc stores a series of attributes that may be used to modify the
95
// way the channel funding occurs. This struct contains information that can
96
// only be derived once both sides have received and sent their contributions
97
// to the channel (keys, etc.).
98
type AuxFundingDesc struct {
99
        // CustomFundingBlob is a custom blob that'll be stored in the database
100
        // within the OpenChannel struct. This should represent information
101
        // static to the channel lifetime.
102
        CustomFundingBlob tlv.Blob
103

104
        // CustomLocalCommitBlob is a custom blob that'll be stored in the
105
        // first commitment entry for the local party.
106
        CustomLocalCommitBlob tlv.Blob
107

108
        // CustomRemoteCommitBlob is a custom blob that'll be stored in the
109
        // first commitment entry for the remote party.
110
        CustomRemoteCommitBlob tlv.Blob
111

112
        // LocalInitAuxLeaves is the set of aux leaves that'll be used for our
113
        // very first commitment state.
114
        LocalInitAuxLeaves CommitAuxLeaves
115

116
        // RemoteInitAuxLeaves is the set of aux leaves that'll be used for the
117
        // very first commitment state for the remote party.
118
        RemoteInitAuxLeaves CommitAuxLeaves
119
}
120

121
// InitFundingReserveMsg is the first message sent to initiate the workflow
122
// required to open a payment channel with a remote peer. The initial required
123
// parameters are configurable across channels. These parameters are to be
124
// chosen depending on the fee climate within the network, and time value of
125
// funds to be locked up within the channel. Upon success a ChannelReservation
126
// will be created in order to track the lifetime of this pending channel.
127
// Outputs selected will be 'locked', making them unavailable, for any other
128
// pending reservations. Therefore, all channels in reservation limbo will be
129
// periodically timed out after an idle period in order to avoid "exhaustion"
130
// attacks.
131
type InitFundingReserveMsg struct {
132
        // ChainHash denotes that chain to be used to ultimately open the
133
        // target channel.
134
        ChainHash *chainhash.Hash
135

136
        // PendingChanID is the pending channel ID for this funding flow as
137
        // used in the wire protocol.
138
        PendingChanID [32]byte
139

140
        // NodeID is the ID of the remote node we would like to open a channel
141
        // with.
142
        NodeID *btcec.PublicKey
143

144
        // NodeAddr is the address port that we used to either establish or
145
        // accept the connection which led to the negotiation of this funding
146
        // workflow.
147
        NodeAddr net.Addr
148

149
        // SubtractFees should be set if we intend to spend exactly
150
        // LocalFundingAmt when opening the channel, subtracting the fees from
151
        // the funding output. This can be used for instance to use all our
152
        // remaining funds to open the channel, since it will take fees into
153
        // account.
154
        SubtractFees bool
155

156
        // LocalFundingAmt is the amount of funds requested from us for this
157
        // channel.
158
        LocalFundingAmt btcutil.Amount
159

160
        // RemoteFundingAmnt is the amount of funds the remote will contribute
161
        // to this channel.
162
        RemoteFundingAmt btcutil.Amount
163

164
        // FundUpToMaxAmt defines if channel funding should try to add as many
165
        // funds to the channel opening as possible up to this amount. If used,
166
        // then MinFundAmt is treated as the minimum amount of funds that must
167
        // be available to open the channel. If set to zero it is ignored.
168
        FundUpToMaxAmt btcutil.Amount
169

170
        // MinFundAmt denotes the minimum channel capacity that has to be
171
        // allocated iff the FundUpToMaxAmt is set.
172
        MinFundAmt btcutil.Amount
173

174
        // Outpoints is a list of client-selected outpoints that should be used
175
        // for funding a channel. If LocalFundingAmt is specified then this
176
        // amount is allocated from the sum of outpoints towards funding. If the
177
        // FundUpToMaxAmt is specified the entirety of selected funds is
178
        // allocated towards channel funding.
179
        Outpoints []wire.OutPoint
180

181
        // RemoteChanReserve is the channel reserve we required for the remote
182
        // peer.
183
        RemoteChanReserve btcutil.Amount
184

185
        // CommitFeePerKw is the starting accepted satoshis/Kw fee for the set
186
        // of initial commitment transactions. In order to ensure timely
187
        // confirmation, it is recommended that this fee should be generous,
188
        // paying some multiple of the accepted base fee rate of the network.
189
        CommitFeePerKw chainfee.SatPerKWeight
190

191
        // FundingFeePerKw is the fee rate in sat/kw to use for the initial
192
        // funding transaction.
193
        FundingFeePerKw chainfee.SatPerKWeight
194

195
        // PushMSat is the number of milli-satoshis that should be pushed over
196
        // the responder as part of the initial channel creation.
197
        PushMSat lnwire.MilliSatoshi
198

199
        // Flags are the channel flags specified by the initiator in the
200
        // open_channel message.
201
        Flags lnwire.FundingFlag
202

203
        // MinConfs indicates the minimum number of confirmations that each
204
        // output selected to fund the channel should satisfy.
205
        MinConfs int32
206

207
        // CommitType indicates what type of commitment type the channel should
208
        // be using, like tweakless or anchors.
209
        CommitType CommitmentType
210

211
        // ChanFunder is an optional channel funder that allows the caller to
212
        // control exactly how the channel funding is carried out. If not
213
        // specified, then the default chanfunding.WalletAssembler will be
214
        // used.
215
        ChanFunder chanfunding.Assembler
216

217
        // AllowUtxoForFunding enables the channel funding workflow to restrict
218
        // the selection of utxos when selecting the inputs for the channel
219
        // opening. This does ONLY apply for the internal wallet backed channel
220
        // opening case.
221
        //
222
        // NOTE: This is very useful when opening channels with unconfirmed
223
        // inputs to make sure stable non-replaceable inputs are used.
224
        AllowUtxoForFunding func(Utxo) bool
225

226
        // ZeroConf is a boolean that is true if a zero-conf channel was
227
        // negotiated.
228
        ZeroConf bool
229

230
        // OptionScidAlias is a boolean that is true if an option-scid-alias
231
        // channel type was explicitly negotiated.
232
        OptionScidAlias bool
233

234
        // ScidAliasFeature is true if the option-scid-alias feature bit was
235
        // negotiated.
236
        ScidAliasFeature bool
237

238
        // Memo is any arbitrary information we wish to store locally about the
239
        // channel that will be useful to our future selves.
240
        Memo []byte
241

242
        // TapscriptRoot is an optional tapscript root that if provided, will
243
        // be used to create the combined key for musig2 based channels.
244
        TapscriptRoot fn.Option[chainhash.Hash]
245

246
        // err is a channel in which all errors will be sent across. Will be
247
        // nil if this initial set is successful.
248
        //
249
        // NOTE: In order to avoid deadlocks, this channel MUST be buffered.
250
        err chan error
251

252
        // resp is channel in which a ChannelReservation with our contributions
253
        // filled in will be sent across this channel in the case of a
254
        // successfully reservation initiation. In the case of an error, this
255
        // will read a nil pointer.
256
        //
257
        // NOTE: In order to avoid deadlocks, this channel MUST be buffered.
258
        resp chan *ChannelReservation
259
}
260

261
// fundingReserveCancelMsg is a message reserved for cancelling an existing
262
// channel reservation identified by its reservation ID. Cancelling a reservation
263
// frees its locked outputs up, for inclusion within further reservations.
264
type fundingReserveCancelMsg struct {
265
        pendingFundingID uint64
266

267
        // NOTE: In order to avoid deadlocks, this channel MUST be buffered.
268
        err chan error // Buffered
269
}
270

271
// addContributionMsg represents a message executing the second phase of the
272
// channel reservation workflow. This message carries the counterparty's
273
// "contribution" to the payment channel. In the case that this message is
274
// processed without generating any errors, then channel reservation will then
275
// be able to construct the funding tx, both commitment transactions, and
276
// finally generate signatures for all our inputs to the funding transaction,
277
// and for the remote node's version of the commitment transaction.
278
type addContributionMsg struct {
279
        pendingFundingID uint64
280

281
        contribution *ChannelContribution
282

283
        // NOTE: In order to avoid deadlocks, this channel MUST be buffered.
284
        err chan error
285
}
286

287
// continueContributionMsg represents a message that signals that the
288
// interrupted funding process involving a PSBT can now be continued because the
289
// finalized transaction is now available.
290
type continueContributionMsg struct {
291
        pendingFundingID uint64
292

293
        // auxFundingDesc is an optional descriptor that contains information
294
        // about the custom channel funding flow.
295
        auxFundingDesc fn.Option[AuxFundingDesc]
296

297
        // NOTE: In order to avoid deadlocks, this channel MUST be buffered.
298
        err chan error
299
}
300

301
// addSingleContributionMsg represents a message executing the second phase of
302
// a single funder channel reservation workflow. This messages carries the
303
// counterparty's "contribution" to the payment channel. As this message is
304
// sent when on the responding side to a single funder workflow, no further
305
// action apart from storing the provided contribution is carried out.
306
type addSingleContributionMsg struct {
307
        pendingFundingID uint64
308

309
        contribution *ChannelContribution
310

311
        // NOTE: In order to avoid deadlocks, this channel MUST be buffered.
312
        err chan error
313
}
314

315
// addCounterPartySigsMsg represents the final message required to complete,
316
// and 'open' a payment channel. This message carries the counterparty's
317
// signatures for each of their inputs to the funding transaction, and also a
318
// signature allowing us to spend our version of the commitment transaction.
319
// If we're able to verify all the signatures are valid, the funding transaction
320
// will be broadcast to the network. After the funding transaction gains a
321
// configurable number of confirmations, the channel is officially considered
322
// 'open'.
323
type addCounterPartySigsMsg struct {
324
        pendingFundingID uint64
325

326
        // Should be order of sorted inputs that are theirs. Sorting is done
327
        // in accordance to BIP-69:
328
        // https://github.com/bitcoin/bips/blob/master/bip-0069.mediawiki.
329
        theirFundingInputScripts []*input.Script
330

331
        // This should be 1/2 of the signatures needed to successfully spend our
332
        // version of the commitment transaction.
333
        theirCommitmentSig input.Signature
334

335
        // This channel is used to return the completed channel after the wallet
336
        // has completed all of its stages in the funding process.
337
        completeChan chan *channeldb.OpenChannel
338

339
        // NOTE: In order to avoid deadlocks, this channel MUST be buffered.
340
        err chan error
341
}
342

343
// addSingleFunderSigsMsg represents the next-to-last message required to
344
// complete a single-funder channel workflow. Once the initiator is able to
345
// construct the funding transaction, they send both the outpoint and a
346
// signature for our version of the commitment transaction. Once this message
347
// is processed we (the responder) are able to construct both commitment
348
// transactions, signing the remote party's version.
349
type addSingleFunderSigsMsg struct {
350
        pendingFundingID uint64
351

352
        // auxFundingDesc is an optional descriptor that contains information
353
        // about the custom channel funding flow.
354
        auxFundingDesc fn.Option[AuxFundingDesc]
355

356
        // fundingOutpoint is the outpoint of the completed funding
357
        // transaction as assembled by the workflow initiator.
358
        fundingOutpoint *wire.OutPoint
359

360
        // theirCommitmentSig are the 1/2 of the signatures needed to
361
        // successfully spend our version of the commitment transaction.
362
        theirCommitmentSig input.Signature
363

364
        // This channel is used to return the completed channel after the wallet
365
        // has completed all of its stages in the funding process.
366
        completeChan chan *channeldb.OpenChannel
367

368
        // NOTE: In order to avoid deadlocks, this channel MUST be buffered.
369
        err chan error
370
}
371

372
// CheckReservedValueTxReq is the request struct used to call
373
// CheckReservedValueTx with. It contains the transaction to check as well as
374
// an optional explicitly defined index to denote a change output that is not
375
// watched by the wallet.
376
type CheckReservedValueTxReq struct {
377
        // Tx is the transaction to check the outputs for.
378
        Tx *wire.MsgTx
379

380
        // ChangeIndex denotes an optional output index that can be explicitly
381
        // set for a change that is not being watched by the wallet and would
382
        // otherwise not be recognized as a change output.
383
        ChangeIndex *int
384
}
385

386
// LightningWallet is a domain specific, yet general Bitcoin wallet capable of
387
// executing workflow required to interact with the Lightning Network. It is
388
// domain specific in the sense that it understands all the fancy scripts used
389
// within the Lightning Network, channel lifetimes, etc. However, it embeds a
390
// general purpose Bitcoin wallet within it. Therefore, it is also able to
391
// serve as a regular Bitcoin wallet which uses HD keys. The wallet is highly
392
// concurrent internally. All communication, and requests towards the wallet
393
// are dispatched as messages over channels, ensuring thread safety across all
394
// operations. Interaction has been designed independent of any peer-to-peer
395
// communication protocol, allowing the wallet to be self-contained and
396
// embeddable within future projects interacting with the Lightning Network.
397
//
398
// NOTE: At the moment the wallet requires a btcd full node, as it's dependent
399
// on btcd's websockets notifications as event triggers during the lifetime of a
400
// channel. However, once the chainntnfs package is complete, the wallet will
401
// be compatible with multiple RPC/notification services such as Electrum,
402
// Bitcoin Core + ZeroMQ, etc. Eventually, the wallet won't require a full-node
403
// at all, as SPV support is integrated into btcwallet.
404
type LightningWallet struct {
405
        started  int32 // To be used atomically.
406
        shutdown int32 // To be used atomically.
407

408
        nextFundingID uint64 // To be used atomically.
409

410
        // Cfg is the configuration struct that will be used by the wallet to
411
        // access the necessary interfaces and default it needs to carry on its
412
        // duties.
413
        Cfg Config
414

415
        // WalletController is the core wallet, all non Lightning Network
416
        // specific interaction is proxied to the internal wallet.
417
        WalletController
418

419
        // SecretKeyRing is the interface we'll use to derive any keys related
420
        // to our purpose within the network including: multi-sig keys, node
421
        // keys, revocation keys, etc.
422
        keychain.SecretKeyRing
423

424
        // This mutex MUST be held when performing coin selection in order to
425
        // avoid inadvertently creating multiple funding transaction which
426
        // double spend inputs across each other.
427
        coinSelectMtx sync.RWMutex
428

429
        // All messages to the wallet are to be sent across this channel.
430
        msgChan chan interface{}
431

432
        // Incomplete payment channels are stored in the map below. An intent
433
        // to create a payment channel is tracked as a "reservation" within
434
        // limbo. Once the final signatures have been exchanged, a reservation
435
        // is removed from limbo. Each reservation is tracked by a unique
436
        // monotonically integer. All requests concerning the channel MUST
437
        // carry a valid, active funding ID.
438
        fundingLimbo map[uint64]*ChannelReservation
439

440
        // reservationIDs maps a pending channel ID to the reservation ID used
441
        // as key in the fundingLimbo map. Used to easily look up a channel
442
        // reservation given a pending channel ID.
443
        reservationIDs map[[32]byte]uint64
444
        limboMtx       sync.RWMutex
445

446
        // lockedOutPoints is a set of the currently locked outpoint. This
447
        // information is kept in order to provide an easy way to unlock all
448
        // the currently locked outpoints.
449
        lockedOutPoints map[wire.OutPoint]struct{}
450

451
        // fundingIntents houses all the "interception" registered by a caller
452
        // using the RegisterFundingIntent method.
453
        intentMtx      sync.RWMutex
454
        fundingIntents map[[32]byte]chanfunding.Intent
455

456
        quit chan struct{}
457

458
        wg sync.WaitGroup
459
}
460

461
// NewLightningWallet creates/opens and initializes a LightningWallet instance.
462
// If the wallet has never been created (according to the passed dataDir), first-time
463
// setup is executed.
464
func NewLightningWallet(Cfg Config) (*LightningWallet, error) {
3✔
465

3✔
466
        return &LightningWallet{
3✔
467
                Cfg:              Cfg,
3✔
468
                SecretKeyRing:    Cfg.SecretKeyRing,
3✔
469
                WalletController: Cfg.WalletController,
3✔
470
                msgChan:          make(chan interface{}, msgBufferSize),
3✔
471
                nextFundingID:    0,
3✔
472
                fundingLimbo:     make(map[uint64]*ChannelReservation),
3✔
473
                reservationIDs:   make(map[[32]byte]uint64),
3✔
474
                lockedOutPoints:  make(map[wire.OutPoint]struct{}),
3✔
475
                fundingIntents:   make(map[[32]byte]chanfunding.Intent),
3✔
476
                quit:             make(chan struct{}),
3✔
477
        }, nil
3✔
478
}
3✔
479

480
// Startup establishes a connection to the RPC source, and spins up all
481
// goroutines required to handle incoming messages.
482
func (l *LightningWallet) Startup() error {
3✔
483
        // Already started?
3✔
484
        if atomic.AddInt32(&l.started, 1) != 1 {
3✔
485
                return nil
×
486
        }
×
487

488
        // Start the underlying wallet controller.
489
        if err := l.Start(); err != nil {
3✔
490
                return err
×
491
        }
×
492

493
        if l.Cfg.Rebroadcaster != nil {
5✔
494
                go func() {
4✔
495
                        if err := l.Cfg.Rebroadcaster.Start(); err != nil {
2✔
496
                                walletLog.Errorf("unable to start "+
×
497
                                        "rebroadcaster: %v", err)
×
498
                        }
×
499
                }()
500
        }
501

502
        l.wg.Add(1)
3✔
503
        go l.requestHandler()
3✔
504

3✔
505
        return nil
3✔
506
}
507

508
// Shutdown gracefully stops the wallet, and all active goroutines.
509
func (l *LightningWallet) Shutdown() error {
3✔
510
        if atomic.AddInt32(&l.shutdown, 1) != 1 {
3✔
511
                return nil
×
512
        }
×
513

514
        // Signal the underlying wallet controller to shutdown, waiting until
515
        // all active goroutines have been shutdown.
516
        if err := l.Stop(); err != nil {
3✔
517
                return err
×
518
        }
×
519

520
        if l.Cfg.Rebroadcaster != nil && l.Cfg.Rebroadcaster.Started() {
5✔
521
                l.Cfg.Rebroadcaster.Stop()
2✔
522
        }
2✔
523

524
        close(l.quit)
3✔
525
        l.wg.Wait()
3✔
526
        return nil
3✔
527
}
528

529
// PublishTransaction wraps the wallet controller tx publish method with an
530
// extra rebroadcaster layer if the sub-system is configured.
531
func (l *LightningWallet) PublishTransaction(tx *wire.MsgTx,
532
        label string) error {
3✔
533

3✔
534
        sendTxToWallet := func() error {
6✔
535
                return l.WalletController.PublishTransaction(tx, label)
3✔
536
        }
3✔
537

538
        // If we don't have rebroadcaster then we can exit early (and send only
539
        // to the wallet).
540
        if l.Cfg.Rebroadcaster == nil || !l.Cfg.Rebroadcaster.Started() {
6✔
541
                return sendTxToWallet()
3✔
542
        }
3✔
543

544
        // We pass this into the rebroadcaster first, so the initial attempt
545
        // will succeed if the transaction isn't yet in the mempool. However we
546
        // ignore the error here as this might be resent on start up and the
547
        // transaction already exists.
548
        _ = l.Cfg.Rebroadcaster.Broadcast(tx)
2✔
549

2✔
550
        // Then we pass things into the wallet as normal, which'll add the
2✔
551
        // transaction label on disk.
2✔
552
        if err := sendTxToWallet(); err != nil {
4✔
553
                return err
2✔
554
        }
2✔
555

556
        // TODO(roasbeef): want diff height actually? no context though
557
        _, bestHeight, err := l.Cfg.ChainIO.GetBestBlock()
2✔
558
        if err != nil {
2✔
559
                return err
×
560
        }
×
561

562
        txHash := tx.TxHash()
2✔
563
        go func() {
4✔
564
                const numConfs = 6
2✔
565

2✔
566
                txConf, err := l.Cfg.Notifier.RegisterConfirmationsNtfn(
2✔
567
                        &txHash, tx.TxOut[0].PkScript, numConfs,
2✔
568
                        uint32(bestHeight),
2✔
569
                )
2✔
570
                if err != nil {
2✔
571
                        return
×
572
                }
×
573

574
                select {
2✔
575
                case <-txConf.Confirmed:
2✔
576
                        // TODO(roasbeef): also want to remove from
2✔
577
                        // rebroadcaster if conflict happens...deeper wallet
2✔
578
                        // integration?
2✔
579
                        l.Cfg.Rebroadcaster.MarkAsConfirmed(tx.TxHash())
2✔
580

581
                case <-l.quit:
×
582
                        return
×
583
                }
584
        }()
585

586
        return nil
2✔
587
}
588

589
// ConfirmedBalance returns the current confirmed balance of a wallet account.
590
// This methods wraps the internal WalletController method so we're able to
591
// properly hold the coin select mutex while we compute the balance.
592
func (l *LightningWallet) ConfirmedBalance(confs int32,
593
        account string) (btcutil.Amount, error) {
3✔
594

3✔
595
        l.coinSelectMtx.Lock()
3✔
596
        defer l.coinSelectMtx.Unlock()
3✔
597

3✔
598
        return l.WalletController.ConfirmedBalance(confs, account)
3✔
599
}
3✔
600

601
// ListUnspentWitnessFromDefaultAccount returns all unspent outputs from the
602
// default wallet account which are version 0 witness programs. The 'minConfs'
603
// and 'maxConfs' parameters indicate the minimum and maximum number of
604
// confirmations an output needs in order to be returned by this method. Passing
605
// -1 as 'minConfs' indicates that even unconfirmed outputs should be returned.
606
// Using MaxInt32 as 'maxConfs' implies returning all outputs with at least
607
// 'minConfs'.
608
//
609
// NOTE: This method requires the global coin selection lock to be held.
610
func (l *LightningWallet) ListUnspentWitnessFromDefaultAccount(
611
        minConfs, maxConfs int32) ([]*Utxo, error) {
3✔
612

3✔
613
        return l.WalletController.ListUnspentWitness(
3✔
614
                minConfs, maxConfs, DefaultAccountName,
3✔
615
        )
3✔
616
}
3✔
617

618
// LockedOutpoints returns a list of all currently locked outpoint.
619
func (l *LightningWallet) LockedOutpoints() []*wire.OutPoint {
×
620
        outPoints := make([]*wire.OutPoint, 0, len(l.lockedOutPoints))
×
621
        for outPoint := range l.lockedOutPoints {
×
622
                outPoint := outPoint
×
623

×
624
                outPoints = append(outPoints, &outPoint)
×
625
        }
×
626

627
        return outPoints
×
628
}
629

630
// ResetReservations reset the volatile wallet state which tracks all currently
631
// active reservations.
632
func (l *LightningWallet) ResetReservations() {
×
633
        l.nextFundingID = 0
×
634
        l.fundingLimbo = make(map[uint64]*ChannelReservation)
×
635
        l.reservationIDs = make(map[[32]byte]uint64)
×
636

×
637
        for outpoint := range l.lockedOutPoints {
×
638
                _ = l.ReleaseOutput(chanfunding.LndInternalLockID, outpoint)
×
639
        }
×
640
        l.lockedOutPoints = make(map[wire.OutPoint]struct{})
×
641
}
642

643
// ActiveReservations returns a slice of all the currently active
644
// (non-canceled) reservations.
645
func (l *LightningWallet) ActiveReservations() []*ChannelReservation {
×
646
        reservations := make([]*ChannelReservation, 0, len(l.fundingLimbo))
×
647
        for _, reservation := range l.fundingLimbo {
×
648
                reservations = append(reservations, reservation)
×
649
        }
×
650

651
        return reservations
×
652
}
653

654
// requestHandler is the primary goroutine(s) responsible for handling, and
655
// dispatching replies to all messages.
656
func (l *LightningWallet) requestHandler() {
3✔
657
        defer l.wg.Done()
3✔
658

3✔
659
out:
3✔
660
        for {
6✔
661
                select {
3✔
662
                case m := <-l.msgChan:
3✔
663
                        switch msg := m.(type) {
3✔
664
                        case *InitFundingReserveMsg:
3✔
665
                                l.handleFundingReserveRequest(msg)
3✔
666
                        case *fundingReserveCancelMsg:
3✔
667
                                l.handleFundingCancelRequest(msg)
3✔
668
                        case *addSingleContributionMsg:
3✔
669
                                l.handleSingleContribution(msg)
3✔
670
                        case *addContributionMsg:
3✔
671
                                l.handleContributionMsg(msg)
3✔
672
                        case *continueContributionMsg:
3✔
673
                                l.handleChanPointReady(msg)
3✔
674
                        case *addSingleFunderSigsMsg:
3✔
675
                                l.handleSingleFunderSigs(msg)
3✔
676
                        case *addCounterPartySigsMsg:
3✔
677
                                l.handleFundingCounterPartySigs(msg)
3✔
678
                        }
679
                case <-l.quit:
3✔
680
                        // TODO: do some clean up
3✔
681
                        break out
3✔
682
                }
683
        }
684
}
685

686
// InitChannelReservation kicks off the 3-step workflow required to successfully
687
// open a payment channel with a remote node. As part of the funding
688
// reservation, the inputs selected for the funding transaction are 'locked'.
689
// This ensures that multiple channel reservations aren't double spending the
690
// same inputs in the funding transaction. If reservation initialization is
691
// successful, a ChannelReservation containing our completed contribution is
692
// returned. Our contribution contains all the items necessary to allow the
693
// counterparty to build the funding transaction, and both versions of the
694
// commitment transaction. Otherwise, an error occurred and a nil pointer along
695
// with an error are returned.
696
//
697
// Once a ChannelReservation has been obtained, two additional steps must be
698
// processed before a payment channel can be considered 'open'. The second step
699
// validates, and processes the counterparty's channel contribution. The third,
700
// and final step verifies all signatures for the inputs of the funding
701
// transaction, and that the signature we record for our version of the
702
// commitment transaction is valid.
703
func (l *LightningWallet) InitChannelReservation(
704
        req *InitFundingReserveMsg) (*ChannelReservation, error) {
3✔
705

3✔
706
        req.resp = make(chan *ChannelReservation, 1)
3✔
707
        req.err = make(chan error, 1)
3✔
708

3✔
709
        select {
3✔
710
        case l.msgChan <- req:
3✔
711
        case <-l.quit:
×
712
                return nil, errors.New("wallet shutting down")
×
713
        }
714

715
        return <-req.resp, <-req.err
3✔
716
}
717

718
// RegisterFundingIntent allows a caller to signal to the wallet that if a
719
// pending channel ID of expectedID is found, then it can skip constructing a
720
// new chanfunding.Assembler, and instead use the specified chanfunding.Intent.
721
// As an example, this lets some of the parameters for funding transaction to
722
// be negotiated outside the regular funding protocol.
723
func (l *LightningWallet) RegisterFundingIntent(expectedID [32]byte,
724
        shimIntent chanfunding.Intent) error {
3✔
725

3✔
726
        l.intentMtx.Lock()
3✔
727
        defer l.intentMtx.Unlock()
3✔
728

3✔
729
        // Sanity check the pending channel ID is not empty.
3✔
730
        var zeroID [32]byte
3✔
731
        if expectedID == zeroID {
3✔
732
                return ErrEmptyPendingChanID
×
733
        }
×
734

735
        if _, ok := l.fundingIntents[expectedID]; ok {
6✔
736
                return fmt.Errorf("%w: already has intent registered: %x",
3✔
737
                        ErrDuplicatePendingChanID, expectedID[:])
3✔
738
        }
3✔
739

740
        l.fundingIntents[expectedID] = shimIntent
3✔
741

3✔
742
        return nil
3✔
743
}
744

745
// PsbtFundingVerify looks up a previously registered funding intent by its
746
// pending channel ID and tries to advance the state machine by verifying the
747
// passed PSBT.
748
func (l *LightningWallet) PsbtFundingVerify(pendingChanID [32]byte,
749
        packet *psbt.Packet, skipFinalize bool) error {
3✔
750

3✔
751
        l.intentMtx.Lock()
3✔
752
        defer l.intentMtx.Unlock()
3✔
753

3✔
754
        intent, ok := l.fundingIntents[pendingChanID]
3✔
755
        if !ok {
3✔
756
                return fmt.Errorf("no funding intent found for "+
×
757
                        "pendingChannelID(%x)", pendingChanID[:])
×
758
        }
×
759
        psbtIntent, ok := intent.(*chanfunding.PsbtIntent)
3✔
760
        if !ok {
3✔
761
                return fmt.Errorf("incompatible funding intent")
×
762
        }
×
763

764
        if skipFinalize && psbtIntent.ShouldPublishFundingTX() {
3✔
765
                return fmt.Errorf("cannot set skip_finalize for channel that " +
×
766
                        "did not set no_publish")
×
767
        }
×
768

769
        err := psbtIntent.Verify(packet, skipFinalize)
3✔
770
        if err != nil {
3✔
771
                return fmt.Errorf("error verifying PSBT: %w", err)
×
772
        }
×
773

774
        // Get the channel reservation for that corresponds to this pending
775
        // channel ID.
776
        l.limboMtx.Lock()
3✔
777
        pid, ok := l.reservationIDs[pendingChanID]
3✔
778
        if !ok {
3✔
779
                l.limboMtx.Unlock()
×
780
                return fmt.Errorf("no channel reservation found for "+
×
781
                        "pendingChannelID(%x)", pendingChanID[:])
×
782
        }
×
783

784
        pendingReservation, ok := l.fundingLimbo[pid]
3✔
785
        l.limboMtx.Unlock()
3✔
786

3✔
787
        if !ok {
3✔
788
                return fmt.Errorf("no channel reservation found for "+
×
789
                        "reservation ID %v", pid)
×
790
        }
×
791

792
        // Now the PSBT has been populated and verified, we can again check
793
        // whether the value reserved for anchor fee bumping is respected.
794
        isPublic := pendingReservation.partialState.ChannelFlags&lnwire.FFAnnounceChannel != 0
3✔
795
        hasAnchors := pendingReservation.partialState.ChanType.HasAnchors()
3✔
796
        return l.enforceNewReservedValue(intent, isPublic, hasAnchors)
3✔
797
}
798

799
// PsbtFundingFinalize looks up a previously registered funding intent by its
800
// pending channel ID and tries to advance the state machine by finalizing the
801
// passed PSBT.
802
func (l *LightningWallet) PsbtFundingFinalize(pid [32]byte, packet *psbt.Packet,
803
        rawTx *wire.MsgTx) error {
3✔
804

3✔
805
        l.intentMtx.Lock()
3✔
806
        defer l.intentMtx.Unlock()
3✔
807

3✔
808
        intent, ok := l.fundingIntents[pid]
3✔
809
        if !ok {
3✔
810
                return fmt.Errorf("no funding intent found for "+
×
811
                        "pendingChannelID(%x)", pid[:])
×
812
        }
×
813
        psbtIntent, ok := intent.(*chanfunding.PsbtIntent)
3✔
814
        if !ok {
3✔
815
                return fmt.Errorf("incompatible funding intent")
×
816
        }
×
817

818
        // Either the PSBT or the raw TX must be set.
819
        switch {
3✔
820
        case packet != nil && rawTx == nil:
3✔
821
                err := psbtIntent.Finalize(packet)
3✔
822
                if err != nil {
3✔
823
                        return fmt.Errorf("error finalizing PSBT: %w", err)
×
824
                }
×
825

826
        case rawTx != nil && packet == nil:
3✔
827
                err := psbtIntent.FinalizeRawTX(rawTx)
3✔
828
                if err != nil {
3✔
829
                        return fmt.Errorf("error finalizing raw TX: %w", err)
×
830
                }
×
831

832
        default:
×
833
                return fmt.Errorf("either a PSBT or raw TX must be specified")
×
834
        }
835

836
        return nil
3✔
837
}
838

839
// CancelFundingIntent allows a caller to cancel a previously registered
840
// funding intent. If no intent was found, then an error will be returned.
841
func (l *LightningWallet) CancelFundingIntent(pid [32]byte) error {
3✔
842
        l.intentMtx.Lock()
3✔
843
        defer l.intentMtx.Unlock()
3✔
844

3✔
845
        intent, ok := l.fundingIntents[pid]
3✔
846
        if !ok {
6✔
847
                return fmt.Errorf("no funding intent found for "+
3✔
848
                        "pendingChannelID(%x)", pid[:])
3✔
849
        }
3✔
850

851
        // Give the intent a chance to clean up after itself, removing coin
852
        // locks or similar reserved resources.
853
        intent.Cancel()
3✔
854

3✔
855
        delete(l.fundingIntents, pid)
3✔
856

3✔
857
        return nil
3✔
858
}
859

860
// handleFundingReserveRequest processes a message intending to create, and
861
// validate a funding reservation request.
862
func (l *LightningWallet) handleFundingReserveRequest(req *InitFundingReserveMsg) {
3✔
863

3✔
864
        noFundsCommitted := req.LocalFundingAmt == 0 &&
3✔
865
                req.RemoteFundingAmt == 0 && req.FundUpToMaxAmt == 0
3✔
866

3✔
867
        // It isn't possible to create a channel with zero funds committed.
3✔
868
        if noFundsCommitted {
3✔
869
                err := ErrZeroCapacity()
×
870
                req.err <- err
×
871
                req.resp <- nil
×
872
                return
×
873
        }
×
874

875
        // If the funding request is for a different chain than the one the
876
        // wallet is aware of, then we'll reject the request.
877
        if !bytes.Equal(l.Cfg.NetParams.GenesisHash[:], req.ChainHash[:]) {
3✔
878
                err := ErrChainMismatch(
×
879
                        l.Cfg.NetParams.GenesisHash, req.ChainHash,
×
880
                )
×
881
                req.err <- err
×
882
                req.resp <- nil
×
883
                return
×
884
        }
×
885

886
        // We need to avoid enforcing reserved value in the middle of PSBT
887
        // funding because some of the following steps may add UTXOs funding
888
        // the on-chain wallet.
889
        // The enforcement still happens at the last step - in PsbtFundingVerify
890
        enforceNewReservedValue := true
3✔
891

3✔
892
        // If no chanFunder was provided, then we'll assume the default
3✔
893
        // assembler, which is backed by the wallet's internal coin selection.
3✔
894
        if req.ChanFunder == nil {
6✔
895
                // We use the P2WSH dust limit since it is larger than the
3✔
896
                // P2WPKH dust limit and to avoid threading through two
3✔
897
                // different dust limits.
3✔
898
                cfg := chanfunding.WalletConfig{
3✔
899
                        CoinSource: NewCoinSource(
3✔
900
                                l, req.AllowUtxoForFunding,
3✔
901
                        ),
3✔
902
                        CoinSelectLocker: l,
3✔
903
                        CoinLeaser:       l,
3✔
904
                        Signer:           l.Cfg.Signer,
3✔
905
                        DustLimit: DustLimitForSize(
3✔
906
                                input.P2WSHSize,
3✔
907
                        ),
3✔
908
                        CoinSelectionStrategy: l.Cfg.CoinSelectionStrategy,
3✔
909
                }
3✔
910
                req.ChanFunder = chanfunding.NewWalletAssembler(cfg)
3✔
911
        } else {
6✔
912
                _, isPsbtFunder := req.ChanFunder.(*chanfunding.PsbtAssembler)
3✔
913
                enforceNewReservedValue = !isPsbtFunder
3✔
914
        }
3✔
915

916
        localFundingAmt := req.LocalFundingAmt
3✔
917
        remoteFundingAmt := req.RemoteFundingAmt
3✔
918
        hasAnchors := req.CommitType.HasAnchors()
3✔
919

3✔
920
        var (
3✔
921
                fundingIntent chanfunding.Intent
3✔
922
                err           error
3✔
923
        )
3✔
924

3✔
925
        // If we've just received an inbound funding request that we have a
3✔
926
        // registered shim intent to, then we'll obtain the backing intent now.
3✔
927
        // In this case, we're doing a special funding workflow that allows
3✔
928
        // more advanced constructions such as channel factories to be
3✔
929
        // instantiated.
3✔
930
        l.intentMtx.Lock()
3✔
931
        fundingIntent, ok := l.fundingIntents[req.PendingChanID]
3✔
932
        l.intentMtx.Unlock()
3✔
933

3✔
934
        // Otherwise, this is a normal funding flow, so we'll use the chan
3✔
935
        // funder in the attached request to provision the inputs/outputs
3✔
936
        // that'll ultimately be used to construct the funding transaction.
3✔
937
        if !ok {
6✔
938
                var err error
3✔
939
                var numAnchorChans int
3✔
940

3✔
941
                // Get the number of anchor channels to determine if there is a
3✔
942
                // reserved value that must be respected when funding up to the
3✔
943
                // maximum amount. Since private channels (most likely) won't be
3✔
944
                // used for routing other than the last hop, they bear a smaller
3✔
945
                // risk that we must force close them in order to resolve a HTLC
3✔
946
                // up/downstream. Hence we exclude them from the count of anchor
3✔
947
                // channels in order to attribute the respective anchor amount
3✔
948
                // to the channel capacity.
3✔
949
                if req.FundUpToMaxAmt > 0 && req.MinFundAmt > 0 {
6✔
950
                        numAnchorChans, err = l.CurrentNumAnchorChans()
3✔
951
                        if err != nil {
3✔
952
                                req.err <- err
×
953
                                req.resp <- nil
×
954
                                return
×
955
                        }
×
956

957
                        isPublic := req.Flags&lnwire.FFAnnounceChannel != 0
3✔
958
                        if hasAnchors && isPublic {
6✔
959
                                numAnchorChans++
3✔
960
                        }
3✔
961
                }
962

963
                // Coin selection is done on the basis of sat/kw, so we'll use
964
                // the fee rate passed in to perform coin selection.
965
                fundingReq := &chanfunding.Request{
3✔
966
                        RemoteAmt:         req.RemoteFundingAmt,
3✔
967
                        LocalAmt:          req.LocalFundingAmt,
3✔
968
                        FundUpToMaxAmt:    req.FundUpToMaxAmt,
3✔
969
                        MinFundAmt:        req.MinFundAmt,
3✔
970
                        RemoteChanReserve: req.RemoteChanReserve,
3✔
971
                        PushAmt: lnwire.MilliSatoshi.ToSatoshis(
3✔
972
                                req.PushMSat,
3✔
973
                        ),
3✔
974
                        WalletReserve: l.RequiredReserve(
3✔
975
                                uint32(numAnchorChans),
3✔
976
                        ),
3✔
977
                        Outpoints:    req.Outpoints,
3✔
978
                        MinConfs:     req.MinConfs,
3✔
979
                        SubtractFees: req.SubtractFees,
3✔
980
                        FeeRate:      req.FundingFeePerKw,
3✔
981
                        ChangeAddr: func() (btcutil.Address, error) {
6✔
982
                                return l.NewAddress(
3✔
983
                                        TaprootPubkey, true, DefaultAccountName,
3✔
984
                                )
3✔
985
                        },
3✔
986
                        Musig2: req.CommitType.IsTaproot(),
987
                }
988
                fundingIntent, err = req.ChanFunder.ProvisionChannel(
3✔
989
                        fundingReq,
3✔
990
                )
3✔
991
                if err != nil {
6✔
992
                        req.err <- err
3✔
993
                        req.resp <- nil
3✔
994
                        return
3✔
995
                }
3✔
996

997
                // Register the funding intent now in case we need to access it
998
                // again later, as it's the case for the PSBT state machine for
999
                // example.
1000
                err = l.RegisterFundingIntent(req.PendingChanID, fundingIntent)
3✔
1001
                if err != nil {
3✔
1002
                        req.err <- err
×
1003
                        req.resp <- nil
×
1004
                        return
×
1005
                }
×
1006

1007
                walletLog.Debugf("Registered funding intent for "+
3✔
1008
                        "PendingChanID: %x", req.PendingChanID)
3✔
1009

3✔
1010
                localFundingAmt = fundingIntent.LocalFundingAmt()
3✔
1011
                remoteFundingAmt = fundingIntent.RemoteFundingAmt()
3✔
1012
        }
1013

1014
        // At this point there _has_ to be a funding intent, otherwise something
1015
        // went really wrong.
1016
        if fundingIntent == nil {
3✔
1017
                req.err <- fmt.Errorf("no funding intent present")
×
1018
                req.resp <- nil
×
1019
                return
×
1020
        }
×
1021

1022
        // If this is a shim intent, then it may be attempting to use an
1023
        // existing set of keys for the funding workflow. In this case, we'll
1024
        // make a simple wrapper keychain.KeyRing that will proxy certain
1025
        // derivation calls to future callers.
1026
        var (
3✔
1027
                keyRing    keychain.KeyRing = l.SecretKeyRing
3✔
1028
                thawHeight uint32
3✔
1029
        )
3✔
1030
        if shimIntent, ok := fundingIntent.(*chanfunding.ShimIntent); ok {
6✔
1031
                keyRing = &shimKeyRing{
3✔
1032
                        KeyRing:    keyRing,
3✔
1033
                        ShimIntent: shimIntent,
3✔
1034
                }
3✔
1035

3✔
1036
                // As this was a registered shim intent, we'll obtain the thaw
3✔
1037
                // height of the intent, if present at all. If this is
3✔
1038
                // non-zero, then we'll mark this as the proper channel type.
3✔
1039
                thawHeight = shimIntent.ThawHeight()
3✔
1040
        }
3✔
1041

1042
        // Now that we have a funding intent, we'll check whether funding a
1043
        // channel using it would violate our reserved value for anchor channel
1044
        // fee bumping.
1045
        //
1046
        // Check the reserved value using the inputs and outputs given by the
1047
        // intent. Note that for the PSBT intent type we don't yet have the
1048
        // funding tx ready, so this will always pass.  We'll do another check
1049
        // when the PSBT has been verified.
1050
        isPublic := req.Flags&lnwire.FFAnnounceChannel != 0
3✔
1051
        if enforceNewReservedValue {
6✔
1052
                err = l.enforceNewReservedValue(fundingIntent, isPublic, hasAnchors)
3✔
1053
                if err != nil {
6✔
1054
                        fundingIntent.Cancel()
3✔
1055

3✔
1056
                        req.err <- err
3✔
1057
                        req.resp <- nil
3✔
1058
                        return
3✔
1059
                }
3✔
1060
        }
1061

1062
        // The total channel capacity will be the size of the funding output we
1063
        // created plus the remote contribution.
1064
        capacity := localFundingAmt + remoteFundingAmt
3✔
1065

3✔
1066
        id := atomic.AddUint64(&l.nextFundingID, 1)
3✔
1067
        reservation, err := NewChannelReservation(
3✔
1068
                capacity, localFundingAmt, l, id, l.Cfg.NetParams.GenesisHash,
3✔
1069
                thawHeight, req,
3✔
1070
        )
3✔
1071
        if err != nil {
6✔
1072
                fundingIntent.Cancel()
3✔
1073

3✔
1074
                req.err <- err
3✔
1075
                req.resp <- nil
3✔
1076
                return
3✔
1077
        }
3✔
1078

1079
        err = l.initOurContribution(
3✔
1080
                reservation, fundingIntent, req.NodeAddr, req.NodeID, keyRing,
3✔
1081
        )
3✔
1082
        if err != nil {
3✔
1083
                fundingIntent.Cancel()
×
1084

×
1085
                req.err <- err
×
1086
                req.resp <- nil
×
1087
                return
×
1088
        }
×
1089

1090
        // Create a limbo and record entry for this newly pending funding
1091
        // request.
1092
        l.limboMtx.Lock()
3✔
1093
        l.fundingLimbo[id] = reservation
3✔
1094
        l.reservationIDs[req.PendingChanID] = id
3✔
1095
        l.limboMtx.Unlock()
3✔
1096

3✔
1097
        // Funding reservation request successfully handled. The funding inputs
3✔
1098
        // will be marked as unavailable until the reservation is either
3✔
1099
        // completed, or canceled.
3✔
1100
        req.resp <- reservation
3✔
1101
        req.err <- nil
3✔
1102

3✔
1103
        walletLog.Debugf("Successfully handled funding reservation with "+
3✔
1104
                "pendingChanID: %x, reservationID: %v",
3✔
1105
                reservation.pendingChanID, reservation.reservationID)
3✔
1106
}
1107

1108
// enforceReservedValue enforces that the wallet, upon a new channel being
1109
// opened, meets the minimum amount of funds required for each advertised anchor
1110
// channel.
1111
//
1112
// We only enforce the reserve if we are contributing funds to the channel. This
1113
// is done to still allow incoming channels even though we have no UTXOs
1114
// available, as in bootstrapping phases.
1115
func (l *LightningWallet) enforceNewReservedValue(fundingIntent chanfunding.Intent,
1116
        isPublic, hasAnchors bool) error {
3✔
1117

3✔
1118
        // Only enforce the reserve when an advertised channel is being opened
3✔
1119
        // in which we are contributing funds to. This ensures we never dip
3✔
1120
        // below the reserve.
3✔
1121
        if !isPublic || fundingIntent.LocalFundingAmt() == 0 {
6✔
1122
                return nil
3✔
1123
        }
3✔
1124

1125
        numAnchors, err := l.CurrentNumAnchorChans()
3✔
1126
        if err != nil {
3✔
1127
                return err
×
1128
        }
×
1129

1130
        // Add the to-be-opened channel.
1131
        if hasAnchors {
6✔
1132
                numAnchors++
3✔
1133
        }
3✔
1134

1135
        return l.WithCoinSelectLock(func() error {
6✔
1136
                _, err := l.CheckReservedValue(
3✔
1137
                        fundingIntent.Inputs(), fundingIntent.Outputs(),
3✔
1138
                        numAnchors,
3✔
1139
                )
3✔
1140
                return err
3✔
1141
        })
3✔
1142
}
1143

1144
// CurrentNumAnchorChans returns the current number of non-private anchor
1145
// channels the wallet should be ready to fee bump if needed.
1146
func (l *LightningWallet) CurrentNumAnchorChans() (int, error) {
3✔
1147
        // Count all anchor channels that are open or pending
3✔
1148
        // open, or waiting close.
3✔
1149
        chans, err := l.Cfg.Database.FetchAllChannels()
3✔
1150
        if err != nil {
3✔
1151
                return 0, err
×
1152
        }
×
1153

1154
        var numAnchors int
3✔
1155
        cntChannel := func(c *channeldb.OpenChannel) {
6✔
1156
                // We skip private channels, as we assume they won't be used
3✔
1157
                // for routing.
3✔
1158
                if c.ChannelFlags&lnwire.FFAnnounceChannel == 0 {
6✔
1159
                        return
3✔
1160
                }
3✔
1161

1162
                // Count anchor channels.
1163
                if c.ChanType.HasAnchors() {
6✔
1164
                        numAnchors++
3✔
1165
                }
3✔
1166
        }
1167

1168
        for _, c := range chans {
6✔
1169
                cntChannel(c)
3✔
1170
        }
3✔
1171

1172
        // We also count pending close channels.
1173
        pendingClosed, err := l.Cfg.Database.FetchClosedChannels(
3✔
1174
                true,
3✔
1175
        )
3✔
1176
        if err != nil {
3✔
1177
                return 0, err
×
1178
        }
×
1179

1180
        for _, c := range pendingClosed {
6✔
1181
                c, err := l.Cfg.Database.FetchHistoricalChannel(
3✔
1182
                        &c.ChanPoint,
3✔
1183
                )
3✔
1184
                if err != nil {
3✔
1185
                        // We don't have a guarantee that all channels re found
×
1186
                        // in the historical channels bucket, so we continue.
×
1187
                        walletLog.Warnf("Unable to fetch historical "+
×
1188
                                "channel: %v", err)
×
1189
                        continue
×
1190
                }
1191

1192
                cntChannel(c)
3✔
1193
        }
1194

1195
        return numAnchors, nil
3✔
1196
}
1197

1198
// CheckReservedValue checks whether publishing a transaction with the given
1199
// inputs and outputs would violate the value we reserve in the wallet for
1200
// bumping the fee of anchor channels. The numAnchorChans argument should be
1201
// set the number of open anchor channels controlled by the wallet after
1202
// the transaction has been published.
1203
//
1204
// If the reserved value is violated, the returned error will be
1205
// ErrReservedValueInvalidated. The method will also return the current
1206
// reserved value, both in case of success and in case of
1207
// ErrReservedValueInvalidated.
1208
//
1209
// NOTE: This method should only be run with the CoinSelectLock held.
1210
func (l *LightningWallet) CheckReservedValue(in []wire.OutPoint,
1211
        out []*wire.TxOut, numAnchorChans int) (btcutil.Amount, error) {
3✔
1212

3✔
1213
        // Get all unspent coins in the wallet. We only care about those part of
3✔
1214
        // the wallet's default account as we know we can readily sign for those
3✔
1215
        // at any time.
3✔
1216
        witnessOutputs, err := l.ListUnspentWitnessFromDefaultAccount(
3✔
1217
                0, math.MaxInt32,
3✔
1218
        )
3✔
1219
        if err != nil {
3✔
1220
                return 0, err
×
1221
        }
×
1222

1223
        ourInput := make(map[wire.OutPoint]struct{})
3✔
1224
        for _, op := range in {
6✔
1225
                ourInput[op] = struct{}{}
3✔
1226
        }
3✔
1227

1228
        // When crafting a transaction with inputs from the wallet, these coins
1229
        // will usually be locked in the process, and not be returned when
1230
        // listing unspents. In this case they have already been deducted from
1231
        // the wallet balance. In case they haven't been properly locked, we
1232
        // check whether they are still listed among our unspents and deduct
1233
        // them.
1234
        var walletBalance btcutil.Amount
3✔
1235
        for _, in := range witnessOutputs {
6✔
1236
                // Spending an unlocked wallet UTXO, don't add it to the
3✔
1237
                // balance.
3✔
1238
                if _, ok := ourInput[in.OutPoint]; ok {
6✔
1239
                        continue
3✔
1240
                }
1241

1242
                walletBalance += in.Value
3✔
1243
        }
1244

1245
        // Now we go through the outputs of the transaction, if any of the
1246
        // outputs are paying into the wallet (likely a change output), we add
1247
        // it to our final balance.
1248
        for _, txOut := range out {
6✔
1249
                _, addrs, _, err := txscript.ExtractPkScriptAddrs(
3✔
1250
                        txOut.PkScript, &l.Cfg.NetParams,
3✔
1251
                )
3✔
1252
                if err != nil {
3✔
1253
                        // Non-standard outputs can safely be skipped because
×
1254
                        // they're not supported by the wallet.
×
1255
                        continue
×
1256
                }
1257

1258
                for _, addr := range addrs {
6✔
1259
                        if !l.IsOurAddress(addr) {
6✔
1260
                                continue
3✔
1261
                        }
1262

1263
                        walletBalance += btcutil.Amount(txOut.Value)
3✔
1264

3✔
1265
                        // We break since we don't want to double count the output.
3✔
1266
                        break
3✔
1267
                }
1268
        }
1269

1270
        // We reserve a given amount for each anchor channel.
1271
        reserved := l.RequiredReserve(uint32(numAnchorChans))
3✔
1272

3✔
1273
        if walletBalance < reserved {
6✔
1274
                walletLog.Debugf("Reserved value=%v above final "+
3✔
1275
                        "walletbalance=%v with %d anchor channels open",
3✔
1276
                        reserved, walletBalance, numAnchorChans)
3✔
1277
                return reserved, ErrReservedValueInvalidated
3✔
1278
        }
3✔
1279

1280
        return reserved, nil
3✔
1281
}
1282

1283
// CheckReservedValueTx calls CheckReservedValue with the inputs and outputs
1284
// from the given tx, with the number of anchor channels currently open in the
1285
// database.
1286
//
1287
// NOTE: This method should only be run with the CoinSelectLock held.
1288
func (l *LightningWallet) CheckReservedValueTx(req CheckReservedValueTxReq) (
1289
        btcutil.Amount, error) {
3✔
1290

3✔
1291
        numAnchors, err := l.CurrentNumAnchorChans()
3✔
1292
        if err != nil {
3✔
1293
                return 0, err
×
1294
        }
×
1295

1296
        var inputs []wire.OutPoint
3✔
1297
        for _, txIn := range req.Tx.TxIn {
6✔
1298
                inputs = append(inputs, txIn.PreviousOutPoint)
3✔
1299
        }
3✔
1300

1301
        reservedVal, err := l.CheckReservedValue(
3✔
1302
                inputs, req.Tx.TxOut, numAnchors,
3✔
1303
        )
3✔
1304
        switch {
3✔
1305
        // If the error returned from CheckReservedValue is
1306
        // ErrReservedValueInvalidated, then it did nonetheless return
1307
        // the required reserved value and we check for the optional
1308
        // change index.
1309
        case errors.Is(err, ErrReservedValueInvalidated):
3✔
1310
                // Without a change index provided there is nothing more to
3✔
1311
                // check and the error is returned.
3✔
1312
                if req.ChangeIndex == nil {
6✔
1313
                        return reservedVal, err
3✔
1314
                }
3✔
1315

1316
                // If a change index was provided we make only sure that it
1317
                // would leave sufficient funds for the reserved balance value.
1318
                //
1319
                // Note: This is used if a change output index is explicitly set
1320
                // but that may not be watched by the wallet and therefore is
1321
                // not picked up by the call to CheckReservedValue above.
1322
                chIdx := *req.ChangeIndex
3✔
1323
                if chIdx < 0 || chIdx >= len(req.Tx.TxOut) ||
3✔
1324
                        req.Tx.TxOut[chIdx].Value < int64(reservedVal) {
6✔
1325

3✔
1326
                        return reservedVal, err
3✔
1327
                }
3✔
1328

1329
        case err != nil:
×
1330
                return reservedVal, err
×
1331
        }
1332

1333
        return reservedVal, nil
3✔
1334
}
1335

1336
// initOurContribution initializes the given ChannelReservation with our coins
1337
// and change reserved for the channel, and derives the keys to use for this
1338
// channel.
1339
func (l *LightningWallet) initOurContribution(reservation *ChannelReservation,
1340
        fundingIntent chanfunding.Intent, nodeAddr net.Addr,
1341
        nodeID *btcec.PublicKey, keyRing keychain.KeyRing) error {
3✔
1342

3✔
1343
        // Grab the mutex on the ChannelReservation to ensure thread-safety
3✔
1344
        reservation.Lock()
3✔
1345
        defer reservation.Unlock()
3✔
1346

3✔
1347
        // At this point, if we have a funding intent, we'll use it to populate
3✔
1348
        // the existing reservation state entries for our coin selection.
3✔
1349
        if fundingIntent != nil {
6✔
1350
                if intent, ok := fundingIntent.(*chanfunding.FullIntent); ok {
6✔
1351
                        for _, coin := range intent.InputCoins {
6✔
1352
                                reservation.ourContribution.Inputs = append(
3✔
1353
                                        reservation.ourContribution.Inputs,
3✔
1354
                                        &wire.TxIn{
3✔
1355
                                                PreviousOutPoint: coin.OutPoint,
3✔
1356
                                        },
3✔
1357
                                )
3✔
1358
                        }
3✔
1359
                        reservation.ourContribution.ChangeOutputs = intent.ChangeOutputs
3✔
1360
                }
1361

1362
                reservation.fundingIntent = fundingIntent
3✔
1363
        }
1364

1365
        reservation.nodeAddr = nodeAddr
3✔
1366
        reservation.partialState.IdentityPub = nodeID
3✔
1367

3✔
1368
        var err error
3✔
1369
        reservation.ourContribution.MultiSigKey, err = keyRing.DeriveNextKey(
3✔
1370
                keychain.KeyFamilyMultiSig,
3✔
1371
        )
3✔
1372
        if err != nil {
3✔
1373
                return err
×
1374
        }
×
1375
        reservation.ourContribution.RevocationBasePoint, err = keyRing.DeriveNextKey(
3✔
1376
                keychain.KeyFamilyRevocationBase,
3✔
1377
        )
3✔
1378
        if err != nil {
3✔
1379
                return err
×
1380
        }
×
1381
        reservation.ourContribution.HtlcBasePoint, err = keyRing.DeriveNextKey(
3✔
1382
                keychain.KeyFamilyHtlcBase,
3✔
1383
        )
3✔
1384
        if err != nil {
3✔
1385
                return err
×
1386
        }
×
1387
        reservation.ourContribution.PaymentBasePoint, err = keyRing.DeriveNextKey(
3✔
1388
                keychain.KeyFamilyPaymentBase,
3✔
1389
        )
3✔
1390
        if err != nil {
3✔
1391
                return err
×
1392
        }
×
1393
        reservation.ourContribution.DelayBasePoint, err = keyRing.DeriveNextKey(
3✔
1394
                keychain.KeyFamilyDelayBase,
3✔
1395
        )
3✔
1396
        if err != nil {
3✔
1397
                return err
×
1398
        }
×
1399

1400
        // With the above keys created, we'll also need to initialize our
1401
        // revocation tree state, and from that generate the per-commitment
1402
        // point.
1403
        producer, taprootNonceProducer, err := l.nextRevocationProducer(
3✔
1404
                reservation, keyRing,
3✔
1405
        )
3✔
1406
        if err != nil {
3✔
1407
                return err
×
1408
        }
×
1409

1410
        firstPreimage, err := producer.AtIndex(0)
3✔
1411
        if err != nil {
3✔
1412
                return err
×
1413
        }
×
1414
        reservation.ourContribution.FirstCommitmentPoint = input.ComputeCommitmentPoint(
3✔
1415
                firstPreimage[:],
3✔
1416
        )
3✔
1417

3✔
1418
        reservation.partialState.RevocationProducer = producer
3✔
1419
        reservation.ourContribution.CommitmentParams.DustLimit =
3✔
1420
                DustLimitUnknownWitness()
3✔
1421

3✔
1422
        // If taproot channels are active, then we'll generate our verification
3✔
1423
        // nonce here. We'll use this nonce to verify the signature for our
3✔
1424
        // local commitment transaction. If we need to force close, then this
3✔
1425
        // is also what'll be used to sign that transaction.
3✔
1426
        if reservation.partialState.ChanType.IsTaproot() {
6✔
1427
                firstNoncePreimage, err := taprootNonceProducer.AtIndex(0)
3✔
1428
                if err != nil {
3✔
1429
                        return err
×
1430
                }
×
1431

1432
                // As we'd like the local nonce we send over to be generated
1433
                // deterministically, we'll provide a custom reader that
1434
                // actually just uses our sha-chain pre-image as the primary
1435
                // randomness source.
1436
                shaChainRand := musig2.WithCustomRand(
3✔
1437
                        bytes.NewBuffer(firstNoncePreimage[:]),
3✔
1438
                )
3✔
1439
                pubKeyOpt := musig2.WithPublicKey(
3✔
1440
                        reservation.ourContribution.MultiSigKey.PubKey,
3✔
1441
                )
3✔
1442
                reservation.ourContribution.LocalNonce, err = musig2.GenNonces(
3✔
1443
                        pubKeyOpt, shaChainRand,
3✔
1444
                )
3✔
1445
                if err != nil {
3✔
1446
                        return err
×
1447
                }
×
1448
        }
1449

1450
        return nil
3✔
1451
}
1452

1453
// handleFundingReserveCancel cancels an existing channel reservation. As part
1454
// of the cancellation, outputs previously selected as inputs for the funding
1455
// transaction via coin selection are freed allowing future reservations to
1456
// include them.
1457
func (l *LightningWallet) handleFundingCancelRequest(req *fundingReserveCancelMsg) {
3✔
1458
        l.limboMtx.Lock()
3✔
1459
        defer l.limboMtx.Unlock()
3✔
1460

3✔
1461
        pendingReservation, ok := l.fundingLimbo[req.pendingFundingID]
3✔
1462
        if !ok {
3✔
1463
                // TODO(roasbeef): make new error, "unknown funding state" or something
×
1464
                req.err <- fmt.Errorf("attempted to cancel non-existent funding state")
×
1465
                return
×
1466
        }
×
1467

1468
        // Grab the mutex on the ChannelReservation to ensure thread-safety
1469
        pendingReservation.Lock()
3✔
1470
        defer pendingReservation.Unlock()
3✔
1471

3✔
1472
        // Mark all previously locked outpoints as usable for future funding
3✔
1473
        // requests.
3✔
1474
        for _, unusedInput := range pendingReservation.ourContribution.Inputs {
6✔
1475
                delete(l.lockedOutPoints, unusedInput.PreviousOutPoint)
3✔
1476
                _ = l.ReleaseOutput(
3✔
1477
                        chanfunding.LndInternalLockID,
3✔
1478
                        unusedInput.PreviousOutPoint,
3✔
1479
                )
3✔
1480
        }
3✔
1481

1482
        delete(l.fundingLimbo, req.pendingFundingID)
3✔
1483

3✔
1484
        pid := pendingReservation.pendingChanID
3✔
1485
        delete(l.reservationIDs, pid)
3✔
1486

3✔
1487
        l.intentMtx.Lock()
3✔
1488
        if intent, ok := l.fundingIntents[pid]; ok {
6✔
1489
                intent.Cancel()
3✔
1490

3✔
1491
                delete(l.fundingIntents, pendingReservation.pendingChanID)
3✔
1492
        }
3✔
1493
        l.intentMtx.Unlock()
3✔
1494

3✔
1495
        req.err <- nil
3✔
1496
}
1497

1498
// createCommitOpts is a struct that holds the options for creating a new
1499
// commitment transaction.
1500
type createCommitOpts struct {
1501
        localAuxLeaves  fn.Option[CommitAuxLeaves]
1502
        remoteAuxLeaves fn.Option[CommitAuxLeaves]
1503
}
1504

1505
// defaultCommitOpts returns a new createCommitOpts with default values.
1506
func defaultCommitOpts() createCommitOpts {
3✔
1507
        return createCommitOpts{}
3✔
1508
}
3✔
1509

1510
// WithAuxLeaves is a functional option that can be used to set the aux leaves
1511
// for a new commitment transaction.
1512
func WithAuxLeaves(localLeaves,
1513
        remoteLeaves fn.Option[CommitAuxLeaves]) CreateCommitOpt {
3✔
1514

3✔
1515
        return func(o *createCommitOpts) {
6✔
1516
                o.localAuxLeaves = localLeaves
3✔
1517
                o.remoteAuxLeaves = remoteLeaves
3✔
1518
        }
3✔
1519
}
1520

1521
// CreateCommitOpt is a functional option that can be used to modify the way a
1522
// new commitment transaction is created.
1523
type CreateCommitOpt func(*createCommitOpts)
1524

1525
// CreateCommitmentTxns is a helper function that creates the initial
1526
// commitment transaction for both parties. This function is used during the
1527
// initial funding workflow as both sides must generate a signature for the
1528
// remote party's commitment transaction, and verify the signature for their
1529
// version of the commitment transaction.
1530
func CreateCommitmentTxns(localBalance, remoteBalance btcutil.Amount,
1531
        ourChanCfg, theirChanCfg *channeldb.ChannelConfig,
1532
        localCommitPoint, remoteCommitPoint *btcec.PublicKey,
1533
        fundingTxIn wire.TxIn, chanType channeldb.ChannelType, initiator bool,
1534
        leaseExpiry uint32, opts ...CreateCommitOpt) (*wire.MsgTx, *wire.MsgTx,
1535
        error) {
3✔
1536

3✔
1537
        options := defaultCommitOpts()
3✔
1538
        for _, optFunc := range opts {
6✔
1539
                optFunc(&options)
3✔
1540
        }
3✔
1541

1542
        localCommitmentKeys := DeriveCommitmentKeys(
3✔
1543
                localCommitPoint, lntypes.Local, chanType, ourChanCfg,
3✔
1544
                theirChanCfg,
3✔
1545
        )
3✔
1546
        remoteCommitmentKeys := DeriveCommitmentKeys(
3✔
1547
                remoteCommitPoint, lntypes.Remote, chanType, ourChanCfg,
3✔
1548
                theirChanCfg,
3✔
1549
        )
3✔
1550

3✔
1551
        ourCommitTx, err := CreateCommitTx(
3✔
1552
                chanType, fundingTxIn, localCommitmentKeys, ourChanCfg,
3✔
1553
                theirChanCfg, localBalance, remoteBalance, 0, initiator,
3✔
1554
                leaseExpiry, options.localAuxLeaves,
3✔
1555
        )
3✔
1556
        if err != nil {
3✔
1557
                return nil, nil, err
×
1558
        }
×
1559

1560
        otxn := btcutil.NewTx(ourCommitTx)
3✔
1561
        if err := blockchain.CheckTransactionSanity(otxn); err != nil {
3✔
1562
                return nil, nil, err
×
1563
        }
×
1564

1565
        theirCommitTx, err := CreateCommitTx(
3✔
1566
                chanType, fundingTxIn, remoteCommitmentKeys, theirChanCfg,
3✔
1567
                ourChanCfg, remoteBalance, localBalance, 0, !initiator,
3✔
1568
                leaseExpiry, options.remoteAuxLeaves,
3✔
1569
        )
3✔
1570
        if err != nil {
3✔
1571
                return nil, nil, err
×
1572
        }
×
1573

1574
        ttxn := btcutil.NewTx(theirCommitTx)
3✔
1575
        if err := blockchain.CheckTransactionSanity(ttxn); err != nil {
3✔
1576
                return nil, nil, err
×
1577
        }
×
1578

1579
        return ourCommitTx, theirCommitTx, nil
3✔
1580
}
1581

1582
// handleContributionMsg processes the second workflow step for the lifetime of
1583
// a channel reservation. Upon completion, the reservation will carry a
1584
// completed funding transaction (minus the counterparty's input signatures),
1585
// both versions of the commitment transaction, and our signature for their
1586
// version of the commitment transaction.
1587
func (l *LightningWallet) handleContributionMsg(req *addContributionMsg) {
3✔
1588

3✔
1589
        l.limboMtx.Lock()
3✔
1590
        pendingReservation, ok := l.fundingLimbo[req.pendingFundingID]
3✔
1591
        l.limboMtx.Unlock()
3✔
1592
        if !ok {
3✔
1593
                req.err <- fmt.Errorf("attempted to update non-existent funding state")
×
1594
                return
×
1595
        }
×
1596

1597
        // Grab the mutex on the ChannelReservation to ensure thread-safety
1598
        pendingReservation.Lock()
3✔
1599
        defer pendingReservation.Unlock()
3✔
1600

3✔
1601
        // If UpfrontShutdownScript is set, validate that it is a valid script.
3✔
1602
        shutdown := req.contribution.UpfrontShutdown
3✔
1603
        if len(shutdown) > 0 {
3✔
1604
                // Validate the shutdown script.
×
1605
                if !ValidateUpfrontShutdown(shutdown, &l.Cfg.NetParams) {
×
1606
                        req.err <- fmt.Errorf("invalid shutdown script")
×
1607
                        return
×
1608
                }
×
1609
        }
1610

1611
        // Some temporary variables to cut down on the resolution verbosity.
1612
        pendingReservation.theirContribution = req.contribution
3✔
1613
        theirContribution := req.contribution
3✔
1614
        ourContribution := pendingReservation.ourContribution
3✔
1615

3✔
1616
        // Perform bounds-checking on both ChannelReserve and DustLimit
3✔
1617
        // parameters.
3✔
1618
        if !pendingReservation.validateReserveBounds() {
3✔
1619
                req.err <- fmt.Errorf("invalid reserve and dust bounds")
×
1620
                return
×
1621
        }
×
1622

1623
        var (
3✔
1624
                chanPoint *wire.OutPoint
3✔
1625
                err       error
3✔
1626
        )
3✔
1627

3✔
1628
        // At this point, we can now construct our channel point. Depending on
3✔
1629
        // which type of intent we obtained from our chanfunding.Assembler,
3✔
1630
        // we'll carry out a distinct set of steps.
3✔
1631
        switch fundingIntent := pendingReservation.fundingIntent.(type) {
3✔
1632
        // The transaction was created outside of the wallet and might already
1633
        // be published. Nothing left to do other than using the correct
1634
        // outpoint.
1635
        case *chanfunding.ShimIntent:
3✔
1636
                chanPoint, err = fundingIntent.ChanPoint()
3✔
1637
                if err != nil {
3✔
1638
                        req.err <- fmt.Errorf("unable to obtain chan point: %w",
×
1639
                                err)
×
1640
                        return
×
1641
                }
×
1642

1643
                pendingReservation.partialState.FundingOutpoint = *chanPoint
3✔
1644

1645
        // The user has signaled that they want to use a PSBT to construct the
1646
        // funding transaction. Because we now have the multisig keys from both
1647
        // parties, we can create the multisig script that needs to be funded
1648
        // and then pause the process until the user supplies the PSBT
1649
        // containing the eventual funding transaction.
1650
        case *chanfunding.PsbtIntent:
3✔
1651
                if fundingIntent.PendingPsbt != nil {
3✔
1652
                        req.err <- fmt.Errorf("PSBT funding already in" +
×
1653
                                "progress")
×
1654
                        return
×
1655
                }
×
1656

1657
                // Now that we know our contribution, we can bind both the local
1658
                // and remote key which will be needed to calculate the multisig
1659
                // funding output in a next step.
1660
                pendingChanID := pendingReservation.pendingChanID
3✔
1661

3✔
1662
                walletLog.Debugf("Advancing PSBT funding flow for "+
3✔
1663
                        "pending_id(%x), binding keys local_key=%v, "+
3✔
1664
                        "remote_key=%x", pendingChanID,
3✔
1665
                        &ourContribution.MultiSigKey,
3✔
1666
                        theirContribution.MultiSigKey.PubKey.SerializeCompressed())
3✔
1667

3✔
1668
                fundingIntent.BindKeys(
3✔
1669
                        &ourContribution.MultiSigKey,
3✔
1670
                        theirContribution.MultiSigKey.PubKey,
3✔
1671
                )
3✔
1672

3✔
1673
                // We might have a tapscript root, so we'll bind that now to
3✔
1674
                // ensure we make the proper funding output.
3✔
1675
                fundingIntent.BindTapscriptRoot(
3✔
1676
                        pendingReservation.partialState.TapscriptRoot,
3✔
1677
                )
3✔
1678

3✔
1679
                // Exit early because we can't continue the funding flow yet.
3✔
1680
                req.err <- &PsbtFundingRequired{
3✔
1681
                        Intent: fundingIntent,
3✔
1682
                }
3✔
1683
                return
3✔
1684

1685
        case *chanfunding.FullIntent:
3✔
1686
                // Now that we know their public key, we can bind theirs as
3✔
1687
                // well as ours to the funding intent.
3✔
1688
                fundingIntent.BindKeys(
3✔
1689
                        &pendingReservation.ourContribution.MultiSigKey,
3✔
1690
                        theirContribution.MultiSigKey.PubKey,
3✔
1691
                )
3✔
1692

3✔
1693
                // With our keys bound, we can now construct+sign the final
3✔
1694
                // funding transaction and also obtain the chanPoint that
3✔
1695
                // creates the channel.
3✔
1696
                fundingTx, err := fundingIntent.CompileFundingTx(
3✔
1697
                        theirContribution.Inputs,
3✔
1698
                        theirContribution.ChangeOutputs,
3✔
1699
                )
3✔
1700
                if err != nil {
3✔
1701
                        req.err <- fmt.Errorf("unable to construct funding "+
×
1702
                                "tx: %v", err)
×
1703
                        return
×
1704
                }
×
1705
                chanPoint, err = fundingIntent.ChanPoint()
3✔
1706
                if err != nil {
3✔
1707
                        req.err <- fmt.Errorf("unable to obtain chan "+
×
1708
                                "point: %v", err)
×
1709
                        return
×
1710
                }
×
1711

1712
                // Finally, we'll populate the relevant information in our
1713
                // pendingReservation so the rest of the funding flow can
1714
                // continue as normal.
1715
                pendingReservation.fundingTx = fundingTx
3✔
1716
                pendingReservation.partialState.FundingOutpoint = *chanPoint
3✔
1717
                pendingReservation.ourFundingInputScripts = make(
3✔
1718
                        []*input.Script, 0, len(ourContribution.Inputs),
3✔
1719
                )
3✔
1720
                for _, txIn := range fundingTx.TxIn {
6✔
1721
                        _, err := l.FetchOutpointInfo(&txIn.PreviousOutPoint)
3✔
1722
                        if err != nil {
3✔
1723
                                continue
×
1724
                        }
1725

1726
                        pendingReservation.ourFundingInputScripts = append(
3✔
1727
                                pendingReservation.ourFundingInputScripts,
3✔
1728
                                &input.Script{
3✔
1729
                                        Witness:   txIn.Witness,
3✔
1730
                                        SigScript: txIn.SignatureScript,
3✔
1731
                                },
3✔
1732
                        )
3✔
1733
                }
1734

1735
                walletLog.Tracef("Funding tx for ChannelPoint(%v) "+
3✔
1736
                        "generated: %v", chanPoint, spew.Sdump(fundingTx))
3✔
1737
        }
1738

1739
        // If we landed here and didn't exit early, it means we already have
1740
        // the channel point ready. We can jump directly to the next step.
1741
        l.handleChanPointReady(&continueContributionMsg{
3✔
1742
                pendingFundingID: req.pendingFundingID,
3✔
1743
                err:              req.err,
3✔
1744
        })
3✔
1745
}
1746

1747
// genMusigSession generates a new musig2 pair session that we can use to sign
1748
// the commitment transaction for the remote party, and verify their incoming
1749
// partial signature.
1750
func genMusigSession(ourContribution, theirContribution *ChannelContribution,
1751
        signer input.MuSig2Signer, fundingOutput *wire.TxOut,
1752
        tapscriptRoot fn.Option[chainhash.Hash]) *MusigPairSession {
3✔
1753

3✔
1754
        return NewMusigPairSession(&MusigSessionCfg{
3✔
1755
                LocalKey:       ourContribution.MultiSigKey,
3✔
1756
                RemoteKey:      theirContribution.MultiSigKey,
3✔
1757
                LocalNonce:     *ourContribution.LocalNonce,
3✔
1758
                RemoteNonce:    *theirContribution.LocalNonce,
3✔
1759
                Signer:         signer,
3✔
1760
                InputTxOut:     fundingOutput,
3✔
1761
                TapscriptTweak: tapscriptRoot,
3✔
1762
        })
3✔
1763
}
3✔
1764

1765
// signCommitTx generates a valid input.Signature to send to the remote party
1766
// for their version of the commitment transaction. For regular channels, this
1767
// will be a normal ECDSA signature. For taproot channels, this will instead be
1768
// a musig2 partial signature that also includes the nonce used to generate it.
1769
func (l *LightningWallet) signCommitTx(pendingReservation *ChannelReservation,
1770
        commitTx *wire.MsgTx, fundingOutput *wire.TxOut,
1771
        fundingWitnessScript []byte) (input.Signature, error) {
3✔
1772

3✔
1773
        ourContribution := pendingReservation.ourContribution
3✔
1774
        theirContribution := pendingReservation.theirContribution
3✔
1775

3✔
1776
        var (
3✔
1777
                sigTheirCommit input.Signature
3✔
1778
                err            error
3✔
1779
        )
3✔
1780
        switch {
3✔
1781
        // For regular channels, we can just send over a normal ECDSA signature
1782
        // w/o any extra steps.
1783
        case !pendingReservation.partialState.ChanType.IsTaproot():
3✔
1784
                ourKey := ourContribution.MultiSigKey
3✔
1785
                signDesc := input.SignDescriptor{
3✔
1786
                        WitnessScript: fundingWitnessScript,
3✔
1787
                        KeyDesc:       ourKey,
3✔
1788
                        Output:        fundingOutput,
3✔
1789
                        HashType:      txscript.SigHashAll,
3✔
1790
                        SigHashes: input.NewTxSigHashesV0Only(
3✔
1791
                                commitTx,
3✔
1792
                        ),
3✔
1793
                        InputIndex: 0,
3✔
1794
                }
3✔
1795
                sigTheirCommit, err = l.Cfg.Signer.SignOutputRaw(
3✔
1796
                        commitTx, &signDesc,
3✔
1797
                )
3✔
1798
                if err != nil {
3✔
1799
                        return nil, err
×
1800
                }
×
1801

1802
        // If this is a taproot channel, then we'll need to create an initial
1803
        // musig2 session here as we'll be sending over a _partial_ signature.
1804
        default:
3✔
1805
                // We're now ready to sign the first commitment. However, we'll
3✔
1806
                // only create the session if that hasn't been done already.
3✔
1807
                if pendingReservation.musigSessions == nil {
6✔
1808
                        musigSessions := genMusigSession(
3✔
1809
                                ourContribution, theirContribution,
3✔
1810
                                l.Cfg.Signer, fundingOutput,
3✔
1811
                                pendingReservation.partialState.TapscriptRoot,
3✔
1812
                        )
3✔
1813
                        pendingReservation.musigSessions = musigSessions
3✔
1814
                }
3✔
1815

1816
                // Now that we have the funding outpoint, we'll generate a
1817
                // musig2 signature for their version of the commitment
1818
                // transaction. We use the remote session as this is for the
1819
                // remote commitment transaction.
1820
                musigSessions := pendingReservation.musigSessions
3✔
1821
                partialSig, err := musigSessions.RemoteSession.SignCommit(
3✔
1822
                        commitTx,
3✔
1823
                )
3✔
1824
                if err != nil {
3✔
1825
                        return nil, fmt.Errorf("unable to sign "+
×
1826
                                "commitment: %w", err)
×
1827
                }
×
1828

1829
                sigTheirCommit = partialSig
3✔
1830
        }
1831

1832
        return sigTheirCommit, nil
3✔
1833
}
1834

1835
// handleChanPointReady continues the funding process once the channel point is
1836
// known and the funding transaction can be completed.
1837
func (l *LightningWallet) handleChanPointReady(req *continueContributionMsg) {
3✔
1838
        l.limboMtx.Lock()
3✔
1839
        pendingReservation, ok := l.fundingLimbo[req.pendingFundingID]
3✔
1840
        l.limboMtx.Unlock()
3✔
1841
        if !ok {
3✔
1842
                req.err <- fmt.Errorf("attempted to update non-existent " +
×
1843
                        "funding state")
×
1844
                return
×
1845
        }
×
1846

1847
        chanState := pendingReservation.partialState
3✔
1848

3✔
1849
        // If we have an aux funding desc, then we can use it to populate some
3✔
1850
        // of the optional, but opaque TLV blobs we'll carry for the channel.
3✔
1851
        chanState.CustomBlob = fn.MapOption(func(desc AuxFundingDesc) tlv.Blob {
3✔
1852
                return desc.CustomFundingBlob
×
1853
        })(req.auxFundingDesc)
×
1854

1855
        chanState.LocalCommitment.CustomBlob = fn.MapOption(
3✔
1856
                func(desc AuxFundingDesc) tlv.Blob {
3✔
1857
                        return desc.CustomLocalCommitBlob
×
1858
                },
×
1859
        )(req.auxFundingDesc)
1860

1861
        chanState.RemoteCommitment.CustomBlob = fn.MapOption(
3✔
1862
                func(desc AuxFundingDesc) tlv.Blob {
3✔
1863
                        return desc.CustomRemoteCommitBlob
×
1864
                },
×
1865
        )(req.auxFundingDesc)
1866

1867
        ourContribution := pendingReservation.ourContribution
3✔
1868
        theirContribution := pendingReservation.theirContribution
3✔
1869
        chanPoint := pendingReservation.partialState.FundingOutpoint
3✔
1870

3✔
1871
        // If we're in the PSBT funding flow, we now should have everything that
3✔
1872
        // is needed to construct and publish the full funding transaction.
3✔
1873
        intent := pendingReservation.fundingIntent
3✔
1874
        if psbtIntent, ok := intent.(*chanfunding.PsbtIntent); ok {
6✔
1875
                // With our keys bound, we can now construct and possibly sign
3✔
1876
                // the final funding transaction and also obtain the chanPoint
3✔
1877
                // that creates the channel. We _have_ to call CompileFundingTx
3✔
1878
                // even if we don't publish ourselves as that sets the actual
3✔
1879
                // funding outpoint in stone for this channel.
3✔
1880
                fundingTx, err := psbtIntent.CompileFundingTx()
3✔
1881
                if err != nil {
3✔
1882
                        req.err <- fmt.Errorf("unable to construct funding "+
×
1883
                                "tx: %v", err)
×
1884
                        return
×
1885
                }
×
1886
                chanPointPtr, err := psbtIntent.ChanPoint()
3✔
1887
                if err != nil {
3✔
1888
                        req.err <- fmt.Errorf("unable to obtain chan "+
×
1889
                                "point: %v", err)
×
1890
                        return
×
1891
                }
×
1892

1893
                pendingReservation.partialState.FundingOutpoint = *chanPointPtr
3✔
1894
                chanPoint = *chanPointPtr
3✔
1895

3✔
1896
                // Finally, we'll populate the relevant information in our
3✔
1897
                // pendingReservation so the rest of the funding flow can
3✔
1898
                // continue as normal in case we are going to publish ourselves.
3✔
1899
                if psbtIntent.ShouldPublishFundingTX() {
6✔
1900
                        pendingReservation.fundingTx = fundingTx
3✔
1901
                        pendingReservation.ourFundingInputScripts = make(
3✔
1902
                                []*input.Script, 0, len(ourContribution.Inputs),
3✔
1903
                        )
3✔
1904
                        for _, txIn := range fundingTx.TxIn {
6✔
1905
                                pendingReservation.ourFundingInputScripts = append(
3✔
1906
                                        pendingReservation.ourFundingInputScripts,
3✔
1907
                                        &input.Script{
3✔
1908
                                                Witness:   txIn.Witness,
3✔
1909
                                                SigScript: txIn.SignatureScript,
3✔
1910
                                        },
3✔
1911
                                )
3✔
1912
                        }
3✔
1913
                }
1914
        }
1915

1916
        // Initialize an empty sha-chain for them, tracking the current pending
1917
        // revocation hash (we don't yet know the preimage so we can't add it
1918
        // to the chain).
1919
        s := shachain.NewRevocationStore()
3✔
1920
        pendingReservation.partialState.RevocationStore = s
3✔
1921

3✔
1922
        // Store their current commitment point. We'll need this after the
3✔
1923
        // first state transition in order to verify the authenticity of the
3✔
1924
        // revocation.
3✔
1925
        chanState.RemoteCurrentRevocation = theirContribution.FirstCommitmentPoint
3✔
1926

3✔
1927
        // Create the txin to our commitment transaction; required to construct
3✔
1928
        // the commitment transactions.
3✔
1929
        fundingTxIn := wire.TxIn{
3✔
1930
                PreviousOutPoint: chanPoint,
3✔
1931
        }
3✔
1932

3✔
1933
        // With the funding tx complete, create both commitment transactions.
3✔
1934
        localBalance := pendingReservation.partialState.LocalCommitment.LocalBalance.ToSatoshis()
3✔
1935
        remoteBalance := pendingReservation.partialState.LocalCommitment.RemoteBalance.ToSatoshis()
3✔
1936
        var leaseExpiry uint32
3✔
1937
        if pendingReservation.partialState.ChanType.HasLeaseExpiration() {
6✔
1938
                leaseExpiry = pendingReservation.partialState.ThawHeight
3✔
1939
        }
3✔
1940

1941
        localAuxLeaves := fn.MapOption(
3✔
1942
                func(desc AuxFundingDesc) CommitAuxLeaves {
3✔
1943
                        return desc.LocalInitAuxLeaves
×
1944
                },
×
1945
        )(req.auxFundingDesc)
1946
        remoteAuxLeaves := fn.MapOption(
3✔
1947
                func(desc AuxFundingDesc) CommitAuxLeaves {
3✔
1948
                        return desc.RemoteInitAuxLeaves
×
1949
                },
×
1950
        )(req.auxFundingDesc)
1951

1952
        ourCommitTx, theirCommitTx, err := CreateCommitmentTxns(
3✔
1953
                localBalance, remoteBalance, ourContribution.ChannelConfig,
3✔
1954
                theirContribution.ChannelConfig,
3✔
1955
                ourContribution.FirstCommitmentPoint,
3✔
1956
                theirContribution.FirstCommitmentPoint, fundingTxIn,
3✔
1957
                pendingReservation.partialState.ChanType,
3✔
1958
                pendingReservation.partialState.IsInitiator, leaseExpiry,
3✔
1959
                WithAuxLeaves(localAuxLeaves, remoteAuxLeaves),
3✔
1960
        )
3✔
1961
        if err != nil {
3✔
1962
                req.err <- err
×
1963
                return
×
1964
        }
×
1965

1966
        // With both commitment transactions constructed, generate the state
1967
        // obfuscator then use it to encode the current state number within
1968
        // both commitment transactions.
1969
        var stateObfuscator [StateHintSize]byte
3✔
1970
        if chanState.ChanType.IsSingleFunder() {
6✔
1971
                stateObfuscator = DeriveStateHintObfuscator(
3✔
1972
                        ourContribution.PaymentBasePoint.PubKey,
3✔
1973
                        theirContribution.PaymentBasePoint.PubKey,
3✔
1974
                )
3✔
1975
        } else {
3✔
1976
                ourSer := ourContribution.PaymentBasePoint.PubKey.SerializeCompressed()
×
1977
                theirSer := theirContribution.PaymentBasePoint.PubKey.SerializeCompressed()
×
1978
                switch bytes.Compare(ourSer, theirSer) {
×
1979
                case -1:
×
1980
                        stateObfuscator = DeriveStateHintObfuscator(
×
1981
                                ourContribution.PaymentBasePoint.PubKey,
×
1982
                                theirContribution.PaymentBasePoint.PubKey,
×
1983
                        )
×
1984
                default:
×
1985
                        stateObfuscator = DeriveStateHintObfuscator(
×
1986
                                theirContribution.PaymentBasePoint.PubKey,
×
1987
                                ourContribution.PaymentBasePoint.PubKey,
×
1988
                        )
×
1989
                }
1990
        }
1991
        err = initStateHints(ourCommitTx, theirCommitTx, stateObfuscator)
3✔
1992
        if err != nil {
3✔
1993
                req.err <- err
×
1994
                return
×
1995
        }
×
1996

1997
        // Sort both transactions according to the agreed upon canonical
1998
        // ordering. This lets us skip sending the entire transaction over,
1999
        // instead we'll just send signatures.
2000
        txsort.InPlaceSort(ourCommitTx)
3✔
2001
        txsort.InPlaceSort(theirCommitTx)
3✔
2002

3✔
2003
        walletLog.Tracef("Local commit tx for ChannelPoint(%v): %v",
3✔
2004
                chanPoint, spew.Sdump(ourCommitTx))
3✔
2005
        walletLog.Tracef("Remote commit tx for ChannelPoint(%v): %v",
3✔
2006
                chanPoint, spew.Sdump(theirCommitTx))
3✔
2007

3✔
2008
        // Record newly available information within the open channel state.
3✔
2009
        chanState.FundingOutpoint = chanPoint
3✔
2010
        chanState.LocalCommitment.CommitTx = ourCommitTx
3✔
2011
        chanState.RemoteCommitment.CommitTx = theirCommitTx
3✔
2012

3✔
2013
        // Next, we'll obtain the funding witness script, and the funding
3✔
2014
        // output itself so we can generate a valid signature for the remote
3✔
2015
        // party.
3✔
2016
        fundingIntent := pendingReservation.fundingIntent
3✔
2017
        fundingWitnessScript, fundingOutput, err := fundingIntent.FundingOutput()
3✔
2018
        if err != nil {
3✔
2019
                req.err <- fmt.Errorf("unable to obtain funding "+
×
2020
                        "output: %w", err)
×
2021
                return
×
2022
        }
×
2023

2024
        // Generate a signature for their version of the initial commitment
2025
        // transaction.
2026
        sigTheirCommit, err := l.signCommitTx(
3✔
2027
                pendingReservation, theirCommitTx, fundingOutput,
3✔
2028
                fundingWitnessScript,
3✔
2029
        )
3✔
2030
        if err != nil {
3✔
2031
                req.err <- err
×
2032
                return
×
2033
        }
×
2034

2035
        pendingReservation.ourCommitmentSig = sigTheirCommit
3✔
2036

3✔
2037
        req.err <- nil
3✔
2038
}
2039

2040
// handleSingleContribution is called as the second step to a single funder
2041
// workflow to which we are the responder. It simply saves the remote peer's
2042
// contribution to the channel, as solely the remote peer will contribute any
2043
// funds to the channel.
2044
func (l *LightningWallet) handleSingleContribution(req *addSingleContributionMsg) {
3✔
2045
        l.limboMtx.Lock()
3✔
2046
        pendingReservation, ok := l.fundingLimbo[req.pendingFundingID]
3✔
2047
        l.limboMtx.Unlock()
3✔
2048
        if !ok {
3✔
2049
                req.err <- fmt.Errorf("attempted to update non-existent funding state")
×
2050
                return
×
2051
        }
×
2052

2053
        // Grab the mutex on the channelReservation to ensure thread-safety.
2054
        pendingReservation.Lock()
3✔
2055
        defer pendingReservation.Unlock()
3✔
2056

3✔
2057
        // Validate that the remote's UpfrontShutdownScript is a valid script
3✔
2058
        // if it's set.
3✔
2059
        shutdown := req.contribution.UpfrontShutdown
3✔
2060
        if len(shutdown) > 0 {
6✔
2061
                // Validate the shutdown script.
3✔
2062
                if !ValidateUpfrontShutdown(shutdown, &l.Cfg.NetParams) {
3✔
2063
                        req.err <- fmt.Errorf("invalid shutdown script")
×
2064
                        return
×
2065
                }
×
2066
        }
2067

2068
        // Simply record the counterparty's contribution into the pending
2069
        // reservation data as they'll be solely funding the channel entirely.
2070
        pendingReservation.theirContribution = req.contribution
3✔
2071
        theirContribution := pendingReservation.theirContribution
3✔
2072
        chanState := pendingReservation.partialState
3✔
2073

3✔
2074
        // Perform bounds checking on both ChannelReserve and DustLimit
3✔
2075
        // parameters. The ChannelReserve may have been changed by the
3✔
2076
        // ChannelAcceptor RPC, so this is necessary.
3✔
2077
        if !pendingReservation.validateReserveBounds() {
3✔
2078
                req.err <- fmt.Errorf("invalid reserve and dust bounds")
×
2079
                return
×
2080
        }
×
2081

2082
        // Initialize an empty sha-chain for them, tracking the current pending
2083
        // revocation hash (we don't yet know the preimage so we can't add it
2084
        // to the chain).
2085
        remotePreimageStore := shachain.NewRevocationStore()
3✔
2086
        chanState.RevocationStore = remotePreimageStore
3✔
2087

3✔
2088
        // Now that we've received their first commitment point, we'll store it
3✔
2089
        // within the channel state so we can sync it to disk once the funding
3✔
2090
        // process is complete.
3✔
2091
        chanState.RemoteCurrentRevocation = theirContribution.FirstCommitmentPoint
3✔
2092

3✔
2093
        req.err <- nil
3✔
2094
}
2095

2096
// verifyFundingInputs attempts to verify all remote inputs to the funding
2097
// transaction.
2098
func (l *LightningWallet) verifyFundingInputs(fundingTx *wire.MsgTx,
2099
        remoteInputScripts []*input.Script) error {
3✔
2100

3✔
2101
        sigIndex := 0
3✔
2102
        fundingHashCache := input.NewTxSigHashesV0Only(fundingTx)
3✔
2103
        inputScripts := remoteInputScripts
3✔
2104
        for i, txin := range fundingTx.TxIn {
6✔
2105
                if len(inputScripts) != 0 && len(txin.Witness) == 0 {
3✔
2106
                        // Attach the input scripts so we can verify it below.
×
2107
                        txin.Witness = inputScripts[sigIndex].Witness
×
2108
                        txin.SignatureScript = inputScripts[sigIndex].SigScript
×
2109

×
2110
                        // Fetch the alleged previous output along with the
×
2111
                        // pkscript referenced by this input.
×
2112
                        //
×
2113
                        // TODO(roasbeef): when dual funder pass actual
×
2114
                        // height-hint
×
2115
                        //
×
2116
                        // TODO(roasbeef): this fails for neutrino always as it
×
2117
                        // treats the height hint as an exact birthday of the
×
2118
                        // utxo rather than a lower bound
×
2119
                        pkScript, err := txscript.ComputePkScript(
×
2120
                                txin.SignatureScript, txin.Witness,
×
2121
                        )
×
2122
                        if err != nil {
×
2123
                                return fmt.Errorf("cannot create script: %w",
×
2124
                                        err)
×
2125
                        }
×
2126
                        output, err := l.Cfg.ChainIO.GetUtxo(
×
2127
                                &txin.PreviousOutPoint,
×
2128
                                pkScript.Script(), 0, l.quit,
×
2129
                        )
×
2130
                        if output == nil {
×
2131
                                return fmt.Errorf("input to funding tx does "+
×
2132
                                        "not exist: %v", err)
×
2133
                        }
×
2134

2135
                        // Ensure that the witness+sigScript combo is valid.
2136
                        vm, err := txscript.NewEngine(
×
2137
                                output.PkScript, fundingTx, i,
×
2138
                                txscript.StandardVerifyFlags, nil,
×
2139
                                fundingHashCache, output.Value,
×
2140
                                txscript.NewCannedPrevOutputFetcher(
×
2141
                                        output.PkScript, output.Value,
×
2142
                                ),
×
2143
                        )
×
2144
                        if err != nil {
×
2145
                                return fmt.Errorf("cannot create script "+
×
2146
                                        "engine: %s", err)
×
2147
                        }
×
2148
                        if err = vm.Execute(); err != nil {
×
2149
                                return fmt.Errorf("cannot validate "+
×
2150
                                        "transaction: %s", err)
×
2151
                        }
×
2152

2153
                        sigIndex++
×
2154
                }
2155
        }
2156

2157
        return nil
3✔
2158
}
2159

2160
// verifyCommitSig verifies an incoming signature for our version of the
2161
// commitment transaction. For normal channels, this will verify that the ECDSA
2162
// signature is valid. For taproot channels, we'll verify that their partial
2163
// signature is valid, so it can properly be combined with our eventual
2164
// signature when we need to broadcast.
2165
func (l *LightningWallet) verifyCommitSig(res *ChannelReservation,
2166
        commitSig input.Signature, commitTx *wire.MsgTx) error {
3✔
2167

3✔
2168
        localKey := res.ourContribution.MultiSigKey.PubKey
3✔
2169
        remoteKey := res.theirContribution.MultiSigKey.PubKey
3✔
2170
        channelValue := int64(res.partialState.Capacity)
3✔
2171

3✔
2172
        switch {
3✔
2173
        // If this isn't a taproot channel, then we'll construct a segwit v0
2174
        // p2wsh sighash.
2175
        case !res.partialState.ChanType.IsTaproot():
3✔
2176
                hashCache := input.NewTxSigHashesV0Only(commitTx)
3✔
2177
                witnessScript, _, err := input.GenFundingPkScript(
3✔
2178
                        localKey.SerializeCompressed(),
3✔
2179
                        remoteKey.SerializeCompressed(), channelValue,
3✔
2180
                )
3✔
2181
                if err != nil {
3✔
2182
                        return err
×
2183
                }
×
2184

2185
                sigHash, err := txscript.CalcWitnessSigHash(
3✔
2186
                        witnessScript, hashCache, txscript.SigHashAll,
3✔
2187
                        commitTx, 0, channelValue,
3✔
2188
                )
3✔
2189
                if err != nil {
3✔
2190
                        return err
×
2191
                }
×
2192

2193
                // Verify that we've received a valid signature from the remote
2194
                // party for our version of the commitment transaction.
2195
                if !commitSig.Verify(sigHash, remoteKey) {
3✔
2196
                        return fmt.Errorf("counterparty's commitment " +
×
2197
                                "signature is invalid")
×
2198
                }
×
2199

2200
                return nil
3✔
2201

2202
        // Otherwise for taproot channels, we'll compute the segwit v1 sighash,
2203
        // which is slightly different.
2204
        default:
3✔
2205
                // First, check to see if we've generated the musig session
3✔
2206
                // already. If we're the responder in the funding flow, we may
3✔
2207
                // not have generated it already.
3✔
2208
                if res.musigSessions == nil {
6✔
2209
                        _, fundingOutput, err := input.GenTaprootFundingScript(
3✔
2210
                                localKey, remoteKey, channelValue,
3✔
2211
                                res.partialState.TapscriptRoot,
3✔
2212
                        )
3✔
2213
                        if err != nil {
3✔
2214
                                return err
×
2215
                        }
×
2216

2217
                        res.musigSessions = genMusigSession(
3✔
2218
                                res.ourContribution, res.theirContribution,
3✔
2219
                                l.Cfg.Signer, fundingOutput,
3✔
2220
                                res.partialState.TapscriptRoot,
3✔
2221
                        )
3✔
2222
                }
2223

2224
                // For the musig2 based channels, we'll use the generated local
2225
                // musig2 session to verify the signature.
2226
                localSession := res.musigSessions.LocalSession
3✔
2227

3✔
2228
                // At this point, the commitment signature passed in should
3✔
2229
                // actually be a wrapped musig2 signature, so we'll do a type
3✔
2230
                // asset to the get the signature we actually need.
3✔
2231
                partialSig, ok := commitSig.(*MusigPartialSig)
3✔
2232
                if !ok {
3✔
2233
                        return fmt.Errorf("expected *musig2.PartialSignature, "+
×
2234
                                "got: %T", commitSig)
×
2235
                }
×
2236

2237
                _, err := localSession.VerifyCommitSig(
3✔
2238
                        commitTx, partialSig.ToWireSig(),
3✔
2239
                )
3✔
2240

3✔
2241
                return err
3✔
2242
        }
2243
}
2244

2245
// handleFundingCounterPartySigs is the final step in the channel reservation
2246
// workflow. During this step, we validate *all* the received signatures for
2247
// inputs to the funding transaction. If any of these are invalid, we bail,
2248
// and forcibly cancel this funding request. Additionally, we ensure that the
2249
// signature we received from the counterparty for our version of the commitment
2250
// transaction allows us to spend from the funding output with the addition of
2251
// our signature.
2252
func (l *LightningWallet) handleFundingCounterPartySigs(msg *addCounterPartySigsMsg) {
3✔
2253
        l.limboMtx.RLock()
3✔
2254
        res, ok := l.fundingLimbo[msg.pendingFundingID]
3✔
2255
        l.limboMtx.RUnlock()
3✔
2256
        if !ok {
3✔
2257
                msg.err <- fmt.Errorf("attempted to update non-existent funding state")
×
2258
                return
×
2259
        }
×
2260

2261
        // Grab the mutex on the ChannelReservation to ensure thread-safety
2262
        res.Lock()
3✔
2263
        defer res.Unlock()
3✔
2264

3✔
2265
        // Now we can complete the funding transaction by adding their
3✔
2266
        // signatures to their inputs.
3✔
2267
        res.theirFundingInputScripts = msg.theirFundingInputScripts
3✔
2268
        inputScripts := msg.theirFundingInputScripts
3✔
2269

3✔
2270
        // Only if we have the final funding transaction do we need to verify
3✔
2271
        // the final set of inputs. Otherwise, it may be the case that the
3✔
2272
        // channel was funded via an external wallet.
3✔
2273
        fundingTx := res.fundingTx
3✔
2274
        if res.partialState.ChanType.HasFundingTx() {
6✔
2275
                err := l.verifyFundingInputs(fundingTx, inputScripts)
3✔
2276
                if err != nil {
3✔
2277
                        msg.err <- err
×
2278
                        msg.completeChan <- nil
×
2279
                        return
×
2280
                }
×
2281
        }
2282

2283
        // At this point, we can also record and verify their signature for our
2284
        // commitment transaction.
2285
        res.theirCommitmentSig = msg.theirCommitmentSig
3✔
2286
        commitTx := res.partialState.LocalCommitment.CommitTx
3✔
2287

3✔
2288
        err := l.verifyCommitSig(res, msg.theirCommitmentSig, commitTx)
3✔
2289
        if err != nil {
3✔
2290
                msg.err <- fmt.Errorf("counterparty's commitment signature is "+
×
2291
                        "invalid: %w", err)
×
2292
                msg.completeChan <- nil
×
2293
                return
×
2294
        }
×
2295

2296
        theirCommitSigBytes := msg.theirCommitmentSig.Serialize()
3✔
2297
        res.partialState.LocalCommitment.CommitSig = theirCommitSigBytes
3✔
2298

3✔
2299
        // Funding complete, this entry can be removed from limbo.
3✔
2300
        l.limboMtx.Lock()
3✔
2301
        delete(l.fundingLimbo, res.reservationID)
3✔
2302
        delete(l.reservationIDs, res.pendingChanID)
3✔
2303
        l.limboMtx.Unlock()
3✔
2304

3✔
2305
        l.intentMtx.Lock()
3✔
2306
        delete(l.fundingIntents, res.pendingChanID)
3✔
2307
        l.intentMtx.Unlock()
3✔
2308

3✔
2309
        // As we're about to broadcast the funding transaction, we'll take note
3✔
2310
        // of the current height for record keeping purposes.
3✔
2311
        _, bestHeight, err := l.Cfg.ChainIO.GetBestBlock()
3✔
2312
        if err != nil {
3✔
2313
                msg.err <- err
×
2314
                msg.completeChan <- nil
×
2315
                return
×
2316
        }
×
2317

2318
        // As we've completed the funding process, we'll no convert the
2319
        // contribution structs into their underlying channel config objects to
2320
        // he stored within the database.
2321
        res.partialState.LocalChanCfg = res.ourContribution.toChanConfig()
3✔
2322
        res.partialState.RemoteChanCfg = res.theirContribution.toChanConfig()
3✔
2323

3✔
2324
        // We'll also record the finalized funding txn, which will allow us to
3✔
2325
        // rebroadcast on startup in case we fail.
3✔
2326
        res.partialState.FundingTxn = fundingTx
3✔
2327

3✔
2328
        // Set optional upfront shutdown scripts on the channel state so that they
3✔
2329
        // are persisted. These values may be nil.
3✔
2330
        res.partialState.LocalShutdownScript =
3✔
2331
                res.ourContribution.UpfrontShutdown
3✔
2332
        res.partialState.RemoteShutdownScript =
3✔
2333
                res.theirContribution.UpfrontShutdown
3✔
2334

3✔
2335
        res.partialState.RevocationKeyLocator = res.nextRevocationKeyLoc
3✔
2336

3✔
2337
        // Add the complete funding transaction to the DB, in its open bucket
3✔
2338
        // which will be used for the lifetime of this channel.
3✔
2339
        nodeAddr := res.nodeAddr
3✔
2340
        err = res.partialState.SyncPending(nodeAddr, uint32(bestHeight))
3✔
2341
        if err != nil {
3✔
2342
                msg.err <- err
×
2343
                msg.completeChan <- nil
×
2344
                return
×
2345
        }
×
2346

2347
        msg.completeChan <- res.partialState
3✔
2348
        msg.err <- nil
3✔
2349
}
2350

2351
// handleSingleFunderSigs is called once the remote peer who initiated the
2352
// single funder workflow has assembled the funding transaction, and generated
2353
// a signature for our version of the commitment transaction. This method
2354
// progresses the workflow by generating a signature for the remote peer's
2355
// version of the commitment transaction.
2356
func (l *LightningWallet) handleSingleFunderSigs(req *addSingleFunderSigsMsg) {
3✔
2357
        l.limboMtx.RLock()
3✔
2358
        pendingReservation, ok := l.fundingLimbo[req.pendingFundingID]
3✔
2359
        l.limboMtx.RUnlock()
3✔
2360
        if !ok {
3✔
2361
                req.err <- fmt.Errorf("attempted to update non-existent funding state")
×
2362
                req.completeChan <- nil
×
2363
                return
×
2364
        }
×
2365

2366
        // Grab the mutex on the ChannelReservation to ensure thread-safety
2367
        pendingReservation.Lock()
3✔
2368
        defer pendingReservation.Unlock()
3✔
2369

3✔
2370
        chanState := pendingReservation.partialState
3✔
2371

3✔
2372
        // If we have an aux funding desc, then we can use it to populate some
3✔
2373
        // of the optional, but opaque TLV blobs we'll carry for the channel.
3✔
2374
        chanState.CustomBlob = fn.MapOption(func(desc AuxFundingDesc) tlv.Blob {
3✔
2375
                return desc.CustomFundingBlob
×
2376
        })(req.auxFundingDesc)
×
2377
        chanState.LocalCommitment.CustomBlob = fn.MapOption(
3✔
2378
                func(desc AuxFundingDesc) tlv.Blob {
3✔
2379
                        return desc.CustomLocalCommitBlob
×
2380
                },
×
2381
        )(req.auxFundingDesc)
2382
        chanState.RemoteCommitment.CustomBlob = fn.MapOption(
3✔
2383
                func(desc AuxFundingDesc) tlv.Blob {
3✔
2384
                        return desc.CustomRemoteCommitBlob
×
2385
                },
×
2386
        )(req.auxFundingDesc)
2387

2388
        chanType := pendingReservation.partialState.ChanType
3✔
2389
        chanState.FundingOutpoint = *req.fundingOutpoint
3✔
2390
        fundingTxIn := wire.NewTxIn(req.fundingOutpoint, nil, nil)
3✔
2391

3✔
2392
        // Now that we have the funding outpoint, we can generate both versions
3✔
2393
        // of the commitment transaction, and generate a signature for the
3✔
2394
        // remote node's commitment transactions.
3✔
2395
        localBalance := pendingReservation.partialState.LocalCommitment.LocalBalance.ToSatoshis()
3✔
2396
        remoteBalance := pendingReservation.partialState.LocalCommitment.RemoteBalance.ToSatoshis()
3✔
2397
        var leaseExpiry uint32
3✔
2398
        if pendingReservation.partialState.ChanType.HasLeaseExpiration() {
6✔
2399
                leaseExpiry = pendingReservation.partialState.ThawHeight
3✔
2400
        }
3✔
2401

2402
        localAuxLeaves := fn.MapOption(
3✔
2403
                func(desc AuxFundingDesc) CommitAuxLeaves {
3✔
2404
                        return desc.LocalInitAuxLeaves
×
2405
                },
×
2406
        )(req.auxFundingDesc)
2407
        remoteAuxLeaves := fn.MapOption(
3✔
2408
                func(desc AuxFundingDesc) CommitAuxLeaves {
3✔
2409
                        return desc.RemoteInitAuxLeaves
×
2410
                },
×
2411
        )(req.auxFundingDesc)
2412

2413
        ourCommitTx, theirCommitTx, err := CreateCommitmentTxns(
3✔
2414
                localBalance, remoteBalance,
3✔
2415
                pendingReservation.ourContribution.ChannelConfig,
3✔
2416
                pendingReservation.theirContribution.ChannelConfig,
3✔
2417
                pendingReservation.ourContribution.FirstCommitmentPoint,
3✔
2418
                pendingReservation.theirContribution.FirstCommitmentPoint,
3✔
2419
                *fundingTxIn, chanType,
3✔
2420
                pendingReservation.partialState.IsInitiator, leaseExpiry,
3✔
2421
                WithAuxLeaves(localAuxLeaves, remoteAuxLeaves),
3✔
2422
        )
3✔
2423
        if err != nil {
3✔
2424
                req.err <- err
×
2425
                req.completeChan <- nil
×
2426
                return
×
2427
        }
×
2428

2429
        // With both commitment transactions constructed, we can now use the
2430
        // generator state obfuscator to encode the current state number within
2431
        // both commitment transactions.
2432
        stateObfuscator := DeriveStateHintObfuscator(
3✔
2433
                pendingReservation.theirContribution.PaymentBasePoint.PubKey,
3✔
2434
                pendingReservation.ourContribution.PaymentBasePoint.PubKey,
3✔
2435
        )
3✔
2436
        err = initStateHints(ourCommitTx, theirCommitTx, stateObfuscator)
3✔
2437
        if err != nil {
3✔
2438
                req.err <- err
×
2439
                req.completeChan <- nil
×
2440
                return
×
2441
        }
×
2442

2443
        // Sort both transactions according to the agreed upon canonical
2444
        // ordering. This ensures that both parties sign the same sighash
2445
        // without further synchronization.
2446
        txsort.InPlaceSort(ourCommitTx)
3✔
2447
        txsort.InPlaceSort(theirCommitTx)
3✔
2448
        chanState.LocalCommitment.CommitTx = ourCommitTx
3✔
2449
        chanState.RemoteCommitment.CommitTx = theirCommitTx
3✔
2450

3✔
2451
        walletLog.Debugf("Local commit tx for ChannelPoint(%v): %v",
3✔
2452
                req.fundingOutpoint, spew.Sdump(ourCommitTx))
3✔
2453
        walletLog.Debugf("Remote commit tx for ChannelPoint(%v): %v",
3✔
2454
                req.fundingOutpoint, spew.Sdump(theirCommitTx))
3✔
2455

3✔
2456
        // With both commitment transactions created, we'll now verify their
3✔
2457
        // signature on our commitment.
3✔
2458
        err = l.verifyCommitSig(
3✔
2459
                pendingReservation, req.theirCommitmentSig, ourCommitTx,
3✔
2460
        )
3✔
2461
        if err != nil {
3✔
2462
                req.err <- err
×
2463
                req.completeChan <- nil
×
2464
                return
×
2465
        }
×
2466

2467
        theirCommitSigBytes := req.theirCommitmentSig.Serialize()
3✔
2468
        chanState.LocalCommitment.CommitSig = theirCommitSigBytes
3✔
2469

3✔
2470
        channelValue := int64(pendingReservation.partialState.Capacity)
3✔
2471
        theirKey := pendingReservation.theirContribution.MultiSigKey
3✔
2472
        ourKey := pendingReservation.ourContribution.MultiSigKey
3✔
2473

3✔
2474
        var (
3✔
2475
                fundingWitnessScript []byte
3✔
2476
                fundingTxOut         *wire.TxOut
3✔
2477
        )
3✔
2478
        if chanType.IsTaproot() {
6✔
2479
                //nolint:ll
3✔
2480
                fundingWitnessScript, fundingTxOut, err = input.GenTaprootFundingScript(
3✔
2481
                        ourKey.PubKey, theirKey.PubKey, channelValue,
3✔
2482
                        pendingReservation.partialState.TapscriptRoot,
3✔
2483
                )
3✔
2484
        } else {
6✔
2485
                //nolint:ll
3✔
2486
                fundingWitnessScript, fundingTxOut, err = input.GenFundingPkScript(
3✔
2487
                        ourKey.PubKey.SerializeCompressed(),
3✔
2488
                        theirKey.PubKey.SerializeCompressed(), channelValue,
3✔
2489
                )
3✔
2490
        }
3✔
2491
        if err != nil {
3✔
2492
                req.err <- err
×
2493
                req.completeChan <- nil
×
2494
                return
×
2495
        }
×
2496

2497
        // With their signature for our version of the commitment transactions
2498
        // verified, we can now generate a signature for their version,
2499
        // allowing the funding transaction to be safely broadcast.
2500
        sigTheirCommit, err := l.signCommitTx(
3✔
2501
                pendingReservation, theirCommitTx, fundingTxOut,
3✔
2502
                fundingWitnessScript,
3✔
2503
        )
3✔
2504
        if err != nil {
3✔
2505
                req.err <- err
×
2506
                req.completeChan <- nil
×
2507
                return
×
2508
        }
×
2509

2510
        pendingReservation.ourCommitmentSig = sigTheirCommit
3✔
2511

3✔
2512
        _, bestHeight, err := l.Cfg.ChainIO.GetBestBlock()
3✔
2513
        if err != nil {
3✔
2514
                req.err <- err
×
2515
                req.completeChan <- nil
×
2516
                return
×
2517
        }
×
2518

2519
        // Set optional upfront shutdown scripts on the channel state so that they
2520
        // are persisted. These values may be nil.
2521
        chanState.LocalShutdownScript =
3✔
2522
                pendingReservation.ourContribution.UpfrontShutdown
3✔
2523
        chanState.RemoteShutdownScript =
3✔
2524
                pendingReservation.theirContribution.UpfrontShutdown
3✔
2525

3✔
2526
        // Add the complete funding transaction to the DB, in it's open bucket
3✔
2527
        // which will be used for the lifetime of this channel.
3✔
2528
        chanState.LocalChanCfg = pendingReservation.ourContribution.toChanConfig()
3✔
2529
        chanState.RemoteChanCfg = pendingReservation.theirContribution.toChanConfig()
3✔
2530

3✔
2531
        chanState.RevocationKeyLocator = pendingReservation.nextRevocationKeyLoc
3✔
2532

3✔
2533
        err = chanState.SyncPending(pendingReservation.nodeAddr, uint32(bestHeight))
3✔
2534
        if err != nil {
3✔
2535
                req.err <- err
×
2536
                req.completeChan <- nil
×
2537
                return
×
2538
        }
×
2539

2540
        req.completeChan <- chanState
3✔
2541
        req.err <- nil
3✔
2542

3✔
2543
        l.limboMtx.Lock()
3✔
2544
        delete(l.fundingLimbo, req.pendingFundingID)
3✔
2545
        delete(l.reservationIDs, pendingReservation.pendingChanID)
3✔
2546
        l.limboMtx.Unlock()
3✔
2547

3✔
2548
        l.intentMtx.Lock()
3✔
2549
        delete(l.fundingIntents, pendingReservation.pendingChanID)
3✔
2550
        l.intentMtx.Unlock()
3✔
2551
}
2552

2553
// WithCoinSelectLock will execute the passed function closure in a
2554
// synchronized manner preventing any coin selection operations from proceeding
2555
// while the closure is executing. This can be seen as the ability to execute a
2556
// function closure under an exclusive coin selection lock.
2557
func (l *LightningWallet) WithCoinSelectLock(f func() error) error {
3✔
2558
        l.coinSelectMtx.Lock()
3✔
2559
        defer l.coinSelectMtx.Unlock()
3✔
2560

3✔
2561
        return f()
3✔
2562
}
3✔
2563

2564
// DeriveStateHintObfuscator derives the bytes to be used for obfuscating the
2565
// state hints from the root to be used for a new channel. The obfuscator is
2566
// generated via the following computation:
2567
//
2568
//   - sha256(initiatorKey || responderKey)[26:]
2569
//     -- where both keys are the multi-sig keys of the respective parties
2570
//
2571
// The first 6 bytes of the resulting hash are used as the state hint.
2572
func DeriveStateHintObfuscator(key1, key2 *btcec.PublicKey) [StateHintSize]byte {
3✔
2573
        h := sha256.New()
3✔
2574
        h.Write(key1.SerializeCompressed())
3✔
2575
        h.Write(key2.SerializeCompressed())
3✔
2576

3✔
2577
        sha := h.Sum(nil)
3✔
2578

3✔
2579
        var obfuscator [StateHintSize]byte
3✔
2580
        copy(obfuscator[:], sha[26:])
3✔
2581

3✔
2582
        return obfuscator
3✔
2583
}
3✔
2584

2585
// initStateHints properly sets the obfuscated state hints on both commitment
2586
// transactions using the passed obfuscator.
2587
func initStateHints(commit1, commit2 *wire.MsgTx,
2588
        obfuscator [StateHintSize]byte) error {
3✔
2589

3✔
2590
        if err := SetStateNumHint(commit1, 0, obfuscator); err != nil {
3✔
2591
                return err
×
2592
        }
×
2593
        if err := SetStateNumHint(commit2, 0, obfuscator); err != nil {
3✔
2594
                return err
×
2595
        }
×
2596

2597
        return nil
3✔
2598
}
2599

2600
// ValidateChannel will attempt to fully validate a newly mined channel, given
2601
// its funding transaction and existing channel state. If this method returns
2602
// an error, then the mined channel is invalid, and shouldn't be used.
2603
func (l *LightningWallet) ValidateChannel(channelState *channeldb.OpenChannel,
2604
        fundingTx *wire.MsgTx) error {
3✔
2605

3✔
2606
        var chanOpts []ChannelOpt
3✔
2607
        l.Cfg.AuxLeafStore.WhenSome(func(s AuxLeafStore) {
3✔
2608
                chanOpts = append(chanOpts, WithLeafStore(s))
×
2609
        })
×
2610
        l.Cfg.AuxSigner.WhenSome(func(s AuxSigner) {
3✔
2611
                chanOpts = append(chanOpts, WithAuxSigner(s))
×
2612
        })
×
2613

2614
        // First, we'll obtain a fully signed commitment transaction so we can
2615
        // pass into it on the chanvalidate package for verification.
2616
        channel, err := NewLightningChannel(
3✔
2617
                l.Cfg.Signer, channelState, nil, chanOpts...,
3✔
2618
        )
3✔
2619
        if err != nil {
3✔
2620
                return err
×
2621
        }
×
2622

2623
        localKey := channelState.LocalChanCfg.MultiSigKey.PubKey
3✔
2624
        remoteKey := channelState.RemoteChanCfg.MultiSigKey.PubKey
3✔
2625

3✔
2626
        // We'll also need the multi-sig witness script itself so the
3✔
2627
        // chanvalidate package can check it for correctness against the
3✔
2628
        // funding transaction, and also commitment validity.
3✔
2629
        var fundingScript []byte
3✔
2630
        if channelState.ChanType.IsTaproot() {
6✔
2631
                fundingScript, _, err = input.GenTaprootFundingScript(
3✔
2632
                        localKey, remoteKey, int64(channel.Capacity),
3✔
2633
                        channelState.TapscriptRoot,
3✔
2634
                )
3✔
2635
                if err != nil {
3✔
2636
                        return err
×
2637
                }
×
2638
        } else {
3✔
2639
                witnessScript, err := input.GenMultiSigScript(
3✔
2640
                        localKey.SerializeCompressed(),
3✔
2641
                        remoteKey.SerializeCompressed(),
3✔
2642
                )
3✔
2643
                if err != nil {
3✔
2644
                        return err
×
2645
                }
×
2646
                fundingScript, err = input.WitnessScriptHash(witnessScript)
3✔
2647
                if err != nil {
3✔
2648
                        return err
×
2649
                }
×
2650
        }
2651

2652
        signedCommitTx, err := channel.getSignedCommitTx()
3✔
2653
        if err != nil {
3✔
2654
                return err
×
2655
        }
×
2656
        commitCtx := &chanvalidate.CommitmentContext{
3✔
2657
                Value:               channel.Capacity,
3✔
2658
                FullySignedCommitTx: signedCommitTx,
3✔
2659
        }
3✔
2660

3✔
2661
        // Finally, we'll pass in all the necessary context needed to fully
3✔
2662
        // validate that this channel is indeed what we expect, and can be
3✔
2663
        // used.
3✔
2664
        _, err = chanvalidate.Validate(&chanvalidate.Context{
3✔
2665
                Locator: &chanvalidate.OutPointChanLocator{
3✔
2666
                        ChanPoint: channelState.FundingOutpoint,
3✔
2667
                },
3✔
2668
                MultiSigPkScript: fundingScript,
3✔
2669
                FundingTx:        fundingTx,
3✔
2670
                CommitCtx:        commitCtx,
3✔
2671
        })
3✔
2672
        if err != nil {
3✔
2673
                return err
×
2674
        }
×
2675

2676
        return nil
3✔
2677
}
2678

2679
// CancelRebroadcast cancels the rebroadcast of the given transaction.
2680
func (l *LightningWallet) CancelRebroadcast(txid chainhash.Hash) {
3✔
2681
        // For neutrino, we don't config the rebroadcaster for the wallet as it
3✔
2682
        // manages the rebroadcasting logic in neutrino itself.
3✔
2683
        if l.Cfg.Rebroadcaster != nil {
5✔
2684
                l.Cfg.Rebroadcaster.MarkAsConfirmed(txid)
2✔
2685
        }
2✔
2686
}
2687

2688
// CoinSource is a wrapper around the wallet that implements the
2689
// chanfunding.CoinSource interface.
2690
type CoinSource struct {
2691
        wallet    *LightningWallet
2692
        allowUtxo func(Utxo) bool
2693
}
2694

2695
// NewCoinSource creates a new instance of the CoinSource wrapper struct.
2696
func NewCoinSource(w *LightningWallet, allowUtxo func(Utxo) bool) *CoinSource {
3✔
2697
        return &CoinSource{
3✔
2698
                wallet:    w,
3✔
2699
                allowUtxo: allowUtxo,
3✔
2700
        }
3✔
2701
}
3✔
2702

2703
// ListCoins returns all UTXOs from the source that have between
2704
// minConfs and maxConfs number of confirmations.
2705
func (c *CoinSource) ListCoins(minConfs int32,
2706
        maxConfs int32) ([]wallet.Coin, error) {
3✔
2707

3✔
2708
        utxos, err := c.wallet.ListUnspentWitnessFromDefaultAccount(
3✔
2709
                minConfs, maxConfs,
3✔
2710
        )
3✔
2711
        if err != nil {
3✔
2712
                return nil, err
×
2713
        }
×
2714

2715
        var coins []wallet.Coin
3✔
2716

3✔
2717
        for _, utxo := range utxos {
6✔
2718
                // If there is a filter function supplied all utxos not adhering
3✔
2719
                // to these conditions will be discarded.
3✔
2720
                if c.allowUtxo != nil && !c.allowUtxo(*utxo) {
6✔
2721
                        walletLog.Infof("Cannot use unconfirmed "+
3✔
2722
                                "utxo=%v because it is unstable and could be "+
3✔
2723
                                "replaced", utxo.OutPoint)
3✔
2724

3✔
2725
                        continue
3✔
2726
                }
2727

2728
                coins = append(coins, wallet.Coin{
3✔
2729
                        TxOut: wire.TxOut{
3✔
2730
                                Value:    int64(utxo.Value),
3✔
2731
                                PkScript: utxo.PkScript,
3✔
2732
                        },
3✔
2733
                        OutPoint: utxo.OutPoint,
3✔
2734
                })
3✔
2735
        }
2736

2737
        return coins, nil
3✔
2738
}
2739

2740
// CoinFromOutPoint attempts to locate details pertaining to a coin based on
2741
// its outpoint. If the coin isn't under the control of the backing CoinSource,
2742
// then an error should be returned.
2743
func (c *CoinSource) CoinFromOutPoint(op wire.OutPoint) (*wallet.Coin, error) {
3✔
2744
        inputInfo, err := c.wallet.FetchOutpointInfo(&op)
3✔
2745
        if err != nil {
3✔
2746
                return nil, err
×
2747
        }
×
2748

2749
        return &wallet.Coin{
3✔
2750
                TxOut: wire.TxOut{
3✔
2751
                        Value:    int64(inputInfo.Value),
3✔
2752
                        PkScript: inputInfo.PkScript,
3✔
2753
                },
3✔
2754
                OutPoint: inputInfo.OutPoint,
3✔
2755
        }, nil
3✔
2756
}
2757

2758
// shimKeyRing is a wrapper struct that's used to provide the proper multi-sig
2759
// key for an initiated external funding flow.
2760
type shimKeyRing struct {
2761
        keychain.KeyRing
2762

2763
        *chanfunding.ShimIntent
2764
}
2765

2766
// DeriveNextKey intercepts the normal DeriveNextKey call to a keychain.KeyRing
2767
// instance, and supplies the multi-sig key specified by the ShimIntent. This
2768
// allows us to transparently insert new keys into the existing funding flow,
2769
// as these keys may not come from the wallet itself.
2770
func (s *shimKeyRing) DeriveNextKey(keyFam keychain.KeyFamily) (keychain.KeyDescriptor, error) {
3✔
2771
        if keyFam != keychain.KeyFamilyMultiSig {
6✔
2772
                return s.KeyRing.DeriveNextKey(keyFam)
3✔
2773
        }
3✔
2774

2775
        fundingKeys, err := s.ShimIntent.MultiSigKeys()
3✔
2776
        if err != nil {
3✔
2777
                return keychain.KeyDescriptor{}, err
×
2778
        }
×
2779

2780
        return *fundingKeys.LocalKey, nil
3✔
2781
}
2782

2783
// ValidateUpfrontShutdown checks whether the provided upfront_shutdown_script
2784
// is of a valid type that we accept.
2785
func ValidateUpfrontShutdown(shutdown lnwire.DeliveryAddress,
2786
        params *chaincfg.Params) bool {
3✔
2787

3✔
2788
        // We don't need to worry about a large UpfrontShutdownScript since it
3✔
2789
        // was already checked in lnwire when decoding from the wire.
3✔
2790
        scriptClass, _, _, _ := txscript.ExtractPkScriptAddrs(shutdown, params)
3✔
2791

3✔
2792
        switch {
3✔
2793
        case scriptClass == txscript.WitnessV0PubKeyHashTy,
2794
                scriptClass == txscript.WitnessV0ScriptHashTy,
2795
                scriptClass == txscript.WitnessV1TaprootTy:
3✔
2796

3✔
2797
                // The above three types are permitted according to BOLT#02 and
3✔
2798
                // BOLT#05.  Everything else is disallowed.
3✔
2799
                return true
3✔
2800

2801
        // In this case, we don't know about the actual script template, but it
2802
        // might be a witness program with versions 2-16. So we'll check that
2803
        // now
2804
        case txscript.IsWitnessProgram(shutdown):
×
2805
                version, _, err := txscript.ExtractWitnessProgramInfo(shutdown)
×
2806
                if err != nil {
×
2807
                        walletLog.Warnf("unable to extract witness program "+
×
2808
                                "version (script=%x): %v", shutdown, err)
×
2809
                        return false
×
2810
                }
×
2811

2812
                return version >= 1 && version <= 16
×
2813

2814
        default:
×
2815
                return false
×
2816
        }
2817
}
2818

2819
// WalletPrevOutputFetcher is a txscript.PrevOutputFetcher that can fetch
2820
// outputs from a given wallet controller.
2821
type WalletPrevOutputFetcher struct {
2822
        wc WalletController
2823
}
2824

2825
// A compile time assertion that WalletPrevOutputFetcher implements the
2826
// txscript.PrevOutputFetcher interface.
2827
var _ txscript.PrevOutputFetcher = (*WalletPrevOutputFetcher)(nil)
2828

2829
// NewWalletPrevOutputFetcher creates a new WalletPrevOutputFetcher that fetches
2830
// previous outputs from the given wallet controller.
2831
func NewWalletPrevOutputFetcher(wc WalletController) *WalletPrevOutputFetcher {
3✔
2832
        return &WalletPrevOutputFetcher{
3✔
2833
                wc: wc,
3✔
2834
        }
3✔
2835
}
3✔
2836

2837
// FetchPrevOutput attempts to fetch the previous output referenced by the
2838
// passed outpoint. A nil value will be returned if the passed outpoint doesn't
2839
// exist.
2840
func (w *WalletPrevOutputFetcher) FetchPrevOutput(op wire.OutPoint) *wire.TxOut {
3✔
2841
        utxo, err := w.wc.FetchOutpointInfo(&op)
3✔
2842
        if err != nil {
3✔
2843
                return nil
×
2844
        }
×
2845

2846
        return &wire.TxOut{
3✔
2847
                Value:    int64(utxo.Value),
3✔
2848
                PkScript: utxo.PkScript,
3✔
2849
        }
3✔
2850
}
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