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

lightningnetwork / lnd / 11216766535

07 Oct 2024 01:37PM UTC coverage: 57.817% (-1.0%) from 58.817%
11216766535

Pull #9148

github

ProofOfKeags
lnwire: remove kickoff feerate from propose/commit
Pull Request #9148: DynComms [2/n]: lnwire: add authenticated wire messages for Dyn*

571 of 879 new or added lines in 16 files covered. (64.96%)

23253 existing lines in 251 files now uncovered.

99022 of 171268 relevant lines covered (57.82%)

38420.67 hits per line

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

67.05
/contractcourt/commit_sweep_resolver.go
1
package contractcourt
2

3
import (
4
        "encoding/binary"
5
        "fmt"
6
        "io"
7
        "math"
8
        "sync"
9

10
        "github.com/btcsuite/btcd/btcutil"
11
        "github.com/btcsuite/btcd/chaincfg/chainhash"
12
        "github.com/btcsuite/btcd/txscript"
13
        "github.com/btcsuite/btcd/wire"
14
        "github.com/lightningnetwork/lnd/chainntnfs"
15
        "github.com/lightningnetwork/lnd/channeldb"
16
        "github.com/lightningnetwork/lnd/fn"
17
        "github.com/lightningnetwork/lnd/input"
18
        "github.com/lightningnetwork/lnd/lnwallet"
19
        "github.com/lightningnetwork/lnd/sweep"
20
)
21

22
// commitSweepResolver is a resolver that will attempt to sweep the commitment
23
// output paying to us, in the case that the remote party broadcasts their
24
// version of the commitment transaction. We can sweep this output immediately,
25
// as it doesn't have a time-lock delay.
26
type commitSweepResolver struct {
27
        // localChanCfg is used to provide the resolver with the keys required
28
        // to identify whether the commitment transaction was broadcast by the
29
        // local or remote party.
30
        localChanCfg channeldb.ChannelConfig
31

32
        // commitResolution contains all data required to successfully sweep
33
        // this HTLC on-chain.
34
        commitResolution lnwallet.CommitOutputResolution
35

36
        // resolved reflects if the contract has been fully resolved or not.
37
        resolved bool
38

39
        // broadcastHeight is the height that the original contract was
40
        // broadcast to the main-chain at. We'll use this value to bound any
41
        // historical queries to the chain for spends/confirmations.
42
        broadcastHeight uint32
43

44
        // chanPoint is the channel point of the original contract.
45
        chanPoint wire.OutPoint
46

47
        // channelInitiator denotes whether the party responsible for resolving
48
        // the contract initiated the channel.
49
        channelInitiator bool
50

51
        // leaseExpiry denotes the additional waiting period the contract must
52
        // hold until it can be resolved. This waiting period is known as the
53
        // expiration of a script-enforced leased channel and only applies to
54
        // the channel initiator.
55
        //
56
        // NOTE: This value should only be set when the contract belongs to a
57
        // leased channel.
58
        leaseExpiry uint32
59

60
        // chanType denotes the type of channel the contract belongs to.
61
        chanType channeldb.ChannelType
62

63
        // currentReport stores the current state of the resolver for reporting
64
        // over the rpc interface.
65
        currentReport ContractReport
66

67
        // reportLock prevents concurrent access to the resolver report.
68
        reportLock sync.Mutex
69

70
        contractResolverKit
71
}
72

73
// newCommitSweepResolver instantiates a new direct commit output resolver.
74
func newCommitSweepResolver(res lnwallet.CommitOutputResolution,
75
        broadcastHeight uint32, chanPoint wire.OutPoint,
76
        resCfg ResolverConfig) *commitSweepResolver {
3✔
77

3✔
78
        r := &commitSweepResolver{
3✔
79
                contractResolverKit: *newContractResolverKit(resCfg),
3✔
80
                commitResolution:    res,
3✔
81
                broadcastHeight:     broadcastHeight,
3✔
82
                chanPoint:           chanPoint,
3✔
83
        }
3✔
84

3✔
85
        r.initLogger(r)
3✔
86
        r.initReport()
3✔
87

3✔
88
        return r
3✔
89
}
3✔
90

91
// ResolverKey returns an identifier which should be globally unique for this
92
// particular resolver within the chain the original contract resides within.
93
func (c *commitSweepResolver) ResolverKey() []byte {
3✔
94
        key := newResolverID(c.commitResolution.SelfOutPoint)
3✔
95
        return key[:]
3✔
96
}
3✔
97

98
// waitForHeight registers for block notifications and waits for the provided
99
// block height to be reached.
100
func waitForHeight(waitHeight uint32, notifier chainntnfs.ChainNotifier,
101
        quit <-chan struct{}) error {
6✔
102

6✔
103
        // Register for block epochs. After registration, the current height
6✔
104
        // will be sent on the channel immediately.
6✔
105
        blockEpochs, err := notifier.RegisterBlockEpochNtfn(nil)
6✔
106
        if err != nil {
6✔
107
                return err
×
108
        }
×
109
        defer blockEpochs.Cancel()
6✔
110

6✔
111
        for {
14✔
112
                select {
8✔
113
                case newBlock, ok := <-blockEpochs.Epochs:
8✔
114
                        if !ok {
8✔
115
                                return errResolverShuttingDown
×
116
                        }
×
117
                        height := newBlock.Height
8✔
118
                        if height >= int32(waitHeight) {
14✔
119
                                return nil
6✔
120
                        }
6✔
121

UNCOV
122
                case <-quit:
×
UNCOV
123
                        return errResolverShuttingDown
×
124
                }
125
        }
126
}
127

128
// waitForSpend waits for the given outpoint to be spent, and returns the
129
// details of the spending tx.
130
func waitForSpend(op *wire.OutPoint, pkScript []byte, heightHint uint32,
131
        notifier chainntnfs.ChainNotifier, quit <-chan struct{}) (
132
        *chainntnfs.SpendDetail, error) {
28✔
133

28✔
134
        spendNtfn, err := notifier.RegisterSpendNtfn(
28✔
135
                op, pkScript, heightHint,
28✔
136
        )
28✔
137
        if err != nil {
28✔
138
                return nil, err
×
139
        }
×
140

141
        select {
28✔
142
        case spendDetail, ok := <-spendNtfn.Spend:
28✔
143
                if !ok {
28✔
144
                        return nil, errResolverShuttingDown
×
145
                }
×
146

147
                return spendDetail, nil
28✔
148

UNCOV
149
        case <-quit:
×
UNCOV
150
                return nil, errResolverShuttingDown
×
151
        }
152
}
153

154
// getCommitTxConfHeight waits for confirmation of the commitment tx and
155
// returns the confirmation height.
156
func (c *commitSweepResolver) getCommitTxConfHeight() (uint32, error) {
3✔
157
        txID := c.commitResolution.SelfOutPoint.Hash
3✔
158
        signDesc := c.commitResolution.SelfOutputSignDesc
3✔
159
        pkScript := signDesc.Output.PkScript
3✔
160

3✔
161
        const confDepth = 1
3✔
162

3✔
163
        confChan, err := c.Notifier.RegisterConfirmationsNtfn(
3✔
164
                &txID, pkScript, confDepth, c.broadcastHeight,
3✔
165
        )
3✔
166
        if err != nil {
3✔
167
                return 0, err
×
168
        }
×
169
        defer confChan.Cancel()
3✔
170

3✔
171
        select {
3✔
172
        case txConfirmation, ok := <-confChan.Confirmed:
3✔
173
                if !ok {
3✔
174
                        return 0, fmt.Errorf("cannot get confirmation "+
×
175
                                "for commit tx %v", txID)
×
176
                }
×
177

178
                return txConfirmation.BlockHeight, nil
3✔
179

180
        case <-c.quit:
×
181
                return 0, errResolverShuttingDown
×
182
        }
183
}
184

185
// Resolve instructs the contract resolver to resolve the output on-chain. Once
186
// the output has been *fully* resolved, the function should return immediately
187
// with a nil ContractResolver value for the first return value.  In the case
188
// that the contract requires further resolution, then another resolve is
189
// returned.
190
//
191
// NOTE: This function MUST be run as a goroutine.
192
//
193
//nolint:funlen
194
func (c *commitSweepResolver) Resolve(_ bool) (ContractResolver, error) {
3✔
195
        // If we're already resolved, then we can exit early.
3✔
196
        if c.resolved {
3✔
197
                return nil, nil
×
198
        }
×
199

200
        confHeight, err := c.getCommitTxConfHeight()
3✔
201
        if err != nil {
3✔
202
                return nil, err
×
203
        }
×
204

205
        // Wait up until the CSV expires, unless we also have a CLTV that
206
        // expires after.
207
        unlockHeight := confHeight + c.commitResolution.MaturityDelay
3✔
208
        if c.hasCLTV() {
3✔
UNCOV
209
                unlockHeight = uint32(math.Max(
×
UNCOV
210
                        float64(unlockHeight), float64(c.leaseExpiry),
×
UNCOV
211
                ))
×
UNCOV
212
        }
×
213

214
        c.log.Debugf("commit conf_height=%v, unlock_height=%v",
3✔
215
                confHeight, unlockHeight)
3✔
216

3✔
217
        // Update report now that we learned the confirmation height.
3✔
218
        c.reportLock.Lock()
3✔
219
        c.currentReport.MaturityHeight = unlockHeight
3✔
220
        c.reportLock.Unlock()
3✔
221

3✔
222
        // If there is a csv/cltv lock, we'll wait for that.
3✔
223
        if c.commitResolution.MaturityDelay > 0 || c.hasCLTV() {
5✔
224
                // Determine what height we should wait until for the locks to
2✔
225
                // expire.
2✔
226
                var waitHeight uint32
2✔
227
                switch {
2✔
228
                // If we have both a csv and cltv lock, we'll need to look at
229
                // both and see which expires later.
UNCOV
230
                case c.commitResolution.MaturityDelay > 0 && c.hasCLTV():
×
UNCOV
231
                        c.log.Debugf("waiting for CSV and CLTV lock to expire "+
×
UNCOV
232
                                "at height %v", unlockHeight)
×
UNCOV
233
                        // If the CSV expires after the CLTV, or there is no
×
UNCOV
234
                        // CLTV, then we can broadcast a sweep a block before.
×
UNCOV
235
                        // Otherwise, we need to broadcast at our expected
×
UNCOV
236
                        // unlock height.
×
UNCOV
237
                        waitHeight = uint32(math.Max(
×
UNCOV
238
                                float64(unlockHeight-1), float64(c.leaseExpiry),
×
UNCOV
239
                        ))
×
240

241
                // If we only have a csv lock, wait for the height before the
242
                // lock expires as the spend path should be unlocked by then.
243
                case c.commitResolution.MaturityDelay > 0:
2✔
244
                        c.log.Debugf("waiting for CSV lock to expire at "+
2✔
245
                                "height %v", unlockHeight)
2✔
246
                        waitHeight = unlockHeight - 1
2✔
247
                }
248

249
                err := waitForHeight(waitHeight, c.Notifier, c.quit)
2✔
250
                if err != nil {
2✔
UNCOV
251
                        return nil, err
×
UNCOV
252
                }
×
253
        }
254

255
        var (
3✔
256
                isLocalCommitTx bool
3✔
257

3✔
258
                signDesc = c.commitResolution.SelfOutputSignDesc
3✔
259
        )
3✔
260

3✔
261
        switch {
3✔
262
        // For taproot channels, we'll know if this is the local commit based
263
        // on the timelock value. For remote commitment transactions, the
264
        // witness script has a timelock of 1.
UNCOV
265
        case c.chanType.IsTaproot():
×
UNCOV
266
                delayKey := c.localChanCfg.DelayBasePoint.PubKey
×
UNCOV
267
                nonDelayKey := c.localChanCfg.PaymentBasePoint.PubKey
×
UNCOV
268

×
UNCOV
269
                signKey := c.commitResolution.SelfOutputSignDesc.KeyDesc.PubKey
×
UNCOV
270

×
UNCOV
271
                // If the key in the script is neither of these, we shouldn't
×
UNCOV
272
                // proceed. This should be impossible.
×
UNCOV
273
                if !signKey.IsEqual(delayKey) && !signKey.IsEqual(nonDelayKey) {
×
274
                        return nil, fmt.Errorf("unknown sign key %v", signKey)
×
275
                }
×
276

277
                // The commitment transaction is ours iff the signing key is
278
                // the delay key.
UNCOV
279
                isLocalCommitTx = signKey.IsEqual(delayKey)
×
280

281
        // The output is on our local commitment if the script starts with
282
        // OP_IF for the revocation clause. On the remote commitment it will
283
        // either be a regular P2WKH or a simple sig spend with a CSV delay.
284
        default:
3✔
285
                isLocalCommitTx = signDesc.WitnessScript[0] == txscript.OP_IF
3✔
286
        }
287
        isDelayedOutput := c.commitResolution.MaturityDelay != 0
3✔
288

3✔
289
        c.log.Debugf("isDelayedOutput=%v, isLocalCommitTx=%v", isDelayedOutput,
3✔
290
                isLocalCommitTx)
3✔
291

3✔
292
        // There're three types of commitments, those that have tweaks for the
3✔
293
        // remote key (us in this case), those that don't, and a third where
3✔
294
        // there is no tweak and the output is delayed. On the local commitment
3✔
295
        // our output will always be delayed. We'll rely on the presence of the
3✔
296
        // commitment tweak to discern which type of commitment this is.
3✔
297
        var witnessType input.WitnessType
3✔
298
        switch {
3✔
299
        // The local delayed output for a taproot channel.
UNCOV
300
        case isLocalCommitTx && c.chanType.IsTaproot():
×
UNCOV
301
                witnessType = input.TaprootLocalCommitSpend
×
302

303
        // The CSV 1 delayed output for a taproot channel.
UNCOV
304
        case !isLocalCommitTx && c.chanType.IsTaproot():
×
UNCOV
305
                witnessType = input.TaprootRemoteCommitSpend
×
306

307
        // Delayed output to us on our local commitment for a channel lease in
308
        // which we are the initiator.
UNCOV
309
        case isLocalCommitTx && c.hasCLTV():
×
UNCOV
310
                witnessType = input.LeaseCommitmentTimeLock
×
311

312
        // Delayed output to us on our local commitment.
UNCOV
313
        case isLocalCommitTx:
×
UNCOV
314
                witnessType = input.CommitmentTimeLock
×
315

316
        // A confirmed output to us on the remote commitment for a channel lease
317
        // in which we are the initiator.
UNCOV
318
        case isDelayedOutput && c.hasCLTV():
×
UNCOV
319
                witnessType = input.LeaseCommitmentToRemoteConfirmed
×
320

321
        // A confirmed output to us on the remote commitment.
322
        case isDelayedOutput:
2✔
323
                witnessType = input.CommitmentToRemoteConfirmed
2✔
324

325
        // A non-delayed output on the remote commitment where the key is
326
        // tweakless.
327
        case c.commitResolution.SelfOutputSignDesc.SingleTweak == nil:
1✔
328
                witnessType = input.CommitSpendNoDelayTweakless
1✔
329

330
        // A non-delayed output on the remote commitment where the key is
331
        // tweaked.
332
        default:
×
333
                witnessType = input.CommitmentNoDelay
×
334
        }
335

336
        c.log.Infof("Sweeping with witness type: %v", witnessType)
3✔
337

3✔
338
        // We'll craft an input with all the information required for the
3✔
339
        // sweeper to create a fully valid sweeping transaction to recover
3✔
340
        // these coins.
3✔
341
        var inp *input.BaseInput
3✔
342
        if c.hasCLTV() {
3✔
UNCOV
343
                inp = input.NewCsvInputWithCltv(
×
UNCOV
344
                        &c.commitResolution.SelfOutPoint, witnessType,
×
UNCOV
345
                        &c.commitResolution.SelfOutputSignDesc,
×
UNCOV
346
                        c.broadcastHeight, c.commitResolution.MaturityDelay,
×
UNCOV
347
                        c.leaseExpiry,
×
UNCOV
348
                )
×
UNCOV
349
        } else {
×
UNCOV
350
                inp = input.NewCsvInput(
×
UNCOV
351
                        &c.commitResolution.SelfOutPoint, witnessType,
×
352
                        &c.commitResolution.SelfOutputSignDesc,
3✔
353
                        c.broadcastHeight, c.commitResolution.MaturityDelay,
3✔
354
                )
3✔
355
        }
3✔
356

3✔
357
        // TODO(roasbeef): instead of ading ctrl block to the sign desc, make
3✔
358
        // new input type, have sweeper set it?
3✔
359

3✔
360
        // Calculate the budget for the sweeping this input.
3✔
361
        budget := calculateBudget(
3✔
362
                btcutil.Amount(inp.SignDesc().Output.Value),
363
                c.Budget.ToLocalRatio, c.Budget.ToLocal,
364
        )
365
        c.log.Infof("Sweeping commit output using budget=%v", budget)
366

367
        // With our input constructed, we'll now offer it to the sweeper.
3✔
368
        resultChan, err := c.Sweeper.SweepInput(
3✔
369
                inp, sweep.Params{
3✔
370
                        Budget: budget,
3✔
371

3✔
372
                        // Specify a nil deadline here as there's no time
3✔
373
                        // pressure.
3✔
374
                        DeadlineHeight: fn.None[int32](),
3✔
375
                },
3✔
376
        )
3✔
377
        if err != nil {
3✔
378
                c.log.Errorf("unable to sweep input: %v", err)
3✔
379

3✔
380
                return nil, err
3✔
381
        }
3✔
382

3✔
383
        var sweepTxID chainhash.Hash
3✔
UNCOV
384

×
UNCOV
385
        // Sweeper is going to join this input with other inputs if possible
×
UNCOV
386
        // and publish the sweep tx. When the sweep tx confirms, it signals us
×
UNCOV
387
        // through the result channel with the outcome. Wait for this to
×
388
        // happen.
389
        outcome := channeldb.ResolverOutcomeClaimed
3✔
390
        select {
3✔
391
        case sweepResult := <-resultChan:
3✔
392
                switch sweepResult.Err {
3✔
393
                // If the remote party was able to sweep this output it's
3✔
394
                // likely what we sent was actually a revoked commitment.
3✔
395
                // Report the error and continue to wrap up the contract.
3✔
396
                case sweep.ErrRemoteSpend:
3✔
397
                        c.log.Warnf("local commitment output was swept by "+
3✔
398
                                "remote party via %v", sweepResult.Tx.TxHash())
3✔
399
                        outcome = channeldb.ResolverOutcomeUnclaimed
400

401
                // No errors, therefore continue processing.
402
                case nil:
1✔
403
                        c.log.Infof("local commitment output fully resolved by "+
1✔
404
                                "sweep tx: %v", sweepResult.Tx.TxHash())
1✔
405
                // Unknown errors.
1✔
406
                default:
407
                        c.log.Errorf("unable to sweep input: %v",
408
                                sweepResult.Err)
2✔
409

2✔
410
                        return nil, sweepResult.Err
2✔
411
                }
UNCOV
412

×
UNCOV
413
                sweepTxID = sweepResult.Tx.TxHash()
×
UNCOV
414

×
UNCOV
415
        case <-c.quit:
×
UNCOV
416
                return nil, errResolverShuttingDown
×
417
        }
418

419
        // Funds have been swept and balance is no longer in limbo.
3✔
420
        c.reportLock.Lock()
UNCOV
421
        if outcome == channeldb.ResolverOutcomeClaimed {
×
UNCOV
422
                // We only record the balance as recovered if it actually came
×
423
                // back to us.
424
                c.currentReport.RecoveredBalance = c.currentReport.LimboBalance
425
        }
426
        c.currentReport.LimboBalance = 0
3✔
427
        c.reportLock.Unlock()
5✔
428
        report := c.currentReport.resolverReport(
2✔
429
                &sweepTxID, channeldb.ResolverTypeCommit, outcome,
2✔
430
        )
2✔
431
        c.resolved = true
2✔
432

3✔
433
        // Checkpoint the resolver with a closure that will write the outcome
3✔
434
        // of the resolver and its sweep transaction to disk.
3✔
435
        return nil, c.Checkpoint(c, report)
3✔
436
}
3✔
437

