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

lightningnetwork / lnd / 18852986778

27 Oct 2025 07:10PM UTC coverage: 54.859% (-11.8%) from 66.648%
18852986778

Pull #10265

github

web-flow
Merge 45787b3d5 into 9a7b526c0
Pull Request #10265: multi: update close logic to handle re-orgs of depth n-1, where n is num confs - add min conf floor

529 of 828 new or added lines in 17 files covered. (63.89%)

24026 existing lines in 286 files now uncovered.

110927 of 202205 relevant lines covered (54.86%)

21658.16 hits per line

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

0.0
/lntest/harness_miner.go
1
package lntest
2

3
import (
4
        "fmt"
5

6
        "github.com/btcsuite/btcd/blockchain"
7
        "github.com/btcsuite/btcd/btcutil"
8
        "github.com/btcsuite/btcd/chaincfg/chainhash"
9
        "github.com/btcsuite/btcd/wire"
10
        "github.com/lightningnetwork/lnd/lntest/miner"
11
        "github.com/lightningnetwork/lnd/lntest/node"
12
        "github.com/lightningnetwork/lnd/lntest/wait"
13
        "github.com/stretchr/testify/require"
14
)
15

16
// Miner returns the miner instance.
17
//
18
// NOTE: Caller should keep in mind that when using this private instance,
19
// certain states won't be managed by the HarnessTest anymore. For instance,
20
// when mining directly, the nodes managed by the HarnessTest can be out of
21
// sync, and the `HarnessTest.CurrentHeight()` won't be accurate.
22
func (h *HarnessTest) Miner() *miner.HarnessMiner {
×
23
        return h.miner
×
24
}
×
25

26
// MineBlocks mines blocks and asserts all active nodes have synced to the
27
// chain. It assumes no txns are expected in the blocks.
28
//
29
// NOTE: Use `MineBlocksAndAssertNumTxes` if you expect txns in the blocks. Use
30
// `MineEmptyBlocks` if you want to make sure that txns stay unconfirmed.
31
func (h *HarnessTest) MineBlocks(num int) {
×
32
        require.Less(h, num, maxBlocksAllowed, "too many blocks to mine")
×
33

×
34
        // Update the harness's current height.
×
35
        defer h.updateCurrentHeight()
×
36

×
37
        // Mine num of blocks.
×
38
        for i := 0; i < num; i++ {
×
39
                block := h.miner.MineBlocks(1)[0]
×
40

×
41
                // Check the block doesn't have any txns except the coinbase.
×
42
                if len(block.Transactions) <= 1 {
×
43
                        // Make sure all the active nodes are synced.
×
44
                        h.AssertActiveNodesSyncedTo(block.BlockHash())
×
45

×
46
                        // Mine the next block.
×
47
                        continue
×
48
                }
49

50
                // Create a detailed description.
51
                desc := fmt.Sprintf("block %v has %d txns:\n",
×
52
                        block.BlockHash(), len(block.Transactions)-1)
×
53

×
54
                // Print all the txns except the coinbase.
×
55
                for _, tx := range block.Transactions {
×
56
                        if blockchain.IsCoinBaseTx(tx) {
×
57
                                continue
×
58
                        }
59

60
                        desc += fmt.Sprintf("%v\n", tx.TxHash())
×
61
                }
62

63
                desc += "Consider using `MineBlocksAndAssertNumTxes` if you " +
×
64
                        "expect txns, or `MineEmptyBlocks` if you want to " +
×
65
                        "keep the txns unconfirmed."
×
66

×
67
                // Raise an error if the block has txns.
×
68
                require.Fail(h, "MineBlocks", desc)
×
69
        }
70
}
71

72
// MineEmptyBlocks mines a given number of empty blocks.
73
//
74
// NOTE: this differs from miner's `MineEmptyBlocks` as it requires the nodes
75
// to be synced.
76
func (h *HarnessTest) MineEmptyBlocks(num int) []*wire.MsgBlock {
×
77
        require.Less(h, num, maxBlocksAllowed, "too many blocks to mine")
×
78

×
79
        // Update the harness's current height.
×
80
        defer h.updateCurrentHeight()
×
81

×
82
        blocks := h.miner.MineEmptyBlocks(num)
×
83

×
84
        // Finally, make sure all the active nodes are synced.
×
85
        h.AssertActiveNodesSynced()
×
86

×
87
        return blocks
×
88
}
×
89

