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

lightningnetwork / lnd / 12986279612

27 Jan 2025 09:51AM UTC coverage: 57.652% (-1.1%) from 58.788%
12986279612

Pull #9447

github

yyforyongyu
sweep: rename methods for clarity

We now rename "third party" to "unknown" as the inputs can be spent via
an older sweeping tx, a third party (anchor), or a remote party (pin).
In fee bumper we don't have the info to distinguish the above cases, and
leave them to be further handled by the sweeper as it has more context.
Pull Request #9447: sweep: start tracking input spending status in the fee bumper

83 of 87 new or added lines in 2 files covered. (95.4%)

19578 existing lines in 256 files now uncovered.

103448 of 179434 relevant lines covered (57.65%)

24884.58 hits per line

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

50.92
/contractcourt/briefcase.go
1
package contractcourt
2

3
import (
4
        "bytes"
5
        "encoding/binary"
6
        "fmt"
7
        "io"
8

9
        "github.com/btcsuite/btcd/chaincfg/chainhash"
10
        "github.com/btcsuite/btcd/txscript"
11
        "github.com/btcsuite/btcd/wire"
12
        "github.com/lightningnetwork/lnd/channeldb"
13
        "github.com/lightningnetwork/lnd/fn/v2"
14
        "github.com/lightningnetwork/lnd/input"
15
        "github.com/lightningnetwork/lnd/kvdb"
16
        "github.com/lightningnetwork/lnd/lnwallet"
17
        "github.com/lightningnetwork/lnd/tlv"
18
)
19

20
// ContractResolutions is a wrapper struct around the two forms of resolutions
21
// we may need to carry out once a contract is closing: resolving the
22
// commitment output, and resolving any incoming+outgoing HTLC's still present
23
// in the commitment.
24
type ContractResolutions struct {
25
        // CommitHash is the txid of the commitment transaction.
26
        CommitHash chainhash.Hash
27

28
        // CommitResolution contains all data required to fully resolve a
29
        // commitment output.
30
        CommitResolution *lnwallet.CommitOutputResolution
31

32
        // HtlcResolutions contains all data required to fully resolve any
33
        // incoming+outgoing HTLC's present within the commitment transaction.
34
        HtlcResolutions lnwallet.HtlcResolutions
35

36
        // AnchorResolution contains the data required to sweep the anchor
37
        // output. If the channel type doesn't include anchors, the value of
38
        // this field will be nil.
39
        AnchorResolution *lnwallet.AnchorResolution
40

41
        // BreachResolution contains the data required to manage the lifecycle
42
        // of a breach in the ChannelArbitrator.
43
        BreachResolution *BreachResolution
44
}
45

46
// IsEmpty returns true if the set of resolutions is "empty". A resolution is
47
// empty if: our commitment output has been trimmed, we don't have any
48
// incoming or outgoing HTLC's active, there is no anchor output to sweep, or
49
// there are no breached outputs to resolve.
50
func (c *ContractResolutions) IsEmpty() bool {
20✔
51
        return c.CommitResolution == nil &&
20✔
52
                len(c.HtlcResolutions.IncomingHTLCs) == 0 &&
20✔
53
                len(c.HtlcResolutions.OutgoingHTLCs) == 0 &&
20✔
54
                c.AnchorResolution == nil && c.BreachResolution == nil
20✔
55
}
20✔
56

57
// ArbitratorLog is the primary source of persistent storage for the
58
// ChannelArbitrator. The log stores the current state of the
59
// ChannelArbitrator's internal state machine, any items that are required to
60
// properly make a state transition, and any unresolved contracts.
61
type ArbitratorLog interface {
62
        // TODO(roasbeef): document on interface the errors expected to be
63
        // returned
64

65
        // CurrentState returns the current state of the ChannelArbitrator. It
66
        // takes an optional database transaction, which will be used if it is
67
        // non-nil, otherwise the lookup will be done in its own transaction.
68
        CurrentState(tx kvdb.RTx) (ArbitratorState, error)
69

70
        // CommitState persists, the current state of the chain attendant.
71
        CommitState(ArbitratorState) error
72

73
        // InsertUnresolvedContracts inserts a set of unresolved contracts into
74
        // the log. The log will then persistently store each contract until
75
        // they've been swapped out, or resolved. It takes a set of report which
76
        // should be written to disk if as well if it is non-nil.
77
        InsertUnresolvedContracts(reports []*channeldb.ResolverReport,
78
                resolvers ...ContractResolver) error
79

80
        // FetchUnresolvedContracts returns all unresolved contracts that have
81
        // been previously written to the log.
82
        FetchUnresolvedContracts() ([]ContractResolver, error)
83

84
        // SwapContract performs an atomic swap of the old contract for the new
85
        // contract. This method is used when after a contract has been fully
86
        // resolved, it produces another contract that needs to be resolved.
87
        SwapContract(old ContractResolver, new ContractResolver) error
88

89
        // ResolveContract marks a contract as fully resolved. Once a contract
90
        // has been fully resolved, it is deleted from persistent storage.
91
        ResolveContract(ContractResolver) error
92

93
        // LogContractResolutions stores a complete contract resolution for the
94
        // contract under watch. This method will be called once the
95
        // ChannelArbitrator either force closes a channel, or detects that the
96
        // remote party has broadcast their commitment on chain.
97
        LogContractResolutions(*ContractResolutions) error
98

99
        // FetchContractResolutions fetches the set of previously stored
100
        // contract resolutions from persistent storage.
101
        FetchContractResolutions() (*ContractResolutions, error)
102

103
        // InsertConfirmedCommitSet stores the known set of active HTLCs at the
104
        // time channel closure. We'll use this to reconstruct our set of chain
105
        // actions anew based on the confirmed and pending commitment state.
106
        InsertConfirmedCommitSet(c *CommitSet) error
107

108
        // FetchConfirmedCommitSet fetches the known confirmed active HTLC set
109
        // from the database. It takes an optional database transaction, which
110
        // will be used if it is non-nil, otherwise the lookup will be done in
111
        // its own transaction.
112
        FetchConfirmedCommitSet(tx kvdb.RTx) (*CommitSet, error)
113

114
        // FetchChainActions attempts to fetch the set of previously stored
115
        // chain actions. We'll use this upon restart to properly advance our
116
        // state machine forward.
117
        //
118
        // NOTE: This method only exists in order to be able to serve nodes had
119
        // channels in the process of closing before the CommitSet struct was
120
        // introduced.
121
        FetchChainActions() (ChainActionMap, error)
122

123
        // WipeHistory is to be called ONLY once *all* contracts have been
124
        // fully resolved, and the channel closure if finalized. This method
125
        // will delete all on-disk state within the persistent log.
126
        WipeHistory() error
127
}
128

129
// ArbitratorState is an enum that details the current state of the
130
// ChannelArbitrator's state machine.
131
type ArbitratorState uint8
132

133
const (
134
        // While some state transition is allowed, certain transitions are not
135
        // possible. Listed below is the full state transition map which
136
        // contains all possible paths. We start at StateDefault and end at
137
        // StateFullyResolved, or StateError(not listed as its a possible state
138
        // in every path). The format is,
139
        //         -> state: conditions we switch to this state.
140
        //
141
        // StateDefault
142
        // |
143
        // |-> StateDefault: no actions and chain trigger
144
        // |
145
        // |-> StateBroadcastCommit: chain/user trigger
146
        // |   |
147
        // |   |-> StateCommitmentBroadcasted: chain/user trigger
148
        // |   |   |
149
        // |   |   |-> StateCommitmentBroadcasted: chain/user trigger
150
        // |   |   |
151
        // |   |   |-> StateContractClosed: local/remote/breach close trigger
152
        // |   |   |   |
153
        // |   |   |   |-> StateWaitingFullResolution: contract resolutions not empty
154
        // |   |   |   |   |
155
        // |   |   |   |   |-> StateWaitingFullResolution: contract resolutions not empty
156
        // |   |   |   |   |
157
        // |   |   |   |   |-> StateFullyResolved: contract resolutions empty
158
        // |   |   |   |
159
        // |   |   |   |-> StateFullyResolved: contract resolutions empty
160
        // |   |   |
161
        // |   |   |-> StateFullyResolved: coop/breach(legacy) close trigger
162
        // |   |
163
        // |   |-> StateContractClosed: local/remote/breach close trigger
164
        // |   |   |
165
        // |   |   |-> StateWaitingFullResolution: contract resolutions not empty
166
        // |   |   |   |
167
        // |   |   |   |-> StateWaitingFullResolution: contract resolutions not empty
168
        // |   |   |   |
169
        // |   |   |   |-> StateFullyResolved: contract resolutions empty
170
        // |   |   |
171
        // |   |   |-> StateFullyResolved: contract resolutions empty
172
        // |   |
173
        // |   |-> StateFullyResolved: coop/breach(legacy) close trigger
174
        // |
175
        // |-> StateContractClosed: local/remote/breach close trigger
176
        // |   |
177
        // |   |-> StateWaitingFullResolution: contract resolutions not empty
178
        // |   |   |
179
        // |   |   |-> StateWaitingFullResolution: contract resolutions not empty
180
        // |   |   |
181
        // |   |   |-> StateFullyResolved: contract resolutions empty
182
        // |   |
183
        // |   |-> StateFullyResolved: contract resolutions empty
184
        // |
185
        // |-> StateFullyResolved: coop/breach(legacy) close trigger.
186

187
        // StateDefault is the default state. In this state, no major actions
188
        // need to be executed.
189
        StateDefault ArbitratorState = 0
190

191
        // StateBroadcastCommit is a state that indicates that the attendant
192
        // has decided to broadcast the commitment transaction, but hasn't done
193
        // so yet.
194
        StateBroadcastCommit ArbitratorState = 1
195

196
        // StateCommitmentBroadcasted is a state that indicates that the
197
        // attendant has broadcasted the commitment transaction, and is now
198
        // waiting for it to confirm.
199
        StateCommitmentBroadcasted ArbitratorState = 6
200

201
        // StateContractClosed is a state that indicates the contract has
202
        // already been "closed", meaning the commitment is confirmed on chain.
203
        // At this point, we can now examine our active contracts, in order to
204
        // create the proper resolver for each one.
205
        StateContractClosed ArbitratorState = 2
206

207
        // StateWaitingFullResolution is a state that indicates that the
208
        // commitment transaction has been confirmed, and the attendant is now
209
        // waiting for all unresolved contracts to be fully resolved.
210
        StateWaitingFullResolution ArbitratorState = 3
211

212
        // StateFullyResolved is the final state of the attendant. In this
213
        // state, all related contracts have been resolved, and the attendant
214
        // can now be garbage collected.
215
        StateFullyResolved ArbitratorState = 4
216

217
        // StateError is the only error state of the resolver. If we enter this
218
        // state, then we cannot proceed with manual intervention as a state
219
        // transition failed.
220
        StateError ArbitratorState = 5
221
)
222

