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

lightningnetwork / lnd / 13211764208

08 Feb 2025 03:08AM UTC coverage: 49.288% (-9.5%) from 58.815%
13211764208

Pull #9489

github

calvinrzachman
itest: verify switchrpc server enforces send then track

We prevent the rpc server from allowing onion dispatches for
attempt IDs which have already been tracked by rpc clients.

This helps protect the client from leaking a duplicate onion
attempt. NOTE: This is not the only method for solving this
issue! The issue could be addressed via careful client side
programming which accounts for the uncertainty and async
nature of dispatching onions to a remote process via RPC.
This would require some lnd ChannelRouter changes for how
we intend to use these RPCs though.
Pull Request #9489: multi: add BuildOnion, SendOnion, and TrackOnion RPCs

474 of 990 new or added lines in 11 files covered. (47.88%)

27321 existing lines in 435 files now uncovered.

101192 of 205306 relevant lines covered (49.29%)

1.54 hits per line

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

0.0
/lnwallet/mock.go
1
package lnwallet
2

3
import (
4
        "encoding/hex"
5
        "sync/atomic"
6
        "time"
7

8
        "github.com/btcsuite/btcd/btcec/v2"
9
        "github.com/btcsuite/btcd/btcutil"
10
        "github.com/btcsuite/btcd/btcutil/hdkeychain"
11
        "github.com/btcsuite/btcd/btcutil/psbt"
12
        "github.com/btcsuite/btcd/chaincfg"
13
        "github.com/btcsuite/btcd/chaincfg/chainhash"
14
        "github.com/btcsuite/btcd/wire"
15
        "github.com/btcsuite/btcwallet/waddrmgr"
16
        base "github.com/btcsuite/btcwallet/wallet"
17
        "github.com/btcsuite/btcwallet/wallet/txauthor"
18
        "github.com/btcsuite/btcwallet/wtxmgr"
19
        "github.com/lightningnetwork/lnd/chainntnfs"
20
        "github.com/lightningnetwork/lnd/channeldb"
21
        "github.com/lightningnetwork/lnd/fn/v2"
22
        "github.com/lightningnetwork/lnd/lntypes"
23
        "github.com/lightningnetwork/lnd/lnwallet/chainfee"
24
        "github.com/lightningnetwork/lnd/tlv"
25
        "github.com/stretchr/testify/mock"
26
)
27

28
var (
29
        CoinPkScript, _ = hex.DecodeString(
30
                "001431df1bde03c074d0cf21ea2529427e1499b8f1de",
31
        )
32
)
33

34
// mockWalletController is a mock implementation of the WalletController
35
// interface. It let's us mock the interaction with the bitcoin network.
36
type mockWalletController struct {
37
        RootKey               *btcec.PrivateKey
38
        PublishedTransactions chan *wire.MsgTx
39
        index                 uint32
40
        Utxos                 []*Utxo
41
}
42

43
// A compile time check to ensure that mockWalletController implements the
44
// WalletController.
45
var _ WalletController = (*mockWalletController)(nil)
46

47
// BackEnd returns "mock" to signify a mock wallet controller.
48
func (w *mockWalletController) BackEnd() string {
×
49
        return "mock"
×
50
}
×
51

52
// FetchOutpointInfo will be called to get info about the inputs to the funding
53
// transaction.
54
func (w *mockWalletController) FetchOutpointInfo(
55
        prevOut *wire.OutPoint) (*Utxo, error) {
×
56

×
57
        utxo := &Utxo{
×
58
                AddressType:   WitnessPubKey,
×
59
                Value:         10 * btcutil.SatoshiPerBitcoin,
×
60
                PkScript:      []byte("dummy"),
×
61
                Confirmations: 1,
×
62
                OutPoint:      *prevOut,
×
63
        }
×
64

×
65
        return utxo, nil
×
66
}
×
67