3✔
438
// Stop signals the resolver to cancel any current resolution processes, and
3✔
439
// suspend.
3✔
440
//
3✔
441
// NOTE: Part of the ContractResolver interface.
3✔
442
func (c *commitSweepResolver) Stop() {
443
        close(c.quit)
444
}
445

446
// IsResolved returns true if the stored state in the resolve is fully
447
// resolved. In this case the target output can be forgotten.
UNCOV
448
//
×
UNCOV
449
// NOTE: Part of the ContractResolver interface.
×
UNCOV
450
func (c *commitSweepResolver) IsResolved() bool {
×
451
        return c.resolved
452
}
453

454
// SupplementState allows the user of a ContractResolver to supplement it with
455
// state required for the proper resolution of a contract.
UNCOV
456
//
×
UNCOV
457
// NOTE: Part of the ContractResolver interface.
×
UNCOV
458
func (c *commitSweepResolver) SupplementState(state *channeldb.OpenChannel) {
×
459
        if state.ChanType.HasLeaseExpiration() {
460
                c.leaseExpiry = state.ThawHeight
461
        }
462
        c.localChanCfg = state.LocalChanCfg
463
        c.channelInitiator = state.IsInitiator
UNCOV
464
        c.chanType = state.ChanType
×
UNCOV
465
}
×
UNCOV
466