223
// String returns a human readable string describing the ArbitratorState.
224
func (a ArbitratorState) String() string {
3✔
225
        switch a {
3✔
UNCOV
226
        case StateDefault:
×
UNCOV
227
                return "StateDefault"
×
228

UNCOV
229
        case StateBroadcastCommit:
×
UNCOV
230
                return "StateBroadcastCommit"
×
231

UNCOV
232
        case StateCommitmentBroadcasted:
×
UNCOV
233
                return "StateCommitmentBroadcasted"
×
234

235
        case StateContractClosed:
2✔
236
                return "StateContractClosed"
2✔
237

UNCOV
238
        case StateWaitingFullResolution:
×
UNCOV
239
                return "StateWaitingFullResolution"
×
240

241
        case StateFullyResolved:
1✔
242
                return "StateFullyResolved"
1✔
243

244
        case StateError:
×
245
                return "StateError"
×
246

247
        default:
×
248
                return "unknown state"
×
249
        }
250
}
251

252
// IsContractClosed returns a bool to indicate whether the closing/breaching tx
253
// has been confirmed onchain. If the state is StateContractClosed,
254
// StateWaitingFullResolution, or StateFullyResolved, it means the contract has
255
// been closed and all related contracts have been launched.
256
func (a ArbitratorState) IsContractClosed() bool {
6✔
257
        return a == StateContractClosed || a == StateWaitingFullResolution ||
6✔
258
                a == StateFullyResolved
6✔
259
}
6✔
260

261
// resolverType is an enum that enumerates the various types of resolvers. When
262
// writing resolvers to disk, we prepend this to the raw bytes stored. This
263
// allows us to properly decode the resolver into the proper type.
264
type resolverType uint8
265

266
const (
267
        // resolverTimeout is the type of a resolver that's tasked with
268
        // resolving an outgoing HTLC that is very close to timing out.
269
        resolverTimeout resolverType = 0
270

271
        // resolverSuccess is the type of a resolver that's tasked with
272
        // resolving an incoming HTLC that we already know the preimage of.
273
        resolverSuccess resolverType = 1
274

275
        // resolverOutgoingContest is the type of a resolver that's tasked with
276
        // resolving an outgoing HTLC that hasn't yet timed out.
277
        resolverOutgoingContest resolverType = 2
278

279
        // resolverIncomingContest is the type of a resolver that's tasked with
280
        // resolving an incoming HTLC that we don't yet know the preimage to.
281
        resolverIncomingContest resolverType = 3
282

283
        // resolverUnilateralSweep is the type of resolver that's tasked with
284
        // sweeping out direct commitment output form the remote party's
285
        // commitment transaction.
286
        resolverUnilateralSweep resolverType = 4
287

288
        // resolverBreach is the type of resolver that manages a contract
289
        // breach on-chain.
290
        resolverBreach resolverType = 5
291
)
292

293
// resolverIDLen is the size of the resolver ID key. This is 36 bytes as we get
294
// 32 bytes from the hash of the prev tx, and 4 bytes for the output index.
295
const resolverIDLen = 36
296

297
// resolverID is a key that uniquely identifies a resolver within a particular
298
// chain. For this value we use the full outpoint of the resolver.
299
type resolverID [resolverIDLen]byte
300

301
// newResolverID returns a resolverID given the outpoint of a contract.
302
func newResolverID(op wire.OutPoint) resolverID {
32✔
303
        var r resolverID
32✔
304

32✔
305
        copy(r[:], op.Hash[:])
32✔
306

32✔
307
        endian.PutUint32(r[32:], op.Index)
32✔
308

32✔
309
        return r
32✔
310
}
32✔
311

312
// logScope is a key that we use to scope the storage of a ChannelArbitrator
313
// within the global log. We use this key to create a unique bucket within the
314
// database and ensure that we don't have any key collisions. The log's scope
315
// is define as: chainHash || chanPoint, where chanPoint is the chan point of
316
// the original channel.
317
type logScope [32 + 36]byte
318

319
// newLogScope creates a new logScope key from the passed chainhash and
320
// chanPoint.
321
func newLogScope(chain chainhash.Hash, op wire.OutPoint) (*logScope, error) {
20✔
322
        var l logScope
20✔
323
        b := bytes.NewBuffer(l[0:0])
20✔
324

20✔
325
        if _, err := b.Write(chain[:]); err != nil {
20✔
326
                return nil, err
×
327
        }
×
328
        if _, err := b.Write(op.Hash[:]); err != nil {
20✔
329
                return nil, err
×
330
        }
×
331

332
        if err := binary.Write(b, endian, op.Index); err != nil {
20✔
333
                return nil, err
×
334
        }
×
335

336
        return &l, nil
20✔
337
}
338

339
var (
340
        // stateKey is the key that we use to store the current state of the
341
        // arbitrator.
342
        stateKey = []byte("state")
343

344
        // contractsBucketKey is the bucket within the logScope that will store
345
        // all the active unresolved contracts.
346
        contractsBucketKey = []byte("contractkey")
347

348
        // resolutionsKey is the key under the logScope that we'll use to store
349
        // the full set of resolutions for a channel.
350
        resolutionsKey = []byte("resolutions")
351

352
        // resolutionsSignDetailsKey is the key under the logScope where we
353
        // will store input.SignDetails for each HTLC resolution. If this is
354
        // not found under the logScope, it means it was written before
355
        // SignDetails was introduced, and should be set nil for each HTLC
356
        // resolution.
357
        resolutionsSignDetailsKey = []byte("resolutions-sign-details")
358

359
        // anchorResolutionKey is the key under the logScope that we'll use to
360
        // store the anchor resolution, if any.
361
        anchorResolutionKey = []byte("anchor-resolution")
362

363
        // breachResolutionKey is the key under the logScope that we'll use to
364
        // store the breach resolution, if any. This is used rather than the
365
        // resolutionsKey.
366
        breachResolutionKey = []byte("breach-resolution")
367

368
        // actionsBucketKey is the key under the logScope that we'll use to
369
        // store all chain actions once they're determined.
370
        actionsBucketKey = []byte("chain-actions")
371

372
        // commitSetKey is the primary key under the logScope that we'll use to
373
        // store the confirmed active HTLC sets once we learn that a channel
374
        // has closed out on chain.
375
        commitSetKey = []byte("commit-set")
376

377
        // taprootDataKey is the key we'll use to store taproot specific data
378
        // for the set of channels we'll need to sweep/claim.
379
        taprootDataKey = []byte("taproot-data")
380
)
381

382
var (
383
        // errScopeBucketNoExist is returned when we can't find the proper
384
        // bucket for an arbitrator's scope.
385
        errScopeBucketNoExist = fmt.Errorf("scope bucket not found")
386

387
        // errNoContracts is returned when no contracts are found within the
388
        // log.
389
        errNoContracts = fmt.Errorf("no stored contracts")
390

391
        // errNoResolutions is returned when the log doesn't contain any active
392
        // chain resolutions.
393
        errNoResolutions = fmt.Errorf("no contract resolutions exist")
394

395
        // errNoActions is returned when the log doesn't contain any stored
396
        // chain actions.
397
        errNoActions = fmt.Errorf("no chain actions exist")
398

399
        // errNoCommitSet is return when the log doesn't contained a CommitSet.
400
        // This can happen if the channel hasn't closed yet, or a client is
401
        // running an older version that didn't yet write this state.
402
        errNoCommitSet = fmt.Errorf("no commit set exists")
403
)
404

405
// boltArbitratorLog is an implementation of the ArbitratorLog interface backed
406
// by a bolt DB instance.
407
type boltArbitratorLog struct {
408
        db kvdb.Backend
409

410
        cfg ChannelArbitratorConfig
411

412
        scopeKey logScope
413
}
414

415
// newBoltArbitratorLog returns a new instance of the boltArbitratorLog given
416
// an arbitrator config, and the items needed to create its log scope.
417
func newBoltArbitratorLog(db kvdb.Backend, cfg ChannelArbitratorConfig,
418
        chainHash chainhash.Hash, chanPoint wire.OutPoint) (*boltArbitratorLog, error) {
20✔
419

20✔
420
        scope, err := newLogScope(chainHash, chanPoint)
20✔
421
        if err != nil {
20✔
422
                return nil, err
×
423
        }
×
424

425
        return &boltArbitratorLog{
20✔
426
                db:       db,
20✔
427
                cfg:      cfg,
20✔
428
                scopeKey: *scope,
20✔
429
        }, nil
20✔
430
}
431

432
// A compile time check to ensure boltArbitratorLog meets the ArbitratorLog
433
// interface.
434
var _ ArbitratorLog = (*boltArbitratorLog)(nil)
435

436
func fetchContractReadBucket(tx kvdb.RTx, scopeKey []byte) (kvdb.RBucket, error) {
9✔
437
        scopeBucket := tx.ReadBucket(scopeKey)
9✔
438
        if scopeBucket == nil {
10✔
439
                return nil, errScopeBucketNoExist
1✔
440
        }
1✔
441

442
        contractBucket := scopeBucket.NestedReadBucket(contractsBucketKey)
8✔
443
        if contractBucket == nil {
8✔
444
                return nil, errNoContracts
×
445
        }
×
446

447
        return contractBucket, nil
8✔
448
}
449

450
func fetchContractWriteBucket(tx kvdb.RwTx, scopeKey []byte) (kvdb.RwBucket, error) {
10✔
451
        scopeBucket, err := tx.CreateTopLevelBucket(scopeKey)
10✔
452
        if err != nil {
10✔
453
                return nil, err
×
454
        }
×
455

456
        contractBucket, err := scopeBucket.CreateBucketIfNotExists(
10✔
457
                contractsBucketKey,
10✔
458
        )
10✔
459
        if err != nil {
10✔
460
                return nil, err
×
461
        }
×
462

463
        return contractBucket, nil
10✔
464
}
465

466
// writeResolver is a helper method that writes a contract resolver and stores
467
// it it within the passed contractBucket using its unique resolutionsKey key.
468
func (b *boltArbitratorLog) writeResolver(contractBucket kvdb.RwBucket,
469
        res ContractResolver) error {
12✔
470

12✔
471
        // Only persist resolvers that are stateful. Stateless resolvers don't
12✔
472
        // expose a resolver key.
12✔
473
        resKey := res.ResolverKey()
12✔
474
        if resKey == nil {
12✔
UNCOV
475
                return nil
×
UNCOV
476
        }
×
477

478
        // First, we'll write to the buffer the type of this resolver. Using
479
        // this byte, we can later properly deserialize the resolver properly.
480
        var (
12✔
481
                buf   bytes.Buffer
12✔
482
                rType resolverType
12✔
483
        )
12✔
484
        switch res.(type) {
12✔
485
        case *htlcTimeoutResolver:
6✔
486
                rType = resolverTimeout
6✔
487
        case *htlcSuccessResolver:
1✔
488
                rType = resolverSuccess
1✔
489
        case *htlcOutgoingContestResolver:
3✔
490
                rType = resolverOutgoingContest
3✔
491
        case *htlcIncomingContestResolver:
1✔
492
                rType = resolverIncomingContest
1✔
493
        case *commitSweepResolver:
1✔
494
                rType = resolverUnilateralSweep
1✔
UNCOV
495
        case *breachResolver:
×
UNCOV
496
                rType = resolverBreach
×
497
        }
498
        if _, err := buf.Write([]byte{byte(rType)}); err != nil {
12✔
499
                return err
×
500
        }
×
501

502
        // With the type of the resolver written, we can then write out the raw
503
        // bytes of the resolver itself.
504
        if err := res.Encode(&buf); err != nil {
12✔
505
                return err
×
506
        }
×
507

508
        return contractBucket.Put(resKey, buf.Bytes())
12✔
509
}
510

511
// CurrentState returns the current state of the ChannelArbitrator. It takes an
512
// optional database transaction, which will be used if it is non-nil, otherwise
513
// the lookup will be done in its own transaction.
514
//
515
// NOTE: Part of the ContractResolver interface.
516
func (b *boltArbitratorLog) CurrentState(tx kvdb.RTx) (ArbitratorState, error) {
18✔
517
        var (
18✔
518
                s   ArbitratorState
18✔
519
                err error
18✔
520
        )
18✔
521

18✔
522
        if tx != nil {
29✔
523
                s, err = b.currentState(tx)
11✔
524
        } else {
18✔
525
                err = kvdb.View(b.db, func(tx kvdb.RTx) error {
14✔
526
                        s, err = b.currentState(tx)
7✔
527
                        return err
7✔
528
                }, func() {
14✔
529
                        s = 0
7✔
530
                })
7✔
531
        }
532

533
        if err != nil && err != errScopeBucketNoExist {
18✔
534
                return s, err
×
535
        }
×
536

537
        return s, nil
18✔
538
}
539

540
func (b *boltArbitratorLog) currentState(tx kvdb.RTx) (ArbitratorState, error) {
18✔
541
        scopeBucket := tx.ReadBucket(b.scopeKey[:])
18✔
542
        if scopeBucket == nil {
32✔
543
                return 0, errScopeBucketNoExist
14✔
544
        }
14✔
545

546
        stateBytes := scopeBucket.Get(stateKey)
4✔
547
        if stateBytes == nil {
4✔
548
                return 0, nil
×
549
        }
×
550

551
        return ArbitratorState(stateBytes[0]), nil
4✔
552
}
553

554
// CommitState persists, the current state of the chain attendant.
555
//
556
// NOTE: Part of the ContractResolver interface.
557
func (b *boltArbitratorLog) CommitState(s ArbitratorState) error {
8✔
558
        return kvdb.Batch(b.db, func(tx kvdb.RwTx) error {
16✔
559
                scopeBucket, err := tx.CreateTopLevelBucket(b.scopeKey[:])
8✔
560
                if err != nil {
8✔
561
                        return err
×
562
                }
×
563

564
                return scopeBucket.Put(stateKey[:], []byte{uint8(s)})
8✔
565
        })
566
}
567

568
// FetchUnresolvedContracts returns all unresolved contracts that have been
569
// previously written to the log.
570
//
571
// NOTE: Part of the ContractResolver interface.
572
func (b *boltArbitratorLog) FetchUnresolvedContracts() ([]ContractResolver, error) {
9✔
573
        resolverCfg := ResolverConfig{
9✔
574
                ChannelArbitratorConfig: b.cfg,
9✔
575
                Checkpoint:              b.checkpointContract,
9✔
576
        }
9✔
577
        var contracts []ContractResolver
9✔
578
        err := kvdb.View(b.db, func(tx kvdb.RTx) error {
18✔
579
                contractBucket, err := fetchContractReadBucket(tx, b.scopeKey[:])
9✔
580
                if err != nil {
10✔
581
                        return err
1✔
582
                }
1✔
583

584
                return contractBucket.ForEach(func(resKey, resBytes []byte) error {
18✔
585
                        if len(resKey) != resolverIDLen {
10✔
586
                                return nil
×
587
                        }
×
588

589
                        var res ContractResolver
10✔
590

10✔
591
                        // We'll snip off the first byte of the raw resolver
10✔
592
                        // bytes in order to extract what type of resolver
10✔
593
                        // we're about to encode.
10✔
594
                        resType := resolverType(resBytes[0])
10✔
595

10✔
596
                        // Then we'll create a reader using the remaining
10✔
597
                        // bytes.
10✔
598
                        resReader := bytes.NewReader(resBytes[1:])
10✔
599

10✔
600
                        switch resType {
10✔
601
                        case resolverTimeout:
3✔
602
                                res, err = newTimeoutResolverFromReader(
3✔
603
                                        resReader, resolverCfg,
3✔
604
                                )
3✔
605

606
                        case resolverSuccess:
1✔
607
                                res, err = newSuccessResolverFromReader(
1✔
608
                                        resReader, resolverCfg,
1✔
609
                                )
1✔
610

611
                        case resolverOutgoingContest:
4✔
612
                                res, err = newOutgoingContestResolverFromReader(
4✔
613
                                        resReader, resolverCfg,
4✔
614
                                )
4✔
615

616
                        case resolverIncomingContest:
1✔
617
                                res, err = newIncomingContestResolverFromReader(
1✔
618
                                        resReader, resolverCfg,
1✔
619
                                )
1✔
620

621
                        case resolverUnilateralSweep:
1✔
622
                                res, err = newCommitSweepResolverFromReader(
1✔
623
                                        resReader, resolverCfg,
1✔
624
                                )
1✔
625

UNCOV
626
                        case resolverBreach:
×
UNCOV
627
                                res, err = newBreachResolverFromReader(
×
UNCOV
628
                                        resReader, resolverCfg,
×
UNCOV
629
                                )
×
630

631
                        default:
×
632
                                return fmt.Errorf("unknown resolver type: %v", resType)
×
633
                        }
634

635
                        if err != nil {
10✔
636
                                return err
×
637
                        }
×
638

639
                        contracts = append(contracts, res)
10✔
640
                        return nil
10✔
641
                })
642
        }, func() {
9✔
643
                contracts = nil
9✔
644
        })
9✔
645
        if err != nil && err != errScopeBucketNoExist && err != errNoContracts {
9✔
646
                return nil, err
×
647
        }
×
648

649
        return contracts, nil
9✔
650
}
651

652
// InsertUnresolvedContracts inserts a set of unresolved contracts into the
653
// log. The log will then persistently store each contract until they've been
654
// swapped out, or resolved.
655
//
656
// NOTE: Part of the ContractResolver interface.
657
func (b *boltArbitratorLog) InsertUnresolvedContracts(reports []*channeldb.ResolverReport,
658
        resolvers ...ContractResolver) error {
4✔
659

4✔
660
        return kvdb.Batch(b.db, func(tx kvdb.RwTx) error {
8✔
661
                contractBucket, err := fetchContractWriteBucket(tx, b.scopeKey[:])
4✔
662
                if err != nil {
4✔
663
                        return err
×
664
                }
×
665

666
                for _, resolver := range resolvers {
12✔
667
                        err = b.writeResolver(contractBucket, resolver)
8✔
668
                        if err != nil {
8✔
669
                                return err
×
670
                        }
×
671
                }
672

673
                // Persist any reports that are present.
674
                for _, report := range reports {
4✔
UNCOV
675
                        err := b.cfg.PutResolverReport(tx, report)
×
UNCOV
676
                        if err != nil {
×
677
                                return err
×
678
                        }
×
679
                }
680

681
                return nil
4✔
682
        })
683
}
684

