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

lightningnetwork / lnd / 10189747109

01 Aug 2024 12:31AM UTC coverage: 58.641% (+0.2%) from 58.459%
10189747109

push

github

web-flow
Merge pull request #8949 from ProofOfKeags/fn/req

[MICRO]: fn: Add new Req type to abstract the pattern of remote processing.

125217 of 213532 relevant lines covered (58.64%)

29382.04 hits per line

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

78.44
/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/input"
27
        "github.com/lightningnetwork/lnd/keychain"
28
        "github.com/lightningnetwork/lnd/lntypes"
29
        "github.com/lightningnetwork/lnd/lnwallet/chainfee"
30
        "github.com/lightningnetwork/lnd/lnwallet/chanfunding"
31
        "github.com/lightningnetwork/lnd/lnwallet/chanvalidate"
32
        "github.com/lightningnetwork/lnd/lnwire"
33
        "github.com/lightningnetwork/lnd/shachain"
34
)
35

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

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

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

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

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

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

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

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

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

92
// InitFundingReserveMsg is the first message sent to initiate the workflow
93
// required to open a payment channel with a remote peer. The initial required
94
// parameters are configurable across channels. These parameters are to be
95
// chosen depending on the fee climate within the network, and time value of
96
// funds to be locked up within the channel. Upon success a ChannelReservation
97
// will be created in order to track the lifetime of this pending channel.
98
// Outputs selected will be 'locked', making them unavailable, for any other
99
// pending reservations. Therefore, all channels in reservation limbo will be
100
// periodically timed out after an idle period in order to avoid "exhaustion"
101
// attacks.
102
type InitFundingReserveMsg struct {
103
        // ChainHash denotes that chain to be used to ultimately open the
104
        // target channel.
105
        ChainHash *chainhash.Hash
106

107
        // PendingChanID is the pending channel ID for this funding flow as
108
        // used in the wire protocol.
109
        PendingChanID [32]byte
110

111
        // NodeID is the ID of the remote node we would like to open a channel
112
        // with.
113
        NodeID *btcec.PublicKey
114

115
        // NodeAddr is the address port that we used to either establish or
116
        // accept the connection which led to the negotiation of this funding
117
        // workflow.
118
        NodeAddr net.Addr
119

120
        // SubtractFees should be set if we intend to spend exactly
121
        // LocalFundingAmt when opening the channel, subtracting the fees from
122
        // the funding output. This can be used for instance to use all our
123
        // remaining funds to open the channel, since it will take fees into
124
        // account.
125
        SubtractFees bool
126

127
        // LocalFundingAmt is the amount of funds requested from us for this
128
        // channel.
129
        LocalFundingAmt btcutil.Amount
130

131
        // RemoteFundingAmnt is the amount of funds the remote will contribute
132
        // to this channel.
133
        RemoteFundingAmt btcutil.Amount
134

135
        // FundUpToMaxAmt defines if channel funding should try to add as many
136
        // funds to the channel opening as possible up to this amount. If used,
137
        // then MinFundAmt is treated as the minimum amount of funds that must
138
        // be available to open the channel. If set to zero it is ignored.
139
        FundUpToMaxAmt btcutil.Amount
140

141
        // MinFundAmt denotes the minimum channel capacity that has to be
142
        // allocated iff the FundUpToMaxAmt is set.
143
        MinFundAmt btcutil.Amount
144

145
        // Outpoints is a list of client-selected outpoints that should be used
146
        // for funding a channel. If LocalFundingAmt is specified then this
147
        // amount is allocated from the sum of outpoints towards funding. If the
148
        // FundUpToMaxAmt is specified the entirety of selected funds is
149
        // allocated towards channel funding.
150
        Outpoints []wire.OutPoint
151

152
        // RemoteChanReserve is the channel reserve we required for the remote
153
        // peer.
154
        RemoteChanReserve btcutil.Amount
155

156
        // CommitFeePerKw is the starting accepted satoshis/Kw fee for the set
157
        // of initial commitment transactions. In order to ensure timely
158
        // confirmation, it is recommended that this fee should be generous,
159
        // paying some multiple of the accepted base fee rate of the network.
160
        CommitFeePerKw chainfee.SatPerKWeight
161

162
        // FundingFeePerKw is the fee rate in sat/kw to use for the initial
163
        // funding transaction.
164
        FundingFeePerKw chainfee.SatPerKWeight
165

166
        // PushMSat is the number of milli-satoshis that should be pushed over
167
        // the responder as part of the initial channel creation.
168
        PushMSat lnwire.MilliSatoshi
169

170
        // Flags are the channel flags specified by the initiator in the
171
        // open_channel message.
172
        Flags lnwire.FundingFlag
173

174
        // MinConfs indicates the minimum number of confirmations that each
175
        // output selected to fund the channel should satisfy.
176
        MinConfs int32
177

178
        // CommitType indicates what type of commitment type the channel should
179
        // be using, like tweakless or anchors.
180
        CommitType CommitmentType
181

182
        // ChanFunder is an optional channel funder that allows the caller to
183
        // control exactly how the channel funding is carried out. If not
184
        // specified, then the default chanfunding.WalletAssembler will be
185
        // used.
186
        ChanFunder chanfunding.Assembler
187

188
        // AllowUtxoForFunding enables the channel funding workflow to restrict
189
        // the selection of utxos when selecting the inputs for the channel
190
        // opening. This does ONLY apply for the internal wallet backed channel
191
        // opening case.
192
        //
193
        // NOTE: This is very useful when opening channels with unconfirmed
194
        // inputs to make sure stable non-replaceable inputs are used.
195
        AllowUtxoForFunding func(Utxo) bool
196

197
        // ZeroConf is a boolean that is true if a zero-conf channel was
198
        // negotiated.
199
        ZeroConf bool
200

201
        // OptionScidAlias is a boolean that is true if an option-scid-alias
202
        // channel type was explicitly negotiated.
203
        OptionScidAlias bool
204

205
        // ScidAliasFeature is true if the option-scid-alias feature bit was
206
        // negotiated.
207
        ScidAliasFeature bool
208

209
        // Memo is any arbitrary information we wish to store locally about the
210
        // channel that will be useful to our future selves.
211
        Memo []byte
212

213
        // err is a channel in which all errors will be sent across. Will be
214
        // nil if this initial set is successful.
215
        //
216
        // NOTE: In order to avoid deadlocks, this channel MUST be buffered.
217
        err chan error
218

219
        // resp is channel in which a ChannelReservation with our contributions
220
        // filled in will be sent across this channel in the case of a
221
        // successfully reservation initiation. In the case of an error, this
222
        // will read a nil pointer.
223
        //
224
        // NOTE: In order to avoid deadlocks, this channel MUST be buffered.
225
        resp chan *ChannelReservation
226
}
227

228
// fundingReserveCancelMsg is a message reserved for cancelling an existing
229
// channel reservation identified by its reservation ID. Cancelling a reservation
230
// frees its locked outputs up, for inclusion within further reservations.
231
type fundingReserveCancelMsg struct {
232
        pendingFundingID uint64
233

234
        // NOTE: In order to avoid deadlocks, this channel MUST be buffered.
235
        err chan error // Buffered
236
}
237

238
// addContributionMsg represents a message executing the second phase of the
239
// channel reservation workflow. This message carries the counterparty's
240
// "contribution" to the payment channel. In the case that this message is
241
// processed without generating any errors, then channel reservation will then
242
// be able to construct the funding tx, both commitment transactions, and
243
// finally generate signatures for all our inputs to the funding transaction,
244
// and for the remote node's version of the commitment transaction.
245
type addContributionMsg struct {
246
        pendingFundingID uint64
247

248
        // TODO(roasbeef): Should also carry SPV proofs in we're in SPV mode
249
        contribution *ChannelContribution
250

251
        // NOTE: In order to avoid deadlocks, this channel MUST be buffered.
252
        err chan error
253
}
254

255
// continueContributionMsg represents a message that signals that the
256
// interrupted funding process involving a PSBT can now be continued because the
257
// finalized transaction is now available.
258
type continueContributionMsg struct {
259
        pendingFundingID uint64
260

261
        // NOTE: In order to avoid deadlocks, this channel MUST be buffered.
262
        err chan error
263
}
264

265
// addSingleContributionMsg represents a message executing the second phase of
266
// a single funder channel reservation workflow. This messages carries the
267
// counterparty's "contribution" to the payment channel. As this message is
268
// sent when on the responding side to a single funder workflow, no further
269
// action apart from storing the provided contribution is carried out.
270
type addSingleContributionMsg struct {
271
        pendingFundingID uint64
272

273
        contribution *ChannelContribution
274

275
        // NOTE: In order to avoid deadlocks, this channel MUST be buffered.
276
        err chan error
277
}
278

279
// addCounterPartySigsMsg represents the final message required to complete,
280
// and 'open' a payment channel. This message carries the counterparty's
281
// signatures for each of their inputs to the funding transaction, and also a
282
// signature allowing us to spend our version of the commitment transaction.
283
// If we're able to verify all the signatures are valid, the funding transaction
284
// will be broadcast to the network. After the funding transaction gains a
285
// configurable number of confirmations, the channel is officially considered
286
// 'open'.
287
type addCounterPartySigsMsg struct {
288
        pendingFundingID uint64
289

290
        // Should be order of sorted inputs that are theirs. Sorting is done
291
        // in accordance to BIP-69:
292
        // https://github.com/bitcoin/bips/blob/master/bip-0069.mediawiki.
293
        theirFundingInputScripts []*input.Script
294

295
        // This should be 1/2 of the signatures needed to successfully spend our
296
        // version of the commitment transaction.
297
        theirCommitmentSig input.Signature
298

299
        // This channel is used to return the completed channel after the wallet
300
        // has completed all of its stages in the funding process.
301
        completeChan chan *channeldb.OpenChannel
302

303
        // NOTE: In order to avoid deadlocks, this channel MUST be buffered.
304
        err chan error
305
}
306

307
// addSingleFunderSigsMsg represents the next-to-last message required to
308
// complete a single-funder channel workflow. Once the initiator is able to
309
// construct the funding transaction, they send both the outpoint and a
310
// signature for our version of the commitment transaction. Once this message
311
// is processed we (the responder) are able to construct both commitment
312
// transactions, signing the remote party's version.
313
type addSingleFunderSigsMsg struct {
314
        pendingFundingID uint64
315

316
        // fundingOutpoint is the outpoint of the completed funding
317
        // transaction as assembled by the workflow initiator.
318
        fundingOutpoint *wire.OutPoint
319

320
        // theirCommitmentSig are the 1/2 of the signatures needed to
321
        // successfully spend our version of the commitment transaction.
322
        theirCommitmentSig input.Signature
323

324
        // This channel is used to return the completed channel after the wallet
325
        // has completed all of its stages in the funding process.
326
        completeChan chan *channeldb.OpenChannel
327

328
        // NOTE: In order to avoid deadlocks, this channel MUST be buffered.
329
        err chan error
330
}
331

332
// CheckReservedValueTxReq is the request struct used to call
333
// CheckReservedValueTx with. It contains the transaction to check as well as
334
// an optional explicitly defined index to denote a change output that is not
335
// watched by the wallet.
336
type CheckReservedValueTxReq struct {
337
        // Tx is the transaction to check the outputs for.
338
        Tx *wire.MsgTx
339

340
        // ChangeIndex denotes an optional output index that can be explicitly
341
        // set for a change that is not being watched by the wallet and would
342
        // otherwise not be recognized as a change output.
343
        ChangeIndex *int
344
}
345

346
// LightningWallet is a domain specific, yet general Bitcoin wallet capable of
347
// executing workflow required to interact with the Lightning Network. It is
348
// domain specific in the sense that it understands all the fancy scripts used
349
// within the Lightning Network, channel lifetimes, etc. However, it embeds a
350
// general purpose Bitcoin wallet within it. Therefore, it is also able to
351
// serve as a regular Bitcoin wallet which uses HD keys. The wallet is highly
352
// concurrent internally. All communication, and requests towards the wallet
353
// are dispatched as messages over channels, ensuring thread safety across all
354
// operations. Interaction has been designed independent of any peer-to-peer
355
// communication protocol, allowing the wallet to be self-contained and
356
// embeddable within future projects interacting with the Lightning Network.
357
//
358
// NOTE: At the moment the wallet requires a btcd full node, as it's dependent
359
// on btcd's websockets notifications as event triggers during the lifetime of a
360
// channel. However, once the chainntnfs package is complete, the wallet will
361
// be compatible with multiple RPC/notification services such as Electrum,
362
// Bitcoin Core + ZeroMQ, etc. Eventually, the wallet won't require a full-node
363
// at all, as SPV support is integrated into btcwallet.
364
type LightningWallet struct {
365
        started  int32 // To be used atomically.
366
        shutdown int32 // To be used atomically.
367

368
        nextFundingID uint64 // To be used atomically.
369

370
        // Cfg is the configuration struct that will be used by the wallet to
371
        // access the necessary interfaces and default it needs to carry on its
372
        // duties.
373
        Cfg Config
374

375
        // WalletController is the core wallet, all non Lightning Network
376
        // specific interaction is proxied to the internal wallet.
377
        WalletController
378

379
        // SecretKeyRing is the interface we'll use to derive any keys related
380
        // to our purpose within the network including: multi-sig keys, node
381
        // keys, revocation keys, etc.
382
        keychain.SecretKeyRing
383

384
        // This mutex MUST be held when performing coin selection in order to
385
        // avoid inadvertently creating multiple funding transaction which
386
        // double spend inputs across each other.
387
        coinSelectMtx sync.RWMutex
388

389
        // All messages to the wallet are to be sent across this channel.
390
        msgChan chan interface{}
391

392
        // Incomplete payment channels are stored in the map below. An intent
393
        // to create a payment channel is tracked as a "reservation" within
394
        // limbo. Once the final signatures have been exchanged, a reservation
395
        // is removed from limbo. Each reservation is tracked by a unique
396
        // monotonically integer. All requests concerning the channel MUST
397
        // carry a valid, active funding ID.
398
        fundingLimbo map[uint64]*ChannelReservation
399

400
        // reservationIDs maps a pending channel ID to the reservation ID used
401
        // as key in the fundingLimbo map. Used to easily look up a channel
402
        // reservation given a pending channel ID.
403
        reservationIDs map[[32]byte]uint64
404
        limboMtx       sync.RWMutex
405

406
        // lockedOutPoints is a set of the currently locked outpoint. This
407
        // information is kept in order to provide an easy way to unlock all
408
        // the currently locked outpoints.
409
        lockedOutPoints map[wire.OutPoint]struct{}
410

411
        // fundingIntents houses all the "interception" registered by a caller
412
        // using the RegisterFundingIntent method.
413
        intentMtx      sync.RWMutex
414
        fundingIntents map[[32]byte]chanfunding.Intent
415

416
        quit chan struct{}
417

418
        wg sync.WaitGroup
419

420
        // TODO(roasbeef): handle wallet lock/unlock
421
}
422