68
// ScriptForOutput returns the address, witness program and redeem script for a
69
// given UTXO. An error is returned if the UTXO does not belong to our wallet or
70
// it is not a managed pubKey address.
71
func (w *mockWalletController) ScriptForOutput(*wire.TxOut) (
72
        waddrmgr.ManagedPubKeyAddress, []byte, []byte, error) {
×
73

×
74
        return nil, nil, nil, nil
×
75
}
×
76

77
// ConfirmedBalance currently returns dummy values.
78
func (w *mockWalletController) ConfirmedBalance(int32, string) (btcutil.Amount,
79
        error) {
×
80

×
81
        return 0, nil
×
82
}
×
83

84
// NewAddress is called to get new addresses for delivery, change etc.
85
func (w *mockWalletController) NewAddress(AddressType, bool,
86
        string) (btcutil.Address, error) {
×
87

×
88
        addr, _ := btcutil.NewAddressPubKey(
×
89
                w.RootKey.PubKey().SerializeCompressed(),
×
90
                &chaincfg.MainNetParams,
×
91
        )
×
92

×
93
        return addr, nil
×
94
}
×
95

96
// LastUnusedAddress currently returns dummy values.
97
func (w *mockWalletController) LastUnusedAddress(AddressType,
98
        string) (btcutil.Address, error) {
×
99

×
100
        return nil, nil
×
101
}
×
102

103
// IsOurAddress currently returns a dummy value.
104
func (w *mockWalletController) IsOurAddress(btcutil.Address) bool {
×
105
        return false
×
106
}
×
107

108
// AddressInfo currently returns a dummy value.
109
func (w *mockWalletController) AddressInfo(
110
        btcutil.Address) (waddrmgr.ManagedAddress, error) {
×
111

×
112
        return nil, nil
×
113
}
×
114

115
// ListAccounts currently returns a dummy value.
116
func (w *mockWalletController) ListAccounts(string,
117
        *waddrmgr.KeyScope) ([]*waddrmgr.AccountProperties, error) {
×
118

×
119
        return nil, nil
×
120
}
×
121

122
// RequiredReserve currently returns a dummy value.
123
func (w *mockWalletController) RequiredReserve(uint32) btcutil.Amount {
×
124
        return 0
×
125
}
×
126

127
// ListAddresses currently returns a dummy value.
128
func (w *mockWalletController) ListAddresses(string,
129
        bool) (AccountAddressMap, error) {
×
130

×
131
        return nil, nil
×
132
}
×
133

134
// ImportAccount currently returns a dummy value.
135
func (w *mockWalletController) ImportAccount(string, *hdkeychain.ExtendedKey,
136
        uint32, *waddrmgr.AddressType, bool) (*waddrmgr.AccountProperties,
137
        []btcutil.Address, []btcutil.Address, error) {
×
138

×
139
        return nil, nil, nil, nil
×
140
}
×
141

142
// ImportPublicKey currently returns a dummy value.
143
func (w *mockWalletController) ImportPublicKey(*btcec.PublicKey,
144
        waddrmgr.AddressType) error {
×
145

×
146
        return nil
×
147
}
×
148

149
// ImportTaprootScript currently returns a dummy value.
150
func (w *mockWalletController) ImportTaprootScript(waddrmgr.KeyScope,
151
        *waddrmgr.Tapscript) (waddrmgr.ManagedAddress, error) {
×
152

×
153
        return nil, nil
×
154
}
×
155

156
// SendOutputs currently returns dummy values.
157
func (w *mockWalletController) SendOutputs(fn.Set[wire.OutPoint], []*wire.TxOut,
158
        chainfee.SatPerKWeight, int32, string,
159
        base.CoinSelectionStrategy) (*wire.MsgTx, error) {
×
160

×
161
        return nil, nil
×
162
}
×
163