×
UNCOV
467
// hasCLTV denotes whether the resolver must wait for an additional CLTV to
×
UNCOV
468
// expire before resolving the contract.
×
UNCOV
469
func (c *commitSweepResolver) hasCLTV() bool {
×
UNCOV
470
        return c.channelInitiator && c.leaseExpiry > 0
×
471
}
472

473
// Encode writes an encoded version of the ContractResolver into the passed
474
// Writer.
475
//
11✔
476
// NOTE: Part of the ContractResolver interface.
11✔
477
func (c *commitSweepResolver) Encode(w io.Writer) error {
11✔
478
        if err := encodeCommitResolution(w, &c.commitResolution); err != nil {
479
                return err
480
        }
481

482
        if err := binary.Write(w, endian, c.resolved); err != nil {
483
                return err
1✔
484
        }
1✔
UNCOV
485
        if err := binary.Write(w, endian, c.broadcastHeight); err != nil {
×
486
                return err
×
487
        }
488
        if _, err := w.Write(c.chanPoint.Hash[:]); err != nil {
1✔
489
                return err
×
490
        }
×
491
        err := binary.Write(w, endian, c.chanPoint.Index)
1✔
UNCOV
492
        if err != nil {
×
493
                return err
×
494
        }
1✔
UNCOV
495

×
UNCOV
496
        // Previously a sweep tx was serialized at this point. Refactoring
×
497
        // removed this, but keep in mind that this data may still be present in
1✔
498
        // the database.
1✔
UNCOV
499

×
UNCOV
500
        return nil
×
501
}
502