423
// NewLightningWallet creates/opens and initializes a LightningWallet instance.
424
// If the wallet has never been created (according to the passed dataDir), first-time
425
// setup is executed.
426
func NewLightningWallet(Cfg Config) (*LightningWallet, error) {
114✔
427

114✔
428
        return &LightningWallet{
114✔
429
                Cfg:              Cfg,
114✔
430
                SecretKeyRing:    Cfg.SecretKeyRing,
114✔
431
                WalletController: Cfg.WalletController,
114✔
432
                msgChan:          make(chan interface{}, msgBufferSize),
114✔
433
                nextFundingID:    0,
114✔
434
                fundingLimbo:     make(map[uint64]*ChannelReservation),
114✔
435
                reservationIDs:   make(map[[32]byte]uint64),
114✔
436
                lockedOutPoints:  make(map[wire.OutPoint]struct{}),
114✔
437
                fundingIntents:   make(map[[32]byte]chanfunding.Intent),
114✔
438
                quit:             make(chan struct{}),
114✔
439
        }, nil
114✔
440
}
114✔
441

442
// Startup establishes a connection to the RPC source, and spins up all
443
// goroutines required to handle incoming messages.
444
func (l *LightningWallet) Startup() error {
113✔
445
        // Already started?
113✔
446
        if atomic.AddInt32(&l.started, 1) != 1 {
113✔
447
                return nil
×
448
        }
×
449

450
        // Start the underlying wallet controller.
451
        if err := l.Start(); err != nil {
113✔
452
                return err
×
453
        }
×
454

455
        if l.Cfg.Rebroadcaster != nil {
118✔
456
                go func() {
10✔
457
                        if err := l.Cfg.Rebroadcaster.Start(); err != nil {
5✔
458
                                walletLog.Errorf("unable to start "+
×
459
                                        "rebroadcaster: %v", err)
×
460
                        }
×
461
                }()
462
        }
463

464
        l.wg.Add(1)
113✔
465
        // TODO(roasbeef): multiple request handlers?
113✔
466
        go l.requestHandler()
113✔
467

113✔
468
        return nil
113✔
469
}
470

471
// Shutdown gracefully stops the wallet, and all active goroutines.
472
func (l *LightningWallet) Shutdown() error {
15✔
473
        if atomic.AddInt32(&l.shutdown, 1) != 1 {
15✔
474
                return nil
×
475
        }
×
476

477
        // Signal the underlying wallet controller to shutdown, waiting until
478
        // all active goroutines have been shutdown.
479
        if err := l.Stop(); err != nil {
15✔
480
                return err
×
481
        }
×
482

483
        if l.Cfg.Rebroadcaster != nil && l.Cfg.Rebroadcaster.Started() {
19✔
484
                l.Cfg.Rebroadcaster.Stop()
4✔
485
        }
4✔
486

487
        close(l.quit)
15✔
488
        l.wg.Wait()
15✔
489
        return nil
15✔
490
}
491

492
// PublishTransaction wraps the wallet controller tx publish method with an
493
// extra rebroadcaster layer if the sub-system is configured.
494
func (l *LightningWallet) PublishTransaction(tx *wire.MsgTx,
495
        label string) error {
82✔
496

82✔
497
        sendTxToWallet := func() error {
164✔
498
                return l.WalletController.PublishTransaction(tx, label)
82✔
499
        }
82✔
500

501
        // If we don't have rebroadcaster then we can exit early (and send only
502
        // to the wallet).
503
        if l.Cfg.Rebroadcaster == nil || !l.Cfg.Rebroadcaster.Started() {
163✔
504
                return sendTxToWallet()
81✔
505
        }
81✔
506

507
        // We pass this into the rebroadcaster first, so the initial attempt
508
        // will succeed if the transaction isn't yet in the mempool. However we
509
        // ignore the error here as this might be resent on start up and the
510
        // transaction already exists.
511
        _ = l.Cfg.Rebroadcaster.Broadcast(tx)
4✔
512

4✔
513
        // Then we pass things into the wallet as normal, which'll add the
4✔
514
        // transaction label on disk.
4✔
515
        if err := sendTxToWallet(); err != nil {
7✔
516
                return err
3✔
517
        }
3✔
518

519
        // TODO(roasbeef): want diff height actually? no context though
520
        _, bestHeight, err := l.Cfg.ChainIO.GetBestBlock()
4✔
521
        if err != nil {
4✔
522
                return err
×
523
        }
×
524

525
        txHash := tx.TxHash()
4✔
526
        go func() {
8✔
527
                const numConfs = 6
4✔
528

4✔
529
                txConf, err := l.Cfg.Notifier.RegisterConfirmationsNtfn(
4✔
530
                        &txHash, tx.TxOut[0].PkScript, numConfs,
4✔
531
                        uint32(bestHeight),
4✔
532
                )
4✔
533
                if err != nil {
4✔
534
                        return
×
535
                }
×
536

537
                select {
4✔
538
                case <-txConf.Confirmed:
4✔
539
                        // TODO(roasbeef): also want to remove from
4✔
540
                        // rebroadcaster if conflict happens...deeper wallet
4✔
541
                        // integration?
4✔
542
                        l.Cfg.Rebroadcaster.MarkAsConfirmed(tx.TxHash())
4✔
543

544
                case <-l.quit:
×
545
                        return
×
546
                }
547
        }()
548

549
        return nil
4✔
550
}
551

552
// ConfirmedBalance returns the current confirmed balance of a wallet account.
553
// This methods wraps the internal WalletController method so we're able to
554
// properly hold the coin select mutex while we compute the balance.
555
func (l *LightningWallet) ConfirmedBalance(confs int32,
556
        account string) (btcutil.Amount, error) {
110✔
557

110✔
558
        l.coinSelectMtx.Lock()
110✔
559
        defer l.coinSelectMtx.Unlock()
110✔
560

110✔
561
        return l.WalletController.ConfirmedBalance(confs, account)
110✔
562
}
110✔
563

564
// ListUnspentWitnessFromDefaultAccount returns all unspent outputs from the
565
// default wallet account which are version 0 witness programs. The 'minConfs'
566
// and 'maxConfs' parameters indicate the minimum and maximum number of
567
// confirmations an output needs in order to be returned by this method. Passing
568
// -1 as 'minConfs' indicates that even unconfirmed outputs should be returned.
569
// Using MaxInt32 as 'maxConfs' implies returning all outputs with at least
570
// 'minConfs'.
571
//
572
// NOTE: This method requires the global coin selection lock to be held.
573
func (l *LightningWallet) ListUnspentWitnessFromDefaultAccount(
574
        minConfs, maxConfs int32) ([]*Utxo, error) {
232✔
575

232✔
576
        return l.WalletController.ListUnspentWitness(
232✔
577
                minConfs, maxConfs, DefaultAccountName,
232✔
578
        )
232✔
579
}
232✔
580

581
// LockedOutpoints returns a list of all currently locked outpoint.
582
func (l *LightningWallet) LockedOutpoints() []*wire.OutPoint {
4✔
583
        outPoints := make([]*wire.OutPoint, 0, len(l.lockedOutPoints))
4✔
584
        for outPoint := range l.lockedOutPoints {
4✔
585
                outPoint := outPoint
×
586

×
587
                outPoints = append(outPoints, &outPoint)
×
588
        }
×
589

590
        return outPoints
4✔
591
}
592

593
// ResetReservations reset the volatile wallet state which tracks all currently
594
// active reservations.
595
func (l *LightningWallet) ResetReservations() {
168✔
596
        l.nextFundingID = 0
168✔
597
        l.fundingLimbo = make(map[uint64]*ChannelReservation)
168✔
598
        l.reservationIDs = make(map[[32]byte]uint64)
168✔
599

168✔
600
        for outpoint := range l.lockedOutPoints {
168✔
601
                _ = l.ReleaseOutput(chanfunding.LndInternalLockID, outpoint)
×
602
        }
×
603
        l.lockedOutPoints = make(map[wire.OutPoint]struct{})
168✔
604
}
605

606
// ActiveReservations returns a slice of all the currently active
607
// (non-canceled) reservations.
608
func (l *LightningWallet) ActiveReservations() []*ChannelReservation {
8✔
609
        reservations := make([]*ChannelReservation, 0, len(l.fundingLimbo))
8✔
610
        for _, reservation := range l.fundingLimbo {
8✔
611
                reservations = append(reservations, reservation)
×
612
        }
×
613

614
        return reservations
8✔
615
}
616

617
// requestHandler is the primary goroutine(s) responsible for handling, and
618
// dispatching replies to all messages.
619
func (l *LightningWallet) requestHandler() {
113✔
620
        defer l.wg.Done()
113✔
621

113✔
622
out:
113✔
623
        for {
631✔
624
                select {
518✔
625
                case m := <-l.msgChan:
409✔
626
                        switch msg := m.(type) {
409✔
627
                        case *InitFundingReserveMsg:
162✔
628
                                l.handleFundingReserveRequest(msg)
162✔
629
                        case *fundingReserveCancelMsg:
58✔
630
                                l.handleFundingCancelRequest(msg)
58✔
631
                        case *addSingleContributionMsg:
66✔
632
                                l.handleSingleContribution(msg)
66✔
633
                        case *addContributionMsg:
49✔
634
                                l.handleContributionMsg(msg)
49✔
635
                        case *continueContributionMsg:
4✔
636
                                l.handleChanPointReady(msg)
4✔
637
                        case *addSingleFunderSigsMsg:
47✔
638
                                l.handleSingleFunderSigs(msg)
47✔
639
                        case *addCounterPartySigsMsg:
47✔
640
                                l.handleFundingCounterPartySigs(msg)
47✔
641
                        }
642
                case <-l.quit:
15✔
643
                        // TODO: do some clean up
15✔
644
                        break out
15✔
645
                }
646
        }
647
}
648

649
// InitChannelReservation kicks off the 3-step workflow required to successfully
650
// open a payment channel with a remote node. As part of the funding
651
// reservation, the inputs selected for the funding transaction are 'locked'.
652
// This ensures that multiple channel reservations aren't double spending the
653
// same inputs in the funding transaction. If reservation initialization is
654
// successful, a ChannelReservation containing our completed contribution is
655
// returned. Our contribution contains all the items necessary to allow the
656
// counterparty to build the funding transaction, and both versions of the
657
// commitment transaction. Otherwise, an error occurred and a nil pointer along
658
// with an error are returned.
659
//
660
// Once a ChannelReservation has been obtained, two additional steps must be
661
// processed before a payment channel can be considered 'open'. The second step
662
// validates, and processes the counterparty's channel contribution. The third,
663
// and final step verifies all signatures for the inputs of the funding
664
// transaction, and that the signature we record for our version of the
665
// commitment transaction is valid.
666
func (l *LightningWallet) InitChannelReservation(
667
        req *InitFundingReserveMsg) (*ChannelReservation, error) {
162✔
668

162✔
669
        req.resp = make(chan *ChannelReservation, 1)
162✔
670
        req.err = make(chan error, 1)
162✔
671

162✔
672
        select {
162✔
673
        case l.msgChan <- req:
162✔
674
        case <-l.quit:
×
675
                return nil, errors.New("wallet shutting down")
×
676
        }
677

678
        return <-req.resp, <-req.err
162✔
679
}
680

681
// RegisterFundingIntent allows a caller to signal to the wallet that if a
682
// pending channel ID of expectedID is found, then it can skip constructing a
683
// new chanfunding.Assembler, and instead use the specified chanfunding.Intent.
684
// As an example, this lets some of the parameters for funding transaction to
685
// be negotiated outside the regular funding protocol.
686
func (l *LightningWallet) RegisterFundingIntent(expectedID [32]byte,
687
        shimIntent chanfunding.Intent) error {
150✔
688

150✔
689
        l.intentMtx.Lock()
150✔
690
        defer l.intentMtx.Unlock()
150✔
691

150✔
692
        // Sanity check the pending channel ID is not empty.
150✔
693
        var zeroID [32]byte
150✔
694
        if expectedID == zeroID {
151✔
695
                return ErrEmptyPendingChanID
1✔
696
        }
1✔
697

698
        if _, ok := l.fundingIntents[expectedID]; ok {
154✔
699
                return fmt.Errorf("%w: already has intent registered: %v",
5✔
700
                        ErrDuplicatePendingChanID, expectedID[:])
5✔
701
        }
5✔
702

703
        l.fundingIntents[expectedID] = shimIntent
148✔
704

148✔
705
        return nil
148✔
706
}
707

708
// PsbtFundingVerify looks up a previously registered funding intent by its
709
// pending channel ID and tries to advance the state machine by verifying the
710
// passed PSBT.
711
func (l *LightningWallet) PsbtFundingVerify(pendingChanID [32]byte,
712
        packet *psbt.Packet, skipFinalize bool) error {
4✔
713

4✔
714
        l.intentMtx.Lock()
4✔
715
        defer l.intentMtx.Unlock()
4✔
716

4✔
717
        intent, ok := l.fundingIntents[pendingChanID]
4✔
718
        if !ok {
4✔
719
                return fmt.Errorf("no funding intent found for "+
×
720
                        "pendingChannelID(%x)", pendingChanID[:])
×
721
        }
×
722
        psbtIntent, ok := intent.(*chanfunding.PsbtIntent)
4✔
723
        if !ok {
4✔
724
                return fmt.Errorf("incompatible funding intent")
×
725
        }
×
726

727
        if skipFinalize && psbtIntent.ShouldPublishFundingTX() {
4✔
728
                return fmt.Errorf("cannot set skip_finalize for channel that " +
×
729
                        "did not set no_publish")
×
730
        }
×
731

732
        err := psbtIntent.Verify(packet, skipFinalize)
4✔
733
        if err != nil {
4✔
734
                return fmt.Errorf("error verifying PSBT: %w", err)
×
735
        }
×
736

737
        // Get the channel reservation for that corresponds to this pending
738
        // channel ID.
739
        l.limboMtx.Lock()
4✔
740
        pid, ok := l.reservationIDs[pendingChanID]
4✔
741
        if !ok {
4✔
742
                l.limboMtx.Unlock()
×
743
                return fmt.Errorf("no channel reservation found for "+
×
744
                        "pendingChannelID(%x)", pendingChanID[:])
×
745
        }
×
746

747
        pendingReservation, ok := l.fundingLimbo[pid]
4✔
748
        l.limboMtx.Unlock()
4✔
749

4✔
750
        if !ok {
4✔
751
                return fmt.Errorf("no channel reservation found for "+
×
752
                        "reservation ID %v", pid)
×
753
        }
×
754

755
        // Now the PSBT has been populated and verified, we can again check
756
        // whether the value reserved for anchor fee bumping is respected.
757
        isPublic := pendingReservation.partialState.ChannelFlags&lnwire.FFAnnounceChannel != 0
4✔
758
        hasAnchors := pendingReservation.partialState.ChanType.HasAnchors()
4✔
759
        return l.enforceNewReservedValue(intent, isPublic, hasAnchors)
4✔
760
}
761

762
// PsbtFundingFinalize looks up a previously registered funding intent by its
763
// pending channel ID and tries to advance the state machine by finalizing the
764
// passed PSBT.
765
func (l *LightningWallet) PsbtFundingFinalize(pid [32]byte, packet *psbt.Packet,
766
        rawTx *wire.MsgTx) error {
4✔
767

4✔
768
        l.intentMtx.Lock()
4✔
769
        defer l.intentMtx.Unlock()
4✔
770

4✔
771
        intent, ok := l.fundingIntents[pid]
4✔
772
        if !ok {
4✔
773
                return fmt.Errorf("no funding intent found for "+
×
774
                        "pendingChannelID(%x)", pid[:])
×
775
        }
×
776
        psbtIntent, ok := intent.(*chanfunding.PsbtIntent)
4✔
777
        if !ok {
4✔
778
                return fmt.Errorf("incompatible funding intent")
×
779
        }
×
780

781
        // Either the PSBT or the raw TX must be set.
782
        switch {
4✔
783
        case packet != nil && rawTx == nil:
4✔
784
                err := psbtIntent.Finalize(packet)
4✔
785
                if err != nil {
4✔
786
                        return fmt.Errorf("error finalizing PSBT: %w", err)
×
787
                }
×
788

789
        case rawTx != nil && packet == nil:
4✔
790
                err := psbtIntent.FinalizeRawTX(rawTx)
4✔
791
                if err != nil {
4✔
792
                        return fmt.Errorf("error finalizing raw TX: %w", err)
×
793
                }
×
794

795
        default:
×
796
                return fmt.Errorf("either a PSBT or raw TX must be specified")
×
797
        }
798

799
        return nil
4✔
800
}
801

802
// CancelFundingIntent allows a caller to cancel a previously registered
803
// funding intent. If no intent was found, then an error will be returned.
804
func (l *LightningWallet) CancelFundingIntent(pid [32]byte) error {
4✔
805
        l.intentMtx.Lock()
4✔
806
        defer l.intentMtx.Unlock()
4✔
807

4✔
808
        intent, ok := l.fundingIntents[pid]
4✔
809
        if !ok {
8✔
810
                return fmt.Errorf("no funding intent found for "+
4✔
811
                        "pendingChannelID(%x)", pid[:])
4✔
812
        }
4✔
813

814
        // Give the intent a chance to clean up after itself, removing coin
815
        // locks or similar reserved resources.
816
        intent.Cancel()
4✔
817

4✔
818
        delete(l.fundingIntents, pid)
4✔
819

4✔
820
        return nil
4✔
821
}
822

823
// handleFundingReserveRequest processes a message intending to create, and
824
// validate a funding reservation request.
825
func (l *LightningWallet) handleFundingReserveRequest(req *InitFundingReserveMsg) {
162✔
826

162✔
827
        noFundsCommitted := req.LocalFundingAmt == 0 &&
162✔
828
                req.RemoteFundingAmt == 0 && req.FundUpToMaxAmt == 0
162✔
829

162✔
830
        // It isn't possible to create a channel with zero funds committed.
162✔
831
        if noFundsCommitted {
162✔
832
                err := ErrZeroCapacity()
×
833
                req.err <- err
×
834
                req.resp <- nil
×
835
                return
×
836
        }
×
837

838
        // If the funding request is for a different chain than the one the
839
        // wallet is aware of, then we'll reject the request.
840
        if !bytes.Equal(l.Cfg.NetParams.GenesisHash[:], req.ChainHash[:]) {
162✔
841
                err := ErrChainMismatch(
×
842
                        l.Cfg.NetParams.GenesisHash, req.ChainHash,
×
843
                )
×
844
                req.err <- err
×
845
                req.resp <- nil
×
846
                return
×
847
        }
×
848

849
        // We need to avoid enforcing reserved value in the middle of PSBT
850
        // funding because some of the following steps may add UTXOs funding
851
        // the on-chain wallet.
852
        // The enforcement still happens at the last step - in PsbtFundingVerify
853
        enforceNewReservedValue := true
162✔
854

162✔
855
        // If no chanFunder was provided, then we'll assume the default
162✔
856
        // assembler, which is backed by the wallet's internal coin selection.
162✔
857
        if req.ChanFunder == nil {
311✔
858
                // We use the P2WSH dust limit since it is larger than the
149✔
859
                // P2WPKH dust limit and to avoid threading through two
149✔
860
                // different dust limits.
149✔
861
                cfg := chanfunding.WalletConfig{
149✔
862
                        CoinSource: NewCoinSource(
149✔
863
                                l, req.AllowUtxoForFunding,
149✔
864
                        ),
149✔
865
                        CoinSelectLocker: l,
149✔
866
                        CoinLeaser:       l,
149✔
867
                        Signer:           l.Cfg.Signer,
149✔
868
                        DustLimit: DustLimitForSize(
149✔
869
                                input.P2WSHSize,
149✔
870
                        ),
149✔
871
                        CoinSelectionStrategy: l.Cfg.CoinSelectionStrategy,
149✔
872
                }
149✔
873
                req.ChanFunder = chanfunding.NewWalletAssembler(cfg)
149✔
874
        } else {
166✔
875
                _, isPsbtFunder := req.ChanFunder.(*chanfunding.PsbtAssembler)
17✔
876
                enforceNewReservedValue = !isPsbtFunder
17✔
877
        }
17✔
878

879
        localFundingAmt := req.LocalFundingAmt
162✔
880
        remoteFundingAmt := req.RemoteFundingAmt
162✔
881
        hasAnchors := req.CommitType.HasAnchors()
162✔
882

162✔
883
        var (
162✔
884
                fundingIntent chanfunding.Intent
162✔
885
                err           error
162✔
886
        )
162✔
887

162✔
888
        // If we've just received an inbound funding request that we have a
162✔
889
        // registered shim intent to, then we'll obtain the backing intent now.
162✔
890
        // In this case, we're doing a special funding workflow that allows
162✔
891
        // more advanced constructions such as channel factories to be
162✔
892
        // instantiated.
162✔
893
        l.intentMtx.Lock()
162✔
894
        fundingIntent, ok := l.fundingIntents[req.PendingChanID]
162✔
895
        l.intentMtx.Unlock()
162✔
896

162✔
897
        // Otherwise, this is a normal funding flow, so we'll use the chan
162✔
898
        // funder in the attached request to provision the inputs/outputs
162✔
899
        // that'll ultimately be used to construct the funding transaction.
162✔
900
        if !ok {
313✔
901
                var err error
151✔
902
                var numAnchorChans int
151✔
903

151✔
904
                // Get the number of anchor channels to determine if there is a
151✔
905
                // reserved value that must be respected when funding up to the
151✔
906
                // maximum amount. Since private channels (most likely) won't be
151✔
907
                // used for routing other than the last hop, they bear a smaller
151✔
908
                // risk that we must force close them in order to resolve a HTLC
151✔
909
                // up/downstream. Hence we exclude them from the count of anchor
151✔
910
                // channels in order to attribute the respective anchor amount
151✔
911
                // to the channel capacity.
151✔
912
                if req.FundUpToMaxAmt > 0 && req.MinFundAmt > 0 {
161✔
913
                        numAnchorChans, err = l.CurrentNumAnchorChans()
10✔
914
                        if err != nil {
10✔
915
                                req.err <- err
×
916
                                req.resp <- nil
×
917
                                return
×
918
                        }
×
919

920
                        isPublic := req.Flags&lnwire.FFAnnounceChannel != 0
10✔
921
                        if hasAnchors && isPublic {
14✔
922
                                numAnchorChans++
4✔
923
                        }
4✔
924
                }
925

926
                // Coin selection is done on the basis of sat/kw, so we'll use
927
                // the fee rate passed in to perform coin selection.
928
                fundingReq := &chanfunding.Request{
151✔
929
                        RemoteAmt:         req.RemoteFundingAmt,
151✔
930
                        LocalAmt:          req.LocalFundingAmt,
151✔
931
                        FundUpToMaxAmt:    req.FundUpToMaxAmt,
151✔
932
                        MinFundAmt:        req.MinFundAmt,
151✔
933
                        RemoteChanReserve: req.RemoteChanReserve,
151✔
934
                        PushAmt: lnwire.MilliSatoshi.ToSatoshis(
151✔
935
                                req.PushMSat,
151✔
936
                        ),
151✔
937
                        WalletReserve: l.RequiredReserve(
151✔
938
                                uint32(numAnchorChans),
151✔
939
                        ),
151✔
940
                        Outpoints:    req.Outpoints,
151✔
941
                        MinConfs:     req.MinConfs,
151✔
942
                        SubtractFees: req.SubtractFees,
151✔
943
                        FeeRate:      req.FundingFeePerKw,
151✔
944
                        ChangeAddr: func() (btcutil.Address, error) {
229✔
945
                                return l.NewAddress(
78✔
946
                                        TaprootPubkey, true, DefaultAccountName,
78✔
947
                                )
78✔
948
                        },
78✔
949
                        Musig2: req.CommitType == CommitmentTypeSimpleTaproot,
950
                }
951
                fundingIntent, err = req.ChanFunder.ProvisionChannel(
151✔
952
                        fundingReq,
151✔
953
                )
151✔
954
                if err != nil {
163✔
955
                        req.err <- err
12✔
956
                        req.resp <- nil
12✔
957
                        return
12✔
958
                }
12✔
959

960
                // Register the funding intent now in case we need to access it
961
                // again later, as it's the case for the PSBT state machine for
962
                // example.
963
                err = l.RegisterFundingIntent(req.PendingChanID, fundingIntent)
143✔
964
                if err != nil {
143✔
965
                        req.err <- err
×
966
                        req.resp <- nil
×
967
                        return
×
968
                }
×
969

970
                walletLog.Debugf("Registered funding intent for "+
143✔
971
                        "PendingChanID: %x", req.PendingChanID)
143✔
972

143✔
973
                localFundingAmt = fundingIntent.LocalFundingAmt()
143✔
974
                remoteFundingAmt = fundingIntent.RemoteFundingAmt()
143✔
975
        }
976

977
        // At this point there _has_ to be a funding intent, otherwise something
978
        // went really wrong.
979
        if fundingIntent == nil {
154✔
980
                req.err <- fmt.Errorf("no funding intent present")
×
981
                req.resp <- nil
×
982
                return
×
983
        }
×
984

985
        // If this is a shim intent, then it may be attempting to use an
986
        // existing set of keys for the funding workflow. In this case, we'll
987
        // make a simple wrapper keychain.KeyRing that will proxy certain
988
        // derivation calls to future callers.
989
        var (
154✔
990
                keyRing    keychain.KeyRing = l.SecretKeyRing
154✔
991
                thawHeight uint32
154✔
992
        )
154✔
993
        if shimIntent, ok := fundingIntent.(*chanfunding.ShimIntent); ok {
167✔
994
                keyRing = &shimKeyRing{
13✔
995
                        KeyRing:    keyRing,
13✔
996
                        ShimIntent: shimIntent,
13✔
997
                }
13✔
998

13✔
999
                // As this was a registered shim intent, we'll obtain the thaw
13✔
1000
                // height of the intent, if present at all. If this is
13✔
1001
                // non-zero, then we'll mark this as the proper channel type.
13✔
1002
                thawHeight = shimIntent.ThawHeight()
13✔
1003
        }
13✔
1004

1005
        // Now that we have a funding intent, we'll check whether funding a
1006
        // channel using it would violate our reserved value for anchor channel
1007
        // fee bumping.
1008
        //
1009
        // Check the reserved value using the inputs and outputs given by the
1010
        // intent. Note that for the PSBT intent type we don't yet have the
1011
        // funding tx ready, so this will always pass.  We'll do another check
1012
        // when the PSBT has been verified.
1013
        isPublic := req.Flags&lnwire.FFAnnounceChannel != 0
154✔
1014
        if enforceNewReservedValue {
308✔
1015
                err = l.enforceNewReservedValue(fundingIntent, isPublic, hasAnchors)
154✔
1016
                if err != nil {
158✔
1017
                        fundingIntent.Cancel()
4✔
1018

4✔
1019
                        req.err <- err
4✔
1020
                        req.resp <- nil
4✔
1021
                        return
4✔
1022
                }
4✔
1023
        }
1024

1025
        // The total channel capacity will be the size of the funding output we
1026
        // created plus the remote contribution.
1027
        capacity := localFundingAmt + remoteFundingAmt
154✔
1028

154✔
1029
        id := atomic.AddUint64(&l.nextFundingID, 1)
154✔
1030
        reservation, err := NewChannelReservation(
154✔
1031
                capacity, localFundingAmt, l, id, l.Cfg.NetParams.GenesisHash,
154✔
1032
                thawHeight, req,
154✔
1033
        )
154✔
1034
        if err != nil {
162✔
1035
                fundingIntent.Cancel()
8✔
1036

8✔
1037
                req.err <- err
8✔
1038
                req.resp <- nil
8✔
1039
                return
8✔
1040
        }
8✔
1041

1042
        err = l.initOurContribution(
150✔
1043
                reservation, fundingIntent, req.NodeAddr, req.NodeID, keyRing,
150✔
1044
        )
150✔
1045
        if err != nil {
150✔
1046
                fundingIntent.Cancel()
×
1047

×
1048
                req.err <- err
×
1049
                req.resp <- nil
×
1050
                return
×
1051
        }
×
1052

1053
        // Create a limbo and record entry for this newly pending funding
1054
        // request.
1055
        l.limboMtx.Lock()
150✔
1056
        l.fundingLimbo[id] = reservation
150✔
1057
        l.reservationIDs[req.PendingChanID] = id
150✔
1058
        l.limboMtx.Unlock()
150✔
1059

150✔
1060
        // Funding reservation request successfully handled. The funding inputs
150✔
1061
        // will be marked as unavailable until the reservation is either
150✔
1062
        // completed, or canceled.
150✔
1063
        req.resp <- reservation
150✔
1064
        req.err <- nil
150✔
1065

150✔
1066
        walletLog.Debugf("Successfully handled funding reservation with "+
150✔
1067
                "pendingChanID: %x, reservationID: %v",
150✔
1068
                reservation.pendingChanID, reservation.reservationID)
150✔
1069
}
1070

1071
// enforceReservedValue enforces that the wallet, upon a new channel being
1072
// opened, meets the minimum amount of funds required for each advertised anchor
1073
// channel.
1074
//
1075
// We only enforce the reserve if we are contributing funds to the channel. This
1076
// is done to still allow incoming channels even though we have no UTXOs
1077
// available, as in bootstrapping phases.
1078
func (l *LightningWallet) enforceNewReservedValue(fundingIntent chanfunding.Intent,
1079
        isPublic, hasAnchors bool) error {
154✔
1080

154✔
1081
        // Only enforce the reserve when an advertised channel is being opened
154✔
1082
        // in which we are contributing funds to. This ensures we never dip
154✔
1083
        // below the reserve.
154✔
1084
        if !isPublic || fundingIntent.LocalFundingAmt() == 0 {
226✔
1085
                return nil
72✔
1086
        }
72✔
1087

1088
        numAnchors, err := l.CurrentNumAnchorChans()
86✔
1089
        if err != nil {
86✔
1090
                return err
×
1091
        }
×
1092

1093
        // Add the to-be-opened channel.
1094
        if hasAnchors {
96✔
1095
                numAnchors++
10✔
1096
        }
10✔
1097

1098
        return l.WithCoinSelectLock(func() error {
172✔
1099
                _, err := l.CheckReservedValue(
86✔
1100
                        fundingIntent.Inputs(), fundingIntent.Outputs(),
86✔
1101
                        numAnchors,
86✔
1102
                )
86✔
1103
                return err
86✔
1104
        })
86✔
1105
}
1106

