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

lightningnetwork / lnd / 13236757158

10 Feb 2025 08:39AM UTC coverage: 57.649% (-1.2%) from 58.815%
13236757158

Pull #9493

github

ziggie1984
lncli: for some cmds we don't replace the data of the response.

For some cmds it is not very practical to replace the json output
because we might pipe it into other commands. For example when
creating the route we want to pipe it into sendtoRoute.
Pull Request #9493: For some lncli cmds we should not replace the content with other data

0 of 9 new or added lines in 2 files covered. (0.0%)

19535 existing lines in 252 files now uncovered.

103517 of 179563 relevant lines covered (57.65%)

24878.49 hits per line

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

67.19
/lnwallet/wallet.go
1
package lnwallet
2

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

281
        contribution *ChannelContribution
282

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

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

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

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

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

309
        contribution *ChannelContribution
310

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

408
        nextFundingID uint64 // To be used atomically.
409

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

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

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

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

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

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

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

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

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

456
        quit chan struct{}
457

458
        wg sync.WaitGroup
459
}
460

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

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

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

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

109✔
505
        return nil
109✔
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✔
UNCOV
553
                return err
×
UNCOV
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) {
106✔
594

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

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

229✔
613
        return l.WalletController.ListUnspentWitness(
229✔
614
                minConfs, maxConfs, DefaultAccountName,
229✔
615
        )
229✔
616
}
229✔
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() {
109✔
657
        defer l.wg.Done()
109✔
658

109✔
659
out:
109✔
660
        for {
624✔
661
                select {
515✔
662
                case m := <-l.msgChan:
406✔
663
                        switch msg := m.(type) {
406✔
664
                        case *InitFundingReserveMsg:
159✔
665
                                l.handleFundingReserveRequest(msg)
159✔
666
                        case *fundingReserveCancelMsg:
54✔
667
                                l.handleFundingCancelRequest(msg)
54✔
668
                        case *addSingleContributionMsg:
62✔
669
                                l.handleSingleContribution(msg)
62✔
670
                        case *addContributionMsg:
45✔
671
                                l.handleContributionMsg(msg)
45✔
UNCOV
672
                        case *continueContributionMsg:
×
UNCOV
673
                                l.handleChanPointReady(msg)
×
674
                        case *addSingleFunderSigsMsg:
43✔
675
                                l.handleSingleFunderSigs(msg)
43✔
676
                        case *addCounterPartySigsMsg:
43✔
677
                                l.handleFundingCounterPartySigs(msg)
43✔
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) {
159✔
705

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

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

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

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

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

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

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

145✔
742
        return nil
145✔
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,
UNCOV
749
        packet *psbt.Packet, skipFinalize bool) error {
×
UNCOV
750

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

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

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

UNCOV
769
        err := psbtIntent.Verify(packet, skipFinalize)
×
UNCOV
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.
UNCOV
776
        l.limboMtx.Lock()
×
UNCOV
777
        pid, ok := l.reservationIDs[pendingChanID]
×
UNCOV
778
        if !ok {
×
779
                l.limboMtx.Unlock()
×
780
                return fmt.Errorf("no channel reservation found for "+
×
781
                        "pendingChannelID(%x)", pendingChanID[:])
×
782
        }
×
783

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

×
UNCOV
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.
UNCOV
794
        isPublic := pendingReservation.partialState.ChannelFlags&lnwire.FFAnnounceChannel != 0
×
UNCOV
795
        hasAnchors := pendingReservation.partialState.ChanType.HasAnchors()
×
UNCOV
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,
UNCOV
803
        rawTx *wire.MsgTx) error {
×
UNCOV
804

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

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

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

UNCOV
826
        case rawTx != nil && packet == nil:
×
UNCOV
827
                err := psbtIntent.FinalizeRawTX(rawTx)
×
UNCOV
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

UNCOV
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.
UNCOV
841
func (l *LightningWallet) CancelFundingIntent(pid [32]byte) error {
×
UNCOV
842
        l.intentMtx.Lock()
×
UNCOV
843
        defer l.intentMtx.Unlock()
×
UNCOV
844

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

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

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

×
UNCOV
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) {
159✔
863

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

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

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

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

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

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

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

148✔
941
                // Get the number of anchor channels to determine if there is a
148✔
942
                // reserved value that must be respected when funding up to the
148✔
943
                // maximum amount. Since private channels (most likely) won't be
148✔
944
                // used for routing other than the last hop, they bear a smaller
148✔
945
                // risk that we must force close them in order to resolve a HTLC
148✔
946
                // up/downstream. Hence we exclude them from the count of anchor
148✔
947
                // channels in order to attribute the respective anchor amount
148✔
948
                // to the channel capacity.
148✔
949
                if req.FundUpToMaxAmt > 0 && req.MinFundAmt > 0 {
154✔
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✔
UNCOV
959
                                numAnchorChans++
×
UNCOV
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{
148✔
966
                        RemoteAmt:         req.RemoteFundingAmt,
148✔
967
                        LocalAmt:          req.LocalFundingAmt,
148✔
968
                        FundUpToMaxAmt:    req.FundUpToMaxAmt,
148✔
969
                        MinFundAmt:        req.MinFundAmt,
148✔
970
                        RemoteChanReserve: req.RemoteChanReserve,
148✔
971
                        PushAmt: lnwire.MilliSatoshi.ToSatoshis(
148✔
972
                                req.PushMSat,
148✔
973
                        ),
148✔
974
                        WalletReserve: l.RequiredReserve(
148✔
975
                                uint32(numAnchorChans),
148✔
976
                        ),
148✔
977
                        Outpoints:    req.Outpoints,
148✔
978
                        MinConfs:     req.MinConfs,
148✔
979
                        SubtractFees: req.SubtractFees,
148✔
980
                        FeeRate:      req.FundingFeePerKw,
148✔
981
                        ChangeAddr: func() (btcutil.Address, error) {
222✔
982
                                return l.NewAddress(
74✔
983
                                        TaprootPubkey, true, DefaultAccountName,
74✔
984
                                )
74✔
985
                        },
74✔
986
                        Musig2: req.CommitType.IsTaproot(),
987
                }
988
                fundingIntent, err = req.ChanFunder.ProvisionChannel(
148✔
989
                        fundingReq,
148✔
990
                )
148✔
991
                if err != nil {
156✔
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)
140✔
1001
                if err != nil {
140✔
1002
                        req.err <- err
×
1003
                        req.resp <- nil
×
1004
                        return
×
1005
                }
×
1006

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

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

1014
        // At this point there _has_ to be a funding intent, otherwise something
1015
        // went really wrong.
1016
        if fundingIntent == nil {
151✔
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 (
151✔
1027
                keyRing    keychain.KeyRing = l.SecretKeyRing
151✔
1028
                thawHeight uint32
151✔
1029
        )
151✔
1030
        if shimIntent, ok := fundingIntent.(*chanfunding.ShimIntent); ok {
160✔
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
151✔
1051
        if enforceNewReservedValue {
302✔
1052
                err = l.enforceNewReservedValue(fundingIntent, isPublic, hasAnchors)
151✔
1053
                if err != nil {
151✔
UNCOV
1054
                        fundingIntent.Cancel()
×
UNCOV
1055

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

151✔
1066
        id := atomic.AddUint64(&l.nextFundingID, 1)
151✔
1067
        reservation, err := NewChannelReservation(
151✔
1068
                capacity, localFundingAmt, l, id, l.Cfg.NetParams.GenesisHash,
151✔
1069
                thawHeight, req,
151✔
1070
        )
151✔
1071
        if err != nil {
155✔
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(
147✔
1080
                reservation, fundingIntent, req.NodeAddr, req.NodeID, keyRing,
147✔
1081
        )
147✔
1082
        if err != nil {
147✔
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()
147✔
1093
        l.fundingLimbo[id] = reservation
147✔
1094
        l.reservationIDs[req.PendingChanID] = id
147✔
1095
        l.limboMtx.Unlock()
147✔
1096

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

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

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

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

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

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

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

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

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

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

1180
        for _, c := range pendingClosed {
88✔
UNCOV
1181
                c, err := l.Cfg.Database.FetchHistoricalChannel(
×
UNCOV
1182
                        &c.ChanPoint,
×
UNCOV
1183
                )
×
UNCOV
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

UNCOV
1192
                cntChannel(c)
×
1193
        }
1194

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

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

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

1242
                walletBalance += in.Value
494✔
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 {
162✔
1249
                _, addrs, _, err := txscript.ExtractPkScriptAddrs(
80✔
1250
                        txOut.PkScript, &l.Cfg.NetParams,
80✔
1251
                )
80✔
1252
                if err != nil {
80✔
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 {
160✔
1259
                        if !l.IsOurAddress(addr) {
132✔
1260
                                continue
52✔
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))
82✔
1272

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

1280
        return reserved, nil
82✔
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) (
UNCOV
1289
        btcutil.Amount, error) {
×
UNCOV
1290

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

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

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

×
UNCOV
1326
                        return reservedVal, err
×
UNCOV
1327
                }
×
1328

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

UNCOV
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 {
147✔
1342

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

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

1362
                reservation.fundingIntent = fundingIntent
147✔
1363
        }
1364

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

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

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

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

147✔
1422
        // If taproot channels are active, then we'll generate our verification
147✔
1423
        // nonce here. We'll use this nonce to verify the signature for our
147✔
1424
        // local commitment transaction. If we need to force close, then this
147✔
1425
        // is also what'll be used to sign that transaction.
147✔
1426
        if reservation.partialState.ChanType.IsTaproot() {
159✔
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
147✔
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 {
401✔
1507
        return createCommitOpts{}
401✔
1508
}
401✔
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 {
88✔
1514

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

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

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

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

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

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

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

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

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

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

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

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

45✔
1628
        // At this point, we can now construct our channel point. Depending on
45✔
1629
        // which type of intent we obtained from our chanfunding.Assembler,
45✔
1630
        // we'll carry out a distinct set of steps.
45✔
1631
        switch fundingIntent := pendingReservation.fundingIntent.(type) {
45✔
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.
UNCOV
1650
        case *chanfunding.PsbtIntent:
×
UNCOV
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.
UNCOV
1660
                pendingChanID := pendingReservation.pendingChanID
×
UNCOV
1661

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

1829
                sigTheirCommit = partialSig
12✔
1830
        }
1831

1832
        return sigTheirCommit, nil
88✔
1833
}
1834

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

1847
        chanState := pendingReservation.partialState
45✔
1848

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

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

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

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

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

UNCOV
1893
                pendingReservation.partialState.FundingOutpoint = *chanPointPtr
×
UNCOV
1894
                chanPoint = *chanPointPtr
×
UNCOV
1895

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

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

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

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

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

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

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

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

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

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

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

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

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

2035
        pendingReservation.ourCommitmentSig = sigTheirCommit
45✔
2036

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

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

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

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

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

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

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

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

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

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

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

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

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

2153
                        sigIndex++
×
2154
                }
2155
        }
2156

2157
        return nil
38✔
2158
}
2159

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

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

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

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

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

2200
                return nil
74✔
2201

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

2510
        pendingReservation.ourCommitmentSig = sigTheirCommit
43✔
2511

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

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

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

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

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

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

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

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

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

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

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

1,102✔
2577
        sha := h.Sum(nil)
1,102✔
2578

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

1,102✔
2582
        return obfuscator
1,102✔
2583
}
1,102✔
2584

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

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

2597
        return nil
88✔
2598
}
2599

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

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

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

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

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

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

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

2676
        return nil
34✔
2677
}
2678

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

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

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

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

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

2715
        var coins []wallet.Coin
147✔
2716

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

×
UNCOV
2725
                        continue
×
2726
                }
2727

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

2737
        return coins, nil
147✔
2738
}
2739

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

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

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

2763
        *chanfunding.ShimIntent
2764
}
2765

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

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

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

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

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

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

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

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

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

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

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

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

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

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

UNCOV
2846
        return &wire.TxOut{
×
UNCOV
2847
                Value:    int64(utxo.Value),
×
UNCOV
2848
                PkScript: utxo.PkScript,
×
UNCOV
2849
        }
×
2850
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc