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

lightningnetwork / lnd / 13536249039

26 Feb 2025 03:42AM UTC coverage: 57.462% (-1.4%) from 58.835%
13536249039

Pull #8453

github

Roasbeef
peer: update chooseDeliveryScript to gen script if needed

In this commit, we update `chooseDeliveryScript` to generate a new
script if needed. This allows us to fold in a few other lines that
always followed this function into this expanded function.

The tests have been updated accordingly.
Pull Request #8453: [4/4] - multi: integrate new rbf coop close FSM into the existing peer flow

275 of 1318 new or added lines in 22 files covered. (20.86%)

19521 existing lines in 257 files now uncovered.

103858 of 180741 relevant lines covered (57.46%)

24750.23 hits per line

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

45.8
/lnwallet/interface.go
1
package lnwallet
2

3
import (
4
        "errors"
5
        "fmt"
6
        "sync"
7
        "time"
8

9
        "github.com/btcsuite/btcd/btcec/v2"
10
        "github.com/btcsuite/btcd/btcec/v2/ecdsa"
11
        "github.com/btcsuite/btcd/btcutil"
12
        "github.com/btcsuite/btcd/btcutil/hdkeychain"
13
        "github.com/btcsuite/btcd/btcutil/psbt"
14
        "github.com/btcsuite/btcd/chaincfg"
15
        "github.com/btcsuite/btcd/chaincfg/chainhash"
16
        "github.com/btcsuite/btcd/txscript"
17
        "github.com/btcsuite/btcd/wire"
18
        "github.com/btcsuite/btcwallet/waddrmgr"
19
        base "github.com/btcsuite/btcwallet/wallet"
20
        "github.com/btcsuite/btcwallet/wallet/txauthor"
21
        "github.com/btcsuite/btcwallet/wtxmgr"
22
        "github.com/lightningnetwork/lnd/fn/v2"
23
        "github.com/lightningnetwork/lnd/keychain"
24
        "github.com/lightningnetwork/lnd/lnwallet/chainfee"
25
        "github.com/lightningnetwork/lnd/lnwallet/chanvalidate"
26
        "github.com/lightningnetwork/lnd/lnwire"
27
)
28

29
const (
30
        // DefaultAccountName is the name for the default account used to manage
31
        // on-chain funds within the wallet.
32
        DefaultAccountName = "default"
33
)
34

35
// AddressType is an enum-like type which denotes the possible address types
36
// WalletController supports.
37
type AddressType uint8
38

39
// AccountAddressMap maps the account properties to an array of
40
// address properties.
41
type AccountAddressMap map[*waddrmgr.AccountProperties][]AddressProperty
42

43
const (
44
        // UnknownAddressType represents an output with an unknown or non-standard
45
        // script.
46
        UnknownAddressType AddressType = iota
47

48
        // WitnessPubKey represents a p2wkh address.
49
        WitnessPubKey
50

51
        // NestedWitnessPubKey represents a p2sh output which is itself a
52
        // nested p2wkh output.
53
        NestedWitnessPubKey
54

55
        // TaprootPubkey represents a p2tr key path spending address.
56
        TaprootPubkey
57
)
58

59
var (
60
        // DefaultPublicPassphrase is the default public passphrase used for the
61
        // wallet.
62
        DefaultPublicPassphrase = []byte("public")
63

64
        // DefaultPrivatePassphrase is the default private passphrase used for
65
        // the wallet.
66
        DefaultPrivatePassphrase = []byte("hello")
67

68
        // ErrDoubleSpend is returned from PublishTransaction in case the
69
        // tx being published is spending an output spent by a conflicting
70
        // transaction.
71
        ErrDoubleSpend = errors.New("transaction rejected: output already spent")
72

73
        // ErrNotMine is an error denoting that a WalletController instance is
74
        // unable to spend a specified output.
75
        ErrNotMine = errors.New("the passed output doesn't belong to the wallet")
76

77
        // ErrMempoolFee is returned from PublishTransaction in case the tx
78
        // being published is not accepted into mempool because the fee
79
        // requirements of the mempool backend are not met.
80
        ErrMempoolFee = errors.New("transaction rejected by the mempool " +
81
                "because of low fees")
82
)
83

84
// ErrNoOutputs is returned if we try to create a transaction with no outputs
85
// or send coins to a set of outputs that is empty.
86
var ErrNoOutputs = errors.New("no outputs")
87

88
// ErrInvalidMinconf is returned if we try to create a transaction with
89
// invalid minConfs value.
90
var ErrInvalidMinconf = errors.New("minimum number of confirmations must " +
91
        "be a non-negative number")
92

93
// AddressProperty contains wallet related information of an address.
94
type AddressProperty struct {
95
        // Address is the address of an account.
96
        Address string
97

98
        // Internal denotes if the address is a change address.
99
        Internal bool
100

101
        // Balance returns the total balance of an address.
102
        Balance btcutil.Amount
103

104
        // DerivationPath is the derivation path of the address.
105
        DerivationPath string
106

107
        // PublicKey is the public key of the address.
108
        PublicKey *btcec.PublicKey
109
}
110

111
// AccountIdentifier contains information to uniquely identify an account.
112
type AccountIdentifier struct {
113
        // Name is the name of the account.
114
        Name string
115

116
        // AddressType is the type of addresses supported by the account.
117
        AddressType AddressType
118

119
        // DerivationPath is the derivation path corresponding to the account
120
        // public key.
121
        DerivationPath string
122
}
123

124
// Utxo is an unspent output denoted by its outpoint, and output value of the
125
// original output.
126
type Utxo struct {
127
        AddressType   AddressType
128
        Value         btcutil.Amount
129
        Confirmations int64
130
        PkScript      []byte
131
        wire.OutPoint
132
        PrevTx *wire.MsgTx
133
}
134

135
// OutputDetail contains additional information on a destination address.
136
type OutputDetail struct {
137
        OutputType   txscript.ScriptClass
138
        Addresses    []btcutil.Address
139
        PkScript     []byte
140
        OutputIndex  int
141
        Value        btcutil.Amount
142
        IsOurAddress bool
143
}
144

145
// PreviousOutPoint contains information about the previous outpoint.
146
type PreviousOutPoint struct {
147
        // OutPoint is the transaction out point in the format txid:n.
148
        OutPoint string
149

150
        // IsOurOutput denotes if the previous output is controlled by the
151
        // internal wallet. The flag will only detect p2wkh, np2wkh and p2tr
152
        // inputs as its own.
153
        IsOurOutput bool
154
}
155

156
// TransactionDetail describes a transaction with either inputs which belong to
157
// the wallet, or has outputs that pay to the wallet.
158
type TransactionDetail struct {
159
        // Hash is the transaction hash of the transaction.
160
        Hash chainhash.Hash
161

162
        // Value is the net value of this transaction (in satoshis) from the
163
        // PoV of the wallet. If this transaction purely spends from the
164
        // wallet's funds, then this value will be negative. Similarly, if this
165
        // transaction credits the wallet, then this value will be positive.
166
        Value btcutil.Amount
167

168
        // NumConfirmations is the number of confirmations this transaction
169
        // has. If the transaction is unconfirmed, then this value will be
170
        // zero.
171
        NumConfirmations int32
172

173
        // BlockHeight is the hash of the block which includes this
174
        // transaction. Unconfirmed transactions will have a nil value for this
175
        // field.
176
        BlockHash *chainhash.Hash
177

178
        // BlockHeight is the height of the block including this transaction.
179
        // Unconfirmed transaction will show a height of zero.
180
        BlockHeight int32
181

182
        // Timestamp is the unix timestamp of the block including this
183
        // transaction. If the transaction is unconfirmed, then this will be a
184
        // timestamp of txn creation.
185
        Timestamp int64
186

187
        // TotalFees is the total fee in satoshis paid by this transaction.
188
        TotalFees int64
189

190
        // OutputDetails contains output data for each destination address, such
191
        // as the output script and amount.
192
        OutputDetails []OutputDetail
193

194
        // RawTx returns the raw serialized transaction.
195
        RawTx []byte
196

197
        // Label is an optional transaction label.
198
        Label string
199

200
        // PreviousOutpoints are the inputs for a transaction.
201
        PreviousOutpoints []PreviousOutPoint
202
}
203

204
// TransactionSubscription is an interface which describes an object capable of
205
// receiving notifications of new transaction related to the underlying wallet.
206
// TODO(roasbeef): add balance updates?
207
type TransactionSubscription interface {
208
        // ConfirmedTransactions returns a channel which will be sent on as new
209
        // relevant transactions are confirmed.
210
        ConfirmedTransactions() chan *TransactionDetail
211

212
        // UnconfirmedTransactions returns a channel which will be sent on as
213
        // new relevant transactions are seen within the network.
214
        UnconfirmedTransactions() chan *TransactionDetail
215

216
        // Cancel finalizes the subscription, cleaning up any resources
217
        // allocated.
218
        Cancel()
219
}
220

221
// WalletController defines an abstract interface for controlling a local Pure
222
// Go wallet, a local or remote wallet via an RPC mechanism, or possibly even
223
// a daemon assisted hardware wallet. This interface serves the purpose of
224
// allowing LightningWallet to be seamlessly compatible with several wallets
225
// such as: uspv, btcwallet, Bitcoin Core, Electrum, etc. This interface then
226
// serves as a "base wallet", with Lightning Network awareness taking place at
227
// a "higher" level of abstraction. Essentially, an overlay wallet.
228
// Implementors of this interface must closely adhere to the documented
229
// behavior of all interface methods in order to ensure identical behavior
230
// across all concrete implementations.
231
type WalletController interface {
232
        // FetchOutpointInfo queries for the WalletController's knowledge of
233
        // the passed outpoint. If the base wallet determines this output is
234
        // under its control, then the original txout should be returned.
235
        // Otherwise, a non-nil error value of ErrNotMine should be returned
236
        // instead.
237
        FetchOutpointInfo(prevOut *wire.OutPoint) (*Utxo, error)
238

239
        // FetchDerivationInfo queries for the wallet's knowledge of the passed
240
        // pkScript and constructs the derivation info and returns it.
241
        FetchDerivationInfo(pkScript []byte) (*psbt.Bip32Derivation, error)
242

243
        // ScriptForOutput returns the address, witness program and redeem
244
        // script for a given UTXO. An error is returned if the UTXO does not
245
        // belong to our wallet or it is not a managed pubKey address.
246
        ScriptForOutput(output *wire.TxOut) (waddrmgr.ManagedPubKeyAddress,
247
                []byte, []byte, error)
248

249
        // ConfirmedBalance returns the sum of all the wallet's unspent outputs
250
        // that have at least confs confirmations. If confs is set to zero,
251
        // then all unspent outputs, including those currently in the mempool
252
        // will be included in the final sum. The account parameter serves as a
253
        // filter to retrieve the balance for a specific account. When empty,
254
        // the confirmed balance of all wallet accounts is returned.
255
        //
256
        // NOTE: Only witness outputs should be included in the computation of
257
        // the total spendable balance of the wallet. We require this as only
258
        // witness inputs can be used for funding channels.
259
        ConfirmedBalance(confs int32, accountFilter string) (btcutil.Amount,
260
                error)
261

262
        // NewAddress returns the next external or internal address for the
263
        // wallet dictated by the value of the `change` parameter. If change is
264
        // true, then an internal address should be used, otherwise an external
265
        // address should be returned. The type of address returned is dictated
266
        // by the wallet's capabilities, and may be of type: p2sh, p2wkh,
267
        // p2wsh, etc. The account parameter must be non-empty as it determines
268
        // which account the address should be generated from.
269
        NewAddress(addrType AddressType, change bool,
270
                account string) (btcutil.Address, error)
271

272
        // LastUnusedAddress returns the last *unused* address known by the
273
        // wallet. An address is unused if it hasn't received any payments.
274
        // This can be useful in UIs in order to continually show the
275
        // "freshest" address without having to worry about "address inflation"
276
        // caused by continual refreshing. Similar to NewAddress it can derive
277
        // a specified address type. By default, this is a non-change address.
278
        // The account parameter must be non-empty as it determines which
279
        // account the address should be generated from.
280
        LastUnusedAddress(addrType AddressType,
281
                account string) (btcutil.Address, error)
282

283
        // IsOurAddress checks if the passed address belongs to this wallet
284
        IsOurAddress(a btcutil.Address) bool
285

286
        // AddressInfo returns the information about an address, if it's known
287
        // to this wallet.
288
        AddressInfo(a btcutil.Address) (waddrmgr.ManagedAddress, error)
289

290
        // ListAccounts retrieves all accounts belonging to the wallet by
291
        // default. A name and key scope filter can be provided to filter
292
        // through all of the wallet accounts and return only those matching.
293
        ListAccounts(string, *waddrmgr.KeyScope) ([]*waddrmgr.AccountProperties,
294
                error)
295

296
        // RequiredReserve returns the minimum amount of satoshis that should be
297
        // kept in the wallet in order to fee bump anchor channels if necessary.
298
        // The value scales with the number of public anchor channels but is
299
        // capped at a maximum.
300
        RequiredReserve(uint32) btcutil.Amount
301

302
        // ListAddresses retrieves all the addresses along with their balance. An
303
        // account name filter can be provided to filter through all of the
304
        // wallet accounts and return the addresses of only those matching.
305
        ListAddresses(string, bool) (AccountAddressMap, error)
306

307
        // ImportAccount imports an account backed by an account extended public
308
        // key. The master key fingerprint denotes the fingerprint of the root
309
        // key corresponding to the account public key (also known as the key
310
        // with derivation path m/). This may be required by some hardware
311
        // wallets for proper identification and signing.
312
        //
313
        // The address type can usually be inferred from the key's version, but
314
        // may be required for certain keys to map them into the proper scope.
315
        //
316
        // For BIP-0044 keys, an address type must be specified as we intend to
317
        // not support importing BIP-0044 keys into the wallet using the legacy
318
        // pay-to-pubkey-hash (P2PKH) scheme. A nested witness address type will
319
        // force the standard BIP-0049 derivation scheme, while a witness
320
        // address type will force the standard BIP-0084 derivation scheme.
321
        //
322
        // For BIP-0049 keys, an address type must also be specified to make a
323
        // distinction between the standard BIP-0049 address schema (nested
324
        // witness pubkeys everywhere) and our own BIP-0049Plus address schema
325
        // (nested pubkeys externally, witness pubkeys internally).
326
        ImportAccount(name string, accountPubKey *hdkeychain.ExtendedKey,
327
                masterKeyFingerprint uint32, addrType *waddrmgr.AddressType,
328
                dryRun bool) (*waddrmgr.AccountProperties, []btcutil.Address,
329
                []btcutil.Address, error)
330

331
        // ImportPublicKey imports a single derived public key into the wallet.
332
        // The address type can usually be inferred from the key's version, but
333
        // in the case of legacy versions (xpub, tpub), an address type must be
334
        // specified as we intend to not support importing BIP-44 keys into the
335
        // wallet using the legacy pay-to-pubkey-hash (P2PKH) scheme.
336
        ImportPublicKey(pubKey *btcec.PublicKey,
337
                addrType waddrmgr.AddressType) error
338

339
        // ImportTaprootScript imports a user-provided taproot script into the
340
        // wallet. The imported script will act as a pay-to-taproot address.
341
        //
342
        // NOTE: Taproot keys imported through this RPC currently _cannot_ be
343
        // used for funding PSBTs. Only tracking the balance and UTXOs is
344
        // currently supported.
345
        ImportTaprootScript(scope waddrmgr.KeyScope,
346
                tapscript *waddrmgr.Tapscript) (waddrmgr.ManagedAddress, error)
347

348
        // SendOutputs funds, signs, and broadcasts a Bitcoin transaction paying
349
        // out to the specified outputs. In the case the wallet has insufficient
350
        // funds, or the outputs are non-standard, an error should be returned.
351
        // This method also takes the target fee expressed in sat/kw that should
352
        // be used when crafting the transaction.
353
        //
354
        // NOTE: This method requires the global coin selection lock to be held.
355
        SendOutputs(inputs fn.Set[wire.OutPoint], outputs []*wire.TxOut,
356
                feeRate chainfee.SatPerKWeight, minConfs int32, label string,
357
                strategy base.CoinSelectionStrategy) (*wire.MsgTx, error)
358

359
        // CreateSimpleTx creates a Bitcoin transaction paying to the specified
360
        // outputs. The transaction is not broadcasted to the network. In the
361
        // case the wallet has insufficient funds, or the outputs are
362
        // non-standard, an error should be returned. This method also takes
363
        // the target fee expressed in sat/kw that should be used when crafting
364
        // the transaction.
365
        //
366
        // NOTE: The dryRun argument can be set true to create a tx that
367
        // doesn't alter the database. A tx created with this set to true
368
        // SHOULD NOT be broadcasted.
369
        //
370
        // NOTE: This method requires the global coin selection lock to be held.
371
        CreateSimpleTx(inputs fn.Set[wire.OutPoint], outputs []*wire.TxOut,
372
                feeRate chainfee.SatPerKWeight, minConfs int32,
373
                strategy base.CoinSelectionStrategy, dryRun bool) (
374
                *txauthor.AuthoredTx, error)
375

376
        // GetTransactionDetails returns a detailed description of a transaction
377
        // given its transaction hash.
378
        GetTransactionDetails(txHash *chainhash.Hash) (
379
                *TransactionDetail, error)
380

381
        // ListUnspentWitness returns all unspent outputs which are version 0
382
        // witness programs. The 'minConfs' and 'maxConfs' parameters
383
        // indicate the minimum and maximum number of confirmations an output
384
        // needs in order to be returned by this method. Passing -1 as
385
        // 'minConfs' indicates that even unconfirmed outputs should be
386
        // returned. Using MaxInt32 as 'maxConfs' implies returning all
387
        // outputs with at least 'minConfs'. The account parameter serves as
388
        // a filter to retrieve the unspent outputs for a specific account.
389
        // When empty, the unspent outputs of all wallet accounts are returned.
390
        //
391
        // NOTE: This method requires the global coin selection lock to be held.
392
        ListUnspentWitness(minConfs, maxConfs int32,
393
                accountFilter string) ([]*Utxo, error)
394

395
        // ListTransactionDetails returns a list of all transactions which are
396
        // relevant to the wallet over [startHeight;endHeight]. If start height
397
        // is greater than end height, the transactions will be retrieved in
398
        // reverse order. To include unconfirmed transactions, endHeight should
399
        // be set to the special value -1. This will return transactions from
400
        // the tip of the chain until the start height (inclusive) and
401
        // unconfirmed transactions. The account parameter serves as a filter to
402
        // retrieve the transactions relevant to a specific account. When
403
        // empty, transactions of all wallet accounts are returned.
404
        ListTransactionDetails(startHeight, endHeight int32,
405
                accountFilter string, indexOffset uint32,
406
                maxTransactions uint32) ([]*TransactionDetail, uint64, uint64,
407
                error)
408

409
        // LeaseOutput locks an output to the given ID, preventing it from being
410
        // available for any future coin selection attempts. The absolute time
411
        // of the lock's expiration is returned. The expiration of the lock can
412
        // be extended by successive invocations of this call. Outputs can be
413
        // unlocked before their expiration through `ReleaseOutput`.
414
        //
415
        // If the output is not known, wtxmgr.ErrUnknownOutput is returned. If
416
        // the output has already been locked to a different ID, then
417
        // wtxmgr.ErrOutputAlreadyLocked is returned.
418
        //
419
        // NOTE: This method requires the global coin selection lock to be held.
420
        LeaseOutput(id wtxmgr.LockID, op wire.OutPoint,
421
                duration time.Duration) (time.Time, error)
422

423
        // ReleaseOutput unlocks an output, allowing it to be available for coin
424
        // selection if it remains unspent. The ID should match the one used to
425
        // originally lock the output.
426
        //
427
        // NOTE: This method requires the global coin selection lock to be held.
428
        ReleaseOutput(id wtxmgr.LockID, op wire.OutPoint) error
429

430
        // ListLeasedOutputs returns a list of all currently locked outputs.
431
        ListLeasedOutputs() ([]*base.ListLeasedOutputResult, error)
432

433
        // PublishTransaction performs cursory validation (dust checks, etc),
434
        // then finally broadcasts the passed transaction to the Bitcoin network.
435
        // If the transaction is rejected because it is conflicting with an
436
        // already known transaction, ErrDoubleSpend is returned. If the
437
        // transaction is already known (published already), no error will be
438
        // returned. Other error returned depends on the currently active chain
439
        // backend. It takes an optional label which will save a label with the
440
        // published transaction.
441
        PublishTransaction(tx *wire.MsgTx, label string) error
442

443
        // LabelTransaction adds a label to a transaction. If the tx already
444
        // has a label, this call will fail unless the overwrite parameter
445
        // is set. Labels must not be empty, and they are limited to 500 chars.
446
        LabelTransaction(hash chainhash.Hash, label string, overwrite bool) error
447

448
        // FetchTx attempts to fetch a transaction in the wallet's database
449
        // identified by the passed transaction hash. If the transaction can't
450
        // be found, then a nil pointer is returned.
451
        FetchTx(chainhash.Hash) (*wire.MsgTx, error)
452

453
        // RemoveDescendants attempts to remove any transaction from the
454
        // wallet's tx store (that may be unconfirmed) that spends outputs
455
        // created by the passed transaction. This remove propagates
456
        // recursively down the chain of descendent transactions.
457
        RemoveDescendants(*wire.MsgTx) error
458

459
        // FundPsbt creates a fully populated PSBT packet that contains enough
460
        // inputs to fund the outputs specified in the passed in packet with the
461
        // specified fee rate. If there is change left, a change output from the
462
        // internal wallet is added and the index of the change output is
463
        // returned. Otherwise no additional output is created and the index -1
464
        // is returned. If no custom change scope is specified, the BIP0084 will
465
        // be used for default accounts and single imported public keys. For
466
        // custom account, no key scope should be provided as the coin selection
467
        // key scope will always be used to generate the change address.
468
        //
469
        // NOTE: If the packet doesn't contain any inputs, coin selection is
470
        // performed automatically. The account parameter must be non-empty as
471
        // it determines which set of coins are eligible for coin selection. If
472
        // the packet does contain any inputs, it is assumed that full coin
473
        // selection happened externally and no additional inputs are added. If
474
        // the specified inputs aren't enough to fund the outputs with the given
475
        // fee rate, an error is returned. No lock lease is acquired for any of
476
        // the selected/validated inputs. It is in the caller's responsibility
477
        // to lock the inputs before handing them out.
478
        FundPsbt(packet *psbt.Packet, minConfs int32,
479
                feeRate chainfee.SatPerKWeight, account string,
480
                changeScope *waddrmgr.KeyScope,
481
                strategy base.CoinSelectionStrategy,
482
                allowUtxo func(wtxmgr.Credit) bool) (int32, error)
483

484
        // SignPsbt expects a partial transaction with all inputs and outputs
485
        // fully declared and tries to sign all unsigned inputs that have all
486
        // required fields (UTXO information, BIP32 derivation information,
487
        // witness or sig scripts) set.
488
        // If no error is returned, the PSBT is ready to be given to the next
489
        // signer or to be finalized if lnd was the last signer.
490
        //
491
        // NOTE: This method only signs inputs (and only those it can sign), it
492
        // does not perform any other tasks (such as coin selection, UTXO
493
        // locking or input/output/fee value validation, PSBT finalization). Any
494
        // input that is incomplete will be skipped.
495
        SignPsbt(packet *psbt.Packet) ([]uint32, error)
496

497
        // FinalizePsbt expects a partial transaction with all inputs and
498
        // outputs fully declared and tries to sign all inputs that belong to
499
        // the specified account. Lnd must be the last signer of the
500
        // transaction. That means, if there are any unsigned non-witness inputs
501
        // or inputs without UTXO information attached or inputs without witness
502
        // data that do not belong to lnd's wallet, this method will fail. If no
503
        // error is returned, the PSBT is ready to be extracted and the final TX
504
        // within to be broadcast.
505
        //
506
        // NOTE: This method does NOT publish the transaction after it's been
507
        // finalized successfully.
508
        FinalizePsbt(packet *psbt.Packet, account string) error
509

510
        // DecorateInputs fetches the UTXO information of all inputs it can
511
        // identify and adds the required information to the package's inputs.
512
        // The failOnUnknown boolean controls whether the method should return
513
        // an error if it cannot identify an input or if it should just skip it.
514
        DecorateInputs(packet *psbt.Packet, failOnUnknown bool) error
515

516
        // SubscribeTransactions returns a TransactionSubscription client which
517
        // is capable of receiving async notifications as new transactions
518
        // related to the wallet are seen within the network, or found in
519
        // blocks.
520
        //
521
        // NOTE: a non-nil error should be returned if notifications aren't
522
        // supported.
523
        //
524
        // TODO(roasbeef): make distinct interface?
525
        SubscribeTransactions() (TransactionSubscription, error)
526

527
        // IsSynced returns a boolean indicating if from the PoV of the wallet,
528
        // it has fully synced to the current best block in the main chain.
529
        // It also returns an int64 indicating the timestamp of the best block
530
        // known to the wallet, expressed in Unix epoch time
531
        IsSynced() (bool, int64, error)
532

533
        // GetRecoveryInfo returns a boolean indicating whether the wallet is
534
        // started in recovery mode. It also returns a float64 indicating the
535
        // recovery progress made so far.
536
        GetRecoveryInfo() (bool, float64, error)
537

538
        // Start initializes the wallet, making any necessary connections,
539
        // starting up required goroutines etc.
540
        Start() error
541

542
        // Stop signals the wallet for shutdown. Shutdown may entail closing
543
        // any active sockets, database handles, stopping goroutines, etc.
544
        Stop() error
545

546
        // BackEnd returns a name for the wallet's backing chain service,
547
        // which could be e.g. btcd, bitcoind, neutrino, or another consensus
548
        // service.
549
        BackEnd() string
550

551
        // CheckMempoolAcceptance checks whether a transaction follows mempool
552
        // policies and returns an error if it cannot be accepted into the
553
        // mempool.
554
        CheckMempoolAcceptance(tx *wire.MsgTx) error
555
}
556

557
// BlockChainIO is a dedicated source which will be used to obtain queries
558
// related to the current state of the blockchain. The data returned by each of
559
// the defined methods within this interface should always return the most up
560
// to date data possible.
561
//
562
// TODO(roasbeef): move to diff package perhaps?
563
// TODO(roasbeef): move publish txn here?
564
type BlockChainIO interface {
565
        // GetBestBlock returns the current height and block hash of the valid
566
        // most-work chain the implementation is aware of.
567
        GetBestBlock() (*chainhash.Hash, int32, error)
568

569
        // GetUtxo attempts to return the passed outpoint if it's still a
570
        // member of the utxo set. The passed height hint should be the "birth
571
        // height" of the passed outpoint. The script passed should be the
572
        // script that the outpoint creates. In the case that the output is in
573
        // the UTXO set, then the output corresponding to that output is
574
        // returned.  Otherwise, a non-nil error will be returned.
575
        // As for some backends this call can initiate a rescan, the passed
576
        // cancel channel can be closed to abort the call.
577
        GetUtxo(op *wire.OutPoint, pkScript []byte, heightHint uint32,
578
                cancel <-chan struct{}) (*wire.TxOut, error)
579

580
        // GetBlockHash returns the hash of the block in the best blockchain
581
        // at the given height.
582
        GetBlockHash(blockHeight int64) (*chainhash.Hash, error)
583

584
        // GetBlock returns the block in the main chain identified by the given
585
        // hash.
586
        GetBlock(blockHash *chainhash.Hash) (*wire.MsgBlock, error)
587

588
        // GetBlockHeader returns the block header for the given block hash.
589
        GetBlockHeader(blockHash *chainhash.Hash) (*wire.BlockHeader, error)
590
}
591