685
// SwapContract performs an atomic swap of the old contract for the new
686
// contract. This method is used when after a contract has been fully resolved,
687
// it produces another contract that needs to be resolved.
688
//
689
// NOTE: Part of the ContractResolver interface.
690
func (b *boltArbitratorLog) SwapContract(oldContract, newContract ContractResolver) error {
2✔
691
        return kvdb.Batch(b.db, func(tx kvdb.RwTx) error {
4✔
692
                contractBucket, err := fetchContractWriteBucket(tx, b.scopeKey[:])
2✔
693
                if err != nil {
2✔
694
                        return err
×
695
                }
×
696

697
                oldContractkey := oldContract.ResolverKey()
2✔
698
                if err := contractBucket.Delete(oldContractkey); err != nil {
2✔
699
                        return err
×
700
                }
×
701

702
                return b.writeResolver(contractBucket, newContract)
2✔
703
        })
704
}
705

706
// ResolveContract marks a contract as fully resolved. Once a contract has been
707
// fully resolved, it is deleted from persistent storage.
708
//
709
// NOTE: Part of the ContractResolver interface.
710
func (b *boltArbitratorLog) ResolveContract(res ContractResolver) error {
2✔
711
        return kvdb.Batch(b.db, func(tx kvdb.RwTx) error {
4✔
712
                contractBucket, err := fetchContractWriteBucket(tx, b.scopeKey[:])
2✔
713
                if err != nil {
2✔
714
                        return err
×
715
                }
×
716

717
                resKey := res.ResolverKey()
2✔
718
                return contractBucket.Delete(resKey)
2✔
719
        })
720
}
721

722
// LogContractResolutions stores a set of chain actions which are derived from
723
// our set of active contracts, and the on-chain state. We'll write this et of
724
// cations when: we decide to go on-chain to resolve a contract, or we detect
725
// that the remote party has gone on-chain.
726
//
727
// NOTE: Part of the ContractResolver interface.
728
func (b *boltArbitratorLog) LogContractResolutions(c *ContractResolutions) error {
2✔
729
        return kvdb.Batch(b.db, func(tx kvdb.RwTx) error {
4✔
730
                scopeBucket, err := tx.CreateTopLevelBucket(b.scopeKey[:])
2✔
731
                if err != nil {
2✔
732
                        return err
×
733
                }
×
734

735
                var b bytes.Buffer
2✔
736

2✔
737
                if _, err := b.Write(c.CommitHash[:]); err != nil {
2✔
738
                        return err
×
739
                }
×
740

741
                // First, we'll write out the commit output's resolution.
742
                if c.CommitResolution == nil {
3✔
743
                        if err := binary.Write(&b, endian, false); err != nil {
1✔
744
                                return err
×
745
                        }
×
746
                } else {
1✔
747
                        if err := binary.Write(&b, endian, true); err != nil {
1✔
748
                                return err
×
749
                        }
×
750
                        err = encodeCommitResolution(&b, c.CommitResolution)
1✔
751
                        if err != nil {
1✔
752
                                return err
×
753
                        }
×
754
                }
755

756
                // As we write the HTLC resolutions, we'll serialize the sign
757
                // details for each, to store under a new key.
758
                var signDetailsBuf bytes.Buffer
2✔
759

2✔
760
                // With the output for the commitment transaction written, we
2✔
761
                // can now write out the resolutions for the incoming and
2✔
762
                // outgoing HTLC's.
2✔
763
                numIncoming := uint32(len(c.HtlcResolutions.IncomingHTLCs))
2✔
764
                if err := binary.Write(&b, endian, numIncoming); err != nil {
2✔
765
                        return err
×
766
                }
×
767
                for _, htlc := range c.HtlcResolutions.IncomingHTLCs {
5✔
768
                        err := encodeIncomingResolution(&b, &htlc)
3✔
769
                        if err != nil {
3✔
770
                                return err
×
771
                        }
×
772

773
                        err = encodeSignDetails(&signDetailsBuf, htlc.SignDetails)
3✔
774
                        if err != nil {
3✔
775
                                return err
×
776
                        }
×
777
                }
778
                numOutgoing := uint32(len(c.HtlcResolutions.OutgoingHTLCs))
2✔
779
                if err := binary.Write(&b, endian, numOutgoing); err != nil {
2✔
780
                        return err
×
781
                }
×
782
                for _, htlc := range c.HtlcResolutions.OutgoingHTLCs {
6✔
783
                        err := encodeOutgoingResolution(&b, &htlc)
4✔
784
                        if err != nil {
4✔
785
                                return err
×
786
                        }
×
787

788
                        err = encodeSignDetails(&signDetailsBuf, htlc.SignDetails)
4✔
789
                        if err != nil {
4✔
790
                                return err
×
791
                        }
×
792
                }
793

794
                // Put the resolutions under the resolutionsKey.
795
                err = scopeBucket.Put(resolutionsKey, b.Bytes())
2✔
796
                if err != nil {
2✔
797
                        return err
×
798
                }
×
799

800
                // We'll put the serialized sign details under its own key to
801
                // stay backwards compatible.
802
                err = scopeBucket.Put(
2✔
803
                        resolutionsSignDetailsKey, signDetailsBuf.Bytes(),
2✔
804
                )
2✔
805
                if err != nil {
2✔
806
                        return err
×
807
                }
×
808

809
                // Write out the anchor resolution if present.
810
                if c.AnchorResolution != nil {
3✔
811
                        var b bytes.Buffer
1✔
812
                        err := encodeAnchorResolution(&b, c.AnchorResolution)
1✔
813
                        if err != nil {
1✔
814
                                return err
×
815
                        }
×
816

817
                        err = scopeBucket.Put(anchorResolutionKey, b.Bytes())
1✔
818
                        if err != nil {
1✔
819
                                return err
×
820
                        }
×
821
                }
822

823
                // Write out the breach resolution if present.
824
                if c.BreachResolution != nil {
2✔
UNCOV
825
                        var b bytes.Buffer
×
UNCOV
826
                        err := encodeBreachResolution(&b, c.BreachResolution)
×
UNCOV
827
                        if err != nil {
×
828
                                return err
×
829
                        }
×
830

UNCOV
831
                        err = scopeBucket.Put(breachResolutionKey, b.Bytes())
×
UNCOV
832
                        if err != nil {
×
833
                                return err
×
834
                        }
×
835
                }
836

837
                // If this isn't a taproot channel, then we can exit early here
838
                // as there's no extra data to write.
839
                switch {
2✔
840
                case c.AnchorResolution == nil:
1✔
841
                        return nil
1✔
842
                case !txscript.IsPayToTaproot(
843
                        c.AnchorResolution.AnchorSignDescriptor.Output.PkScript,
844
                ):
1✔
845
                        return nil
1✔
846
                }
847

848
                // With everything else encoded, we'll now populate the taproot
849
                // specific items we need to store for the musig2 channels.
UNCOV
850
                var tb bytes.Buffer
×
UNCOV
851
                err = encodeTaprootAuxData(&tb, c)
×
UNCOV
852
                if err != nil {
×
853
                        return err
×
854
                }
×
855

UNCOV
856
                return scopeBucket.Put(taprootDataKey, tb.Bytes())
×
857
        })
858
}
859

