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

lightningnetwork / lnd / 12312390362

13 Dec 2024 08:44AM UTC coverage: 57.458% (+8.5%) from 48.92%
12312390362

Pull #9343

github

ellemouton
fn: rework the ContextGuard and add tests

In this commit, the ContextGuard struct is re-worked such that the
context that its new main WithCtx method provides is cancelled in sync
with a parent context being cancelled or with it's quit channel being
cancelled. Tests are added to assert the behaviour. In order for the
close of the quit channel to be consistent with the cancelling of the
derived context, the quit channel _must_ be contained internal to the
ContextGuard so that callers are only able to close the channel via the
exposed Quit method which will then take care to first cancel any
derived context that depend on the quit channel before returning.
Pull Request #9343: fn: expand the ContextGuard and add tests

101853 of 177264 relevant lines covered (57.46%)

24972.93 hits per line

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

14.46
/lnwallet/btcwallet/blockchain.go
1
package btcwallet
2

3
import (
4
        "encoding/hex"
5
        "errors"
6
        "fmt"
7

8
        "github.com/btcsuite/btcd/btcutil"
9
        "github.com/btcsuite/btcd/chaincfg/chainhash"
10
        "github.com/btcsuite/btcd/wire"
11
        "github.com/btcsuite/btcwallet/chain"
12
        "github.com/lightninglabs/neutrino"
13
        "github.com/lightninglabs/neutrino/headerfs"
14
        "github.com/lightningnetwork/lnd/lntypes"
15
        "github.com/lightningnetwork/lnd/lnwallet"
16
)
17

18
var (
19
        // ErrOutputSpent is returned by the GetUtxo method if the target output
20
        // for lookup has already been spent.
21
        ErrOutputSpent = errors.New("target output has been spent")
22

23
        // ErrOutputNotFound signals that the desired output could not be
24
        // located.
25
        ErrOutputNotFound = errors.New("target output was not found")
26
)
27

28
// GetBestBlock returns the current height and hash of the best known block
29
// within the main chain.
30
//
31
// This method is a part of the lnwallet.BlockChainIO interface.
32
func (b *BtcWallet) GetBestBlock() (*chainhash.Hash, int32, error) {
209✔
33
        return b.chain.GetBestBlock()
209✔
34
}
209✔
35