592
// MessageSigner represents an abstract object capable of signing arbitrary
593
// messages. The capabilities of this interface are used to sign announcements
594
// to the network, or just arbitrary messages that leverage the wallet's keys
595
// to attest to some message.
596
type MessageSigner interface {
597
        // SignMessage attempts to sign a target message with the private key
598
        // described in the key locator. If the target private key is unable to
599
        // be found, then an error will be returned. The actual digest signed is
600
        // the single or double SHA-256 of the passed message.
601
        SignMessage(keyLoc keychain.KeyLocator, msg []byte,
602
                doubleHash bool) (*ecdsa.Signature, error)
603
}
604

605
// AddrWithKey wraps a normal addr, but also includes the internal key for the
606
// delivery addr if known.
607
type AddrWithKey struct {
608
        lnwire.DeliveryAddress
609

610
        InternalKey fn.Option[keychain.KeyDescriptor]
611

612
        // TODO(roasbeef): consolidate w/ instance in chan closer
613
}
614

615
// InternalKeyForAddr returns the internal key associated with a taproot
616
// address.
617
func InternalKeyForAddr(wallet WalletController, netParams *chaincfg.Params,
618
        deliveryScript []byte) (fn.Option[keychain.KeyDescriptor], error) {
9✔
619

9✔
620
        none := fn.None[keychain.KeyDescriptor]()
9✔
621

9✔
622
        pkScript, err := txscript.ParsePkScript(deliveryScript)
9✔
623
        if err != nil {
9✔
624
                return none, err
×
625
        }
×
626
        addr, err := pkScript.Address(netParams)
9✔
627
        if err != nil {
9✔
628
                return none, err
×
629
        }
×
630

631
        // If it's not a taproot address, we don't require to know the internal
632
        // key in the first place. So we don't return an error here, but also no
633
        // internal key.
634
        _, isTaproot := addr.(*btcutil.AddressTaproot)
9✔
635
        if !isTaproot {
18✔
636
                return none, nil
9✔
637
        }
9✔
638

UNCOV
639
        walletAddr, err := wallet.AddressInfo(addr)
×
UNCOV
640
        if err != nil {
×
UNCOV
641
                // If the error is that the address can't be found, it is not
×
UNCOV
642
                // an error. This happens when any channel which is not a custom
×
UNCOV
643
                // taproot channel is cooperatively closed to an external P2TR
×
UNCOV
644
                // address. In this case there is no internal key associated
×
UNCOV
645
                // with the address. Callers can use the .Option() method to get
×
UNCOV
646
                // an option value.
×
UNCOV
647
                var managerErr waddrmgr.ManagerError
×
UNCOV
648
                if errors.As(err, &managerErr) &&
×
UNCOV
649
                        managerErr.ErrorCode == waddrmgr.ErrAddressNotFound {
×
UNCOV
650

×
UNCOV
651
                        return none, nil
×
UNCOV
652
                }
×
653

654
                return none, err
×
655
        }
656

657
        // No wallet addr. No error, but we'll return an nil error value here,
658
        // as callers can use the .Option() method to get an option value.
UNCOV
659
        if walletAddr == nil {
×
660
                return none, nil
×
661
        }
×
662

UNCOV
663
        pubKeyAddr, ok := walletAddr.(waddrmgr.ManagedPubKeyAddress)
×
UNCOV
664
        if !ok {
×
665
                return none, fmt.Errorf("expected pubkey addr, got %T",
×
666
                        pubKeyAddr)
×
667
        }
×
668

UNCOV
669
        _, derivationPath, _ := pubKeyAddr.DerivationInfo()
×
UNCOV
670

×
UNCOV
671
        return fn.Some[keychain.KeyDescriptor](keychain.KeyDescriptor{
×
UNCOV
672
                KeyLocator: keychain.KeyLocator{
×
UNCOV
673
                        Family: keychain.KeyFamily(derivationPath.Account),
×
UNCOV
674
                        Index:  derivationPath.Index,
×
UNCOV
675
                },
×
UNCOV
676
                PubKey: pubKeyAddr.PubKey(),
×
UNCOV
677
        }), nil
×
678
}
679

