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

lightningnetwork / lnd / 17830307614

18 Sep 2025 01:29PM UTC coverage: 54.617% (-12.0%) from 66.637%
17830307614

Pull #10200

github

web-flow
Merge 181a0a7bc into b34fc964b
Pull Request #10200: github: change to form-based issue template

109249 of 200028 relevant lines covered (54.62%)

21896.43 hits per line

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

67.21
/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/lightningnetwork/lnd/channeldb"
25
        "github.com/lightningnetwork/lnd/fn/v2"
26
        "github.com/lightningnetwork/lnd/input"
27
        "github.com/lightningnetwork/lnd/keychain"
28
        "github.com/lightningnetwork/lnd/lntypes"
29
        "github.com/lightningnetwork/lnd/lnutils"
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) {
112✔
465

112✔
466
        return &LightningWallet{
112✔
467
                Cfg:              Cfg,
112✔
468
                SecretKeyRing:    Cfg.SecretKeyRing,
112✔
469
                WalletController: Cfg.WalletController,
112✔
470
                msgChan:          make(chan interface{}, msgBufferSize),
112✔
471
                nextFundingID:    0,
112✔
472
                fundingLimbo:     make(map[uint64]*ChannelReservation),
112✔
473
                reservationIDs:   make(map[[32]byte]uint64),
112✔
474
                lockedOutPoints:  make(map[wire.OutPoint]struct{}),
112✔
475
                fundingIntents:   make(map[[32]byte]chanfunding.Intent),
112✔
476
                quit:             make(chan struct{}),
112✔
477
        }, nil
112✔
478
}
112✔
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 {
111✔
483
        // Already started?
111✔
484
        if atomic.AddInt32(&l.started, 1) != 1 {
111✔
485
                return nil
×
486
        }
×
487

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

493
        if l.Cfg.Rebroadcaster != nil {
113✔
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)
111✔
503
        go l.requestHandler()
111✔
504

111✔
505
        return nil
111✔
506
}
507

508
// Shutdown gracefully stops the wallet, and all active goroutines.
509
func (l *LightningWallet) Shutdown() error {
11✔
510
        if atomic.AddInt32(&l.shutdown, 1) != 1 {
11✔
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 {
11✔
517
                return err
×
518
        }
×
519

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

524
        close(l.quit)
11✔
525
        l.wg.Wait()
11✔
526
        return nil
11✔
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 {
62✔
533

62✔
534
        sendTxToWallet := func() error {
124✔
535
                return l.WalletController.PublishTransaction(tx, label)
62✔
536
        }
62✔
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() {
123✔
541
                return sendTxToWallet()
61✔
542
        }
61✔
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)
1✔
549

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

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

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

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

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

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

586
        return nil
1✔
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) {
139✔
594

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

139✔
598
        return l.WalletController.ConfirmedBalance(confs, account)
139✔
599
}
139✔
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) {
231✔
612

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

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

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

627
        return outPoints
4✔
628
}
629

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

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

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

651
        return reservations
8✔
652
}
653

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