860
// FetchContractResolutions fetches the set of previously stored contract
861
// resolutions from persistent storage.
862
//
863
// NOTE: Part of the ContractResolver interface.
864
func (b *boltArbitratorLog) FetchContractResolutions() (*ContractResolutions, error) {
6✔
865
        var c *ContractResolutions
6✔
866
        err := kvdb.View(b.db, func(tx kvdb.RTx) error {
12✔
867
                scopeBucket := tx.ReadBucket(b.scopeKey[:])
6✔
868
                if scopeBucket == nil {
9✔
869
                        return errScopeBucketNoExist
3✔
870
                }
3✔
871

872
                resolutionBytes := scopeBucket.Get(resolutionsKey)
3✔
873
                if resolutionBytes == nil {
3✔
874
                        return errNoResolutions
×
875
                }
×
876

877
                resReader := bytes.NewReader(resolutionBytes)
3✔
878

3✔
879
                _, err := io.ReadFull(resReader, c.CommitHash[:])
3✔
880
                if err != nil {
3✔
881
                        return err
×
882
                }
×
883

884
                // First, we'll attempt to read out the commit resolution (if
885
                // it exists).
886
                var haveCommitRes bool
3✔
887
                err = binary.Read(resReader, endian, &haveCommitRes)
3✔
888
                if err != nil {
3✔
889
                        return err
×
890
                }
×
891
                if haveCommitRes {
4✔
892
                        c.CommitResolution = &lnwallet.CommitOutputResolution{}
1✔
893
                        err = decodeCommitResolution(
1✔
894
                                resReader, c.CommitResolution,
1✔
895
                        )
1✔
896
                        if err != nil {
1✔
897
                                return fmt.Errorf("unable to decode "+
×
898
                                        "commit res: %w", err)
×
899
                        }
×
900
                }
901

902
                var (
3✔
903
                        numIncoming uint32
3✔
904
                        numOutgoing uint32
3✔
905
                )
3✔
906

3✔
907
                // Next, we'll read out the incoming and outgoing HTLC
3✔
908
                // resolutions.
3✔
909
                err = binary.Read(resReader, endian, &numIncoming)
3✔
910
                if err != nil {
3✔
911
                        return err
×
912
                }
×
913
                c.HtlcResolutions.IncomingHTLCs = make([]lnwallet.IncomingHtlcResolution, numIncoming)
3✔
914
                for i := uint32(0); i < numIncoming; i++ {
6✔
915
                        err := decodeIncomingResolution(
3✔
916
                                resReader, &c.HtlcResolutions.IncomingHTLCs[i],
3✔
917
                        )
3✔
918
                        if err != nil {
3✔
919
                                return fmt.Errorf("unable to decode "+
×
920
                                        "incoming res: %w", err)
×
921
                        }
×
922
                }
923

924
                err = binary.Read(resReader, endian, &numOutgoing)
3✔
925
                if err != nil {
3✔
926
                        return err
×
927
                }
×
928
                c.HtlcResolutions.OutgoingHTLCs = make([]lnwallet.OutgoingHtlcResolution, numOutgoing)
3✔
929
                for i := uint32(0); i < numOutgoing; i++ {
8✔
930
                        err := decodeOutgoingResolution(
5✔
931
                                resReader, &c.HtlcResolutions.OutgoingHTLCs[i],
5✔
932
                        )
5✔
933
                        if err != nil {
5✔
934
                                return fmt.Errorf("unable to decode "+
×
935
                                        "outgoing res: %w", err)
×
936
                        }
×
937
                }
938

939
                // Now we attempt to get the sign details for our HTLC
940
                // resolutions. If not present the channel is of a type that
941
                // doesn't need them. If present there will be SignDetails
942
                // encoded for each HTLC resolution.
943
                signDetailsBytes := scopeBucket.Get(resolutionsSignDetailsKey)
3✔
944
                if signDetailsBytes != nil {
6✔
945
                        r := bytes.NewReader(signDetailsBytes)
3✔
946

3✔
947
                        // They will be encoded in the same order as the
3✔
948
                        // resolutions: firs incoming HTLCs, then outgoing.
3✔
949
                        for i := uint32(0); i < numIncoming; i++ {
6✔
950
                                htlc := &c.HtlcResolutions.IncomingHTLCs[i]
3✔
951
                                htlc.SignDetails, err = decodeSignDetails(r)
3✔
952
                                if err != nil {
3✔
953
                                        return fmt.Errorf("unable to decode "+
×
954
                                                "incoming sign desc: %w", err)
×
955
                                }
×
956
                        }
957

958
                        for i := uint32(0); i < numOutgoing; i++ {
8✔
959
                                htlc := &c.HtlcResolutions.OutgoingHTLCs[i]
5✔
960
                                htlc.SignDetails, err = decodeSignDetails(r)
5✔
961
                                if err != nil {
5✔
962
                                        return fmt.Errorf("unable to decode "+
×
963
                                                "outgoing sign desc: %w", err)
×
964
                                }
×
965
                        }
966
                }
967

968
                anchorResBytes := scopeBucket.Get(anchorResolutionKey)
3✔
969
                if anchorResBytes != nil {
4✔
970
                        c.AnchorResolution = &lnwallet.AnchorResolution{}
1✔
971
                        resReader := bytes.NewReader(anchorResBytes)
1✔
972
                        err := decodeAnchorResolution(
1✔
973
                                resReader, c.AnchorResolution,
1✔
974
                        )
1✔
975
                        if err != nil {
1✔
976
                                return fmt.Errorf("unable to read anchor "+
×
977
                                        "data: %w", err)
×
978
                        }
×
979
                }
980

981
                breachResBytes := scopeBucket.Get(breachResolutionKey)
3✔
982
                if breachResBytes != nil {
3✔
UNCOV
983
                        c.BreachResolution = &BreachResolution{}
×
UNCOV
984
                        resReader := bytes.NewReader(breachResBytes)
×
UNCOV
985
                        err := decodeBreachResolution(
×
UNCOV
986
                                resReader, c.BreachResolution,
×
UNCOV
987
                        )
×
UNCOV
988
                        if err != nil {
×
989
                                return fmt.Errorf("unable to read breach "+
×
990
                                        "data: %w", err)
×
991
                        }
×
992
                }
993

994
                tapCaseBytes := scopeBucket.Get(taprootDataKey)
3✔
995
                if tapCaseBytes != nil {
3✔
UNCOV
996
                        err = decodeTapRootAuxData(
×
UNCOV
997
                                bytes.NewReader(tapCaseBytes), c,
×
UNCOV
998
                        )
×
UNCOV
999
                        if err != nil {
×
1000
                                return fmt.Errorf("unable to read taproot "+
×
1001
                                        "data: %w", err)
×
1002
                        }
×
1003
                }
1004
                return nil
3✔
1005
        }, func() {
6✔
1006
                c = &ContractResolutions{}
6✔
1007
        })
6✔
1008
        if err != nil {
9✔
1009
                return nil, err
3✔
1010
        }
3✔
1011

1012
        return c, err
3✔
1013
}
1014

1015
// FetchChainActions attempts to fetch the set of previously stored chain
1016
// actions. We'll use this upon restart to properly advance our state machine
1017
// forward.
1018
//
1019
// NOTE: Part of the ContractResolver interface.
1020
func (b *boltArbitratorLog) FetchChainActions() (ChainActionMap, error) {
×
1021
        var actionsMap ChainActionMap
×
1022

×
1023
        err := kvdb.View(b.db, func(tx kvdb.RTx) error {
×
1024
                scopeBucket := tx.ReadBucket(b.scopeKey[:])
×
1025
                if scopeBucket == nil {
×
1026
                        return errScopeBucketNoExist
×
1027
                }
×
1028

1029
                actionsBucket := scopeBucket.NestedReadBucket(actionsBucketKey)
×
1030
                if actionsBucket == nil {
×
1031
                        return errNoActions
×
1032
                }
×
1033

1034
                return actionsBucket.ForEach(func(action, htlcBytes []byte) error {
×
1035
                        if htlcBytes == nil {
×
1036
                                return nil
×
1037
                        }
×
1038

1039
                        chainAction := ChainAction(action[0])
×
1040

×
1041
                        htlcReader := bytes.NewReader(htlcBytes)
×
1042
                        htlcs, err := channeldb.DeserializeHtlcs(htlcReader)
×
1043
                        if err != nil {
×
1044
                                return err
×
1045
                        }
×
1046

1047
                        actionsMap[chainAction] = htlcs
×
1048

×
1049
                        return nil
×
1050
                })
1051
        }, func() {
×
1052
                actionsMap = make(ChainActionMap)
×
1053
        })
×
1054
        if err != nil {
×
1055
                return nil, err
×
1056
        }
×
1057

1058
        return actionsMap, nil
×
1059
}
1060

1061
// InsertConfirmedCommitSet stores the known set of active HTLCs at the time
1062
// channel closure. We'll use this to reconstruct our set of chain actions anew
1063
// based on the confirmed and pending commitment state.
1064
//
1065
// NOTE: Part of the ContractResolver interface.
1066
func (b *boltArbitratorLog) InsertConfirmedCommitSet(c *CommitSet) error {
7✔
1067
        return kvdb.Batch(b.db, func(tx kvdb.RwTx) error {
14✔
1068
                scopeBucket, err := tx.CreateTopLevelBucket(b.scopeKey[:])
7✔
1069
                if err != nil {
7✔
1070
                        return err
×
1071
                }
×
1072

1073
                var b bytes.Buffer
7✔
1074
                if err := encodeCommitSet(&b, c); err != nil {
7✔
1075
                        return err
×
1076
                }
×
1077

1078
                return scopeBucket.Put(commitSetKey, b.Bytes())
7✔
1079
        })
1080
}
1081

1082
// FetchConfirmedCommitSet fetches the known confirmed active HTLC set from the
1083
// database. It takes an optional database transaction, which will be used if it
1084
// is non-nil, otherwise the lookup will be done in its own transaction.
1085
//
1086
// NOTE: Part of the ContractResolver interface.
1087
func (b *boltArbitratorLog) FetchConfirmedCommitSet(tx kvdb.RTx) (*CommitSet, error) {
19✔
1088
        if tx != nil {
30✔
1089
                return b.fetchConfirmedCommitSet(tx)
11✔
1090
        }
11✔
1091

1092
        var c *CommitSet
8✔
1093
        err := kvdb.View(b.db, func(tx kvdb.RTx) error {
16✔
1094
                var err error
8✔
1095
                c, err = b.fetchConfirmedCommitSet(tx)
8✔
1096
                return err
8✔
1097
        }, func() {
16✔
1098
                c = nil
8✔
1099
        })
8✔
1100
        if err != nil {
9✔
1101
                return nil, err
1✔
1102
        }
1✔
1103

1104
        return c, nil
7✔
1105
}
1106

1107
func (b *boltArbitratorLog) fetchConfirmedCommitSet(tx kvdb.RTx) (*CommitSet,
1108
        error) {
19✔
1109

19✔
1110
        scopeBucket := tx.ReadBucket(b.scopeKey[:])
19✔
1111
        if scopeBucket == nil {
31✔
1112
                return nil, errScopeBucketNoExist
12✔
1113
        }
12✔
1114

1115
        commitSetBytes := scopeBucket.Get(commitSetKey)
7✔
1116
        if commitSetBytes == nil {
7✔
UNCOV
1117
                return nil, errNoCommitSet
×
UNCOV
1118
        }
×
1119

1120
        return decodeCommitSet(bytes.NewReader(commitSetBytes))
7✔
1121
}
1122

1123
// WipeHistory is to be called ONLY once *all* contracts have been fully
1124
// resolved, and the channel closure if finalized. This method will delete all
1125
// on-disk state within the persistent log.
1126
//
1127
// NOTE: Part of the ContractResolver interface.
1128
func (b *boltArbitratorLog) WipeHistory() error {
4✔
1129
        return kvdb.Update(b.db, func(tx kvdb.RwTx) error {
8✔
1130
                scopeBucket, err := tx.CreateTopLevelBucket(b.scopeKey[:])
4✔
1131
                if err != nil {
4✔
1132
                        return err
×
1133
                }
×
1134

1135
                // Once we have the main top-level bucket, we'll delete the key
1136
                // that stores the state of the arbitrator.
1137
                if err := scopeBucket.Delete(stateKey[:]); err != nil {
4✔
1138
                        return err
×
1139
                }
×
1140

1141
                // Next, we'll delete any lingering contract state within the
1142
                // contracts bucket by removing the bucket itself.
1143
                err = scopeBucket.DeleteNestedBucket(contractsBucketKey)
4✔
1144
                if err != nil && err != kvdb.ErrBucketNotFound {
4✔
1145
                        return err
×
1146
                }
×
1147

1148
                // Next, we'll delete storage of any lingering contract
1149
                // resolutions.
1150
                if err := scopeBucket.Delete(resolutionsKey); err != nil {
4✔
1151
                        return err
×
1152
                }
×
1153

1154
                err = scopeBucket.Delete(resolutionsSignDetailsKey)
4✔
1155
                if err != nil {
4✔
1156
                        return err
×
1157
                }
×
1158

1159
                // We'll delete any chain actions that are still stored by
1160
                // removing the enclosing bucket.
1161
                err = scopeBucket.DeleteNestedBucket(actionsBucketKey)
4✔
1162
                if err != nil && err != kvdb.ErrBucketNotFound {
4✔
1163
                        return err
×
1164
                }
×
1165

1166
                // Finally, we'll delete the enclosing bucket itself.
1167
                return tx.DeleteTopLevelBucket(b.scopeKey[:])
4✔
1168
        }, func() {})
4✔
1169
}
1170