90
// MineBlocksAndAssertNumTxes mines blocks and asserts the number of
91
// transactions are found in the first block. It also asserts all active nodes
92
// have synced to the chain.
93
//
94
// NOTE: this differs from miner's `MineBlocks` as it requires the nodes to be
95
// synced.
96
func (h *HarnessTest) MineBlocksAndAssertNumTxes(num uint32,
97
        numTxs int) []*wire.MsgBlock {
×
98

×
99
        // Update the harness's current height.
×
100
        defer h.updateCurrentHeight()
×
101

×
102
        // If we expect transactions to be included in the blocks we'll mine,
×
103
        // we wait here until they are seen in the miner's mempool.
×
104
        txids := h.AssertNumTxsInMempool(numTxs)
×
105

×
106
        // Mine blocks.
×
107
        blocks := h.miner.MineBlocks(num)
×
108

×
109
        // Assert that all the transactions were included in the first block.
×
110
        for _, txid := range txids {
×
111
                h.miner.AssertTxInBlock(blocks[0], txid)
×
112
        }
×
113

114
        // Make sure the mempool has been updated.
115
        h.miner.AssertTxnsNotInMempool(txids)
×
116

×
117
        // Finally, make sure all the active nodes are synced.
×
118
        bestBlock := blocks[len(blocks)-1]
×
119
        h.AssertActiveNodesSyncedTo(bestBlock.BlockHash())
×
120

×
121
        return blocks
×
122
}
123

124
// MineBlocksAndAssertNumTxesWithSweep is like MineBlocksAndAssertNumTxes but
125
// handles async confirmation notification races by triggering sweeps if needed.
126
// Use this for tests that expect sweep transactions after force closes or other
127
// events where confirmation notifications may arrive asynchronously.
128
func (h *HarnessTest) MineBlocksAndAssertNumTxesWithSweep(num uint32,
NEW
129
        numTxs int, hn *node.HarnessNode) []*wire.MsgBlock {
×
NEW
130

×
NEW
131
        // Update the harness's current height.
×
NEW
132
        defer h.updateCurrentHeight()
×
NEW
133

×
NEW
134
        // Wait for transactions with sweep triggering support.
×
NEW
135
        txids := h.AssertNumTxsInMempoolWithSweepTrigger(numTxs, hn)
×
NEW
136

×
NEW
137
        // Mine blocks.
×
NEW
138
        blocks := h.miner.MineBlocks(num)
×
NEW
139

×
NEW
140
        // Assert that all the transactions were included in the first block.
×
NEW
141
        for _, txid := range txids {
×
NEW
142
                h.miner.AssertTxInBlock(blocks[0], txid)
×
NEW
143
        }
×
144

145
        // Make sure the mempool has been updated.
NEW
146
        h.miner.AssertTxnsNotInMempool(txids)
×
NEW
147

×
NEW
148
        // Finally, make sure all the active nodes are synced.
×
NEW
149
        bestBlock := blocks[len(blocks)-1]
×
NEW
150
        h.AssertActiveNodesSyncedTo(bestBlock.BlockHash())
×
NEW
151

×
NEW
152
        return blocks
×
153
}
154

155
// ConnectMiner connects the miner with the chain backend in the network.
156
func (h *HarnessTest) ConnectMiner() {
×
157
        err := h.manager.chainBackend.ConnectMiner()
×
158
        require.NoError(h, err, "failed to connect miner")
×
159
}
×
160

161
// DisconnectMiner removes the connection between the miner and the chain
162
// backend in the network.
163
func (h *HarnessTest) DisconnectMiner() {
×
164
        err := h.manager.chainBackend.DisconnectMiner()
×
165
        require.NoError(h, err, "failed to disconnect miner")
×
166
}
×
167

168
// cleanMempool mines blocks till the mempool is empty and asserts all active
169
// nodes have synced to the chain.
170
func (h *HarnessTest) cleanMempool() {
×
171
        _, startHeight := h.GetBestBlock()
×
172

×
173
        // Mining the blocks slow to give `lnd` more time to sync.
×
174
        var bestBlock *wire.MsgBlock
×
175
        err := wait.NoError(func() error {
×
176
                // If mempool is empty, exit.
×
177
                mem := h.miner.GetRawMempool()
×
178
                if len(mem) == 0 {
×
179
                        _, height := h.GetBestBlock()
×
180
                        h.Logf("Mined %d blocks when cleanup the mempool",
×
181
                                height-startHeight)
×
182

×
183
                        return nil
×
184
                }
×
185

186
                // Otherwise mine a block.
187
                blocks := h.miner.MineBlocksSlow(1)
×
188
                bestBlock = blocks[len(blocks)-1]
×
189

×
190
                // Make sure all the active nodes are synced.
×
191
                h.AssertActiveNodesSyncedTo(bestBlock.BlockHash())
×
192

×
193
                return fmt.Errorf("still have %d txes in mempool", len(mem))
×
194
        }, wait.MinerMempoolTimeout)
195
        require.NoError(h, err, "timeout cleaning up mempool")
×
196
}
197

