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

lightningnetwork / lnd / 13586005509

28 Feb 2025 10:14AM UTC coverage: 68.629% (+9.9%) from 58.77%
13586005509

Pull #9521

github

web-flow
Merge 37d3a70a5 into 8532955b3
Pull Request #9521: unit: remove GOACC, use Go 1.20 native coverage functionality

129950 of 189351 relevant lines covered (68.63%)

23726.46 hits per line

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

40.94
/sweep/test_utils.go
1
package sweep
2

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

9
        "github.com/btcsuite/btcd/chaincfg/chainhash"
10
        "github.com/btcsuite/btcd/wire"
11
        "github.com/lightningnetwork/lnd/chainntnfs"
12
)
13

14
var (
15
        defaultTestTimeout = 5 * time.Second
16
        processingDelay    = 1 * time.Second
17
        mockChainHash, _   = chainhash.NewHashFromStr("00aabbccddeeff")
18
        mockChainHeight    = int32(100)
19
)
20

21
// MockNotifier simulates the chain notifier for test purposes. This type is
22
// exported because it is used in nursery tests.
23
type MockNotifier struct {
24
        confChannel map[chainhash.Hash]chan *chainntnfs.TxConfirmation
25
        epochChan   map[chan *chainntnfs.BlockEpoch]int32
26
        spendChan   map[wire.OutPoint][]chan *chainntnfs.SpendDetail
27
        spends      map[wire.OutPoint]*wire.MsgTx
28
        mutex       sync.RWMutex
29
        t           *testing.T
30
}
31

32
// NewMockNotifier instantiates a new mock notifier.
33
func NewMockNotifier(t *testing.T) *MockNotifier {
18✔
34
        return &MockNotifier{
18✔
35
                confChannel: make(map[chainhash.Hash]chan *chainntnfs.TxConfirmation),
18✔
36
                epochChan:   make(map[chan *chainntnfs.BlockEpoch]int32),
18✔
37
                spendChan:   make(map[wire.OutPoint][]chan *chainntnfs.SpendDetail),
18✔
38
                spends:      make(map[wire.OutPoint]*wire.MsgTx),
18✔
39
                t:           t,
18✔
40
        }
18✔
41
}
18✔
42

43
// NotifyEpochNonBlocking simulates a new epoch arriving without blocking when
44
// the epochChan is not read.
45
func (m *MockNotifier) NotifyEpochNonBlocking(height int32) {
×
46
        m.t.Helper()
×
47

×
48
        for epochChan, chanHeight := range m.epochChan {
×
49
                // Only send notifications if the height is greater than the
×
50
                // height the caller passed into the register call.
×
51
                if chanHeight >= height {
×
52
                        continue
×
53
                }
54

55
                log.Debugf("Notifying height %v to listener", height)
×
56

×
57
                select {
×
58
                case epochChan <- &chainntnfs.BlockEpoch{Height: height}:
×
59
                default:
×
60
                }
61
        }
62
}
63

64
// NotifyEpoch simulates a new epoch arriving.
65
func (m *MockNotifier) NotifyEpoch(height int32) {
28✔
66
        m.t.Helper()
28✔
67

28✔
68
        for epochChan, chanHeight := range m.epochChan {
56✔
69
                // Only send notifications if the height is greater than the
28✔
70
                // height the caller passed into the register call.
28✔
71
                if chanHeight >= height {
28✔
72
                        continue
×
73
                }
74

75
                log.Debugf("Notifying height %v to listener", height)
28✔
76

28✔
77
                select {
28✔
78
                case epochChan <- &chainntnfs.BlockEpoch{
79
                        Height: height,
80
                }:
28✔
81
                case <-time.After(defaultTestTimeout):
×
82
                        m.t.Fatal("epoch event not consumed")
×
83
                }
84
        }
85
}
86

87
// ConfirmTx simulates a tx confirming.
88
func (m *MockNotifier) ConfirmTx(txid *chainhash.Hash, height uint32) error {
17✔
89
        confirm := &chainntnfs.TxConfirmation{
17✔
90
                BlockHeight: height,
17✔
91
        }
17✔
92
        select {
17✔
93
        case m.getConfChannel(txid) <- confirm:
17✔
94
        case <-time.After(defaultTestTimeout):
×
95
                return fmt.Errorf("confirmation not consumed")
×
96
        }
97
        return nil
17✔
98
}
99

100
// SpendOutpoint simulates a utxo being spent.
101
func (m *MockNotifier) SpendOutpoint(outpoint wire.OutPoint,
102
        spendingTx wire.MsgTx) {
×
103

×
104
        log.Debugf("Spending outpoint %v", outpoint)
×
105

×
106
        m.mutex.Lock()
×
107
        defer m.mutex.Unlock()
×
108

×
109
        channels, ok := m.spendChan[outpoint]
×
110
        if ok {
×
111
                for _, channel := range channels {
×
112
                        m.sendSpend(channel, &outpoint, &spendingTx)
×
113
                }
×
114
        }
115

116
        m.spends[outpoint] = &spendingTx
×
117
}
118

119
func (m *MockNotifier) sendSpend(channel chan *chainntnfs.SpendDetail,
120
        outpoint *wire.OutPoint,
121
        spendingTx *wire.MsgTx) {
×
122

×
123
        log.Debugf("Notifying spend of outpoint %v", outpoint)
×
124

×
125
        spenderTxHash := spendingTx.TxHash()
×
126
        channel <- &chainntnfs.SpendDetail{
×
127
                SpenderTxHash: &spenderTxHash,
×
128
                SpendingTx:    spendingTx,
×
129
                SpentOutPoint: outpoint,
×
130
        }
×
131
}
×
132