680
// WalletDriver represents a "driver" for a particular concrete
681
// WalletController implementation. A driver is identified by a globally unique
682
// string identifier along with a 'New()' method which is responsible for
683
// initializing a particular WalletController concrete implementation.
684
type WalletDriver struct {
685
        // WalletType is a string which uniquely identifies the
686
        // WalletController that this driver, drives.
687
        WalletType string
688

689
        // New creates a new instance of a concrete WalletController
690
        // implementation given a variadic set up arguments. The function takes
691
        // a variadic number of interface parameters in order to provide
692
        // initialization flexibility, thereby accommodating several potential
693
        // WalletController implementations.
694
        New func(args ...interface{}) (WalletController, error)
695

696
        // BackEnds returns a list of available chain service drivers for the
697
        // wallet driver. This could be e.g. bitcoind, btcd, neutrino, etc.
698
        BackEnds func() []string
699
}
700

701
var (
702
        wallets     = make(map[string]*WalletDriver)
703
        registerMtx sync.Mutex
704
)
705

706
// RegisteredWallets returns a slice of all currently registered notifiers.
707
//
708
// NOTE: This function is safe for concurrent access.
709
func RegisteredWallets() []*WalletDriver {
4✔
710
        registerMtx.Lock()
4✔
711
        defer registerMtx.Unlock()
4✔
712

4✔
713
        registeredWallets := make([]*WalletDriver, 0, len(wallets))
4✔
714
        for _, wallet := range wallets {
8✔
715
                registeredWallets = append(registeredWallets, wallet)
4✔
716
        }
4✔
717

718
        return registeredWallets
4✔
719
}
720