164
// CreateSimpleTx currently returns dummy values.
165
func (w *mockWalletController) CreateSimpleTx(fn.Set[wire.OutPoint],
166
        []*wire.TxOut, chainfee.SatPerKWeight, int32,
167
        base.CoinSelectionStrategy, bool) (*txauthor.AuthoredTx, error) {
×
168

×
169
        return nil, nil
×
170
}
×
171

172
// ListUnspentWitness is called by the wallet when doing coin selection. We just
173
// need one unspent for the funding transaction.
174
func (w *mockWalletController) ListUnspentWitness(int32, int32,
175
        string) ([]*Utxo, error) {
×
176

×
177
        // If the mock already has a list of utxos, return it.
×
178
        if w.Utxos != nil {
×
179
                return w.Utxos, nil
×
180
        }
×
181

182
        // Otherwise create one to return.
183
        utxo := &Utxo{
×
184
                AddressType: WitnessPubKey,
×
185
                Value:       btcutil.Amount(10 * btcutil.SatoshiPerBitcoin),
×
186
                PkScript:    CoinPkScript,
×
187
                OutPoint: wire.OutPoint{
×
188
                        Hash:  chainhash.Hash{},
×
189
                        Index: w.index,
×
190
                },
×
191
        }
×
192
        atomic.AddUint32(&w.index, 1)
×
193
        var ret []*Utxo
×
194
        ret = append(ret, utxo)
×
195

×
196
        return ret, nil
×
197
}
198

199
// ListTransactionDetails currently returns dummy values.
200
func (w *mockWalletController) ListTransactionDetails(int32, int32,
201
        string, uint32, uint32) ([]*TransactionDetail, uint64, uint64, error) {
×
202

×
203
        return nil, 0, 0, nil
×
204
}
×
205

206
// LeaseOutput returns the current time and a nil error.
207
func (w *mockWalletController) LeaseOutput(wtxmgr.LockID, wire.OutPoint,
208
        time.Duration) (time.Time, error) {
×
209

×
210
        return time.Now(), nil
×
211
}
×
212

213
// ReleaseOutput currently does nothing.
214
func (w *mockWalletController) ReleaseOutput(wtxmgr.LockID,
215
        wire.OutPoint) error {
×
216

×
217
        return nil
×
218
}
×
219

220
func (w *mockWalletController) ListLeasedOutputs() (
221
        []*base.ListLeasedOutputResult, error) {
×
222

×
223
        return nil, nil
×
224
}
×
225

226
// FundPsbt currently does nothing.
227
func (w *mockWalletController) FundPsbt(*psbt.Packet, int32,
228
        chainfee.SatPerKWeight, string, *waddrmgr.KeyScope,
229
        base.CoinSelectionStrategy, func(utxo wtxmgr.Credit) bool) (int32,
230
        error) {
×
231

×
232
        return 0, nil
×
233
}
×
234

235
// SignPsbt currently does nothing.
236
func (w *mockWalletController) SignPsbt(*psbt.Packet) ([]uint32, error) {
×
237
        return nil, nil
×
238
}
×
239

240
// FinalizePsbt currently does nothing.
241
func (w *mockWalletController) FinalizePsbt(_ *psbt.Packet, _ string) error {
×
242
        return nil
×
243
}
×
244

245
// DecorateInputs currently does nothing.
246
func (w *mockWalletController) DecorateInputs(*psbt.Packet, bool) error {
×
247
        return nil
×
248
}
×
249

250
// PublishTransaction sends a transaction to the PublishedTransactions chan.
251
func (w *mockWalletController) PublishTransaction(tx *wire.MsgTx,
UNCOV
252
        _ string) error {
×
UNCOV
253

×
UNCOV
254
        w.PublishedTransactions <- tx
×
UNCOV
255
        return nil
×
UNCOV
256
}
×
257

258
// GetTransactionDetails currently does nothing.
259
func (w *mockWalletController) GetTransactionDetails(*chainhash.Hash) (
260
        *TransactionDetail, error) {
×
261

×
262
        return nil, nil
×
263
}
×
264