1107
// CurrentNumAnchorChans returns the current number of non-private anchor
1108
// channels the wallet should be ready to fee bump if needed.
1109
func (l *LightningWallet) CurrentNumAnchorChans() (int, error) {
92✔
1110
        // Count all anchor channels that are open or pending
92✔
1111
        // open, or waiting close.
92✔
1112
        chans, err := l.Cfg.Database.FetchAllChannels()
92✔
1113
        if err != nil {
92✔
1114
                return 0, err
×
1115
        }
×
1116

1117
        var numAnchors int
92✔
1118
        cntChannel := func(c *channeldb.OpenChannel) {
96✔
1119
                // We skip private channels, as we assume they won't be used
4✔
1120
                // for routing.
4✔
1121
                if c.ChannelFlags&lnwire.FFAnnounceChannel == 0 {
8✔
1122
                        return
4✔
1123
                }
4✔
1124

1125
                // Count anchor channels.
1126
                if c.ChanType.HasAnchors() {
8✔
1127
                        numAnchors++
4✔
1128
                }
4✔
1129
        }
1130

1131
        for _, c := range chans {
96✔
1132
                cntChannel(c)
4✔
1133
        }
4✔
1134

1135
        // We also count pending close channels.
1136
        pendingClosed, err := l.Cfg.Database.FetchClosedChannels(
92✔
1137
                true,
92✔
1138
        )
92✔
1139
        if err != nil {
92✔
1140
                return 0, err
×
1141
        }
×
1142

1143
        for _, c := range pendingClosed {
96✔
1144
                c, err := l.Cfg.Database.FetchHistoricalChannel(
4✔
1145
                        &c.ChanPoint,
4✔
1146
                )
4✔
1147
                if err != nil {
4✔
1148
                        // We don't have a guarantee that all channels re found
×
1149
                        // in the historical channels bucket, so we continue.
×
1150
                        walletLog.Warnf("Unable to fetch historical "+
×
1151
                                "channel: %v", err)
×
1152
                        continue
×
1153
                }
1154

1155
                cntChannel(c)
4✔
1156
        }
1157

1158
        return numAnchors, nil
92✔
1159
}
1160

1161
// CheckReservedValue checks whether publishing a transaction with the given
1162
// inputs and outputs would violate the value we reserve in the wallet for
1163
// bumping the fee of anchor channels. The numAnchorChans argument should be
1164
// set the number of open anchor channels controlled by the wallet after
1165
// the transaction has been published.
1166
//
1167
// If the reserved value is violated, the returned error will be
1168
// ErrReservedValueInvalidated. The method will also return the current
1169
// reserved value, both in case of success and in case of
1170
// ErrReservedValueInvalidated.
1171
//
1172
// NOTE: This method should only be run with the CoinSelectLock held.
1173
func (l *LightningWallet) CheckReservedValue(in []wire.OutPoint,
1174
        out []*wire.TxOut, numAnchorChans int) (btcutil.Amount, error) {
86✔
1175

86✔
1176
        // Get all unspent coins in the wallet. We only care about those part of
86✔
1177
        // the wallet's default account as we know we can readily sign for those
86✔
1178
        // at any time.
86✔
1179
        witnessOutputs, err := l.ListUnspentWitnessFromDefaultAccount(
86✔
1180
                0, math.MaxInt32,
86✔
1181
        )
86✔
1182
        if err != nil {
86✔
1183
                return 0, err
×
1184
        }
×
1185

1186
        ourInput := make(map[wire.OutPoint]struct{})
86✔
1187
        for _, op := range in {
283✔
1188
                ourInput[op] = struct{}{}
197✔
1189
        }
197✔
1190

1191
        // When crafting a transaction with inputs from the wallet, these coins
1192
        // will usually be locked in the process, and not be returned when
1193
        // listing unspents. In this case they have already been deducted from
1194
        // the wallet balance. In case they haven't been properly locked, we
1195
        // check whether they are still listed among our unspents and deduct
1196
        // them.
1197
        var walletBalance btcutil.Amount
86✔
1198
        for _, in := range witnessOutputs {
604✔
1199
                // Spending an unlocked wallet UTXO, don't add it to the
518✔
1200
                // balance.
518✔
1201
                if _, ok := ourInput[in.OutPoint]; ok {
542✔
1202
                        continue
24✔
1203
                }
1204

1205
                walletBalance += in.Value
498✔
1206
        }
1207

1208
        // Now we go through the outputs of the transaction, if any of the
1209
        // outputs are paying into the wallet (likely a change output), we add
1210
        // it to our final balance.
1211
        for _, txOut := range out {
170✔
1212
                _, addrs, _, err := txscript.ExtractPkScriptAddrs(
84✔
1213
                        txOut.PkScript, &l.Cfg.NetParams,
84✔
1214
                )
84✔
1215
                if err != nil {
84✔
1216
                        // Non-standard outputs can safely be skipped because
×
1217
                        // they're not supported by the wallet.
×
1218
                        continue
×
1219
                }
1220

1221
                for _, addr := range addrs {
168✔
1222
                        if !l.IsOurAddress(addr) {
140✔
1223
                                continue
56✔
1224
                        }
1225

1226
                        walletBalance += btcutil.Amount(txOut.Value)
32✔
1227

32✔
1228
                        // We break since we don't want to double count the output.
32✔
1229
                        break
32✔
1230
                }
1231
        }
1232

1233
        // We reserve a given amount for each anchor channel.
1234
        reserved := l.RequiredReserve(uint32(numAnchorChans))
86✔
1235

86✔
1236
        if walletBalance < reserved {
90✔
1237
                walletLog.Debugf("Reserved value=%v above final "+
4✔
1238
                        "walletbalance=%v with %d anchor channels open",
4✔
1239
                        reserved, walletBalance, numAnchorChans)
4✔
1240
                return reserved, ErrReservedValueInvalidated
4✔
1241
        }
4✔
1242

1243
        return reserved, nil
86✔
1244
}
1245

1246
// CheckReservedValueTx calls CheckReservedValue with the inputs and outputs
1247
// from the given tx, with the number of anchor channels currently open in the
1248
// database.
1249
//
1250
// NOTE: This method should only be run with the CoinSelectLock held.
1251
func (l *LightningWallet) CheckReservedValueTx(req CheckReservedValueTxReq) (
1252
        btcutil.Amount, error) {
4✔
1253

4✔
1254
        numAnchors, err := l.CurrentNumAnchorChans()
4✔
1255
        if err != nil {
4✔
1256
                return 0, err
×
1257
        }
×
1258

1259
        var inputs []wire.OutPoint
4✔
1260
        for _, txIn := range req.Tx.TxIn {
8✔
1261
                inputs = append(inputs, txIn.PreviousOutPoint)
4✔
1262
        }
4✔
1263

1264
        reservedVal, err := l.CheckReservedValue(
4✔
1265
                inputs, req.Tx.TxOut, numAnchors,
4✔
1266
        )
4✔
1267
        switch {
4✔
1268
        // If the error returned from CheckReservedValue is
1269
        // ErrReservedValueInvalidated, then it did nonetheless return
1270
        // the required reserved value and we check for the optional
1271
        // change index.
1272
        case errors.Is(err, ErrReservedValueInvalidated):
4✔
1273
                // Without a change index provided there is nothing more to
4✔
1274
                // check and the error is returned.
4✔
1275
                if req.ChangeIndex == nil {
8✔
1276
                        return reservedVal, err
4✔
1277
                }
4✔
1278

1279
                // If a change index was provided we make only sure that it
1280
                // would leave sufficient funds for the reserved balance value.
1281
                //
1282
                // Note: This is used if a change output index is explicitly set
1283
                // but that may not be watched by the wallet and therefore is
1284
                // not picked up by the call to CheckReservedValue above.
1285
                chIdx := *req.ChangeIndex
×
1286
                if chIdx < 0 || chIdx >= len(req.Tx.TxOut) ||
×
1287
                        req.Tx.TxOut[chIdx].Value < int64(reservedVal) {
×
1288

×
1289
                        return reservedVal, err
×
1290
                }
×
1291

1292
        case err != nil:
×
1293
                return reservedVal, err
×
1294
        }
1295

1296
        return reservedVal, nil
4✔
1297
}
1298

1299
// initOurContribution initializes the given ChannelReservation with our coins
1300
// and change reserved for the channel, and derives the keys to use for this
1301
// channel.
1302
func (l *LightningWallet) initOurContribution(reservation *ChannelReservation,
1303
        fundingIntent chanfunding.Intent, nodeAddr net.Addr,
1304
        nodeID *btcec.PublicKey, keyRing keychain.KeyRing) error {
150✔
1305

150✔
1306
        // Grab the mutex on the ChannelReservation to ensure thread-safety
150✔
1307
        reservation.Lock()
150✔
1308
        defer reservation.Unlock()
150✔
1309

150✔
1310
        // At this point, if we have a funding intent, we'll use it to populate
150✔
1311
        // the existing reservation state entries for our coin selection.
150✔
1312
        if fundingIntent != nil {
300✔
1313
                if intent, ok := fundingIntent.(*chanfunding.FullIntent); ok {
291✔
1314
                        for _, coin := range intent.InputCoins {
335✔
1315
                                reservation.ourContribution.Inputs = append(
194✔
1316
                                        reservation.ourContribution.Inputs,
194✔
1317
                                        &wire.TxIn{
194✔
1318
                                                PreviousOutPoint: coin.OutPoint,
194✔
1319
                                        },
194✔
1320
                                )
194✔
1321
                        }
194✔
1322
                        reservation.ourContribution.ChangeOutputs = intent.ChangeOutputs
141✔
1323
                }
1324

1325
                reservation.fundingIntent = fundingIntent
150✔
1326
        }
1327

1328
        reservation.nodeAddr = nodeAddr
150✔
1329
        reservation.partialState.IdentityPub = nodeID
150✔
1330

150✔
1331
        var err error
150✔
1332
        reservation.ourContribution.MultiSigKey, err = keyRing.DeriveNextKey(
150✔
1333
                keychain.KeyFamilyMultiSig,
150✔
1334
        )
150✔
1335
        if err != nil {
150✔
1336
                return err
×
1337
        }
×
1338
        reservation.ourContribution.RevocationBasePoint, err = keyRing.DeriveNextKey(
150✔
1339
                keychain.KeyFamilyRevocationBase,
150✔
1340
        )
150✔
1341
        if err != nil {
150✔
1342
                return err
×
1343
        }
×
1344
        reservation.ourContribution.HtlcBasePoint, err = keyRing.DeriveNextKey(
150✔
1345
                keychain.KeyFamilyHtlcBase,
150✔
1346
        )
150✔
1347
        if err != nil {
150✔
1348
                return err
×
1349
        }
×
1350
        reservation.ourContribution.PaymentBasePoint, err = keyRing.DeriveNextKey(
150✔
1351
                keychain.KeyFamilyPaymentBase,
150✔
1352
        )
150✔
1353
        if err != nil {
150✔
1354
                return err
×
1355
        }
×
1356
        reservation.ourContribution.DelayBasePoint, err = keyRing.DeriveNextKey(
150✔
1357
                keychain.KeyFamilyDelayBase,
150✔
1358
        )
150✔
1359
        if err != nil {
150✔
1360
                return err
×
1361
        }
×
1362

1363
        // With the above keys created, we'll also need to initialize our
1364
        // revocation tree state, and from that generate the per-commitment
1365
        // point.
1366
        producer, taprootNonceProducer, err := l.nextRevocationProducer(
150✔
1367
                reservation, keyRing,
150✔
1368
        )
150✔
1369
        if err != nil {
150✔
1370
                return err
×
1371
        }
×
1372

1373
        firstPreimage, err := producer.AtIndex(0)
150✔
1374
        if err != nil {
150✔
1375
                return err
×
1376
        }
×
1377
        reservation.ourContribution.FirstCommitmentPoint = input.ComputeCommitmentPoint(
150✔
1378
                firstPreimage[:],
150✔
1379
        )
150✔
1380

150✔
1381
        reservation.partialState.RevocationProducer = producer
150✔
1382
        reservation.ourContribution.ChannelConstraints.DustLimit =
150✔
1383
                DustLimitUnknownWitness()
150✔
1384

150✔
1385
        // If taproot channels are active, then we'll generate our verification
150✔
1386
        // nonce here. We'll use this nonce to verify the signature for our
150✔
1387
        // local commitment transaction. If we need to force close, then this
150✔
1388
        // is also what'll be used to sign that transaction.
150✔
1389
        if reservation.partialState.ChanType.IsTaproot() {
166✔
1390
                firstNoncePreimage, err := taprootNonceProducer.AtIndex(0)
16✔
1391
                if err != nil {
16✔
1392
                        return err
×
1393
                }
×
1394

1395
                // As we'd like the local nonce we send over to be generated
1396
                // deterministically, we'll provide a custom reader that
1397
                // actually just uses our sha-chain pre-image as the primary
1398
                // randomness source.
1399
                shaChainRand := musig2.WithCustomRand(
16✔
1400
                        bytes.NewBuffer(firstNoncePreimage[:]),
16✔
1401
                )
16✔
1402
                pubKeyOpt := musig2.WithPublicKey(
16✔
1403
                        reservation.ourContribution.MultiSigKey.PubKey,
16✔
1404
                )
16✔
1405
                reservation.ourContribution.LocalNonce, err = musig2.GenNonces(
16✔
1406
                        pubKeyOpt, shaChainRand,
16✔
1407
                )
16✔
1408
                if err != nil {
16✔
1409
                        return err
×
1410
                }
×
1411
        }
1412

1413
        return nil
150✔
1414
}
1415

1416
// handleFundingReserveCancel cancels an existing channel reservation. As part
1417
// of the cancellation, outputs previously selected as inputs for the funding
1418
// transaction via coin selection are freed allowing future reservations to
1419
// include them.
1420
func (l *LightningWallet) handleFundingCancelRequest(req *fundingReserveCancelMsg) {
58✔
1421
        // TODO(roasbeef): holding lock too long
58✔
1422
        l.limboMtx.Lock()
58✔
1423
        defer l.limboMtx.Unlock()
58✔
1424

58✔
1425
        pendingReservation, ok := l.fundingLimbo[req.pendingFundingID]
58✔
1426
        if !ok {
94✔
1427
                // TODO(roasbeef): make new error, "unknown funding state" or something
36✔
1428
                req.err <- fmt.Errorf("attempted to cancel non-existent funding state")
36✔
1429
                return
36✔
1430
        }
36✔
1431

1432
        // Grab the mutex on the ChannelReservation to ensure thread-safety
1433
        pendingReservation.Lock()
22✔
1434
        defer pendingReservation.Unlock()
22✔
1435

22✔
1436
        // Mark all previously locked outpoints as usable for future funding
22✔
1437
        // requests.
22✔
1438
        for _, unusedInput := range pendingReservation.ourContribution.Inputs {
81✔
1439
                delete(l.lockedOutPoints, unusedInput.PreviousOutPoint)
59✔
1440
                _ = l.ReleaseOutput(
59✔
1441
                        chanfunding.LndInternalLockID,
59✔
1442
                        unusedInput.PreviousOutPoint,
59✔
1443
                )
59✔
1444
        }
59✔
1445

1446
        // TODO(roasbeef): is it even worth it to keep track of unused keys?
1447

1448
        // TODO(roasbeef): Is it possible to mark the unused change also as
1449
        // available?
1450

1451
        delete(l.fundingLimbo, req.pendingFundingID)
22✔
1452

22✔
1453
        pid := pendingReservation.pendingChanID
22✔
1454
        delete(l.reservationIDs, pid)
22✔
1455

22✔
1456
        l.intentMtx.Lock()
22✔
1457
        if intent, ok := l.fundingIntents[pid]; ok {
44✔
1458
                intent.Cancel()
22✔
1459

22✔
1460
                delete(l.fundingIntents, pendingReservation.pendingChanID)
22✔
1461
        }
22✔
1462
        l.intentMtx.Unlock()
22✔
1463

22✔
1464
        req.err <- nil
22✔
1465
}
1466