133
// RegisterConfirmationsNtfn registers for tx confirm notifications.
134
func (m *MockNotifier) RegisterConfirmationsNtfn(txid *chainhash.Hash,
135
        _ []byte, numConfs, heightHint uint32,
136
        opt ...chainntnfs.NotifierOption) (*chainntnfs.ConfirmationEvent, error) {
23✔
137

23✔
138
        return &chainntnfs.ConfirmationEvent{
23✔
139
                Confirmed: m.getConfChannel(txid),
23✔
140
        }, nil
23✔
141
}
23✔
142

143
func (m *MockNotifier) getConfChannel(
144
        txid *chainhash.Hash) chan *chainntnfs.TxConfirmation {
40✔
145

40✔
146
        m.mutex.Lock()
40✔
147
        defer m.mutex.Unlock()
40✔
148

40✔
149
        channel, ok := m.confChannel[*txid]
40✔
150
        if ok {
63✔
151
                return channel
23✔
152
        }
23✔
153
        channel = make(chan *chainntnfs.TxConfirmation)
17✔
154
        m.confChannel[*txid] = channel
17✔
155

17✔
156
        return channel
17✔
157
}
158

159
// RegisterBlockEpochNtfn registers a block notification.
160
func (m *MockNotifier) RegisterBlockEpochNtfn(
161
        bestBlock *chainntnfs.BlockEpoch) (*chainntnfs.BlockEpochEvent, error) {
42✔
162

42✔
163
        log.Tracef("Mock block ntfn registered")
42✔
164

42✔
165
        m.mutex.Lock()
42✔
166
        epochChan := make(chan *chainntnfs.BlockEpoch, 1)
42✔
167

42✔
168
        // The real notifier returns a notification with the current block hash
42✔
169
        // and height immediately if no best block hash or height is specified
42✔
170
        // in the request. We want to emulate this behaviour as well for the
42✔
171
        // mock.
42✔
172
        switch {
42✔
173
        case bestBlock == nil:
×
174
                epochChan <- &chainntnfs.BlockEpoch{
×
175
                        Hash:   mockChainHash,
×
176
                        Height: mockChainHeight,
×
177
                }
×
178
                m.epochChan[epochChan] = mockChainHeight
×
179
        default:
42✔
180
                m.epochChan[epochChan] = bestBlock.Height
42✔
181
        }
182
        m.mutex.Unlock()
42✔
183

42✔
184
        return &chainntnfs.BlockEpochEvent{
42✔
185
                Epochs: epochChan,
42✔
186
                Cancel: func() {
83✔
187
                        log.Tracef("Mock block ntfn canceled")
41✔
188
                        m.mutex.Lock()
41✔
189
                        delete(m.epochChan, epochChan)
41✔
190
                        m.mutex.Unlock()
41✔
191
                },
41✔
192
        }, nil
193
}
194

195
// Start the notifier.
196
func (m *MockNotifier) Start() error {
×
197
        return nil
×
198
}
×
199

200
// Started checks if started.
201
func (m *MockNotifier) Started() bool {
×
202
        return true
×
203
}
×
204

205
// Stop the notifier.
206
func (m *MockNotifier) Stop() error {
×
207
        return nil
×
208
}
×
209

210
// RegisterSpendNtfn registers for spend notifications.
211
func (m *MockNotifier) RegisterSpendNtfn(outpoint *wire.OutPoint,
212
        _ []byte, heightHint uint32) (*chainntnfs.SpendEvent, error) {
×
213

×
214
        log.Debugf("RegisterSpendNtfn for outpoint %v", outpoint)
×
215

×
216
        // Add channel to global spend ntfn map.
×
217
        m.mutex.Lock()
×
218

×
219
        channels, ok := m.spendChan[*outpoint]
×
220
        if !ok {
×
221
                channels = make([]chan *chainntnfs.SpendDetail, 0)
×
222
        }
×
223

224
        channel := make(chan *chainntnfs.SpendDetail, 1)
×
225
        channels = append(channels, channel)
×
226
        m.spendChan[*outpoint] = channels
×
227

×
228
        // Check if this output has already been spent.
×
229
        spendingTx, spent := m.spends[*outpoint]
×
230

×
231
        m.mutex.Unlock()
×
232

×
233
        // If output has been spent already, signal now. Do this outside the
×
234
        // lock to prevent a deadlock.
×
235
        if spent {
×
236
                m.sendSpend(channel, outpoint, spendingTx)
×
237
        }
×
238

239
        return &chainntnfs.SpendEvent{
×
240
                Spend: channel,
×
241
                Cancel: func() {
×
242
                        log.Infof("Cancelling RegisterSpendNtfn for %v",
×
243
                                outpoint)
×
244

×
245
                        m.mutex.Lock()
×
246
                        defer m.mutex.Unlock()
×
247
                        channels := m.spendChan[*outpoint]
×
248
                        for i, c := range channels {
×
249
                                if c == channel {
×
250
                                        channels[i] = channels[len(channels)-1]
×
251
                                        m.spendChan[*outpoint] =
×
252
                                                channels[:len(channels)-1]
×
253
                                }
×
254
                        }
255

256
                        close(channel)
×
257

×
258
                        log.Infof("Spend ntfn channel closed for %v",
×
259
                                outpoint)
×
260
                },
261
        }, nil
262
}
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