265
// LabelTransaction currently does nothing.
266
func (w *mockWalletController) LabelTransaction(chainhash.Hash, string,
267
        bool) error {
×
268

×
269
        return nil
×
270
}
×
271

272
// SubscribeTransactions currently does nothing.
273
func (w *mockWalletController) SubscribeTransactions() (TransactionSubscription,
274
        error) {
×
275

×
276
        return nil, nil
×
277
}
×
278

279
// IsSynced currently returns dummy values.
280
func (w *mockWalletController) IsSynced() (bool, int64, error) {
×
281
        return true, int64(0), nil
×
282
}
×
283

284
// GetRecoveryInfo currently returns dummy values.
285
func (w *mockWalletController) GetRecoveryInfo() (bool, float64, error) {
×
286
        return true, float64(1), nil
×
287
}
×
288

289
// Start currently does nothing.
UNCOV
290
func (w *mockWalletController) Start() error {
×
UNCOV
291
        return nil
×
UNCOV
292
}
×
293

294
// Stop currently does nothing.
UNCOV
295
func (w *mockWalletController) Stop() error {
×
UNCOV
296
        return nil
×
UNCOV
297
}
×
298

299
func (w *mockWalletController) FetchTx(chainhash.Hash) (*wire.MsgTx, error) {
×
300
        return nil, nil
×
301
}
×
302

303
func (w *mockWalletController) RemoveDescendants(*wire.MsgTx) error {
×
304
        return nil
×
305
}
×
306

307
// FetchDerivationInfo queries for the wallet's knowledge of the passed
308
// pkScript and constructs the derivation info and returns it.
309
func (w *mockWalletController) FetchDerivationInfo(
310
        pkScript []byte) (*psbt.Bip32Derivation, error) {
×
311

×
312
        return nil, nil
×
313
}
×
314

315
func (w *mockWalletController) CheckMempoolAcceptance(tx *wire.MsgTx) error {
×
316
        return nil
×
317
}
×
318

319
// mockChainNotifier is a mock implementation of the ChainNotifier interface.
320
type mockChainNotifier struct {
321
        SpendChan chan *chainntnfs.SpendDetail
322
        EpochChan chan *chainntnfs.BlockEpoch
323
        ConfChan  chan *chainntnfs.TxConfirmation
324
}
325

326
// RegisterConfirmationsNtfn returns a ConfirmationEvent that contains a channel
327
// that the tx confirmation will go over.
328
func (c *mockChainNotifier) RegisterConfirmationsNtfn(txid *chainhash.Hash,
329
        pkScript []byte, numConfs, heightHint uint32,
330
        opts ...chainntnfs.NotifierOption) (*chainntnfs.ConfirmationEvent,
UNCOV
331
        error) {
×
UNCOV
332

×
UNCOV
333
        return &chainntnfs.ConfirmationEvent{
×
UNCOV
334
                Confirmed: c.ConfChan,
×
UNCOV
335
                Cancel:    func() {},
×
336
        }, nil
337
}
338

339
// RegisterSpendNtfn returns a SpendEvent that contains a channel that the spend
340
// details will go over.
341
func (c *mockChainNotifier) RegisterSpendNtfn(outpoint *wire.OutPoint,
342
        pkScript []byte, heightHint uint32) (*chainntnfs.SpendEvent, error) {
×
343

×
344
        return &chainntnfs.SpendEvent{
×
345
                Spend:  c.SpendChan,
×
346
                Cancel: func() {},
×
347
        }, nil
348
}
349

350
// RegisterBlockEpochNtfn returns a BlockEpochEvent that contains a channel that
351
// block epochs will go over.
352
func (c *mockChainNotifier) RegisterBlockEpochNtfn(
353
        blockEpoch *chainntnfs.BlockEpoch) (*chainntnfs.BlockEpochEvent,
354
        error) {
×
355

×
356
        return &chainntnfs.BlockEpochEvent{
×
357
                Epochs: c.EpochChan,
×
358
                Cancel: func() {},
×
359
        }, nil
360
}
361