1171
// checkpointContract is a private method that will be fed into
1172
// ContractResolver instances to checkpoint their state once they reach
1173
// milestones during contract resolution. If the report provided is non-nil,
1174
// it should also be recorded.
1175
func (b *boltArbitratorLog) checkpointContract(c ContractResolver,
1176
        reports ...*channeldb.ResolverReport) error {
2✔
1177

2✔
1178
        return kvdb.Update(b.db, func(tx kvdb.RwTx) error {
4✔
1179
                contractBucket, err := fetchContractWriteBucket(tx, b.scopeKey[:])
2✔
1180
                if err != nil {
2✔
1181
                        return err
×
1182
                }
×
1183

1184
                if err := b.writeResolver(contractBucket, c); err != nil {
2✔
1185
                        return err
×
1186
                }
×
1187

1188
                for _, report := range reports {
4✔
1189
                        if err := b.cfg.PutResolverReport(tx, report); err != nil {
2✔
1190
                                return err
×
1191
                        }
×
1192
                }
1193

1194
                return nil
2✔
1195
        }, func() {})
2✔
1196
}
1197

1198
// encodeSignDetails encodes the given SignDetails struct to the writer.
1199
// SignDetails is allowed to be nil, in which we will encode that it is not
1200
// present.
1201
func encodeSignDetails(w io.Writer, s *input.SignDetails) error {
35✔
1202
        // If we don't have sign details, write false and return.
35✔
1203
        if s == nil {
61✔
1204
                return binary.Write(w, endian, false)
26✔
1205
        }
26✔
1206

1207
        // Otherwise write true, and the contents of the SignDetails.
1208
        if err := binary.Write(w, endian, true); err != nil {
9✔
1209
                return err
×
1210
        }
×
1211

1212
        err := input.WriteSignDescriptor(w, &s.SignDesc)
9✔
1213
        if err != nil {
9✔
1214
                return err
×
1215
        }
×
1216
        err = binary.Write(w, endian, uint32(s.SigHashType))
9✔
1217
        if err != nil {
9✔
1218
                return err
×
1219
        }
×
1220

1221
        // Write the DER-encoded signature.
1222
        b := s.PeerSig.Serialize()
9✔
1223
        if err := wire.WriteVarBytes(w, 0, b); err != nil {
9✔
1224
                return err
×
1225
        }
×
1226

1227
        return nil
9✔
1228
}
1229

1230
// decodeSignDetails extracts a single SignDetails from the reader. It is
1231
// allowed to return nil in case the SignDetails were empty.
1232
func decodeSignDetails(r io.Reader) (*input.SignDetails, error) {
30✔
1233
        var present bool
30✔
1234
        if err := binary.Read(r, endian, &present); err != nil {
30✔
1235
                return nil, err
×
1236
        }
×
1237

1238
        // Simply return nil if the next SignDetails was not present.
1239
        if !present {
53✔
1240
                return nil, nil
23✔
1241
        }
23✔
1242

1243
        // Otherwise decode the elements of the SignDetails.
1244
        s := input.SignDetails{}
7✔
1245
        err := input.ReadSignDescriptor(r, &s.SignDesc)
7✔
1246
        if err != nil {
7✔
1247
                return nil, err
×
1248
        }
×
1249

1250
        var sigHash uint32
7✔
1251
        err = binary.Read(r, endian, &sigHash)
7✔
1252
        if err != nil {
7✔
1253
                return nil, err
×
1254
        }
×
1255
        s.SigHashType = txscript.SigHashType(sigHash)
7✔
1256

7✔
1257
        // Read DER-encoded signature.
7✔
1258
        rawSig, err := wire.ReadVarBytes(r, 0, 200, "signature")
7✔
1259
        if err != nil {
7✔
1260
                return nil, err
×
1261
        }
×
1262

1263
        s.PeerSig, err = input.ParseSignature(rawSig)
7✔
1264
        if err != nil {
7✔
1265
                return nil, err
×
1266
        }
×
1267

1268
        return &s, nil
7✔
1269
}
1270

1271
func encodeIncomingResolution(w io.Writer, i *lnwallet.IncomingHtlcResolution) error {
12✔
1272
        if _, err := w.Write(i.Preimage[:]); err != nil {
12✔
1273
                return err
×
1274
        }
×
1275

1276
        if i.SignedSuccessTx == nil {
16✔
1277
                if err := binary.Write(w, endian, false); err != nil {
4✔
1278
                        return err
×
1279
                }
×
1280
        } else {
8✔
1281
                if err := binary.Write(w, endian, true); err != nil {
8✔
1282
                        return err
×
1283
                }
×
1284

1285
                if err := i.SignedSuccessTx.Serialize(w); err != nil {
8✔
1286
                        return err
×
1287
                }
×
1288
        }
1289

1290
        if err := binary.Write(w, endian, i.CsvDelay); err != nil {
12✔
1291
                return err
×
1292
        }
×
1293
        if _, err := w.Write(i.ClaimOutpoint.Hash[:]); err != nil {
12✔
1294
                return err
×
1295
        }
×
1296
        if err := binary.Write(w, endian, i.ClaimOutpoint.Index); err != nil {
12✔
1297
                return err
×
1298
        }
×
1299
        err := input.WriteSignDescriptor(w, &i.SweepSignDesc)
12✔
1300
        if err != nil {
12✔
1301
                return err
×
1302
        }
×
1303

1304
        return nil
12✔
1305
}
1306

1307
func decodeIncomingResolution(r io.Reader, h *lnwallet.IncomingHtlcResolution) error {
10✔
1308
        if _, err := io.ReadFull(r, h.Preimage[:]); err != nil {
10✔
1309
                return err
×
1310
        }
×
1311

1312
        var txPresent bool
10✔
1313
        if err := binary.Read(r, endian, &txPresent); err != nil {
10✔
1314
                return err
×
1315
        }
×
1316
        if txPresent {
16✔
1317
                h.SignedSuccessTx = &wire.MsgTx{}
6✔
1318
                if err := h.SignedSuccessTx.Deserialize(r); err != nil {
6✔
1319
                        return err
×
1320
                }
×
1321
        }
1322

1323
        err := binary.Read(r, endian, &h.CsvDelay)
10✔
1324
        if err != nil {
10✔
1325
                return err
×
1326
        }
×
1327
        _, err = io.ReadFull(r, h.ClaimOutpoint.Hash[:])
10✔
1328
        if err != nil {
10✔
1329
                return err
×
1330
        }
×
1331
        err = binary.Read(r, endian, &h.ClaimOutpoint.Index)
10✔
1332
        if err != nil {
10✔
1333
                return err
×
1334
        }
×
1335

1336
        return input.ReadSignDescriptor(r, &h.SweepSignDesc)
10✔
1337
}
1338

1339
func encodeOutgoingResolution(w io.Writer, o *lnwallet.OutgoingHtlcResolution) error {
23✔
1340
        if err := binary.Write(w, endian, o.Expiry); err != nil {
23✔
1341
                return err
×
1342
        }
×
1343

1344
        if o.SignedTimeoutTx == nil {
31✔
1345
                if err := binary.Write(w, endian, false); err != nil {
8✔
1346
                        return err
×
1347
                }
×
1348
        } else {
15✔
1349
                if err := binary.Write(w, endian, true); err != nil {
15✔
1350
                        return err
×
1351
                }
×
1352

1353
                if err := o.SignedTimeoutTx.Serialize(w); err != nil {
15✔
1354
                        return err
×
1355
                }
×
1356
        }
1357

1358
        if err := binary.Write(w, endian, o.CsvDelay); err != nil {
23✔
1359
                return err
×
1360
        }
×
1361
        if _, err := w.Write(o.ClaimOutpoint.Hash[:]); err != nil {
23✔
1362
                return err
×
1363
        }
×
1364
        if err := binary.Write(w, endian, o.ClaimOutpoint.Index); err != nil {
23✔
1365
                return err
×
1366
        }
×
1367

1368
        return input.WriteSignDescriptor(w, &o.SweepSignDesc)
23✔
1369
}
1370

1371
func decodeOutgoingResolution(r io.Reader, o *lnwallet.OutgoingHtlcResolution) error {
20✔
1372
        err := binary.Read(r, endian, &o.Expiry)
20✔
1373
        if err != nil {
20✔
1374
                return err
×
1375
        }
×
1376

1377
        var txPresent bool
20✔
1378
        if err := binary.Read(r, endian, &txPresent); err != nil {
20✔
1379
                return err
×
1380
        }
×
1381
        if txPresent {
33✔
1382
                o.SignedTimeoutTx = &wire.MsgTx{}
13✔
1383
                if err := o.SignedTimeoutTx.Deserialize(r); err != nil {
13✔
1384
                        return err
×
1385
                }
×
1386
        }
1387

1388
        err = binary.Read(r, endian, &o.CsvDelay)
20✔
1389
        if err != nil {
20✔
1390
                return err
×
1391
        }
×
1392
        _, err = io.ReadFull(r, o.ClaimOutpoint.Hash[:])
20✔
1393
        if err != nil {
20✔
1394
                return err
×
1395
        }
×
1396
        err = binary.Read(r, endian, &o.ClaimOutpoint.Index)
20✔
1397
        if err != nil {
20✔
1398
                return err
×
1399
        }
×
1400

1401
        return input.ReadSignDescriptor(r, &o.SweepSignDesc)
20✔
1402
}
1403