503
// newCommitSweepResolverFromReader attempts to decode an encoded
504
// ContractResolver from the passed Reader instance, returning an active
505
// ContractResolver instance.
506
func newCommitSweepResolverFromReader(r io.Reader, resCfg ResolverConfig) (
1✔
507
        *commitSweepResolver, error) {
508

509
        c := &commitSweepResolver{
510
                contractResolverKit: *newContractResolverKit(resCfg),
511
        }
512

513
        if err := decodeCommitResolution(r, &c.commitResolution); err != nil {
1✔
514
                return nil, err
1✔
515
        }
1✔
516

1✔
517
        if err := binary.Read(r, endian, &c.resolved); err != nil {
1✔
518
                return nil, err
1✔
519
        }
1✔
UNCOV
520
        if err := binary.Read(r, endian, &c.broadcastHeight); err != nil {
×
521
                return nil, err
×
522
        }
523
        _, err := io.ReadFull(r, c.chanPoint.Hash[:])
1✔
UNCOV
524
        if err != nil {
×
525
                return nil, err
×
526
        }
1✔
UNCOV
527
        err = binary.Read(r, endian, &c.chanPoint.Index)
×
UNCOV
528
        if err != nil {
×
529
                return nil, err
1✔
530
        }
1✔
UNCOV
531

×
UNCOV
532
        // Previously a sweep tx was deserialized at this point. Refactoring
×
533
        // removed this, but keep in mind that this data may still be present in
1✔
534
        // the database.
1✔
UNCOV
535

×
UNCOV
536
        c.initLogger(c)
×
537
        c.initReport()
538

539
        return c, nil
540
}
541

542
// report returns a report on the resolution state of the contract.
1✔
543
func (c *commitSweepResolver) report() *ContractReport {
1✔
544
        c.reportLock.Lock()
1✔
545
        defer c.reportLock.Unlock()
1✔
546

547
        cpy := c.currentReport
548
        return &cpy
549
}
6✔
550

6✔
551
// initReport initializes the pending channels report for this resolver.
6✔
552
func (c *commitSweepResolver) initReport() {
6✔
553
        amt := btcutil.Amount(
6✔
554
                c.commitResolution.SelfOutputSignDesc.Output.Value,
6✔
555
        )
6✔
556

557
        // Set the initial report. All fields are filled in, except for the
558
        // maturity height which remains 0 until Resolve() is executed.
4✔
559
        //
4✔
560
        // TODO(joostjager): Resolvers only activate after the commit tx
4✔
561
        // confirms. With more refactoring in channel arbitrator, it would be
4✔
562
        // possible to make the confirmation height part of ResolverConfig and
4✔
563
        // populate MaturityHeight here.
4✔
564
        c.currentReport = ContractReport{
4✔
565
                Outpoint:         c.commitResolution.SelfOutPoint,
4✔
566
                Type:             ReportOutputUnencumbered,
4✔
567
                Amount:           amt,
4✔
568
                LimboBalance:     amt,
4✔
569
                RecoveredBalance: 0,
4✔
570
        }
4✔
571
}
4✔
572

4✔
573
// A compile time assertion to ensure commitSweepResolver meets the
4✔
574
// ContractResolver interface.
4✔
575
var _ reportingContractResolver = (*commitSweepResolver)(nil)
4✔
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