362
// Start currently returns a dummy value.
363
func (c *mockChainNotifier) Start() error {
×
364
        return nil
×
365
}
×
366

367
// Started currently returns a dummy value.
368
func (c *mockChainNotifier) Started() bool {
×
369
        return true
×
370
}
×
371

372
// Stop currently returns a dummy value.
373
func (c *mockChainNotifier) Stop() error {
×
374
        return nil
×
375
}
×
376

377
type mockChainIO struct{}
378

UNCOV
379
func (*mockChainIO) GetBestBlock() (*chainhash.Hash, int32, error) {
×
UNCOV
380
        return nil, 0, nil
×
UNCOV
381
}
×
382

383
func (*mockChainIO) GetUtxo(op *wire.OutPoint, _ []byte,
384
        heightHint uint32, _ <-chan struct{}) (*wire.TxOut, error) {
×
385

×
386
        return nil, nil
×
387
}
×
388

389
func (*mockChainIO) GetBlockHash(blockHeight int64) (*chainhash.Hash, error) {
×
390
        return nil, nil
×
391
}
×
392

393
func (*mockChainIO) GetBlock(blockHash *chainhash.Hash) (*wire.MsgBlock,
394
        error) {
×
395

×
396
        return nil, nil
×
397
}
×
398

399
func (*mockChainIO) GetBlockHeader(
400
        blockHash *chainhash.Hash) (*wire.BlockHeader, error) {
×
401

×
402
        return nil, nil
×
403
}
×
404

405
type MockAuxLeafStore struct{}
406

407
// A compile time check to ensure that MockAuxLeafStore implements the
408
// AuxLeafStore interface.
409
var _ AuxLeafStore = (*MockAuxLeafStore)(nil)
410

411
// FetchLeavesFromView attempts to fetch the auxiliary leaves that
412
// correspond to the passed aux blob, and pending original (unfiltered)
413
// HTLC view.
414
func (*MockAuxLeafStore) FetchLeavesFromView(
415
        _ CommitDiffAuxInput) fn.Result[CommitDiffAuxResult] {
×
416

×
417
        return fn.Ok(CommitDiffAuxResult{})
×
418
}
×
419

420
// FetchLeavesFromCommit attempts to fetch the auxiliary leaves that
421
// correspond to the passed aux blob, and an existing channel
422
// commitment.
423
func (*MockAuxLeafStore) FetchLeavesFromCommit(_ AuxChanState,
424
        _ channeldb.ChannelCommitment, _ CommitmentKeyRing,
UNCOV
425
        _ lntypes.ChannelParty) fn.Result[CommitDiffAuxResult] {
×
UNCOV
426

×
UNCOV
427
        return fn.Ok(CommitDiffAuxResult{})
×
UNCOV
428
}
×
429

430
// FetchLeavesFromRevocation attempts to fetch the auxiliary leaves
431
// from a channel revocation that stores balance + blob information.
432
func (*MockAuxLeafStore) FetchLeavesFromRevocation(
UNCOV
433
        _ *channeldb.RevocationLog) fn.Result[CommitDiffAuxResult] {
×
UNCOV
434

×
UNCOV
435
        return fn.Ok(CommitDiffAuxResult{})
×
UNCOV
436
}
×
437

438
// ApplyHtlcView serves as the state transition function for the custom
439
// channel's blob. Given the old blob, and an HTLC view, then a new
440
// blob should be returned that reflects the pending updates.
441
func (*MockAuxLeafStore) ApplyHtlcView(
442
        _ CommitDiffAuxInput) fn.Result[fn.Option[tlv.Blob]] {
×
443

×
444
        return fn.Ok(fn.None[tlv.Blob]())
×
445
}
×
446