36
// GetUtxo returns the original output referenced by the passed outpoint that
37
// creates the target pkScript.
38
//
39
// This method is a part of the lnwallet.BlockChainIO interface.
40
func (b *BtcWallet) GetUtxo(op *wire.OutPoint, pkScript []byte,
41
        heightHint uint32, cancel <-chan struct{}) (*wire.TxOut, error) {
×
42

×
43
        switch backend := b.chain.(type) {
×
44

45
        case *chain.NeutrinoClient:
×
46
                spendReport, err := backend.CS.GetUtxo(
×
47
                        neutrino.WatchInputs(neutrino.InputWithScript{
×
48
                                OutPoint: *op,
×
49
                                PkScript: pkScript,
×
50
                        }),
×
51
                        neutrino.StartBlock(&headerfs.BlockStamp{
×
52
                                Height: int32(heightHint),
×
53
                        }),
×
54
                        neutrino.QuitChan(cancel),
×
55
                )
×
56
                if err != nil {
×
57
                        return nil, err
×
58
                }
×
59

60
                // If the spend report is nil, then the output was not found in
61
                // the rescan.
62
                if spendReport == nil {
×
63
                        return nil, ErrOutputNotFound
×
64
                }
×
65

66
                // If the spending transaction is populated in the spend report,
67
                // this signals that the output has already been spent.
68
                if spendReport.SpendingTx != nil {
×
69
                        return nil, ErrOutputSpent
×
70
                }
×
71

72
                // Otherwise, the output is assumed to be in the UTXO.
73
                return spendReport.Output, nil
×
74

75
        case *chain.RPCClient:
×
76
                txout, err := backend.GetTxOut(&op.Hash, op.Index, false)
×
77
                if err != nil {
×
78
                        return nil, err
×
79
                } else if txout == nil {
×
80
                        return nil, ErrOutputSpent
×
81
                }
×
82

83
                pkScript, err := hex.DecodeString(txout.ScriptPubKey.Hex)
×
84
                if err != nil {
×
85
                        return nil, err
×
86
                }
×
87

88
                // We'll ensure we properly convert the amount given in BTC to
89
                // satoshis.
90
                amt, err := btcutil.NewAmount(txout.Value)
×
91
                if err != nil {
×
92
                        return nil, err
×
93
                }
×
94

95
                return &wire.TxOut{
×
96
                        Value:    int64(amt),
×
97
                        PkScript: pkScript,
×
98
                }, nil
×
99

100
        case *chain.BitcoindClient:
×
101
                txout, err := backend.GetTxOut(&op.Hash, op.Index, false)
×
102
                if err != nil {
×
103
                        return nil, err
×
104
                } else if txout == nil {
×
105
                        return nil, ErrOutputSpent
×
106
                }
×
107

108
                pkScript, err := hex.DecodeString(txout.ScriptPubKey.Hex)
×
109
                if err != nil {
×
110
                        return nil, err
×
111
                }
×
112

113
                // Sadly, gettxout returns the output value in BTC instead of
114
                // satoshis.
115
                amt, err := btcutil.NewAmount(txout.Value)
×
116
                if err != nil {
×
117
                        return nil, err
×
118
                }
×
119

120
                return &wire.TxOut{
×
121
                        Value:    int64(amt),
×
122
                        PkScript: pkScript,
×
123
                }, nil
×
124

125
        default:
×
126
                return nil, fmt.Errorf("unknown backend")
×
127
        }
128
}
129

130
// GetBlock returns a raw block from the server given its hash. For the Neutrino
131
// implementation of the lnwallet.BlockChainIO interface, the Neutrino GetBlock
132
// method is called directly. For other implementations, the block cache is used
133
// to wrap the call to GetBlock.
134
//
135
// This method is a part of the lnwallet.BlockChainIO interface.
136
func (b *BtcWallet) GetBlock(blockHash *chainhash.Hash) (*wire.MsgBlock, error) {
4✔
137
        _, ok := b.chain.(*chain.NeutrinoClient)
4✔
138
        if !ok {
7✔
139
                return b.blockCache.GetBlock(blockHash, b.chain.GetBlock)
3✔
140
        }
3✔
141

142
        // For the neutrino implementation of lnwallet.BlockChainIO the neutrino
143
        // GetBlock function can be called directly since it uses the same block
144
        // cache. However, it does not lock the block cache mutex for the given
145
        // block hash and so that is done here.
146
        b.blockCache.HashMutex.Lock(lntypes.Hash(*blockHash))
1✔
147
        defer b.blockCache.HashMutex.Unlock(lntypes.Hash(*blockHash))
1✔
148

1✔
149
        return b.chain.GetBlock(blockHash)
1✔
150
}
151

152
// GetBlockHeader returns a block header for the block with the given hash.
153
//
154
// This method is a part of the lnwallet.BlockChainIO interface.
155
func (b *BtcWallet) GetBlockHeader(
156
        blockHash *chainhash.Hash) (*wire.BlockHeader, error) {
×
157

×
158
        return b.chain.GetBlockHeader(blockHash)
×
159
}
×
160

161
// GetBlockHash returns the hash of the block in the best blockchain at the
162
// given height.
163
//
164
// This method is a part of the lnwallet.BlockChainIO interface.
165
func (b *BtcWallet) GetBlockHash(blockHeight int64) (*chainhash.Hash, error) {
×
166
        return b.chain.GetBlockHash(blockHeight)
×
167
}
×
168

169
// A compile time check to ensure that BtcWallet implements the BlockChainIO
170
// interface.
171
var _ lnwallet.WalletController = (*BtcWallet)(nil)
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