198
// mineTillForceCloseResolved asserts that the number of pending close channels
199
// are zero. Each time it checks, an empty block is mined, followed by a
200
// mempool check to see if there are any sweeping txns. If found, these txns
201
// are then mined to clean up the mempool.
202
func (h *HarnessTest) mineTillForceCloseResolved(hn *node.HarnessNode) {
×
203
        _, startHeight := h.GetBestBlock()
×
204

×
205
        err := wait.NoError(func() error {
×
206
                resp := hn.RPC.PendingChannels()
×
207
                total := len(resp.PendingForceClosingChannels)
×
208
                if total != 0 {
×
209
                        // Mine an empty block first.
×
210
                        h.MineEmptyBlocks(1)
×
211

×
212
                        // If there are new sweeping txns, mine a block to
×
213
                        // confirm it.
×
214
                        mem := h.GetRawMempool()
×
215
                        if len(mem) != 0 {
×
216
                                h.MineBlocksAndAssertNumTxes(1, len(mem))
×
217
                        }
×
218

219
                        return fmt.Errorf("expected num of pending force " +
×
220
                                "close channel to be zero")
×
221
                }
222

223
                _, height := h.GetBestBlock()
×
224
                h.Logf("Mined %d blocks while waiting for force closed "+
×
225
                        "channel to be resolved", height-startHeight)
×
226

×
227
                return nil
×
228
        }, DefaultTimeout)
229

230
        require.NoErrorf(h, err, "%s: assert force close resolved timeout",
×
231
                hn.Name())
×
232
}
233

234
// AssertTxInMempool asserts a given transaction can be found in the mempool.
235
func (h *HarnessTest) AssertTxInMempool(txid chainhash.Hash) *wire.MsgTx {
×
236
        return h.miner.AssertTxInMempool(txid)
×
237
}
×
238

239
// AssertTxNotInMempool asserts a given transaction cannot be found in the
240
// mempool. It assumes the mempool is not empty.
241
//
242
// NOTE: this should be used after `AssertTxInMempool` to ensure the tx has
243
// entered the mempool before. Otherwise it might give false positive and the
244
// tx may enter the mempool after the check.
245
func (h *HarnessTest) AssertTxNotInMempool(txid chainhash.Hash) {
×
246
        h.miner.AssertTxNotInMempool(txid)
×
247
}
×
248

249
// AssertNumTxsInMempool polls until finding the desired number of transactions
250
// in the provided miner's mempool. It will assert if this number is not met
251
// after the given timeout.
252
func (h *HarnessTest) AssertNumTxsInMempool(n int) []chainhash.Hash {
×
253
        return h.miner.AssertNumTxsInMempool(n)
×
254
}
×
255

256
// AssertNumTxsInMempoolWithSweepTrigger waits for N transactions with sweep
257
// triggering support to handle async confirmation notification races. If
258
// transactions don't appear within a short timeout, it triggers a manual sweep
259
// via the provided node's RPC and waits again.
260
func (h *HarnessTest) AssertNumTxsInMempoolWithSweepTrigger(n int,
NEW
261
        hn *node.HarnessNode) []chainhash.Hash {
×
NEW
262

×
NEW
263
        return h.miner.AssertNumTxsInMempoolWithSweepTrigger(n, hn.RPC)
×
NEW
264
}
×
265

266
// AssertOutpointInMempool asserts a given outpoint can be found in the mempool.
267
func (h *HarnessTest) AssertOutpointInMempool(op wire.OutPoint) *wire.MsgTx {
×
268
        return h.miner.AssertOutpointInMempool(op)
×
269
}
×
270

271
// AssertTxInBlock asserts that a given txid can be found in the passed block.
272
func (h *HarnessTest) AssertTxInBlock(block *wire.MsgBlock,
273
        txid chainhash.Hash) {
×
274

×
275
        h.miner.AssertTxInBlock(block, txid)
×
276
}
×
277

278
// GetNumTxsFromMempool polls until finding the desired number of transactions
279
// in the miner's mempool and returns the full transactions to the caller.
280
func (h *HarnessTest) GetNumTxsFromMempool(n int) []*wire.MsgTx {
×
281
        return h.miner.GetNumTxsFromMempool(n)
×
282
}
×
283

284
// GetNumTxsFromMempoolWithSweep gets N transactions from mempool with sweep
285
// triggering support to handle async confirmation notification races. Use this
286
// for tests that expect sweep transactions after force closes.
287
func (h *HarnessTest) GetNumTxsFromMempoolWithSweep(n int,
NEW
288
        hn *node.HarnessNode) []*wire.MsgTx {
×
NEW
289

×
NEW
290
        txids := h.AssertNumTxsInMempoolWithSweepTrigger(n, hn)
×
NEW
291

×
NEW
292
        var txes []*wire.MsgTx
×
NEW
293
        for _, txid := range txids {
×
NEW
294
                tx := h.miner.GetRawTransaction(txid)
×
NEW
295
                txes = append(txes, tx.MsgTx())
×
NEW
296
        }
×
297

NEW
298
        return txes
×
299
}
300