721
// RegisterWallet registers a WalletDriver which is capable of driving a
722
// concrete WalletController interface. In the case that this driver has
723
// already been registered, an error is returned.
724
//
725
// NOTE: This function is safe for concurrent access.
726
func RegisterWallet(driver *WalletDriver) error {
15✔
727
        registerMtx.Lock()
15✔
728
        defer registerMtx.Unlock()
15✔
729

15✔
730
        if _, ok := wallets[driver.WalletType]; ok {
15✔
731
                return fmt.Errorf("wallet already registered")
×
732
        }
×
733

734
        wallets[driver.WalletType] = driver
15✔
735

15✔
736
        return nil
15✔
737
}
738

739
// SupportedWallets returns a slice of strings that represents the wallet
740
// drivers that have been registered and are therefore supported.
741
//
742
// NOTE: This function is safe for concurrent access.
743
func SupportedWallets() []string {
×
744
        registerMtx.Lock()
×
745
        defer registerMtx.Unlock()
×
746

×
747
        supportedWallets := make([]string, 0, len(wallets))
×
748
        for walletName := range wallets {
×
749
                supportedWallets = append(supportedWallets, walletName)
×
750
        }
×
751

752
        return supportedWallets
×
753
}
754

755
// FetchFundingTxWrapper is a wrapper around FetchFundingTx, except that it will
756
// exit when the supplied quit channel is closed.
757
func FetchFundingTxWrapper(chain BlockChainIO, chanID *lnwire.ShortChannelID,
758
        quit chan struct{}) (*wire.MsgTx, error) {
228✔
759

228✔
760
        txChan := make(chan *wire.MsgTx, 1)
228✔
761
        errChan := make(chan error, 1)
228✔
762

228✔
763
        go func() {
456✔
764
                tx, err := FetchFundingTx(chain, chanID)
228✔
765
                if err != nil {
229✔
766
                        errChan <- err
1✔
767
                        return
1✔
768
                }
1✔
769

770
                txChan <- tx
227✔
771
        }()
772

773
        select {
228✔
774
        case tx := <-txChan:
227✔
775
                return tx, nil
227✔
776

777
        case err := <-errChan:
1✔
778
                return nil, err
1✔
779

780
        case <-quit:
×
781
                return nil, fmt.Errorf("quit channel passed to " +
×
782
                        "lnwallet.FetchFundingTxWrapper has been closed")
×
783
        }
784
}
785