1404
func encodeCommitResolution(w io.Writer,
1405
        c *lnwallet.CommitOutputResolution) error {
2✔
1406

2✔
1407
        if _, err := w.Write(c.SelfOutPoint.Hash[:]); err != nil {
2✔
1408
                return err
×
1409
        }
×
1410
        err := binary.Write(w, endian, c.SelfOutPoint.Index)
2✔
1411
        if err != nil {
2✔
1412
                return err
×
1413
        }
×
1414

1415
        err = input.WriteSignDescriptor(w, &c.SelfOutputSignDesc)
2✔
1416
        if err != nil {
2✔
1417
                return err
×
1418
        }
×
1419

1420
        return binary.Write(w, endian, c.MaturityDelay)
2✔
1421
}
1422

1423
func decodeCommitResolution(r io.Reader,
1424
        c *lnwallet.CommitOutputResolution) error {
2✔
1425

2✔
1426
        _, err := io.ReadFull(r, c.SelfOutPoint.Hash[:])
2✔
1427
        if err != nil {
2✔
1428
                return err
×
1429
        }
×
1430
        err = binary.Read(r, endian, &c.SelfOutPoint.Index)
2✔
1431
        if err != nil {
2✔
1432
                return err
×
1433
        }
×
1434

1435
        err = input.ReadSignDescriptor(r, &c.SelfOutputSignDesc)
2✔
1436
        if err != nil {
2✔
1437
                return err
×
1438
        }
×
1439

1440
        return binary.Read(r, endian, &c.MaturityDelay)
2✔
1441
}
1442

1443
func encodeAnchorResolution(w io.Writer,
1444
        a *lnwallet.AnchorResolution) error {
1✔
1445

1✔
1446
        if _, err := w.Write(a.CommitAnchor.Hash[:]); err != nil {
1✔
1447
                return err
×
1448
        }
×
1449
        err := binary.Write(w, endian, a.CommitAnchor.Index)
1✔
1450
        if err != nil {
1✔
1451
                return err
×
1452
        }
×
1453

1454
        return input.WriteSignDescriptor(w, &a.AnchorSignDescriptor)
1✔
1455
}
1456

1457
func decodeAnchorResolution(r io.Reader,
1458
        a *lnwallet.AnchorResolution) error {
1✔
1459

1✔
1460
        _, err := io.ReadFull(r, a.CommitAnchor.Hash[:])
1✔
1461
        if err != nil {
1✔
1462
                return err
×
1463
        }
×
1464
        err = binary.Read(r, endian, &a.CommitAnchor.Index)
1✔
1465
        if err != nil {
1✔
1466
                return err
×
1467
        }
×
1468

1469
        return input.ReadSignDescriptor(r, &a.AnchorSignDescriptor)
1✔
1470
}
1471

UNCOV
1472
func encodeBreachResolution(w io.Writer, b *BreachResolution) error {
×
UNCOV
1473
        if _, err := w.Write(b.FundingOutPoint.Hash[:]); err != nil {
×
1474
                return err
×
1475
        }
×
UNCOV
1476
        return binary.Write(w, endian, b.FundingOutPoint.Index)
×
1477
}
1478

UNCOV
1479
func decodeBreachResolution(r io.Reader, b *BreachResolution) error {
×
UNCOV
1480
        _, err := io.ReadFull(r, b.FundingOutPoint.Hash[:])
×
UNCOV
1481
        if err != nil {
×
1482
                return err
×
1483
        }
×
UNCOV
1484
        return binary.Read(r, endian, &b.FundingOutPoint.Index)
×
1485
}
1486

1487
func encodeHtlcSetKey(w io.Writer, htlcSetKey HtlcSetKey) error {
23✔
1488
        err := binary.Write(w, endian, htlcSetKey.IsRemote)
23✔
1489
        if err != nil {
23✔
1490
                return err
×
1491
        }
×
1492

1493
        return binary.Write(w, endian, htlcSetKey.IsPending)
23✔
1494
}
1495

1496
func encodeCommitSet(w io.Writer, c *CommitSet) error {
7✔
1497
        confCommitKey, err := c.ConfCommitKey.UnwrapOrErr(
7✔
1498
                fmt.Errorf("HtlcSetKey is not set"),
7✔
1499
        )
7✔
1500
        if err != nil {
7✔
1501
                return err
×
1502
        }
×
1503
        if err := encodeHtlcSetKey(w, confCommitKey); err != nil {
7✔
1504
                return err
×
1505
        }
×
1506

1507
        numSets := uint8(len(c.HtlcSets))
7✔
1508
        if err := binary.Write(w, endian, numSets); err != nil {
7✔
1509
                return err
×
1510
        }
×
1511

1512
        for htlcSetKey, htlcs := range c.HtlcSets {
23✔
1513
                if err := encodeHtlcSetKey(w, htlcSetKey); err != nil {
16✔
1514
                        return err
×
1515
                }
×
1516

1517
                if err := channeldb.SerializeHtlcs(w, htlcs...); err != nil {
16✔
1518
                        return err
×
1519
                }
×
1520
        }
1521

1522
        return nil
7✔
1523
}
1524

1525
func decodeHtlcSetKey(r io.Reader, h *HtlcSetKey) error {
23✔
1526
        err := binary.Read(r, endian, &h.IsRemote)
23✔
1527
        if err != nil {
23✔
1528
                return err
×
1529
        }
×
1530

1531
        return binary.Read(r, endian, &h.IsPending)
23✔
1532
}
1533

1534
func decodeCommitSet(r io.Reader) (*CommitSet, error) {
7✔
1535
        confCommitKey := HtlcSetKey{}
7✔
1536
        if err := decodeHtlcSetKey(r, &confCommitKey); err != nil {
7✔
1537
                return nil, err
×
1538
        }
×
1539

1540
        c := &CommitSet{
7✔
1541
                ConfCommitKey: fn.Some(confCommitKey),
7✔
1542
                HtlcSets:      make(map[HtlcSetKey][]channeldb.HTLC),
7✔
1543
        }
7✔
1544

7✔
1545
        var numSets uint8
7✔
1546
        if err := binary.Read(r, endian, &numSets); err != nil {
7✔
1547
                return nil, err
×
1548
        }
×
1549

1550
        for i := uint8(0); i < numSets; i++ {
23✔
1551
                var htlcSetKey HtlcSetKey
16✔
1552
                if err := decodeHtlcSetKey(r, &htlcSetKey); err != nil {
16✔
1553
                        return nil, err
×
1554
                }
×
1555

1556
                htlcs, err := channeldb.DeserializeHtlcs(r)
16✔
1557
                if err != nil {
16✔
1558
                        return nil, err
×
1559
                }
×
1560

1561
                c.HtlcSets[htlcSetKey] = htlcs
16✔
1562
        }
1563

1564
        return c, nil
7✔
1565
}
1566