447
// EmptyMockJobHandler is a mock job handler that just sends an empty response
448
// to all jobs.
UNCOV
449
func EmptyMockJobHandler(jobs []AuxSigJob) {
×
UNCOV
450
        for _, sigJob := range jobs {
×
UNCOV
451
                sigJob.Resp <- AuxSigJobResp{}
×
UNCOV
452
        }
×
453
}
454

455
// MockAuxSigner is a mock implementation of the AuxSigner interface.
456
type MockAuxSigner struct {
457
        mock.Mock
458

459
        jobHandlerFunc func([]AuxSigJob)
460
}
461

462
// NewAuxSignerMock creates a new mock aux signer with the given job handler.
UNCOV
463
func NewAuxSignerMock(jobHandler func([]AuxSigJob)) *MockAuxSigner {
×
UNCOV
464
        return &MockAuxSigner{
×
UNCOV
465
                jobHandlerFunc: jobHandler,
×
UNCOV
466
        }
×
UNCOV
467
}
×
468

469
// SubmitSecondLevelSigBatch takes a batch of aux sign jobs and
470
// processes them asynchronously.
471
func (a *MockAuxSigner) SubmitSecondLevelSigBatch(chanState AuxChanState,
UNCOV
472
        tx *wire.MsgTx, jobs []AuxSigJob) error {
×
UNCOV
473

×
UNCOV
474
        args := a.Called(chanState, tx, jobs)
×
UNCOV
475

×
UNCOV
476
        if a.jobHandlerFunc != nil {
×
UNCOV
477
                a.jobHandlerFunc(jobs)
×
UNCOV
478
        }
×
479

UNCOV
480
        return args.Error(0)
×
481
}
482

483
// PackSigs takes a series of aux signatures and packs them into a
484
// single blob that can be sent alongside the CommitSig messages.
485
func (a *MockAuxSigner) PackSigs(
UNCOV
486
        sigs []fn.Option[tlv.Blob]) fn.Result[fn.Option[tlv.Blob]] {
×
UNCOV
487

×
UNCOV
488
        args := a.Called(sigs)
×
UNCOV
489

×
UNCOV
490
        return args.Get(0).(fn.Result[fn.Option[tlv.Blob]])
×
UNCOV
491
}
×
492

493
// UnpackSigs takes a packed blob of signatures and returns the
494
// original signatures for each HTLC, keyed by HTLC index.
495
func (a *MockAuxSigner) UnpackSigs(
UNCOV
496
        sigs fn.Option[tlv.Blob]) fn.Result[[]fn.Option[tlv.Blob]] {
×
UNCOV
497

×
UNCOV
498
        args := a.Called(sigs)
×
UNCOV
499

×
UNCOV
500
        return args.Get(0).(fn.Result[[]fn.Option[tlv.Blob]])
×
UNCOV
501
}
×
502

503
// VerifySecondLevelSigs attempts to synchronously verify a batch of aux
504
// sig jobs.
505
func (a *MockAuxSigner) VerifySecondLevelSigs(chanState AuxChanState,
UNCOV
506
        tx *wire.MsgTx, jobs []AuxVerifyJob) error {
×
UNCOV
507

×
UNCOV
508
        args := a.Called(chanState, tx, jobs)
×
UNCOV
509

×
UNCOV
510
        return args.Error(0)
×
UNCOV
511
}
×
512

513
type MockAuxContractResolver struct{}
514

515
// ResolveContract is called to resolve a contract that needs
516
// additional information to resolve properly. If no extra information
517
// is required, a nil Result error is returned.
518
func (*MockAuxContractResolver) ResolveContract(
UNCOV
519
        ResolutionReq) fn.Result[tlv.Blob] {
×
UNCOV
520

×
UNCOV
521
        return fn.Ok[tlv.Blob](nil)
×
UNCOV
522
}
×
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