786
// FetchFundingTx uses the given BlockChainIO to fetch and return the funding
787
// transaction identified by the passed short channel ID.
788
//
789
// TODO(roasbeef): replace with call to GetBlockTransaction? (would allow to
790
// later use getblocktxn).
791
func FetchFundingTx(chain BlockChainIO,
792
        chanID *lnwire.ShortChannelID) (*wire.MsgTx, error) {
228✔
793

228✔
794
        // First fetch the block hash by the block number encoded, then use
228✔
795
        // that hash to fetch the block itself.
228✔
796
        blockNum := int64(chanID.BlockHeight)
228✔
797
        blockHash, err := chain.GetBlockHash(blockNum)
228✔
798
        if err != nil {
228✔
799
                return nil, err
×
800
        }
×
801

802
        fundingBlock, err := chain.GetBlock(blockHash)
228✔
803
        if err != nil {
229✔
804
                return nil, err
1✔
805
        }
1✔
806

807
        // As a sanity check, ensure that the advertised transaction index is
808
        // within the bounds of the total number of transactions within a
809
        // block.
810
        numTxns := uint32(len(fundingBlock.Transactions))
227✔
811
        if chanID.TxIndex > numTxns-1 {
227✔
812
                return nil, fmt.Errorf("tx_index=#%v "+
×
813
                        "is out of range (max_index=%v), network_chan_id=%v",
×
814
                        chanID.TxIndex, numTxns-1, chanID)
×
815
        }
×
816

817
        return fundingBlock.Transactions[chanID.TxIndex].Copy(), nil
227✔
818
}
819

820
// FetchPKScriptWithQuit fetches the output script for the given SCID and exits
821
// early with an error if the provided quit channel is closed before
822
// completion.
823
func FetchPKScriptWithQuit(chain BlockChainIO, chanID *lnwire.ShortChannelID,
824
        quit chan struct{}) ([]byte, error) {
×
825

×
826
        tx, err := FetchFundingTxWrapper(chain, chanID, quit)
×
827
        if err != nil {
×
828
                return nil, err
×
829
        }
×
830

831
        outputLocator := chanvalidate.ShortChanIDChanLocator{
×
832
                ID: *chanID,
×
833
        }
×
834

×
835
        output, _, err := outputLocator.Locate(tx)
×
836
        if err != nil {
×
837
                return nil, err
×
838
        }
×
839

840
        return output.PkScript, nil
×
841
}
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