111✔
659
out:
111✔
660
        for {
633✔
661
                select {
522✔
662
                case m := <-l.msgChan:
411✔
663
                        switch msg := m.(type) {
411✔
664
                        case *InitFundingReserveMsg:
160✔
665
                                l.handleFundingReserveRequest(msg)
160✔
666
                        case *fundingReserveCancelMsg:
54✔
667
                                l.handleFundingCancelRequest(msg)
54✔
668
                        case *addSingleContributionMsg:
63✔
669
                                l.handleSingleContribution(msg)
63✔
670
                        case *addContributionMsg:
46✔
671
                                l.handleContributionMsg(msg)
46✔
672
                        case *continueContributionMsg:
×
673
                                l.handleChanPointReady(msg)
×
674
                        case *addSingleFunderSigsMsg:
44✔
675
                                l.handleSingleFunderSigs(msg)
44✔
676
                        case *addCounterPartySigsMsg:
44✔
677
                                l.handleFundingCounterPartySigs(msg)
44✔
678
                        }
679
                case <-l.quit:
11✔
680
                        // TODO: do some clean up
11✔
681
                        break out
11✔
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) {
160✔
705

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

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

715
        return <-req.resp, <-req.err
160✔
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 {
148✔
725

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

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

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

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

146✔
742
        return nil
146✔
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 {
×
750

×
751
        l.intentMtx.Lock()
×
752
        defer l.intentMtx.Unlock()
×
753

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

764
        if skipFinalize && psbtIntent.ShouldPublishFundingTX() {
×
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)
×
770
        if err != nil {
×
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()
×
777
        pid, ok := l.reservationIDs[pendingChanID]
×
778
        if !ok {
×
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]
×
785
        l.limboMtx.Unlock()
×
786

×
787
        if !ok {
×
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
×
795
        hasAnchors := pendingReservation.partialState.ChanType.HasAnchors()
×
796
        return l.enforceNewReservedValue(intent, isPublic, hasAnchors)
×
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 {
×
804

×
805
        l.intentMtx.Lock()
×
806
        defer l.intentMtx.Unlock()
×
807

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

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

826
        case rawTx != nil && packet == nil:
×
827
                err := psbtIntent.FinalizeRawTX(rawTx)
×
828
                if err != nil {
×
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
×
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 {
×
842
        l.intentMtx.Lock()
×
843
        defer l.intentMtx.Unlock()
×
844

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

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

×
855
        delete(l.fundingIntents, pid)
×
856

×
857
        return nil
×
858
}
859

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

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

160✔
867
        // It isn't possible to create a channel with zero funds committed.
160✔
868
        if noFundsCommitted {
160✔
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[:]) {
160✔
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
160✔
891

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

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

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

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

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

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

957
                        isPublic := req.Flags&lnwire.FFAnnounceChannel != 0
6✔
958
                        if hasAnchors && isPublic {
6✔
959
                                numAnchorChans++
×
960
                        }
×
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{
149✔
966
                        RemoteAmt:         req.RemoteFundingAmt,
149✔
967
                        LocalAmt:          req.LocalFundingAmt,
149✔
968
                        FundUpToMaxAmt:    req.FundUpToMaxAmt,
149✔
969
                        MinFundAmt:        req.MinFundAmt,
149✔
970
                        RemoteChanReserve: req.RemoteChanReserve,
149✔
971
                        PushAmt: lnwire.MilliSatoshi.ToSatoshis(
149✔
972
                                req.PushMSat,
149✔
973
                        ),
149✔
974
                        WalletReserve: l.RequiredReserve(
149✔
975
                                uint32(numAnchorChans),
149✔
976
                        ),
149✔
977
                        Outpoints:    req.Outpoints,
149✔
978
                        MinConfs:     req.MinConfs,
149✔
979
                        SubtractFees: req.SubtractFees,
149✔
980
                        FeeRate:      req.FundingFeePerKw,
149✔
981
                        ChangeAddr: func() (btcutil.Address, error) {
224✔
982
                                return l.NewAddress(
75✔
983
                                        TaprootPubkey, true, DefaultAccountName,
75✔
984
                                )
75✔
985
                        },
75✔
986
                        Musig2: req.CommitType.IsTaproot(),
987
                }
988
                fundingIntent, err = req.ChanFunder.ProvisionChannel(
149✔
989
                        fundingReq,
149✔
990
                )
149✔
991
                if err != nil {
157✔
992
                        req.err <- err
8✔
993
                        req.resp <- nil
8✔
994
                        return
8✔
995
                }
8✔
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)
141✔
1001
                if err != nil {
141✔
1002
                        req.err <- err
×
1003
                        req.resp <- nil
×
1004
                        return
×
1005
                }
×
1006

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

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

1014
        // At this point there _has_ to be a funding intent, otherwise something
1015
        // went really wrong.
1016
        if fundingIntent == nil {
152✔
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 (
152✔
1027
                keyRing    keychain.KeyRing = l.SecretKeyRing
152✔
1028
                thawHeight uint32
152✔
1029
        )
152✔
1030
        if shimIntent, ok := fundingIntent.(*chanfunding.ShimIntent); ok {
161✔
1031
                keyRing = &shimKeyRing{
9✔
1032
                        KeyRing:    keyRing,
9✔
1033
                        ShimIntent: shimIntent,
9✔
1034
                }
9✔
1035

9✔
1036
                // As this was a registered shim intent, we'll obtain the thaw
9✔
1037
                // height of the intent, if present at all. If this is
9✔
1038
                // non-zero, then we'll mark this as the proper channel type.
9✔
1039
                thawHeight = shimIntent.ThawHeight()
9✔
1040
        }
9✔
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
152✔
1051
        if enforceNewReservedValue {
304✔
1052
                err = l.enforceNewReservedValue(fundingIntent, isPublic, hasAnchors)
152✔
1053
                if err != nil {
152✔
1054
                        fundingIntent.Cancel()
×
1055

×
1056
                        req.err <- err
×
1057
                        req.resp <- nil
×
1058
                        return
×
1059
                }
×
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
152✔
1065

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

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

1079
        err = l.initOurContribution(
148✔
1080
                reservation, fundingIntent, req.NodeAddr, req.NodeID, keyRing,
148✔
1081
        )
148✔
1082
        if err != nil {
148✔
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()
148✔
1093
        l.fundingLimbo[id] = reservation
148✔
1094
        l.reservationIDs[req.PendingChanID] = id
148✔
1095
        l.limboMtx.Unlock()
148✔
1096

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

148✔
1103
        walletLog.Debugf("Successfully handled funding reservation with "+
148✔
1104
                "pendingChanID: %x, reservationID: %v",
148✔
1105
                reservation.pendingChanID, reservation.reservationID)
148✔
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 {
152✔
1117

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

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

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

1135
        return l.WithCoinSelectLock(func() error {
166✔
1136
                _, err := l.CheckReservedValue(
83✔
1137
                        fundingIntent.Inputs(), fundingIntent.Outputs(),
83✔
1138
                        numAnchors,
83✔
1139
                )
83✔
1140
                return err
83✔
1141
        })
83✔
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) {
89✔
1147
        // Count all anchor channels that are open or pending
89✔
1148
        // open, or waiting close.
89✔
1149
        chans, err := l.Cfg.Database.FetchAllChannels()
89✔
1150
        if err != nil {
89✔
1151
                return 0, err
×
1152
        }
×
1153

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

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

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

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

1180
        for _, c := range pendingClosed {
89✔
1181
                c, err := l.Cfg.Database.FetchHistoricalChannel(
×
1182
                        &c.ChanPoint,
×
1183
                )
×
1184
                if err != nil {
×
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)
×
1193
        }
1194

1195
        return numAnchors, nil
89✔
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) {
83✔
1212

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

1223
        ourInput := make(map[wire.OutPoint]struct{})
83✔
1224
        for _, op := range in {
277✔
1225
                ourInput[op] = struct{}{}
194✔
1226
        }
194✔
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
83✔
1235
        for _, in := range witnessOutputs {
598✔
1236
                // Spending an unlocked wallet UTXO, don't add it to the
515✔
1237
                // balance.
515✔
1238
                if _, ok := ourInput[in.OutPoint]; ok {
535✔
1239
                        continue
20✔
1240
                }
1241

1242
                walletBalance += in.Value
495✔
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 {
164✔
1249
                _, addrs, _, err := txscript.ExtractPkScriptAddrs(
81✔
1250
                        txOut.PkScript, &l.Cfg.NetParams,
81✔
1251
                )
81✔
1252
                if err != nil {
81✔
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 {
162✔
1259
                        if !l.IsOurAddress(addr) {
134✔
1260
                                continue
53✔
1261
                        }
1262

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

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

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

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

1280
        return reserved, nil
83✔
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) {
×
1290

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

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

1301
        reservedVal, err := l.CheckReservedValue(
×
1302
                inputs, req.Tx.TxOut, numAnchors,
×
1303
        )
×
1304
        switch {
×
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):
×
1310
                // Without a change index provided there is nothing more to
×
1311
                // check and the error is returned.
×
1312
                if req.ChangeIndex == nil {
×
1313
                        return reservedVal, err
×
1314
                }
×
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
×
1323
                if chIdx < 0 || chIdx >= len(req.Tx.TxOut) ||
×
1324
                        req.Tx.TxOut[chIdx].Value < int64(reservedVal) {
×
1325

×
1326
                        return reservedVal, err
×
1327
                }
×
1328

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

1333
        return reservedVal, nil
×
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 {
148✔
1342

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

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

1362
                reservation.fundingIntent = fundingIntent
148✔
1363
        }
1364

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

148✔
1368
        var err error
148✔
1369
        reservation.ourContribution.MultiSigKey, err = keyRing.DeriveNextKey(
148✔
1370
                keychain.KeyFamilyMultiSig,
148✔
1371
        )
148✔
1372
        if err != nil {
148✔
1373
                return err
×
1374
        }
×
1375
        reservation.ourContribution.RevocationBasePoint, err = keyRing.DeriveNextKey(
148✔
1376
                keychain.KeyFamilyRevocationBase,
148✔
1377
        )
148✔
1378
        if err != nil {
148✔
1379
                return err
×
1380
        }
×
1381
        reservation.ourContribution.HtlcBasePoint, err = keyRing.DeriveNextKey(
148✔
1382
                keychain.KeyFamilyHtlcBase,
148✔
1383
        )
148✔
1384
        if err != nil {
148✔
1385
                return err
×
1386
        }
×
1387
        reservation.ourContribution.PaymentBasePoint, err = keyRing.DeriveNextKey(
148✔
1388
                keychain.KeyFamilyPaymentBase,
148✔
1389
        )
148✔
1390
        if err != nil {
148✔
1391
                return err
×
1392
        }
×
1393
        reservation.ourContribution.DelayBasePoint, err = keyRing.DeriveNextKey(
148✔
1394
                keychain.KeyFamilyDelayBase,
148✔
1395
        )
148✔
1396
        if err != nil {
148✔
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(
148✔
1404
                reservation, keyRing,
148✔
1405
        )
148✔
1406
        if err != nil {
148✔
1407
                return err
×
1408
        }
×
1409

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

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

148✔
1422
        // If taproot channels are active, then we'll generate our verification
148✔
1423
        // nonce here. We'll use this nonce to verify the signature for our
148✔
1424
        // local commitment transaction. If we need to force close, then this
148✔
1425
        // is also what'll be used to sign that transaction.
148✔
1426
        if reservation.partialState.ChanType.IsTaproot() {
160✔
1427
                firstNoncePreimage, err := taprootNonceProducer.AtIndex(0)
12✔
1428
                if err != nil {
12✔
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(
12✔
1437
                        bytes.NewBuffer(firstNoncePreimage[:]),
12✔
1438
                )
12✔
1439
                pubKeyOpt := musig2.WithPublicKey(
12✔
1440
                        reservation.ourContribution.MultiSigKey.PubKey,
12✔
1441
                )
12✔
1442
                reservation.ourContribution.LocalNonce, err = musig2.GenNonces(
12✔
1443
                        pubKeyOpt, shaChainRand,
12✔
1444
                )
12✔
1445
                if err != nil {
12✔
1446
                        return err
×
1447
                }
×
1448
        }
1449

1450
        return nil
148✔
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) {
54✔
1458
        l.limboMtx.Lock()
54✔
1459
        defer l.limboMtx.Unlock()
54✔
1460

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

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

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

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

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

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

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

18✔
1495
        req.err <- nil
18✔
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 {
408✔
1507
        return createCommitOpts{}
408✔
1508
}
408✔
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 {
90✔
1514

90✔
1515
        return func(o *createCommitOpts) {
180✔
1516
                o.localAuxLeaves = localLeaves
90✔
1517
                o.remoteAuxLeaves = remoteLeaves
90✔
1518
        }
90✔
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) {
408✔
1536

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

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

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

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

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

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

1579
        return ourCommitTx, theirCommitTx, nil
408✔
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) {
46✔
1588

46✔
1589
        l.limboMtx.Lock()
46✔
1590
        pendingReservation, ok := l.fundingLimbo[req.pendingFundingID]
46✔
1591
        l.limboMtx.Unlock()
46✔
1592
        if !ok {
46✔
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()
46✔
1599
        defer pendingReservation.Unlock()
46✔
1600

46✔
1601
        // If UpfrontShutdownScript is set, validate that it is a valid script.
46✔
1602
        shutdown := req.contribution.UpfrontShutdown
46✔
1603
        if len(shutdown) > 0 {
46✔
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
46✔
1613
        theirContribution := req.contribution
46✔
1614
        ourContribution := pendingReservation.ourContribution
46✔
1615

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

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

46✔
1628
        // At this point, we can now construct our channel point. Depending on
46✔
1629
        // which type of intent we obtained from our chanfunding.Assembler,
46✔
1630
        // we'll carry out a distinct set of steps.
46✔
1631
        switch fundingIntent := pendingReservation.fundingIntent.(type) {
46✔
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:
5✔
1636
                chanPoint, err = fundingIntent.ChanPoint()
5✔
1637
                if err != nil {
5✔
1638
                        req.err <- fmt.Errorf("unable to obtain chan point: %w",
×
1639
                                err)
×
1640
                        return
×
1641
                }
×
1642

1643
                pendingReservation.partialState.FundingOutpoint = *chanPoint
5✔
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:
×
1651
                if fundingIntent.PendingPsbt != nil {
×
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
×
1661

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

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

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

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

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

41✔
1693
                // With our keys bound, we can now construct+sign the final
41✔
1694
                // funding transaction and also obtain the chanPoint that
41✔
1695
                // creates the channel.
41✔
1696
                fundingTx, err := fundingIntent.CompileFundingTx(
41✔
1697
                        theirContribution.Inputs,
41✔
1698
                        theirContribution.ChangeOutputs,
41✔
1699
                )
41✔
1700
                if err != nil {
41✔
1701
                        req.err <- fmt.Errorf("unable to construct funding "+
×
1702
                                "tx: %v", err)
×
1703
                        return
×
1704
                }
×
1705
                chanPoint, err = fundingIntent.ChanPoint()
41✔
1706
                if err != nil {
41✔
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
41✔
1716
                pendingReservation.partialState.FundingOutpoint = *chanPoint
41✔
1717
                pendingReservation.ourFundingInputScripts = make(
41✔
1718
                        []*input.Script, 0, len(ourContribution.Inputs),
41✔
1719
                )
41✔
1720
                for _, txIn := range fundingTx.TxIn {
98✔
1721
                        _, err := l.FetchOutpointInfo(&txIn.PreviousOutPoint)
57✔
1722
                        if err != nil {
57✔
1723
                                continue
×
1724
                        }
1725

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

1735
                walletLog.Tracef("Funding tx for ChannelPoint(%v) "+
41✔
1736
                        "generated: %v", chanPoint,
41✔
1737
                        lnutils.SpewLogClosure(fundingTx))
41✔
1738
        }
1739

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

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

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

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

90✔
1774
        ourContribution := pendingReservation.ourContribution
90✔
1775
        theirContribution := pendingReservation.theirContribution
90✔
1776

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

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

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

1830
                sigTheirCommit = partialSig
12✔
1831
        }
1832

1833
        return sigTheirCommit, nil
90✔
1834
}
1835

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

1848
        chanState := pendingReservation.partialState
46✔
1849

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

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

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

1868
        ourContribution := pendingReservation.ourContribution
46✔
1869
        theirContribution := pendingReservation.theirContribution
46✔
1870
        chanPoint := pendingReservation.partialState.FundingOutpoint
46✔
1871

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

1894
                pendingReservation.partialState.FundingOutpoint = *chanPointPtr
×
1895
                chanPoint = *chanPointPtr
×
1896

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

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

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

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

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

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

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

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

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

46✔
2004
        walletLog.Tracef("Local commit tx for ChannelPoint(%v): %v",
46✔
2005
                chanPoint, lnutils.SpewLogClosure(ourCommitTx))
46✔
2006
        walletLog.Tracef("Remote commit tx for ChannelPoint(%v): %v",
46✔
2007
                chanPoint, lnutils.SpewLogClosure(theirCommitTx))
46✔
2008

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

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

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

2036
        pendingReservation.ourCommitmentSig = sigTheirCommit
46✔
2037

46✔
2038
        req.err <- nil
46✔
2039
}
2040

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

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

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

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

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

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

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

57✔
2094
        req.err <- nil
57✔
2095
}
2096

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

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

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

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

2154
                        sigIndex++
×
2155
                }
2156
        }
2157

2158
        return nil
39✔
2159
}
2160

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

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

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

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

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

2201
                return nil
76✔
2202

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

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

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

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

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

12✔
2242
                return err
12✔
2243
        }
2244
}
2245

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

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

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

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

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

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

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

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

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

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

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

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

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

44✔
2336
        res.partialState.RevocationKeyLocator = res.nextRevocationKeyLoc
44✔
2337

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

2348
        msg.completeChan <- res.partialState
44✔
2349
        msg.err <- nil
44✔
2350
}
2351

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

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

44✔
2371
        chanState := pendingReservation.partialState
44✔
2372

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

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

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

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

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

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

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

44✔
2452
        walletLog.Debugf("Local commit tx for ChannelPoint(%v): %v",
44✔
2453
                req.fundingOutpoint, lnutils.SpewLogClosure(ourCommitTx))
44✔
2454
        walletLog.Debugf("Remote commit tx for ChannelPoint(%v): %v",
44✔
2455
                req.fundingOutpoint, lnutils.SpewLogClosure(theirCommitTx))
44✔
2456

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

2468
        theirCommitSigBytes := req.theirCommitmentSig.Serialize()
44✔
2469
        chanState.LocalCommitment.CommitSig = theirCommitSigBytes
44✔
2470

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

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

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

2511
        pendingReservation.ourCommitmentSig = sigTheirCommit
44✔
2512

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

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

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

44✔
2532
        chanState.RevocationKeyLocator = pendingReservation.nextRevocationKeyLoc
44✔
2533

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

2541
        req.completeChan <- chanState
44✔
2542
        req.err <- nil
44✔
2543

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

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

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

231✔
2562
        return f()
231✔
2563
}
231✔
2564

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

1,120✔
2578
        sha := h.Sum(nil)
1,120✔
2579

1,120✔
2580
        var obfuscator [StateHintSize]byte
1,120✔
2581
        copy(obfuscator[:], sha[26:])
1,120✔
2582

1,120✔
2583
        return obfuscator
1,120✔
2584
}
1,120✔
2585

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

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

2598
        return nil
90✔
2599
}
2600

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

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

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

2624
        localKey := channelState.LocalChanCfg.MultiSigKey.PubKey
34✔
2625
        remoteKey := channelState.RemoteChanCfg.MultiSigKey.PubKey
34✔
2626

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

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

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

2677
        return nil
34✔
2678
}
2679

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

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

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

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

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

2716
        var coins []wallet.Coin
148✔
2717

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

×
2726
                        continue
×
2727
                }
2728

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

2738
        return coins, nil
148✔
2739
}
2740

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

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

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

2764
        *chanfunding.ShimIntent
2765
}
2766

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

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

2781
        return *fundingKeys.LocalKey, nil
9✔
2782
}
2783

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

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

41✔
2793
        switch {
41✔
2794
        case scriptClass == txscript.WitnessV0PubKeyHashTy,
2795
                scriptClass == txscript.WitnessV0ScriptHashTy,
2796
                scriptClass == txscript.WitnessV1TaprootTy:
18✔
2797

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

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

2813
                return version >= 1 && version <= 16
16✔
2814

2815
        default:
7✔
2816
                return false
7✔
2817
        }
2818
}
2819

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

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

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

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

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