1467
// CreateCommitmentTxns is a helper function that creates the initial
1468
// commitment transaction for both parties. This function is used during the
1469
// initial funding workflow as both sides must generate a signature for the
1470
// remote party's commitment transaction, and verify the signature for their
1471
// version of the commitment transaction.
1472
func CreateCommitmentTxns(localBalance, remoteBalance btcutil.Amount,
1473
        ourChanCfg, theirChanCfg *channeldb.ChannelConfig,
1474
        localCommitPoint, remoteCommitPoint *btcec.PublicKey,
1475
        fundingTxIn wire.TxIn, chanType channeldb.ChannelType, initiator bool,
1476
        leaseExpiry uint32) (*wire.MsgTx, *wire.MsgTx, error) {
386✔
1477

386✔
1478
        localCommitmentKeys := DeriveCommitmentKeys(
386✔
1479
                localCommitPoint, lntypes.Local, chanType, ourChanCfg,
386✔
1480
                theirChanCfg,
386✔
1481
        )
386✔
1482
        remoteCommitmentKeys := DeriveCommitmentKeys(
386✔
1483
                remoteCommitPoint, lntypes.Remote, chanType, ourChanCfg,
386✔
1484
                theirChanCfg,
386✔
1485
        )
386✔
1486

386✔
1487
        ourCommitTx, err := CreateCommitTx(
386✔
1488
                chanType, fundingTxIn, localCommitmentKeys, ourChanCfg,
386✔
1489
                theirChanCfg, localBalance, remoteBalance, 0, initiator,
386✔
1490
                leaseExpiry,
386✔
1491
        )
386✔
1492
        if err != nil {
386✔
1493
                return nil, nil, err
×
1494
        }
×
1495

1496
        otxn := btcutil.NewTx(ourCommitTx)
386✔
1497
        if err := blockchain.CheckTransactionSanity(otxn); err != nil {
386✔
1498
                return nil, nil, err
×
1499
        }
×
1500

1501
        theirCommitTx, err := CreateCommitTx(
386✔
1502
                chanType, fundingTxIn, remoteCommitmentKeys, theirChanCfg,
386✔
1503
                ourChanCfg, remoteBalance, localBalance, 0, !initiator,
386✔
1504
                leaseExpiry,
386✔
1505
        )
386✔
1506
        if err != nil {
386✔
1507
                return nil, nil, err
×
1508
        }
×
1509

1510
        ttxn := btcutil.NewTx(theirCommitTx)
386✔
1511
        if err := blockchain.CheckTransactionSanity(ttxn); err != nil {
386✔
1512
                return nil, nil, err
×
1513
        }
×
1514

1515
        return ourCommitTx, theirCommitTx, nil
386✔
1516
}
1517

1518
// handleContributionMsg processes the second workflow step for the lifetime of
1519
// a channel reservation. Upon completion, the reservation will carry a
1520
// completed funding transaction (minus the counterparty's input signatures),
1521
// both versions of the commitment transaction, and our signature for their
1522
// version of the commitment transaction.
1523
func (l *LightningWallet) handleContributionMsg(req *addContributionMsg) {
49✔
1524

49✔
1525
        l.limboMtx.Lock()
49✔
1526
        pendingReservation, ok := l.fundingLimbo[req.pendingFundingID]
49✔
1527
        l.limboMtx.Unlock()
49✔
1528
        if !ok {
49✔
1529
                req.err <- fmt.Errorf("attempted to update non-existent funding state")
×
1530
                return
×
1531
        }
×
1532

1533
        // Grab the mutex on the ChannelReservation to ensure thread-safety
1534
        pendingReservation.Lock()
49✔
1535
        defer pendingReservation.Unlock()
49✔
1536

49✔
1537
        // If UpfrontShutdownScript is set, validate that it is a valid script.
49✔
1538
        shutdown := req.contribution.UpfrontShutdown
49✔
1539
        if len(shutdown) > 0 {
49✔
1540
                // Validate the shutdown script.
×
1541
                if !ValidateUpfrontShutdown(shutdown, &l.Cfg.NetParams) {
×
1542
                        req.err <- fmt.Errorf("invalid shutdown script")
×
1543
                        return
×
1544
                }
×
1545
        }
1546

1547
        // Some temporary variables to cut down on the resolution verbosity.
1548
        pendingReservation.theirContribution = req.contribution
49✔
1549
        theirContribution := req.contribution
49✔
1550
        ourContribution := pendingReservation.ourContribution
49✔
1551

49✔
1552
        // Perform bounds-checking on both ChannelReserve and DustLimit
49✔
1553
        // parameters.
49✔
1554
        if !pendingReservation.validateReserveBounds() {
49✔
1555
                req.err <- fmt.Errorf("invalid reserve and dust bounds")
×
1556
                return
×
1557
        }
×
1558

1559
        var (
49✔
1560
                chanPoint *wire.OutPoint
49✔
1561
                err       error
49✔
1562
        )
49✔
1563

49✔
1564
        // At this point, we can now construct our channel point. Depending on
49✔
1565
        // which type of intent we obtained from our chanfunding.Assembler,
49✔
1566
        // we'll carry out a distinct set of steps.
49✔
1567
        switch fundingIntent := pendingReservation.fundingIntent.(type) {
49✔
1568
        // The transaction was created outside of the wallet and might already
1569
        // be published. Nothing left to do other than using the correct
1570
        // outpoint.
1571
        case *chanfunding.ShimIntent:
9✔
1572
                chanPoint, err = fundingIntent.ChanPoint()
9✔
1573
                if err != nil {
9✔
1574
                        req.err <- fmt.Errorf("unable to obtain chan point: %w",
×
1575
                                err)
×
1576
                        return
×
1577
                }
×
1578

1579
                pendingReservation.partialState.FundingOutpoint = *chanPoint
9✔
1580

1581
        // The user has signaled that they want to use a PSBT to construct the
1582
        // funding transaction. Because we now have the multisig keys from both
1583
        // parties, we can create the multisig script that needs to be funded
1584
        // and then pause the process until the user supplies the PSBT
1585
        // containing the eventual funding transaction.
1586
        case *chanfunding.PsbtIntent:
4✔
1587
                if fundingIntent.PendingPsbt != nil {
4✔
1588
                        req.err <- fmt.Errorf("PSBT funding already in" +
×
1589
                                "progress")
×
1590
                        return
×
1591
                }
×
1592

1593
                // Now that we know our contribution, we can bind both the local
1594
                // and remote key which will be needed to calculate the multisig
1595
                // funding output in a next step.
1596
                pendingChanID := pendingReservation.pendingChanID
4✔
1597
                walletLog.Debugf("Advancing PSBT funding flow for "+
4✔
1598
                        "pending_id(%x), binding keys local_key=%v, "+
4✔
1599
                        "remote_key=%x", pendingChanID,
4✔
1600
                        &ourContribution.MultiSigKey,
4✔
1601
                        theirContribution.MultiSigKey.PubKey.SerializeCompressed())
4✔
1602
                fundingIntent.BindKeys(
4✔
1603
                        &ourContribution.MultiSigKey,
4✔
1604
                        theirContribution.MultiSigKey.PubKey,
4✔
1605
                )
4✔
1606

4✔
1607
                // Exit early because we can't continue the funding flow yet.
4✔
1608
                req.err <- &PsbtFundingRequired{
4✔
1609
                        Intent: fundingIntent,
4✔
1610
                }
4✔
1611
                return
4✔
1612

1613
        case *chanfunding.FullIntent:
44✔
1614
                // Now that we know their public key, we can bind theirs as
44✔
1615
                // well as ours to the funding intent.
44✔
1616
                fundingIntent.BindKeys(
44✔
1617
                        &pendingReservation.ourContribution.MultiSigKey,
44✔
1618
                        theirContribution.MultiSigKey.PubKey,
44✔
1619
                )
44✔
1620

44✔
1621
                // With our keys bound, we can now construct+sign the final
44✔
1622
                // funding transaction and also obtain the chanPoint that
44✔
1623
                // creates the channel.
44✔
1624
                fundingTx, err := fundingIntent.CompileFundingTx(
44✔
1625
                        theirContribution.Inputs,
44✔
1626
                        theirContribution.ChangeOutputs,
44✔
1627
                )
44✔
1628
                if err != nil {
44✔
1629
                        req.err <- fmt.Errorf("unable to construct funding "+
×
1630
                                "tx: %v", err)
×
1631
                        return
×
1632
                }
×
1633
                chanPoint, err = fundingIntent.ChanPoint()
44✔
1634
                if err != nil {
44✔
1635
                        req.err <- fmt.Errorf("unable to obtain chan "+
×
1636
                                "point: %v", err)
×
1637
                        return
×
1638
                }
×
1639

1640
                // Finally, we'll populate the relevant information in our
1641
                // pendingReservation so the rest of the funding flow can
1642
                // continue as normal.
1643
                pendingReservation.fundingTx = fundingTx
44✔
1644
                pendingReservation.partialState.FundingOutpoint = *chanPoint
44✔
1645
                pendingReservation.ourFundingInputScripts = make(
44✔
1646
                        []*input.Script, 0, len(ourContribution.Inputs),
44✔
1647
                )
44✔
1648
                for _, txIn := range fundingTx.TxIn {
104✔
1649
                        _, err := l.FetchInputInfo(&txIn.PreviousOutPoint)
60✔
1650
                        if err != nil {
60✔
1651
                                continue
×
1652
                        }
1653

1654
                        pendingReservation.ourFundingInputScripts = append(
60✔
1655
                                pendingReservation.ourFundingInputScripts,
60✔
1656
                                &input.Script{
60✔
1657
                                        Witness:   txIn.Witness,
60✔
1658
                                        SigScript: txIn.SignatureScript,
60✔
1659
                                },
60✔
1660
                        )
60✔
1661
                }
1662

1663
                walletLog.Tracef("Funding tx for ChannelPoint(%v) "+
44✔
1664
                        "generated: %v", chanPoint, spew.Sdump(fundingTx))
44✔
1665
        }
1666

1667
        // If we landed here and didn't exit early, it means we already have
1668
        // the channel point ready. We can jump directly to the next step.
1669
        l.handleChanPointReady(&continueContributionMsg{
49✔
1670
                pendingFundingID: req.pendingFundingID,
49✔
1671
                err:              req.err,
49✔
1672
        })
49✔
1673
}
1674

1675
// genMusigSession generates a new musig2 pair session that we can use to sign
1676
// the commitment transaction for the remote party, and verify their incoming
1677
// partial signature.
1678
func genMusigSession(ourContribution, theirContribution *ChannelContribution,
1679
        signer input.MuSig2Signer,
1680
        fundingOutput *wire.TxOut) *MusigPairSession {
16✔
1681

16✔
1682
        return NewMusigPairSession(&MusigSessionCfg{
16✔
1683
                LocalKey:    ourContribution.MultiSigKey,
16✔
1684
                RemoteKey:   theirContribution.MultiSigKey,
16✔
1685
                LocalNonce:  *ourContribution.LocalNonce,
16✔
1686
                RemoteNonce: *theirContribution.LocalNonce,
16✔
1687
                Signer:      signer,
16✔
1688
                InputTxOut:  fundingOutput,
16✔
1689
        })
16✔
1690
}
16✔
1691

1692
// signCommitTx generates a valid input.Signature to send to the remote party
1693
// for their version of the commitment transaction. For regular channels, this
1694
// will be a normal ECDSA signature. For taproot channels, this will instead be
1695
// a musig2 partial signature that also includes the nonce used to generate it.
1696
func (l *LightningWallet) signCommitTx(pendingReservation *ChannelReservation,
1697
        commitTx *wire.MsgTx, fundingOutput *wire.TxOut,
1698
        fundingWitnessScript []byte) (input.Signature, error) {
92✔
1699

92✔
1700
        ourContribution := pendingReservation.ourContribution
92✔
1701
        theirContribution := pendingReservation.theirContribution
92✔
1702

92✔
1703
        var (
92✔
1704
                sigTheirCommit input.Signature
92✔
1705
                err            error
92✔
1706
        )
92✔
1707
        switch {
92✔
1708
        // For regular channels, we can just send over a normal ECDSA signature
1709
        // w/o any extra steps.
1710
        case !pendingReservation.partialState.ChanType.IsTaproot():
80✔
1711
                ourKey := ourContribution.MultiSigKey
80✔
1712
                signDesc := input.SignDescriptor{
80✔
1713
                        WitnessScript: fundingWitnessScript,
80✔
1714
                        KeyDesc:       ourKey,
80✔
1715
                        Output:        fundingOutput,
80✔
1716
                        HashType:      txscript.SigHashAll,
80✔
1717
                        SigHashes: input.NewTxSigHashesV0Only(
80✔
1718
                                commitTx,
80✔
1719
                        ),
80✔
1720
                        InputIndex: 0,
80✔
1721
                }
80✔
1722
                sigTheirCommit, err = l.Cfg.Signer.SignOutputRaw(
80✔
1723
                        commitTx, &signDesc,
80✔
1724
                )
80✔
1725
                if err != nil {
80✔
1726
                        return nil, err
×
1727
                }
×
1728

1729
        // If this is a taproot channel, then we'll need to create an initial
1730
        // musig2 session here as we'll be sending over a _partial_ signature.
1731
        default:
16✔
1732
                // We're now ready to sign the first commitment. However, we'll
16✔
1733
                // only create the session if that hasn't been done already.
16✔
1734
                if pendingReservation.musigSessions == nil {
26✔
1735
                        musigSessions := genMusigSession(
10✔
1736
                                ourContribution, theirContribution,
10✔
1737
                                l.Cfg.Signer, fundingOutput,
10✔
1738
                        )
10✔
1739
                        pendingReservation.musigSessions = musigSessions
10✔
1740
                }
10✔
1741

1742
                // Now that we have the funding outpoint, we'll generate a
1743
                // musig2 signature for their version of the commitment
1744
                // transaction. We use the remote session as this is for the
1745
                // remote commitment transaction.
1746
                musigSessions := pendingReservation.musigSessions
16✔
1747
                partialSig, err := musigSessions.RemoteSession.SignCommit(
16✔
1748
                        commitTx,
16✔
1749
                )
16✔
1750
                if err != nil {
16✔
1751
                        return nil, fmt.Errorf("unable to sign "+
×
1752
                                "commitment: %w", err)
×
1753
                }
×
1754

1755
                sigTheirCommit = partialSig
16✔
1756
        }
1757

1758
        return sigTheirCommit, nil
92✔
1759
}
1760