UNCOV
1567
func encodeTaprootAuxData(w io.Writer, c *ContractResolutions) error {
×
UNCOV
1568
        tapCase := newTaprootBriefcase()
×
UNCOV
1569

×
UNCOV
1570
        if c.CommitResolution != nil {
×
UNCOV
1571
                commitResolution := c.CommitResolution
×
UNCOV
1572
                commitSignDesc := commitResolution.SelfOutputSignDesc
×
UNCOV
1573
                //nolint:ll
×
UNCOV
1574
                tapCase.CtrlBlocks.Val.CommitSweepCtrlBlock = commitSignDesc.ControlBlock
×
UNCOV
1575

×
UNCOV
1576
                c.CommitResolution.ResolutionBlob.WhenSome(func(b []byte) {
×
UNCOV
1577
                        tapCase.SettledCommitBlob = tlv.SomeRecordT(
×
UNCOV
1578
                                tlv.NewPrimitiveRecord[tlv.TlvType2](b),
×
UNCOV
1579
                        )
×
UNCOV
1580
                })
×
1581
        }
1582

UNCOV
1583
        htlcBlobs := newAuxHtlcBlobs()
×
UNCOV
1584
        for _, htlc := range c.HtlcResolutions.IncomingHTLCs {
×
UNCOV
1585
                htlc := htlc
×
UNCOV
1586

×
UNCOV
1587
                htlcSignDesc := htlc.SweepSignDesc
×
UNCOV
1588
                ctrlBlock := htlcSignDesc.ControlBlock
×
UNCOV
1589

×
UNCOV
1590
                if ctrlBlock == nil {
×
1591
                        continue
×
1592
                }
1593

UNCOV
1594
                var resID resolverID
×
UNCOV
1595
                if htlc.SignedSuccessTx != nil {
×
UNCOV
1596
                        resID = newResolverID(
×
UNCOV
1597
                                htlc.SignedSuccessTx.TxIn[0].PreviousOutPoint,
×
UNCOV
1598
                        )
×
UNCOV
1599
                        //nolint:ll
×
UNCOV
1600
                        tapCase.CtrlBlocks.Val.SecondLevelCtrlBlocks[resID] = ctrlBlock
×
UNCOV
1601

×
UNCOV
1602
                        // For HTLCs we need to go to the second level for, we
×
UNCOV
1603
                        // also need to store the control block needed to
×
UNCOV
1604
                        // publish the second level transaction.
×
UNCOV
1605
                        if htlc.SignDetails != nil {
×
UNCOV
1606
                                //nolint:ll
×
UNCOV
1607
                                bridgeCtrlBlock := htlc.SignDetails.SignDesc.ControlBlock
×
UNCOV
1608
                                //nolint:ll
×
UNCOV
1609
                                tapCase.CtrlBlocks.Val.IncomingHtlcCtrlBlocks[resID] = bridgeCtrlBlock
×
UNCOV
1610
                        }
×
UNCOV
1611
                } else {
×
UNCOV
1612
                        resID = newResolverID(htlc.ClaimOutpoint)
×
UNCOV
1613
                        //nolint:ll
×
UNCOV
1614
                        tapCase.CtrlBlocks.Val.IncomingHtlcCtrlBlocks[resID] = ctrlBlock
×
UNCOV
1615
                }
×
1616

UNCOV
1617
                htlc.ResolutionBlob.WhenSome(func(b []byte) {
×
UNCOV
1618
                        htlcBlobs[resID] = b
×
UNCOV
1619
                })
×
1620
        }
UNCOV
1621
        for _, htlc := range c.HtlcResolutions.OutgoingHTLCs {
×
UNCOV
1622
                htlc := htlc
×
UNCOV
1623

×
UNCOV
1624
                htlcSignDesc := htlc.SweepSignDesc
×
UNCOV
1625
                ctrlBlock := htlcSignDesc.ControlBlock
×
UNCOV
1626

×
UNCOV
1627
                if ctrlBlock == nil {
×
1628
                        continue
×
1629
                }
1630

UNCOV
1631
                var resID resolverID
×
UNCOV
1632
                if htlc.SignedTimeoutTx != nil {
×
UNCOV
1633
                        resID = newResolverID(
×
UNCOV
1634
                                htlc.SignedTimeoutTx.TxIn[0].PreviousOutPoint,
×
UNCOV
1635
                        )
×
UNCOV
1636
                        //nolint:ll
×
UNCOV
1637
                        tapCase.CtrlBlocks.Val.SecondLevelCtrlBlocks[resID] = ctrlBlock
×
UNCOV
1638

×
UNCOV
1639
                        // For HTLCs we need to go to the second level for, we
×
UNCOV
1640
                        // also need to store the control block needed to
×
UNCOV
1641
                        // publish the second level transaction.
×
UNCOV
1642
                        //
×
UNCOV
1643
                        //nolint:ll
×
UNCOV
1644
                        if htlc.SignDetails != nil {
×
UNCOV
1645
                                //nolint:ll
×
UNCOV
1646
                                bridgeCtrlBlock := htlc.SignDetails.SignDesc.ControlBlock
×
UNCOV
1647
                                //nolint:ll
×
UNCOV
1648
                                tapCase.CtrlBlocks.Val.OutgoingHtlcCtrlBlocks[resID] = bridgeCtrlBlock
×
UNCOV
1649
                        }
×
UNCOV
1650
                } else {
×
UNCOV
1651
                        resID = newResolverID(htlc.ClaimOutpoint)
×
UNCOV
1652
                        //nolint:ll
×
UNCOV
1653
                        tapCase.CtrlBlocks.Val.OutgoingHtlcCtrlBlocks[resID] = ctrlBlock
×
UNCOV
1654
                }
×
1655

UNCOV
1656
                htlc.ResolutionBlob.WhenSome(func(b []byte) {
×
UNCOV
1657
                        htlcBlobs[resID] = b
×
UNCOV
1658
                })
×
1659
        }
1660

UNCOV
1661
        if c.AnchorResolution != nil {
×
UNCOV
1662
                anchorSignDesc := c.AnchorResolution.AnchorSignDescriptor
×
UNCOV
1663
                tapCase.TapTweaks.Val.AnchorTweak = anchorSignDesc.TapTweak
×
UNCOV
1664
        }
×
1665

UNCOV
1666
        if len(htlcBlobs) != 0 {
×
UNCOV
1667
                tapCase.HtlcBlobs = tlv.SomeRecordT(
×
UNCOV
1668
                        tlv.NewRecordT[tlv.TlvType4](htlcBlobs),
×
UNCOV
1669
                )
×
UNCOV
1670
        }
×
1671

UNCOV
1672
        return tapCase.Encode(w)
×
1673
}
1674

UNCOV
1675
func decodeTapRootAuxData(r io.Reader, c *ContractResolutions) error {
×
UNCOV
1676
        tapCase := newTaprootBriefcase()
×
UNCOV
1677
        if err := tapCase.Decode(r); err != nil {
×
1678
                return err
×
1679
        }
×
1680

UNCOV
1681
        if c.CommitResolution != nil {
×
UNCOV
1682
                c.CommitResolution.SelfOutputSignDesc.ControlBlock =
×
UNCOV
1683
                        tapCase.CtrlBlocks.Val.CommitSweepCtrlBlock
×
UNCOV
1684

×
UNCOV
1685
                tapCase.SettledCommitBlob.WhenSomeV(func(b []byte) {
×
UNCOV
1686
                        c.CommitResolution.ResolutionBlob = fn.Some(b)
×
UNCOV
1687
                })
×
1688
        }
1689

UNCOV
1690
        htlcBlobs := tapCase.HtlcBlobs.ValOpt().UnwrapOr(newAuxHtlcBlobs())
×
UNCOV
1691

×
UNCOV
1692
        for i := range c.HtlcResolutions.IncomingHTLCs {
×
UNCOV
1693
                htlc := c.HtlcResolutions.IncomingHTLCs[i]
×
UNCOV
1694

×
UNCOV
1695
                var resID resolverID
×
UNCOV
1696
                if htlc.SignedSuccessTx != nil {
×
UNCOV
1697
                        resID = newResolverID(
×
UNCOV
1698
                                htlc.SignedSuccessTx.TxIn[0].PreviousOutPoint,
×
UNCOV
1699
                        )
×
UNCOV
1700

×
UNCOV
1701
                        //nolint:ll
×
UNCOV
1702
                        ctrlBlock := tapCase.CtrlBlocks.Val.SecondLevelCtrlBlocks[resID]
×
UNCOV
1703
                        htlc.SweepSignDesc.ControlBlock = ctrlBlock
×
UNCOV
1704

×
UNCOV
1705
                        //nolint:ll
×
UNCOV
1706
                        if htlc.SignDetails != nil {
×
UNCOV
1707
                                bridgeCtrlBlock := tapCase.CtrlBlocks.Val.IncomingHtlcCtrlBlocks[resID]
×
UNCOV
1708
                                htlc.SignDetails.SignDesc.ControlBlock = bridgeCtrlBlock
×
UNCOV
1709
                        }
×
UNCOV
1710
                } else {
×
UNCOV
1711
                        resID = newResolverID(htlc.ClaimOutpoint)
×
UNCOV
1712

×
UNCOV
1713
                        //nolint:ll
×
UNCOV
1714
                        ctrlBlock := tapCase.CtrlBlocks.Val.IncomingHtlcCtrlBlocks[resID]
×
UNCOV
1715
                        htlc.SweepSignDesc.ControlBlock = ctrlBlock
×
UNCOV
1716
                }
×
1717

UNCOV
1718
                if htlcBlob, ok := htlcBlobs[resID]; ok {
×
UNCOV
1719
                        htlc.ResolutionBlob = fn.Some(htlcBlob)
×
UNCOV
1720
                }
×
1721

UNCOV
1722
                c.HtlcResolutions.IncomingHTLCs[i] = htlc
×
1723

1724
        }
UNCOV
1725
        for i := range c.HtlcResolutions.OutgoingHTLCs {
×
UNCOV
1726
                htlc := c.HtlcResolutions.OutgoingHTLCs[i]
×
UNCOV
1727

×
UNCOV
1728
                var resID resolverID
×
UNCOV
1729
                if htlc.SignedTimeoutTx != nil {
×
UNCOV
1730
                        resID = newResolverID(
×
UNCOV
1731
                                htlc.SignedTimeoutTx.TxIn[0].PreviousOutPoint,
×
UNCOV
1732
                        )
×
UNCOV
1733

×
UNCOV
1734
                        //nolint:ll
×
UNCOV
1735
                        ctrlBlock := tapCase.CtrlBlocks.Val.SecondLevelCtrlBlocks[resID]
×
UNCOV
1736
                        htlc.SweepSignDesc.ControlBlock = ctrlBlock
×
UNCOV
1737

×
UNCOV
1738
                        //nolint:ll
×
UNCOV
1739
                        if htlc.SignDetails != nil {
×
UNCOV
1740
                                bridgeCtrlBlock := tapCase.CtrlBlocks.Val.OutgoingHtlcCtrlBlocks[resID]
×
UNCOV
1741
                                htlc.SignDetails.SignDesc.ControlBlock = bridgeCtrlBlock
×
UNCOV
1742
                        }
×
UNCOV
1743
                } else {
×
UNCOV
1744
                        resID = newResolverID(htlc.ClaimOutpoint)
×
UNCOV
1745

×
UNCOV
1746
                        //nolint:ll
×
UNCOV
1747
                        ctrlBlock := tapCase.CtrlBlocks.Val.OutgoingHtlcCtrlBlocks[resID]
×
UNCOV
1748
                        htlc.SweepSignDesc.ControlBlock = ctrlBlock
×
UNCOV
1749
                }
×
1750

UNCOV
1751
                if htlcBlob, ok := htlcBlobs[resID]; ok {
×
UNCOV
1752
                        htlc.ResolutionBlob = fn.Some(htlcBlob)
×
UNCOV
1753
                }
×
1754

UNCOV
1755
                c.HtlcResolutions.OutgoingHTLCs[i] = htlc
×
1756
        }
1757

UNCOV
1758
        if c.AnchorResolution != nil {
×
UNCOV
1759
                c.AnchorResolution.AnchorSignDescriptor.TapTweak =
×
UNCOV
1760
                        tapCase.TapTweaks.Val.AnchorTweak
×
UNCOV
1761
        }
×
1762

UNCOV
1763
        return nil
×
1764
}
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