301
// GetBestBlock makes a RPC request to miner and asserts.
302
func (h *HarnessTest) GetBestBlock() (*chainhash.Hash, int32) {
×
303
        return h.miner.GetBestBlock()
×
304
}
×
305

306
// MineBlockWithTx mines a single block to include the specifies tx only.
307
func (h *HarnessTest) MineBlockWithTx(tx *wire.MsgTx) *wire.MsgBlock {
×
308
        // Update the harness's current height.
×
309
        defer h.updateCurrentHeight()
×
310

×
311
        block := h.miner.MineBlockWithTx(tx)
×
312

×
313
        // Finally, make sure all the active nodes are synced.
×
314
        h.AssertActiveNodesSyncedTo(block.BlockHash())
×
315

×
316
        return block
×
317
}
×
318

319
// ConnectToMiner connects the miner to a temp miner.
320
func (h *HarnessTest) ConnectToMiner(tempMiner *miner.HarnessMiner) {
×
321
        h.miner.ConnectMiner(tempMiner)
×
322
}
×
323

324
// DisconnectFromMiner disconnects the miner from the temp miner.
325
func (h *HarnessTest) DisconnectFromMiner(tempMiner *miner.HarnessMiner) {
×
326
        h.miner.DisconnectMiner(tempMiner)
×
327
}
×
328

329
// GetRawMempool makes a RPC call to the miner's GetRawMempool and
330
// asserts.
331
func (h *HarnessTest) GetRawMempool() []chainhash.Hash {
×
332
        return h.miner.GetRawMempool()
×
333
}
×
334

335
// GetRawTransaction makes a RPC call to the miner's GetRawTransaction and
336
// asserts.
337
func (h *HarnessTest) GetRawTransaction(txid chainhash.Hash) *btcutil.Tx {
×
338
        return h.miner.GetRawTransaction(txid)
×
339
}
×
340

341
// NewMinerAddress creates a new address for the miner and asserts.
342
func (h *HarnessTest) NewMinerAddress() btcutil.Address {
×
343
        return h.miner.NewMinerAddress()
×
344
}
×
345

346
// SpawnTempMiner creates a temp miner and syncs it with the current miner.
347
// Once miners are synced, the temp miner is disconnected from the original
348
// miner and returned.
349
func (h *HarnessTest) SpawnTempMiner() *miner.HarnessMiner {
×
350
        return h.miner.SpawnTempMiner()
×
351
}
×
352

353
// CreateTransaction uses the miner to create a transaction using the given
354
// outputs using the specified fee rate and returns the transaction.
355
func (h *HarnessTest) CreateTransaction(outputs []*wire.TxOut,
356
        feeRate btcutil.Amount) *wire.MsgTx {
×
357

×
358
        return h.miner.CreateTransaction(outputs, feeRate)
×
359
}
×
360

361
// SendOutputsWithoutChange uses the miner to send the given outputs using the
362
// specified fee rate and returns the txid.
363
func (h *HarnessTest) SendOutputsWithoutChange(outputs []*wire.TxOut,
364
        feeRate btcutil.Amount) *chainhash.Hash {
×
365

×
366
        return h.miner.SendOutputsWithoutChange(outputs, feeRate)
×
367
}
×
368

369
// AssertMinerBlockHeightDelta ensures that tempMiner is 'delta' blocks ahead
370
// of miner.
371
func (h *HarnessTest) AssertMinerBlockHeightDelta(
372
        tempMiner *miner.HarnessMiner, delta int32) {
×
373

×
374
        h.miner.AssertMinerBlockHeightDelta(tempMiner, delta)
×
375
}
×
376

377
// SendRawTransaction submits the encoded transaction to the server which will
378
// then relay it to the network.
379
func (h *HarnessTest) SendRawTransaction(tx *wire.MsgTx,
380
        allowHighFees bool) (chainhash.Hash, error) {
×
381

×
382
        txid, err := h.miner.Client.SendRawTransaction(tx, allowHighFees)
×
383
        require.NoError(h, err)
×
384

×
385
        return *txid, nil
×
386
}
×
387

388
// CurrentHeight returns the current block height.
389
func (h *HarnessTest) CurrentHeight() uint32 {
×
390
        return h.currentHeight
×
391
}
×
392

393
// updateCurrentHeight set the harness's current height to the best known
394
// height.
395
func (h *HarnessTest) updateCurrentHeight() {
×
396
        _, height := h.GetBestBlock()
×
397
        h.currentHeight = uint32(height)
×
398
}
×
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