1761
// handleChanPointReady continues the funding process once the channel point is
1762
// known and the funding transaction can be completed.
1763
func (l *LightningWallet) handleChanPointReady(req *continueContributionMsg) {
49✔
1764
        l.limboMtx.Lock()
49✔
1765
        pendingReservation, ok := l.fundingLimbo[req.pendingFundingID]
49✔
1766
        l.limboMtx.Unlock()
49✔
1767
        if !ok {
49✔
1768
                req.err <- fmt.Errorf("attempted to update non-existent " +
×
1769
                        "funding state")
×
1770
                return
×
1771
        }
×
1772

1773
        ourContribution := pendingReservation.ourContribution
49✔
1774
        theirContribution := pendingReservation.theirContribution
49✔
1775
        chanPoint := pendingReservation.partialState.FundingOutpoint
49✔
1776

49✔
1777
        // If we're in the PSBT funding flow, we now should have everything that
49✔
1778
        // is needed to construct and publish the full funding transaction.
49✔
1779
        intent := pendingReservation.fundingIntent
49✔
1780
        if psbtIntent, ok := intent.(*chanfunding.PsbtIntent); ok {
53✔
1781
                // With our keys bound, we can now construct and possibly sign
4✔
1782
                // the final funding transaction and also obtain the chanPoint
4✔
1783
                // that creates the channel. We _have_ to call CompileFundingTx
4✔
1784
                // even if we don't publish ourselves as that sets the actual
4✔
1785
                // funding outpoint in stone for this channel.
4✔
1786
                fundingTx, err := psbtIntent.CompileFundingTx()
4✔
1787
                if err != nil {
4✔
1788
                        req.err <- fmt.Errorf("unable to construct funding "+
×
1789
                                "tx: %v", err)
×
1790
                        return
×
1791
                }
×
1792
                chanPointPtr, err := psbtIntent.ChanPoint()
4✔
1793
                if err != nil {
4✔
1794
                        req.err <- fmt.Errorf("unable to obtain chan "+
×
1795
                                "point: %v", err)
×
1796
                        return
×
1797
                }
×
1798

1799
                pendingReservation.partialState.FundingOutpoint = *chanPointPtr
4✔
1800
                chanPoint = *chanPointPtr
4✔
1801

4✔
1802
                // Finally, we'll populate the relevant information in our
4✔
1803
                // pendingReservation so the rest of the funding flow can
4✔
1804
                // continue as normal in case we are going to publish ourselves.
4✔
1805
                if psbtIntent.ShouldPublishFundingTX() {
8✔
1806
                        pendingReservation.fundingTx = fundingTx
4✔
1807
                        pendingReservation.ourFundingInputScripts = make(
4✔
1808
                                []*input.Script, 0, len(ourContribution.Inputs),
4✔
1809
                        )
4✔
1810
                        for _, txIn := range fundingTx.TxIn {
8✔
1811
                                pendingReservation.ourFundingInputScripts = append(
4✔
1812
                                        pendingReservation.ourFundingInputScripts,
4✔
1813
                                        &input.Script{
4✔
1814
                                                Witness:   txIn.Witness,
4✔
1815
                                                SigScript: txIn.SignatureScript,
4✔
1816
                                        },
4✔
1817
                                )
4✔
1818
                        }
4✔
1819
                }
1820
        }
1821

1822
        // Initialize an empty sha-chain for them, tracking the current pending
1823
        // revocation hash (we don't yet know the preimage so we can't add it
1824
        // to the chain).
1825
        s := shachain.NewRevocationStore()
49✔
1826
        pendingReservation.partialState.RevocationStore = s
49✔
1827

49✔
1828
        // Store their current commitment point. We'll need this after the
49✔
1829
        // first state transition in order to verify the authenticity of the
49✔
1830
        // revocation.
49✔
1831
        chanState := pendingReservation.partialState
49✔
1832
        chanState.RemoteCurrentRevocation = theirContribution.FirstCommitmentPoint
49✔
1833

49✔
1834
        // Create the txin to our commitment transaction; required to construct
49✔
1835
        // the commitment transactions.
49✔
1836
        fundingTxIn := wire.TxIn{
49✔
1837
                PreviousOutPoint: chanPoint,
49✔
1838
        }
49✔
1839

49✔
1840
        // With the funding tx complete, create both commitment transactions.
49✔
1841
        localBalance := pendingReservation.partialState.LocalCommitment.LocalBalance.ToSatoshis()
49✔
1842
        remoteBalance := pendingReservation.partialState.LocalCommitment.RemoteBalance.ToSatoshis()
49✔
1843
        var leaseExpiry uint32
49✔
1844
        if pendingReservation.partialState.ChanType.HasLeaseExpiration() {
53✔
1845
                leaseExpiry = pendingReservation.partialState.ThawHeight
4✔
1846
        }
4✔
1847
        ourCommitTx, theirCommitTx, err := CreateCommitmentTxns(
49✔
1848
                localBalance, remoteBalance, ourContribution.ChannelConfig,
49✔
1849
                theirContribution.ChannelConfig,
49✔
1850
                ourContribution.FirstCommitmentPoint,
49✔
1851
                theirContribution.FirstCommitmentPoint, fundingTxIn,
49✔
1852
                pendingReservation.partialState.ChanType,
49✔
1853
                pendingReservation.partialState.IsInitiator, leaseExpiry,
49✔
1854
        )
49✔
1855
        if err != nil {
49✔
1856
                req.err <- err
×
1857
                return
×
1858
        }
×
1859

1860
        // With both commitment transactions constructed, generate the state
1861
        // obfuscator then use it to encode the current state number within
1862
        // both commitment transactions.
1863
        var stateObfuscator [StateHintSize]byte
49✔
1864
        if chanState.ChanType.IsSingleFunder() {
98✔
1865
                stateObfuscator = DeriveStateHintObfuscator(
49✔
1866
                        ourContribution.PaymentBasePoint.PubKey,
49✔
1867
                        theirContribution.PaymentBasePoint.PubKey,
49✔
1868
                )
49✔
1869
        } else {
49✔
1870
                ourSer := ourContribution.PaymentBasePoint.PubKey.SerializeCompressed()
×
1871
                theirSer := theirContribution.PaymentBasePoint.PubKey.SerializeCompressed()
×
1872
                switch bytes.Compare(ourSer, theirSer) {
×
1873
                case -1:
×
1874
                        stateObfuscator = DeriveStateHintObfuscator(
×
1875
                                ourContribution.PaymentBasePoint.PubKey,
×
1876
                                theirContribution.PaymentBasePoint.PubKey,
×
1877
                        )
×
1878
                default:
×
1879
                        stateObfuscator = DeriveStateHintObfuscator(
×
1880
                                theirContribution.PaymentBasePoint.PubKey,
×
1881
                                ourContribution.PaymentBasePoint.PubKey,
×
1882
                        )
×
1883
                }
1884
        }
1885
        err = initStateHints(ourCommitTx, theirCommitTx, stateObfuscator)
49✔
1886
        if err != nil {
49✔
1887
                req.err <- err
×
1888
                return
×
1889
        }
×
1890

1891
        // Sort both transactions according to the agreed upon canonical
1892
        // ordering. This lets us skip sending the entire transaction over,
1893
        // instead we'll just send signatures.
1894
        txsort.InPlaceSort(ourCommitTx)
49✔
1895
        txsort.InPlaceSort(theirCommitTx)
49✔
1896

49✔
1897
        walletLog.Tracef("Local commit tx for ChannelPoint(%v): %v",
49✔
1898
                chanPoint, spew.Sdump(ourCommitTx))
49✔
1899
        walletLog.Tracef("Remote commit tx for ChannelPoint(%v): %v",
49✔
1900
                chanPoint, spew.Sdump(theirCommitTx))
49✔
1901

49✔
1902
        // Record newly available information within the open channel state.
49✔
1903
        chanState.FundingOutpoint = chanPoint
49✔
1904
        chanState.LocalCommitment.CommitTx = ourCommitTx
49✔
1905
        chanState.RemoteCommitment.CommitTx = theirCommitTx
49✔
1906

49✔
1907
        // Next, we'll obtain the funding witness script, and the funding
49✔
1908
        // output itself so we can generate a valid signature for the remote
49✔
1909
        // party.
49✔
1910
        fundingIntent := pendingReservation.fundingIntent
49✔
1911
        fundingWitnessScript, fundingOutput, err := fundingIntent.FundingOutput()
49✔
1912
        if err != nil {
49✔
1913
                req.err <- fmt.Errorf("unable to obtain funding "+
×
1914
                        "output: %w", err)
×
1915
                return
×
1916
        }
×
1917

1918
        // Generate a signature for their version of the initial commitment
1919
        // transaction.
1920
        sigTheirCommit, err := l.signCommitTx(
49✔
1921
                pendingReservation, theirCommitTx, fundingOutput,
49✔
1922
                fundingWitnessScript,
49✔
1923
        )
49✔
1924
        if err != nil {
49✔
1925
                req.err <- err
×
1926
                return
×
1927
        }
×
1928

1929
        pendingReservation.ourCommitmentSig = sigTheirCommit
49✔
1930

49✔
1931
        req.err <- nil
49✔
1932
}
1933

1934
// handleSingleContribution is called as the second step to a single funder
1935
// workflow to which we are the responder. It simply saves the remote peer's
1936
// contribution to the channel, as solely the remote peer will contribute any
1937
// funds to the channel.
1938
func (l *LightningWallet) handleSingleContribution(req *addSingleContributionMsg) {
66✔
1939
        l.limboMtx.Lock()
66✔
1940
        pendingReservation, ok := l.fundingLimbo[req.pendingFundingID]
66✔
1941
        l.limboMtx.Unlock()
66✔
1942
        if !ok {
66✔
1943
                req.err <- fmt.Errorf("attempted to update non-existent funding state")
×
1944
                return
×
1945
        }
×
1946

1947
        // Grab the mutex on the channelReservation to ensure thread-safety.
1948
        pendingReservation.Lock()
66✔
1949
        defer pendingReservation.Unlock()
66✔
1950

66✔
1951
        // Validate that the remote's UpfrontShutdownScript is a valid script
66✔
1952
        // if it's set.
66✔
1953
        shutdown := req.contribution.UpfrontShutdown
66✔
1954
        if len(shutdown) > 0 {
78✔
1955
                // Validate the shutdown script.
12✔
1956
                if !ValidateUpfrontShutdown(shutdown, &l.Cfg.NetParams) {
18✔
1957
                        req.err <- fmt.Errorf("invalid shutdown script")
6✔
1958
                        return
6✔
1959
                }
6✔
1960
        }
1961

1962
        // Simply record the counterparty's contribution into the pending
1963
        // reservation data as they'll be solely funding the channel entirely.
1964
        pendingReservation.theirContribution = req.contribution
60✔
1965
        theirContribution := pendingReservation.theirContribution
60✔
1966
        chanState := pendingReservation.partialState
60✔
1967

60✔
1968
        // Perform bounds checking on both ChannelReserve and DustLimit
60✔
1969
        // parameters. The ChannelReserve may have been changed by the
60✔
1970
        // ChannelAcceptor RPC, so this is necessary.
60✔
1971
        if !pendingReservation.validateReserveBounds() {
60✔
1972
                req.err <- fmt.Errorf("invalid reserve and dust bounds")
×
1973
                return
×
1974
        }
×
1975

1976
        // Initialize an empty sha-chain for them, tracking the current pending
1977
        // revocation hash (we don't yet know the preimage so we can't add it
1978
        // to the chain).
1979
        remotePreimageStore := shachain.NewRevocationStore()
60✔
1980
        chanState.RevocationStore = remotePreimageStore
60✔
1981

60✔
1982
        // Now that we've received their first commitment point, we'll store it
60✔
1983
        // within the channel state so we can sync it to disk once the funding
60✔
1984
        // process is complete.
60✔
1985
        chanState.RemoteCurrentRevocation = theirContribution.FirstCommitmentPoint
60✔
1986

60✔
1987
        req.err <- nil
60✔
1988
}
1989

1990
// verifyFundingInputs attempts to verify all remote inputs to the funding
1991
// transaction.
1992
func (l *LightningWallet) verifyFundingInputs(fundingTx *wire.MsgTx,
1993
        remoteInputScripts []*input.Script) error {
42✔
1994

42✔
1995
        sigIndex := 0
42✔
1996
        fundingHashCache := input.NewTxSigHashesV0Only(fundingTx)
42✔
1997
        inputScripts := remoteInputScripts
42✔
1998
        for i, txin := range fundingTx.TxIn {
100✔
1999
                if len(inputScripts) != 0 && len(txin.Witness) == 0 {
58✔
2000
                        // Attach the input scripts so we can verify it below.
×
2001
                        txin.Witness = inputScripts[sigIndex].Witness
×
2002
                        txin.SignatureScript = inputScripts[sigIndex].SigScript
×
2003

×
2004
                        // Fetch the alleged previous output along with the
×
2005
                        // pkscript referenced by this input.
×
2006
                        //
×
2007
                        // TODO(roasbeef): when dual funder pass actual
×
2008
                        // height-hint
×
2009
                        //
×
2010
                        // TODO(roasbeef): this fails for neutrino always as it
×
2011
                        // treats the height hint as an exact birthday of the
×
2012
                        // utxo rather than a lower bound
×
2013
                        pkScript, err := txscript.ComputePkScript(
×
2014
                                txin.SignatureScript, txin.Witness,
×
2015
                        )
×
2016
                        if err != nil {
×
2017
                                return fmt.Errorf("cannot create script: %w",
×
2018
                                        err)
×
2019
                        }
×
2020
                        output, err := l.Cfg.ChainIO.GetUtxo(
×
2021
                                &txin.PreviousOutPoint,
×
2022
                                pkScript.Script(), 0, l.quit,
×
2023
                        )
×
2024
                        if output == nil {
×
2025
                                return fmt.Errorf("input to funding tx does "+
×
2026
                                        "not exist: %v", err)
×
2027
                        }
×
2028

2029
                        // Ensure that the witness+sigScript combo is valid.
2030
                        vm, err := txscript.NewEngine(
×
2031
                                output.PkScript, fundingTx, i,
×
2032
                                txscript.StandardVerifyFlags, nil,
×
2033
                                fundingHashCache, output.Value,
×
2034
                                txscript.NewCannedPrevOutputFetcher(
×
2035
                                        output.PkScript, output.Value,
×
2036
                                ),
×
2037
                        )
×
2038
                        if err != nil {
×
2039
                                return fmt.Errorf("cannot create script "+
×
2040
                                        "engine: %s", err)
×
2041
                        }
×
2042
                        if err = vm.Execute(); err != nil {
×
2043
                                return fmt.Errorf("cannot validate "+
×
2044
                                        "transaction: %s", err)
×
2045
                        }
×
2046

2047
                        sigIndex++
×
2048
                }
2049
        }
2050

2051
        return nil
42✔
2052
}
2053

2054
// verifyCommitSig verifies an incoming signature for our version of the
2055
// commitment transaction. For normal channels, this will verify that the ECDSA
2056
// signature is valid. For taproot channels, we'll verify that their partial
2057
// signature is valid, so it can properly be combined with our eventual
2058
// signature when we need to broadcast.
2059
func (l *LightningWallet) verifyCommitSig(res *ChannelReservation,
2060
        commitSig input.Signature, commitTx *wire.MsgTx) error {
90✔
2061

90✔
2062
        localKey := res.ourContribution.MultiSigKey.PubKey
90✔
2063
        remoteKey := res.theirContribution.MultiSigKey.PubKey
90✔
2064
        channelValue := int64(res.partialState.Capacity)
90✔
2065

90✔
2066
        switch {
90✔
2067
        // If this isn't a taproot channel, then we'll construct a segwit v0
2068
        // p2wsh sighash.
2069
        case !res.partialState.ChanType.IsTaproot():
78✔
2070
                hashCache := input.NewTxSigHashesV0Only(commitTx)
78✔
2071
                witnessScript, _, err := input.GenFundingPkScript(
78✔
2072
                        localKey.SerializeCompressed(),
78✔
2073
                        remoteKey.SerializeCompressed(), channelValue,
78✔
2074
                )
78✔
2075
                if err != nil {
78✔
2076
                        return err
×
2077
                }
×
2078

2079
                sigHash, err := txscript.CalcWitnessSigHash(
78✔
2080
                        witnessScript, hashCache, txscript.SigHashAll,
78✔
2081
                        commitTx, 0, channelValue,
78✔
2082
                )
78✔
2083
                if err != nil {
78✔
2084
                        return err
×
2085
                }
×
2086

2087
                // Verify that we've received a valid signature from the remote
2088
                // party for our version of the commitment transaction.
2089
                if !commitSig.Verify(sigHash, remoteKey) {
78✔
2090
                        return fmt.Errorf("counterparty's commitment " +
×
2091
                                "signature is invalid")
×
2092
                }
×
2093

2094
                return nil
78✔
2095

2096
        // Otherwise for taproot channels, we'll compute the segwit v1 sighash,
2097
        // which is slightly different.
2098
        default:
16✔
2099
                // First, check to see if we've generated the musig session
16✔
2100
                // already. If we're the responder in the funding flow, we may
16✔
2101
                // not have generated it already.
16✔
2102
                if res.musigSessions == nil {
26✔
2103
                        _, fundingOutput, err := input.GenTaprootFundingScript(
10✔
2104
                                localKey, remoteKey, channelValue,
10✔
2105
                        )
10✔
2106
                        if err != nil {
10✔
2107
                                return err
×
2108
                        }
×
2109

2110
                        res.musigSessions = genMusigSession(
10✔
2111
                                res.ourContribution, res.theirContribution,
10✔
2112
                                l.Cfg.Signer, fundingOutput,
10✔
2113
                        )
10✔
2114
                }
2115

2116
                // For the musig2 based channels, we'll use the generated local
2117
                // musig2 session to verify the signature.
2118
                localSession := res.musigSessions.LocalSession
16✔
2119

16✔
2120
                // At this point, the commitment signature passed in should
16✔
2121
                // actually be a wrapped musig2 signature, so we'll do a type
16✔
2122
                // asset to the get the signature we actually need.
16✔
2123
                partialSig, ok := commitSig.(*MusigPartialSig)
16✔
2124
                if !ok {
16✔
2125
                        return fmt.Errorf("expected *musig2.PartialSignature, "+
×
2126
                                "got: %T", commitSig)
×
2127
                }
×
2128

2129
                _, err := localSession.VerifyCommitSig(
16✔
2130
                        commitTx, partialSig.ToWireSig(),
16✔
2131
                )
16✔
2132

16✔
2133
                return err
16✔
2134
        }
2135
}
2136

2137
// handleFundingCounterPartySigs is the final step in the channel reservation
2138
// workflow. During this step, we validate *all* the received signatures for
2139
// inputs to the funding transaction. If any of these are invalid, we bail,
2140
// and forcibly cancel this funding request. Additionally, we ensure that the
2141
// signature we received from the counterparty for our version of the commitment
2142
// transaction allows us to spend from the funding output with the addition of
2143
// our signature.
2144
func (l *LightningWallet) handleFundingCounterPartySigs(msg *addCounterPartySigsMsg) {
47✔
2145
        l.limboMtx.RLock()
47✔
2146
        res, ok := l.fundingLimbo[msg.pendingFundingID]
47✔
2147
        l.limboMtx.RUnlock()
47✔
2148
        if !ok {
47✔
2149
                msg.err <- fmt.Errorf("attempted to update non-existent funding state")
×
2150
                return
×
2151
        }
×
2152

2153
        // Grab the mutex on the ChannelReservation to ensure thread-safety
2154
        res.Lock()
47✔
2155
        defer res.Unlock()
47✔
2156

47✔
2157
        // Now we can complete the funding transaction by adding their
47✔
2158
        // signatures to their inputs.
47✔
2159
        res.theirFundingInputScripts = msg.theirFundingInputScripts
47✔
2160
        inputScripts := msg.theirFundingInputScripts
47✔
2161

47✔
2162
        // Only if we have the final funding transaction do we need to verify
47✔
2163
        // the final set of inputs. Otherwise, it may be the case that the
47✔
2164
        // channel was funded via an external wallet.
47✔
2165
        fundingTx := res.fundingTx
47✔
2166
        if res.partialState.ChanType.HasFundingTx() {
89✔
2167
                err := l.verifyFundingInputs(fundingTx, inputScripts)
42✔
2168
                if err != nil {
42✔
2169
                        msg.err <- err
×
2170
                        msg.completeChan <- nil
×
2171
                        return
×
2172
                }
×
2173
        }
2174

2175
        // At this point, we can also record and verify their signature for our
2176
        // commitment transaction.
2177
        res.theirCommitmentSig = msg.theirCommitmentSig
47✔
2178
        commitTx := res.partialState.LocalCommitment.CommitTx
47✔
2179

47✔
2180
        err := l.verifyCommitSig(res, msg.theirCommitmentSig, commitTx)
47✔
2181
        if err != nil {
47✔
2182
                msg.err <- fmt.Errorf("counterparty's commitment signature is "+
×
2183
                        "invalid: %w", err)
×
2184
                msg.completeChan <- nil
×
2185
                return
×
2186
        }
×
2187

2188
        theirCommitSigBytes := msg.theirCommitmentSig.Serialize()
47✔
2189
        res.partialState.LocalCommitment.CommitSig = theirCommitSigBytes
47✔
2190

47✔
2191
        // Funding complete, this entry can be removed from limbo.
47✔
2192
        l.limboMtx.Lock()
47✔
2193
        delete(l.fundingLimbo, res.reservationID)
47✔
2194
        delete(l.reservationIDs, res.pendingChanID)
47✔
2195
        l.limboMtx.Unlock()
47✔
2196

47✔
2197
        l.intentMtx.Lock()
47✔
2198
        delete(l.fundingIntents, res.pendingChanID)
47✔
2199
        l.intentMtx.Unlock()
47✔
2200

47✔
2201
        // As we're about to broadcast the funding transaction, we'll take note
47✔
2202
        // of the current height for record keeping purposes.
47✔
2203
        //
47✔
2204
        // TODO(roasbeef): this info can also be piped into light client's
47✔
2205
        // basic fee estimation?
47✔
2206
        _, bestHeight, err := l.Cfg.ChainIO.GetBestBlock()
47✔
2207
        if err != nil {
47✔
2208
                msg.err <- err
×
2209
                msg.completeChan <- nil
×
2210
                return
×
2211
        }
×
2212

2213
        // As we've completed the funding process, we'll no convert the
2214
        // contribution structs into their underlying channel config objects to
2215
        // he stored within the database.
2216
        res.partialState.LocalChanCfg = res.ourContribution.toChanConfig()
47✔
2217
        res.partialState.RemoteChanCfg = res.theirContribution.toChanConfig()
47✔
2218

47✔
2219
        // We'll also record the finalized funding txn, which will allow us to
47✔
2220
        // rebroadcast on startup in case we fail.
47✔
2221
        res.partialState.FundingTxn = fundingTx
47✔
2222

47✔
2223
        // Set optional upfront shutdown scripts on the channel state so that they
47✔
2224
        // are persisted. These values may be nil.
47✔
2225
        res.partialState.LocalShutdownScript =
47✔
2226
                res.ourContribution.UpfrontShutdown
47✔
2227
        res.partialState.RemoteShutdownScript =
47✔
2228
                res.theirContribution.UpfrontShutdown
47✔
2229

47✔
2230
        res.partialState.RevocationKeyLocator = res.nextRevocationKeyLoc
47✔
2231

47✔
2232
        // Add the complete funding transaction to the DB, in its open bucket
47✔
2233
        // which will be used for the lifetime of this channel.
47✔
2234
        nodeAddr := res.nodeAddr
47✔
2235
        err = res.partialState.SyncPending(nodeAddr, uint32(bestHeight))
47✔
2236
        if err != nil {
47✔
2237
                msg.err <- err
×
2238
                msg.completeChan <- nil
×
2239
                return
×
2240
        }
×
2241

2242
        msg.completeChan <- res.partialState
47✔
2243
        msg.err <- nil
47✔
2244
}
2245

2246
// handleSingleFunderSigs is called once the remote peer who initiated the
2247
// single funder workflow has assembled the funding transaction, and generated
2248
// a signature for our version of the commitment transaction. This method
2249
// progresses the workflow by generating a signature for the remote peer's
2250
// version of the commitment transaction.
2251
func (l *LightningWallet) handleSingleFunderSigs(req *addSingleFunderSigsMsg) {
47✔
2252
        l.limboMtx.RLock()
47✔
2253
        pendingReservation, ok := l.fundingLimbo[req.pendingFundingID]
47✔
2254
        l.limboMtx.RUnlock()
47✔
2255
        if !ok {
47✔
2256
                req.err <- fmt.Errorf("attempted to update non-existent funding state")
×
2257
                req.completeChan <- nil
×
2258
                return
×
2259
        }
×
2260

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

47✔
2265
        chanState := pendingReservation.partialState
47✔
2266
        chanType := pendingReservation.partialState.ChanType
47✔
2267
        chanState.FundingOutpoint = *req.fundingOutpoint
47✔
2268
        fundingTxIn := wire.NewTxIn(req.fundingOutpoint, nil, nil)
47✔
2269

47✔
2270
        // Now that we have the funding outpoint, we can generate both versions
47✔
2271
        // of the commitment transaction, and generate a signature for the
47✔
2272
        // remote node's commitment transactions.
47✔
2273
        localBalance := pendingReservation.partialState.LocalCommitment.LocalBalance.ToSatoshis()
47✔
2274
        remoteBalance := pendingReservation.partialState.LocalCommitment.RemoteBalance.ToSatoshis()
47✔
2275
        var leaseExpiry uint32
47✔
2276
        if pendingReservation.partialState.ChanType.HasLeaseExpiration() {
51✔
2277
                leaseExpiry = pendingReservation.partialState.ThawHeight
4✔
2278
        }
4✔
2279
        ourCommitTx, theirCommitTx, err := CreateCommitmentTxns(
47✔
2280
                localBalance, remoteBalance,
47✔
2281
                pendingReservation.ourContribution.ChannelConfig,
47✔
2282
                pendingReservation.theirContribution.ChannelConfig,
47✔
2283
                pendingReservation.ourContribution.FirstCommitmentPoint,
47✔
2284
                pendingReservation.theirContribution.FirstCommitmentPoint,
47✔
2285
                *fundingTxIn, chanType,
47✔
2286
                pendingReservation.partialState.IsInitiator, leaseExpiry,
47✔
2287
        )
47✔
2288
        if err != nil {
47✔
2289
                req.err <- err
×
2290
                req.completeChan <- nil
×
2291
                return
×
2292
        }
×
2293

2294
        // With both commitment transactions constructed, we can now use the
2295
        // generator state obfuscator to encode the current state number within
2296
        // both commitment transactions.
2297
        stateObfuscator := DeriveStateHintObfuscator(
47✔
2298
                pendingReservation.theirContribution.PaymentBasePoint.PubKey,
47✔
2299
                pendingReservation.ourContribution.PaymentBasePoint.PubKey,
47✔
2300
        )
47✔
2301
        err = initStateHints(ourCommitTx, theirCommitTx, stateObfuscator)
47✔
2302
        if err != nil {
47✔
2303
                req.err <- err
×
2304
                req.completeChan <- nil
×
2305
                return
×
2306
        }
×
2307

2308
        // Sort both transactions according to the agreed upon canonical
2309
        // ordering. This ensures that both parties sign the same sighash
2310
        // without further synchronization.
2311
        txsort.InPlaceSort(ourCommitTx)
47✔
2312
        txsort.InPlaceSort(theirCommitTx)
47✔
2313
        chanState.LocalCommitment.CommitTx = ourCommitTx
47✔
2314
        chanState.RemoteCommitment.CommitTx = theirCommitTx
47✔
2315

47✔
2316
        walletLog.Debugf("Local commit tx for ChannelPoint(%v): %v",
47✔
2317
                req.fundingOutpoint, spew.Sdump(ourCommitTx))
47✔
2318
        walletLog.Debugf("Remote commit tx for ChannelPoint(%v): %v",
47✔
2319
                req.fundingOutpoint, spew.Sdump(theirCommitTx))
47✔
2320

47✔
2321
        // With both commitment transactions created, we'll now verify their
47✔
2322
        // signature on our commitment.
47✔
2323
        err = l.verifyCommitSig(
47✔
2324
                pendingReservation, req.theirCommitmentSig, ourCommitTx,
47✔
2325
        )
47✔
2326
        if err != nil {
47✔
2327
                req.err <- err
×
2328
                req.completeChan <- nil
×
2329
                return
×
2330
        }
×
2331

2332
        theirCommitSigBytes := req.theirCommitmentSig.Serialize()
47✔
2333
        chanState.LocalCommitment.CommitSig = theirCommitSigBytes
47✔
2334

47✔
2335
        channelValue := int64(pendingReservation.partialState.Capacity)
47✔
2336
        theirKey := pendingReservation.theirContribution.MultiSigKey
47✔
2337
        ourKey := pendingReservation.ourContribution.MultiSigKey
47✔
2338

47✔
2339
        var (
47✔
2340
                fundingWitnessScript []byte
47✔
2341
                fundingTxOut         *wire.TxOut
47✔
2342
        )
47✔
2343
        if chanType.IsTaproot() {
57✔
2344
                fundingWitnessScript, fundingTxOut, err = input.GenTaprootFundingScript( //nolint:lll
10✔
2345
                        ourKey.PubKey, theirKey.PubKey, channelValue,
10✔
2346
                )
10✔
2347
        } else {
51✔
2348
                fundingWitnessScript, fundingTxOut, err = input.GenFundingPkScript( //nolint:lll
41✔
2349
                        ourKey.PubKey.SerializeCompressed(),
41✔
2350
                        theirKey.PubKey.SerializeCompressed(), channelValue,
41✔
2351
                )
41✔
2352
        }
41✔
2353
        if err != nil {
47✔
2354
                req.err <- err
×
2355
                req.completeChan <- nil
×
2356
                return
×
2357
        }
×
2358

2359
        // With their signature for our version of the commitment transactions
2360
        // verified, we can now generate a signature for their version,
2361
        // allowing the funding transaction to be safely broadcast.
2362
        sigTheirCommit, err := l.signCommitTx(
47✔
2363
                pendingReservation, theirCommitTx, fundingTxOut,
47✔
2364
                fundingWitnessScript,
47✔
2365
        )
47✔
2366
        if err != nil {
47✔
2367
                req.err <- err
×
2368
                req.completeChan <- nil
×
2369
                return
×
2370
        }
×
2371

2372
        pendingReservation.ourCommitmentSig = sigTheirCommit
47✔
2373

47✔
2374
        _, bestHeight, err := l.Cfg.ChainIO.GetBestBlock()
47✔
2375
        if err != nil {
47✔
2376
                req.err <- err
×
2377
                req.completeChan <- nil
×
2378
                return
×
2379
        }
×
2380

2381
        // Set optional upfront shutdown scripts on the channel state so that they
2382
        // are persisted. These values may be nil.
2383
        chanState.LocalShutdownScript =
47✔
2384
                pendingReservation.ourContribution.UpfrontShutdown
47✔
2385
        chanState.RemoteShutdownScript =
47✔
2386
                pendingReservation.theirContribution.UpfrontShutdown
47✔
2387

47✔
2388
        // Add the complete funding transaction to the DB, in it's open bucket
47✔
2389
        // which will be used for the lifetime of this channel.
47✔
2390
        chanState.LocalChanCfg = pendingReservation.ourContribution.toChanConfig()
47✔
2391
        chanState.RemoteChanCfg = pendingReservation.theirContribution.toChanConfig()
47✔
2392

47✔
2393
        chanState.RevocationKeyLocator = pendingReservation.nextRevocationKeyLoc
47✔
2394

47✔
2395
        err = chanState.SyncPending(pendingReservation.nodeAddr, uint32(bestHeight))
47✔
2396
        if err != nil {
47✔
2397
                req.err <- err
×
2398
                req.completeChan <- nil
×
2399
                return
×
2400
        }
×
2401

2402
        req.completeChan <- chanState
47✔
2403
        req.err <- nil
47✔
2404

47✔
2405
        l.limboMtx.Lock()
47✔
2406
        delete(l.fundingLimbo, req.pendingFundingID)
47✔
2407
        delete(l.reservationIDs, pendingReservation.pendingChanID)
47✔
2408
        l.limboMtx.Unlock()
47✔
2409

47✔
2410
        l.intentMtx.Lock()
47✔
2411
        delete(l.fundingIntents, pendingReservation.pendingChanID)
47✔
2412
        l.intentMtx.Unlock()
47✔
2413
}
2414

2415
// WithCoinSelectLock will execute the passed function closure in a
2416
// synchronized manner preventing any coin selection operations from proceeding
2417
// while the closure is executing. This can be seen as the ability to execute a
2418
// function closure under an exclusive coin selection lock.
2419
func (l *LightningWallet) WithCoinSelectLock(f func() error) error {
232✔
2420
        l.coinSelectMtx.Lock()
232✔
2421
        defer l.coinSelectMtx.Unlock()
232✔
2422

232✔
2423
        return f()
232✔
2424
}
232✔
2425

2426
// DeriveStateHintObfuscator derives the bytes to be used for obfuscating the
2427
// state hints from the root to be used for a new channel. The obfuscator is
2428
// generated via the following computation:
2429
//
2430
//   - sha256(initiatorKey || responderKey)[26:]
2431
//     -- where both keys are the multi-sig keys of the respective parties
2432
//
2433
// The first 6 bytes of the resulting hash are used as the state hint.
2434
func DeriveStateHintObfuscator(key1, key2 *btcec.PublicKey) [StateHintSize]byte {
1,041✔
2435
        h := sha256.New()
1,041✔
2436
        h.Write(key1.SerializeCompressed())
1,041✔
2437
        h.Write(key2.SerializeCompressed())
1,041✔
2438

1,041✔
2439
        sha := h.Sum(nil)
1,041✔
2440

1,041✔
2441
        var obfuscator [StateHintSize]byte
1,041✔
2442
        copy(obfuscator[:], sha[26:])
1,041✔
2443

1,041✔
2444
        return obfuscator
1,041✔
2445
}
1,041✔
2446

2447
// initStateHints properly sets the obfuscated state hints on both commitment
2448
// transactions using the passed obfuscator.
2449
func initStateHints(commit1, commit2 *wire.MsgTx,
2450
        obfuscator [StateHintSize]byte) error {
92✔
2451

92✔
2452
        if err := SetStateNumHint(commit1, 0, obfuscator); err != nil {
92✔
2453
                return err
×
2454
        }
×
2455
        if err := SetStateNumHint(commit2, 0, obfuscator); err != nil {
92✔
2456
                return err
×
2457
        }
×
2458

2459
        return nil
92✔
2460
}
2461

2462
// ValidateChannel will attempt to fully validate a newly mined channel, given
2463
// its funding transaction and existing channel state. If this method returns
2464
// an error, then the mined channel is invalid, and shouldn't be used.
2465
func (l *LightningWallet) ValidateChannel(channelState *channeldb.OpenChannel,
2466
        fundingTx *wire.MsgTx) error {
38✔
2467

38✔
2468
        // First, we'll obtain a fully signed commitment transaction so we can
38✔
2469
        // pass into it on the chanvalidate package for verification.
38✔
2470
        channel, err := NewLightningChannel(l.Cfg.Signer, channelState, nil)
38✔
2471
        if err != nil {
38✔
2472
                return err
×
2473
        }
×
2474

2475
        localKey := channelState.LocalChanCfg.MultiSigKey.PubKey
38✔
2476
        remoteKey := channelState.RemoteChanCfg.MultiSigKey.PubKey
38✔
2477

38✔
2478
        // We'll also need the multi-sig witness script itself so the
38✔
2479
        // chanvalidate package can check it for correctness against the
38✔
2480
        // funding transaction, and also commitment validity.
38✔
2481
        var fundingScript []byte
38✔
2482
        if channelState.ChanType.IsTaproot() {
46✔
2483
                fundingScript, _, err = input.GenTaprootFundingScript(
8✔
2484
                        localKey, remoteKey, int64(channel.Capacity),
8✔
2485
                )
8✔
2486
                if err != nil {
8✔
2487
                        return err
×
2488
                }
×
2489
        } else {
34✔
2490
                witnessScript, err := input.GenMultiSigScript(
34✔
2491
                        localKey.SerializeCompressed(),
34✔
2492
                        remoteKey.SerializeCompressed(),
34✔
2493
                )
34✔
2494
                if err != nil {
34✔
2495
                        return err
×
2496
                }
×
2497
                fundingScript, err = input.WitnessScriptHash(witnessScript)
34✔
2498
                if err != nil {
34✔
2499
                        return err
×
2500
                }
×
2501
        }
2502

2503
        signedCommitTx, err := channel.getSignedCommitTx()
38✔
2504
        if err != nil {
38✔
2505
                return err
×
2506
        }
×
2507
        commitCtx := &chanvalidate.CommitmentContext{
38✔
2508
                Value:               channel.Capacity,
38✔
2509
                FullySignedCommitTx: signedCommitTx,
38✔
2510
        }
38✔
2511

38✔
2512
        // Finally, we'll pass in all the necessary context needed to fully
38✔
2513
        // validate that this channel is indeed what we expect, and can be
38✔
2514
        // used.
38✔
2515
        _, err = chanvalidate.Validate(&chanvalidate.Context{
38✔
2516
                Locator: &chanvalidate.OutPointChanLocator{
38✔
2517
                        ChanPoint: channelState.FundingOutpoint,
38✔
2518
                },
38✔
2519
                MultiSigPkScript: fundingScript,
38✔
2520
                FundingTx:        fundingTx,
38✔
2521
                CommitCtx:        commitCtx,
38✔
2522
        })
38✔
2523
        if err != nil {
38✔
2524
                return err
×
2525
        }
×
2526

2527
        return nil
38✔
2528
}
2529

2530
// CancelRebroadcast cancels the rebroadcast of the given transaction.
2531
func (l *LightningWallet) CancelRebroadcast(txid chainhash.Hash) {
4✔
2532
        // For neutrino, we don't config the rebroadcaster for the wallet as it
4✔
2533
        // manages the rebroadcasting logic in neutrino itself.
4✔
2534
        if l.Cfg.Rebroadcaster != nil {
7✔
2535
                l.Cfg.Rebroadcaster.MarkAsConfirmed(txid)
3✔
2536
        }
3✔
2537
}
2538

2539
// CoinSource is a wrapper around the wallet that implements the
2540
// chanfunding.CoinSource interface.
2541
type CoinSource struct {
2542
        wallet    *LightningWallet
2543
        allowUtxo func(Utxo) bool
2544
}
2545

2546
// NewCoinSource creates a new instance of the CoinSource wrapper struct.
2547
func NewCoinSource(w *LightningWallet, allowUtxo func(Utxo) bool) *CoinSource {
153✔
2548
        return &CoinSource{
153✔
2549
                wallet:    w,
153✔
2550
                allowUtxo: allowUtxo,
153✔
2551
        }
153✔
2552
}
153✔
2553

2554
// ListCoins returns all UTXOs from the source that have between
2555
// minConfs and maxConfs number of confirmations.
2556
func (c *CoinSource) ListCoins(minConfs int32,
2557
        maxConfs int32) ([]wallet.Coin, error) {
150✔
2558

150✔
2559
        utxos, err := c.wallet.ListUnspentWitnessFromDefaultAccount(
150✔
2560
                minConfs, maxConfs,
150✔
2561
        )
150✔
2562
        if err != nil {
150✔
2563
                return nil, err
×
2564
        }
×
2565

2566
        var coins []wallet.Coin
150✔
2567

150✔
2568
        for _, utxo := range utxos {
935✔
2569
                // If there is a filter function supplied all utxos not adhering
785✔
2570
                // to these conditions will be discarded.
785✔
2571
                if c.allowUtxo != nil && !c.allowUtxo(*utxo) {
789✔
2572
                        walletLog.Infof("Cannot use unconfirmed "+
4✔
2573
                                "utxo=%v because it is unstable and could be "+
4✔
2574
                                "replaced", utxo.OutPoint)
4✔
2575

4✔
2576
                        continue
4✔
2577
                }
2578

2579
                coins = append(coins, wallet.Coin{
785✔
2580
                        TxOut: wire.TxOut{
785✔
2581
                                Value:    int64(utxo.Value),
785✔
2582
                                PkScript: utxo.PkScript,
785✔
2583
                        },
785✔
2584
                        OutPoint: utxo.OutPoint,
785✔
2585
                })
785✔
2586
        }
2587

2588
        return coins, nil
150✔
2589
}
2590

2591
// CoinFromOutPoint attempts to locate details pertaining to a coin based on
2592
// its outpoint. If the coin isn't under the control of the backing CoinSource,
2593
// then an error should be returned.
2594
func (c *CoinSource) CoinFromOutPoint(op wire.OutPoint) (*wallet.Coin, error) {
132✔
2595
        inputInfo, err := c.wallet.FetchInputInfo(&op)
132✔
2596
        if err != nil {
132✔
2597
                return nil, err
×
2598
        }
×
2599

2600
        return &wallet.Coin{
132✔
2601
                TxOut: wire.TxOut{
132✔
2602
                        Value:    int64(inputInfo.Value),
132✔
2603
                        PkScript: inputInfo.PkScript,
132✔
2604
                },
132✔
2605
                OutPoint: inputInfo.OutPoint,
132✔
2606
        }, nil
132✔
2607
}
2608

2609
// shimKeyRing is a wrapper struct that's used to provide the proper multi-sig
2610
// key for an initiated external funding flow.
2611
type shimKeyRing struct {
2612
        keychain.KeyRing
2613

2614
        *chanfunding.ShimIntent
2615
}
2616

2617
// DeriveNextKey intercepts the normal DeriveNextKey call to a keychain.KeyRing
2618
// instance, and supplies the multi-sig key specified by the ShimIntent. This
2619
// allows us to transparently insert new keys into the existing funding flow,
2620
// as these keys may not come from the wallet itself.
2621
func (s *shimKeyRing) DeriveNextKey(keyFam keychain.KeyFamily) (keychain.KeyDescriptor, error) {
59✔
2622
        if keyFam != keychain.KeyFamilyMultiSig {
109✔
2623
                return s.KeyRing.DeriveNextKey(keyFam)
50✔
2624
        }
50✔
2625

2626
        fundingKeys, err := s.ShimIntent.MultiSigKeys()
13✔
2627
        if err != nil {
13✔
2628
                return keychain.KeyDescriptor{}, err
×
2629
        }
×
2630

2631
        return *fundingKeys.LocalKey, nil
13✔
2632
}
2633

2634
// ValidateUpfrontShutdown checks whether the provided upfront_shutdown_script
2635
// is of a valid type that we accept.
2636
func ValidateUpfrontShutdown(shutdown lnwire.DeliveryAddress,
2637
        params *chaincfg.Params) bool {
41✔
2638

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

41✔
2643
        switch {
41✔
2644
        case scriptClass == txscript.WitnessV0PubKeyHashTy,
2645
                scriptClass == txscript.WitnessV0ScriptHashTy,
2646
                scriptClass == txscript.WitnessV1TaprootTy:
18✔
2647

18✔
2648
                // The above three types are permitted according to BOLT#02 and
18✔
2649
                // BOLT#05.  Everything else is disallowed.
18✔
2650
                return true
18✔
2651

2652
        // In this case, we don't know about the actual script template, but it
2653
        // might be a witness program with versions 2-16. So we'll check that
2654
        // now
2655
        case txscript.IsWitnessProgram(shutdown):
16✔
2656
                version, _, err := txscript.ExtractWitnessProgramInfo(shutdown)
16✔
2657
                if err != nil {
16✔
2658
                        walletLog.Warnf("unable to extract witness program "+
×
2659
                                "version (script=%x): %v", shutdown, err)
×
2660
                        return false
×
2661
                }
×
2662

2663
                return version >= 1 && version <= 16
16✔
2664

2665
        default:
7✔
2666
                return false
7✔
2667
        }
2668
}
2669

2670
// WalletPrevOutputFetcher is a txscript.PrevOutputFetcher that can fetch
2671
// outputs from a given wallet controller.
2672
type WalletPrevOutputFetcher struct {
2673
        wc WalletController
2674
}
2675

2676
// A compile time assertion that WalletPrevOutputFetcher implements the
2677
// txscript.PrevOutputFetcher interface.
2678
var _ txscript.PrevOutputFetcher = (*WalletPrevOutputFetcher)(nil)
2679

2680
// NewWalletPrevOutputFetcher creates a new WalletPrevOutputFetcher that fetches
2681
// previous outputs from the given wallet controller.
2682
func NewWalletPrevOutputFetcher(wc WalletController) *WalletPrevOutputFetcher {
4✔
2683
        return &WalletPrevOutputFetcher{
4✔
2684
                wc: wc,
4✔
2685
        }
4✔
2686
}
4✔
2687

2688
// FetchPrevOutput attempts to fetch the previous output referenced by the
2689
// passed outpoint. A nil value will be returned if the passed outpoint doesn't
2690
// exist.
2691
func (w *WalletPrevOutputFetcher) FetchPrevOutput(op wire.OutPoint) *wire.TxOut {
4✔
2692
        utxo, err := w.wc.FetchInputInfo(&op)
4✔
2693
        if err != nil {
4✔
2694
                return nil
×
2695
        }
×
2696

2697
        return &wire.TxOut{
4✔
2698
                Value:    int64(utxo.Value),
4✔
2699
                PkScript: utxo.PkScript,
4✔
2700
        }
4✔
2701
}
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