• 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

51.75
/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/input"
14
        "github.com/lightningnetwork/lnd/kvdb"
15
        "github.com/lightningnetwork/lnd/lnwallet"
16
)
17

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

×
UNCOV
227
        case StateBroadcastCommit:
×
228
                return "StateBroadcastCommit"
UNCOV
229

×
UNCOV
230
        case StateCommitmentBroadcasted:
×
231
                return "StateCommitmentBroadcasted"
UNCOV
232

×
UNCOV
233
        case StateContractClosed:
×
234
                return "StateContractClosed"
235

2✔
236
        case StateWaitingFullResolution:
2✔
237
                return "StateWaitingFullResolution"
UNCOV
238

×
UNCOV
239
        case StateFullyResolved:
×
240
                return "StateFullyResolved"
241

1✔
242
        case StateError:
1✔
243
                return "StateError"
UNCOV
244

×
245
        default:
×
246
                return "unknown state"
UNCOV
247
        }
×
UNCOV
248
}
×
249

250
// resolverType is an enum that enumerates the various types of resolvers. When
251
// writing resolvers to disk, we prepend this to the raw bytes stored. This
252
// allows us to properly decode the resolver into the proper type.
253
type resolverType uint8
254

255
const (
256
        // resolverTimeout is the type of a resolver that's tasked with
257
        // resolving an outgoing HTLC that is very close to timing out.
258
        resolverTimeout resolverType = 0
259

260
        // resolverSuccess is the type of a resolver that's tasked with
261
        // resolving an incoming HTLC that we already know the preimage of.
262
        resolverSuccess resolverType = 1
263

264
        // resolverOutgoingContest is the type of a resolver that's tasked with
265
        // resolving an outgoing HTLC that hasn't yet timed out.
266
        resolverOutgoingContest resolverType = 2
267

268
        // resolverIncomingContest is the type of a resolver that's tasked with
269
        // resolving an incoming HTLC that we don't yet know the preimage to.
270
        resolverIncomingContest resolverType = 3
271

272
        // resolverUnilateralSweep is the type of resolver that's tasked with
273
        // sweeping out direct commitment output form the remote party's
274
        // commitment transaction.
275
        resolverUnilateralSweep resolverType = 4
276

277
        // resolverBreach is the type of resolver that manages a contract
278
        // breach on-chain.
279
        resolverBreach resolverType = 5
280
)
281

282
// resolverIDLen is the size of the resolver ID key. This is 36 bytes as we get
283
// 32 bytes from the hash of the prev tx, and 4 bytes for the output index.
284
const resolverIDLen = 36
285

286
// resolverID is a key that uniquely identifies a resolver within a particular
287
// chain. For this value we use the full outpoint of the resolver.
288
type resolverID [resolverIDLen]byte
289

290
// newResolverID returns a resolverID given the outpoint of a contract.
291
func newResolverID(op wire.OutPoint) resolverID {
292
        var r resolverID
293

32✔
294
        copy(r[:], op.Hash[:])
32✔
295

32✔
296
        endian.PutUint32(r[32:], op.Index)
32✔
297

32✔
298
        return r
32✔
299
}
32✔
300

32✔
301
// logScope is a key that we use to scope the storage of a ChannelArbitrator
32✔
302
// within the global log. We use this key to create a unique bucket within the
303
// database and ensure that we don't have any key collisions. The log's scope
304
// is define as: chainHash || chanPoint, where chanPoint is the chan point of
305
// the original channel.
306
type logScope [32 + 36]byte
307

308
// newLogScope creates a new logScope key from the passed chainhash and
309
// chanPoint.
310
func newLogScope(chain chainhash.Hash, op wire.OutPoint) (*logScope, error) {
311
        var l logScope
312
        b := bytes.NewBuffer(l[0:0])
20✔
313

20✔
314
        if _, err := b.Write(chain[:]); err != nil {
20✔
315
                return nil, err
20✔
316
        }
20✔
UNCOV
317
        if _, err := b.Write(op.Hash[:]); err != nil {
×
318
                return nil, err
×
319
        }
20✔
UNCOV
320

×
UNCOV
321
        if err := binary.Write(b, endian, op.Index); err != nil {
×
322
                return nil, err
323
        }
20✔
UNCOV
324

×
UNCOV
325
        return &l, nil
×
326
}
327

20✔
328
var (
329
        // stateKey is the key that we use to store the current state of the
330
        // arbitrator.
331
        stateKey = []byte("state")
332

333
        // contractsBucketKey is the bucket within the logScope that will store
334
        // all the active unresolved contracts.
335
        contractsBucketKey = []byte("contractkey")
336

337
        // resolutionsKey is the key under the logScope that we'll use to store
338
        // the full set of resolutions for a channel.
339
        resolutionsKey = []byte("resolutions")
340

341
        // resolutionsSignDetailsKey is the key under the logScope where we
342
        // will store input.SignDetails for each HTLC resolution. If this is
343
        // not found under the logScope, it means it was written before
344
        // SignDetails was introduced, and should be set nil for each HTLC
345
        // resolution.
346
        resolutionsSignDetailsKey = []byte("resolutions-sign-details")
347

348
        // anchorResolutionKey is the key under the logScope that we'll use to
349
        // store the anchor resolution, if any.
350
        anchorResolutionKey = []byte("anchor-resolution")
351

352
        // breachResolutionKey is the key under the logScope that we'll use to
353
        // store the breach resolution, if any. This is used rather than the
354
        // resolutionsKey.
355
        breachResolutionKey = []byte("breach-resolution")
356

357
        // actionsBucketKey is the key under the logScope that we'll use to
358
        // store all chain actions once they're determined.
359
        actionsBucketKey = []byte("chain-actions")
360

361
        // commitSetKey is the primary key under the logScope that we'll use to
362
        // store the confirmed active HTLC sets once we learn that a channel
363
        // has closed out on chain.
364
        commitSetKey = []byte("commit-set")
365

366
        // taprootDataKey is the key we'll use to store taproot specific data
367
        // for the set of channels we'll need to sweep/claim.
368
        taprootDataKey = []byte("taproot-data")
369
)
370

371
var (
372
        // errScopeBucketNoExist is returned when we can't find the proper
373
        // bucket for an arbitrator's scope.
374
        errScopeBucketNoExist = fmt.Errorf("scope bucket not found")
375

376
        // errNoContracts is returned when no contracts are found within the
377
        // log.
378
        errNoContracts = fmt.Errorf("no stored contracts")
379

380
        // errNoResolutions is returned when the log doesn't contain any active
381
        // chain resolutions.
382
        errNoResolutions = fmt.Errorf("no contract resolutions exist")
383

384
        // errNoActions is returned when the log doesn't contain any stored
385
        // chain actions.
386
        errNoActions = fmt.Errorf("no chain actions exist")
387

388
        // errNoCommitSet is return when the log doesn't contained a CommitSet.
389
        // This can happen if the channel hasn't closed yet, or a client is
390
        // running an older version that didn't yet write this state.
391
        errNoCommitSet = fmt.Errorf("no commit set exists")
392
)
393

394
// boltArbitratorLog is an implementation of the ArbitratorLog interface backed
395
// by a bolt DB instance.
396
type boltArbitratorLog struct {
397
        db kvdb.Backend
398

399
        cfg ChannelArbitratorConfig
400

401
        scopeKey logScope
402
}
403

404
// newBoltArbitratorLog returns a new instance of the boltArbitratorLog given
405
// an arbitrator config, and the items needed to create its log scope.
406
func newBoltArbitratorLog(db kvdb.Backend, cfg ChannelArbitratorConfig,
407
        chainHash chainhash.Hash, chanPoint wire.OutPoint) (*boltArbitratorLog, error) {
408

409
        scope, err := newLogScope(chainHash, chanPoint)
20✔
410
        if err != nil {
20✔
411
                return nil, err
20✔
412
        }
20✔
UNCOV
413

×
UNCOV
414
        return &boltArbitratorLog{
×
415
                db:       db,
416
                cfg:      cfg,
20✔
417
                scopeKey: *scope,
20✔
418
        }, nil
20✔
419
}
20✔
420

20✔
421
// A compile time check to ensure boltArbitratorLog meets the ArbitratorLog
422
// interface.
423
var _ ArbitratorLog = (*boltArbitratorLog)(nil)
424

425
func fetchContractReadBucket(tx kvdb.RTx, scopeKey []byte) (kvdb.RBucket, error) {
426
        scopeBucket := tx.ReadBucket(scopeKey)
427
        if scopeBucket == nil {
9✔
428
                return nil, errScopeBucketNoExist
9✔
429
        }
10✔
430

1✔
431
        contractBucket := scopeBucket.NestedReadBucket(contractsBucketKey)
1✔
432
        if contractBucket == nil {
433
                return nil, errNoContracts
8✔
434
        }
8✔
UNCOV
435

×
UNCOV
436
        return contractBucket, nil
×
437
}
438

8✔
439
func fetchContractWriteBucket(tx kvdb.RwTx, scopeKey []byte) (kvdb.RwBucket, error) {
440
        scopeBucket, err := tx.CreateTopLevelBucket(scopeKey)
441
        if err != nil {
10✔
442
                return nil, err
10✔
443
        }
10✔
UNCOV
444

×
UNCOV
445
        contractBucket, err := scopeBucket.CreateBucketIfNotExists(
×
446
                contractsBucketKey,
447
        )
10✔
448
        if err != nil {
10✔
449
                return nil, err
10✔
450
        }
10✔
UNCOV
451

×
UNCOV
452
        return contractBucket, nil
×
453
}
454

10✔
455
// writeResolver is a helper method that writes a contract resolver and stores
456
// it it within the passed contractBucket using its unique resolutionsKey key.
457
func (b *boltArbitratorLog) writeResolver(contractBucket kvdb.RwBucket,
458
        res ContractResolver) error {
459

460
        // Only persist resolvers that are stateful. Stateless resolvers don't
12✔
461
        // expose a resolver key.
12✔
462
        resKey := res.ResolverKey()
12✔
463
        if resKey == nil {
12✔
464
                return nil
12✔
465
        }
12✔
UNCOV
466

×
UNCOV
467
        // First, we'll write to the buffer the type of this resolver. Using
×
468
        // this byte, we can later properly deserialize the resolver properly.
469
        var (
470
                buf   bytes.Buffer
471
                rType resolverType
12✔
472
        )
12✔
473
        switch res.(type) {
12✔
474
        case *htlcTimeoutResolver:
12✔
475
                rType = resolverTimeout
12✔
476
        case *htlcSuccessResolver:
6✔
477
                rType = resolverSuccess
6✔
478
        case *htlcOutgoingContestResolver:
1✔
479
                rType = resolverOutgoingContest
1✔
480
        case *htlcIncomingContestResolver:
3✔
481
                rType = resolverIncomingContest
3✔
482
        case *commitSweepResolver:
1✔
483
                rType = resolverUnilateralSweep
1✔
484
        case *breachResolver:
1✔
485
                rType = resolverBreach
1✔
UNCOV
486
        }
×
UNCOV
487
        if _, err := buf.Write([]byte{byte(rType)}); err != nil {
×
488
                return err
489
        }
12✔
UNCOV
490

×
UNCOV
491
        // With the type of the resolver written, we can then write out the raw
×
492
        // bytes of the resolver itself.
493
        if err := res.Encode(&buf); err != nil {
494
                return err
495
        }
12✔
UNCOV
496

×
UNCOV
497
        return contractBucket.Put(resKey, buf.Bytes())
×
498
}
499

12✔
500
// CurrentState returns the current state of the ChannelArbitrator. It takes an
501
// optional database transaction, which will be used if it is non-nil, otherwise
502
// the lookup will be done in its own transaction.
503
//
504
// NOTE: Part of the ContractResolver interface.
505
func (b *boltArbitratorLog) CurrentState(tx kvdb.RTx) (ArbitratorState, error) {
506
        var (
507
                s   ArbitratorState
18✔
508
                err error
18✔
509
        )
18✔
510

18✔
511
        if tx != nil {
18✔
512
                s, err = b.currentState(tx)
18✔
513
        } else {
29✔
514
                err = kvdb.View(b.db, func(tx kvdb.RTx) error {
11✔
515
                        s, err = b.currentState(tx)
18✔
516
                        return err
14✔
517
                }, func() {
7✔
518
                        s = 0
7✔
519
                })
14✔
520
        }
7✔
521

7✔
522
        if err != nil && err != errScopeBucketNoExist {
523
                return s, err
524
        }
18✔
UNCOV
525

×
UNCOV
526
        return s, nil
×
527
}
528

18✔
529
func (b *boltArbitratorLog) currentState(tx kvdb.RTx) (ArbitratorState, error) {
530
        scopeBucket := tx.ReadBucket(b.scopeKey[:])
531
        if scopeBucket == nil {
18✔
532
                return 0, errScopeBucketNoExist
18✔
533
        }
32✔
534

14✔
535
        stateBytes := scopeBucket.Get(stateKey)
14✔
536
        if stateBytes == nil {
537
                return 0, nil
4✔
538
        }
4✔
UNCOV
539

×
UNCOV
540
        return ArbitratorState(stateBytes[0]), nil
×
541
}
542

4✔
543
// CommitState persists, the current state of the chain attendant.
544
//
545
// NOTE: Part of the ContractResolver interface.
546
func (b *boltArbitratorLog) CommitState(s ArbitratorState) error {
547
        return kvdb.Batch(b.db, func(tx kvdb.RwTx) error {
548
                scopeBucket, err := tx.CreateTopLevelBucket(b.scopeKey[:])
8✔
549
                if err != nil {
16✔
550
                        return err
8✔
551
                }
8✔
UNCOV
552

×
UNCOV
553
                return scopeBucket.Put(stateKey[:], []byte{uint8(s)})
×
554
        })
555
}
8✔
556

557
// FetchUnresolvedContracts returns all unresolved contracts that have been
558
// previously written to the log.
559
//
560
// NOTE: Part of the ContractResolver interface.
561
func (b *boltArbitratorLog) FetchUnresolvedContracts() ([]ContractResolver, error) {
562
        resolverCfg := ResolverConfig{
563
                ChannelArbitratorConfig: b.cfg,
9✔
564
                Checkpoint:              b.checkpointContract,
9✔
565
        }
9✔
566
        var contracts []ContractResolver
9✔
567
        err := kvdb.View(b.db, func(tx kvdb.RTx) error {
9✔
568
                contractBucket, err := fetchContractReadBucket(tx, b.scopeKey[:])
9✔
569
                if err != nil {
18✔
570
                        return err
9✔
571
                }
10✔
572

1✔
573
                return contractBucket.ForEach(func(resKey, resBytes []byte) error {
1✔
574
                        if len(resKey) != resolverIDLen {
575
                                return nil
18✔
576
                        }
10✔
UNCOV
577

×
UNCOV
578
                        var res ContractResolver
×
579

580
                        // We'll snip off the first byte of the raw resolver
10✔
581
                        // bytes in order to extract what type of resolver
10✔
582
                        // we're about to encode.
10✔
583
                        resType := resolverType(resBytes[0])
10✔
584

10✔
585
                        // Then we'll create a reader using the remaining
10✔
586
                        // bytes.
10✔
587
                        resReader := bytes.NewReader(resBytes[1:])
10✔
588

10✔
589
                        switch resType {
10✔
590
                        case resolverTimeout:
10✔
591
                                res, err = newTimeoutResolverFromReader(
10✔
592
                                        resReader, resolverCfg,
3✔
593
                                )
3✔
594

3✔
595
                        case resolverSuccess:
3✔
596
                                res, err = newSuccessResolverFromReader(
597
                                        resReader, resolverCfg,
1✔
598
                                )
1✔
599

1✔
600
                        case resolverOutgoingContest:
1✔
601
                                res, err = newOutgoingContestResolverFromReader(
602
                                        resReader, resolverCfg,
4✔
603
                                )
4✔
604

4✔
605
                        case resolverIncomingContest:
4✔
606
                                res, err = newIncomingContestResolverFromReader(
607
                                        resReader, resolverCfg,
1✔
608
                                )
1✔
609

1✔
610
                        case resolverUnilateralSweep:
1✔
611
                                res, err = newCommitSweepResolverFromReader(
612
                                        resReader, resolverCfg,
1✔
613
                                )
1✔
614

1✔
615
                        case resolverBreach:
1✔
616
                                res, err = newBreachResolverFromReader(
UNCOV
617
                                        resReader, resolverCfg,
×
UNCOV
618
                                )
×
UNCOV
619

×
620
                        default:
×
621
                                return fmt.Errorf("unknown resolver type: %v", resType)
UNCOV
622
                        }
×
UNCOV
623

×
624
                        if err != nil {
625
                                return err
626
                        }
10✔
UNCOV
627

×
UNCOV
628
                        contracts = append(contracts, res)
×
629
                        return nil
630
                })
10✔
631
        }, func() {
10✔
632
                contracts = nil
633
        })
9✔
634
        if err != nil && err != errScopeBucketNoExist && err != errNoContracts {
9✔
635
                return nil, err
9✔
636
        }
9✔
UNCOV
637

×
UNCOV
638
        return contracts, nil
×
639
}
640

9✔
641
// InsertUnresolvedContracts inserts a set of unresolved contracts into the
642
// log. The log will then persistently store each contract until they've been
643
// swapped out, or resolved.
644
//
645
// NOTE: Part of the ContractResolver interface.
646
func (b *boltArbitratorLog) InsertUnresolvedContracts(reports []*channeldb.ResolverReport,
647
        resolvers ...ContractResolver) error {
648

649
        return kvdb.Batch(b.db, func(tx kvdb.RwTx) error {
4✔
650
                contractBucket, err := fetchContractWriteBucket(tx, b.scopeKey[:])
4✔
651
                if err != nil {
8✔
652
                        return err
4✔
653
                }
4✔
UNCOV
654

×
UNCOV
655
                for _, resolver := range resolvers {
×
656
                        err = b.writeResolver(contractBucket, resolver)
657
                        if err != nil {
12✔
658
                                return err
8✔
659
                        }
8✔
UNCOV
660
                }
×
UNCOV
661

×
662
                // Persist any reports that are present.
663
                for _, report := range reports {
664
                        err := b.cfg.PutResolverReport(tx, report)
665
                        if err != nil {
4✔
666
                                return err
×
667
                        }
×
UNCOV
668
                }
×
UNCOV
669

×
670
                return nil
671
        })
672
}
4✔
673

674
// SwapContract performs an atomic swap of the old contract for the new
675
// contract. This method is used when after a contract has been fully resolved,
676
// it produces another contract that needs to be resolved.
677
//
678
// NOTE: Part of the ContractResolver interface.
679
func (b *boltArbitratorLog) SwapContract(oldContract, newContract ContractResolver) error {
680
        return kvdb.Batch(b.db, func(tx kvdb.RwTx) error {
681
                contractBucket, err := fetchContractWriteBucket(tx, b.scopeKey[:])
2✔
682
                if err != nil {
4✔
683
                        return err
2✔
684
                }
2✔
UNCOV
685

×
UNCOV
686
                oldContractkey := oldContract.ResolverKey()
×
687
                if err := contractBucket.Delete(oldContractkey); err != nil {
688
                        return err
2✔
689
                }
2✔
UNCOV
690

×
UNCOV
691
                return b.writeResolver(contractBucket, newContract)
×
692
        })
693
}
2✔
694

695
// ResolveContract marks a contract as fully resolved. Once a contract has been
696
// fully resolved, it is deleted from persistent storage.
697
//
698
// NOTE: Part of the ContractResolver interface.
699
func (b *boltArbitratorLog) ResolveContract(res ContractResolver) error {
700
        return kvdb.Batch(b.db, func(tx kvdb.RwTx) error {
701
                contractBucket, err := fetchContractWriteBucket(tx, b.scopeKey[:])
2✔
702
                if err != nil {
4✔
703
                        return err
2✔
704
                }
2✔
UNCOV
705

×
UNCOV
706
                resKey := res.ResolverKey()
×
707
                return contractBucket.Delete(resKey)
708
        })
2✔
709
}
2✔
710

711
// LogContractResolutions stores a set of chain actions which are derived from
712
// our set of active contracts, and the on-chain state. We'll write this et of
713
// cations when: we decide to go on-chain to resolve a contract, or we detect
714
// that the remote party has gone on-chain.
715
//
716
// NOTE: Part of the ContractResolver interface.
717
func (b *boltArbitratorLog) LogContractResolutions(c *ContractResolutions) error {
718
        return kvdb.Batch(b.db, func(tx kvdb.RwTx) error {
719
                scopeBucket, err := tx.CreateTopLevelBucket(b.scopeKey[:])
2✔
720
                if err != nil {
4✔
721
                        return err
2✔
722
                }
2✔
UNCOV
723

×
UNCOV
724
                var b bytes.Buffer
×
725

726
                if _, err := b.Write(c.CommitHash[:]); err != nil {
2✔
727
                        return err
2✔
728
                }
2✔
UNCOV
729

×
UNCOV
730
                // First, we'll write out the commit output's resolution.
×
731
                if c.CommitResolution == nil {
732
                        if err := binary.Write(&b, endian, false); err != nil {
733
                                return err
3✔
734
                        }
1✔
UNCOV
735
                } else {
×
UNCOV
736
                        if err := binary.Write(&b, endian, true); err != nil {
×
737
                                return err
1✔
738
                        }
1✔
UNCOV
739
                        err = encodeCommitResolution(&b, c.CommitResolution)
×
UNCOV
740
                        if err != nil {
×
741
                                return err
1✔
742
                        }
1✔
UNCOV
743
                }
×
UNCOV
744

×
745
                // As we write the HTLC resolutions, we'll serialize the sign
746
                // details for each, to store under a new key.
747
                var signDetailsBuf bytes.Buffer
748

749
                // With the output for the commitment transaction written, we
2✔
750
                // can now write out the resolutions for the incoming and
2✔
751
                // outgoing HTLC's.
2✔
752
                numIncoming := uint32(len(c.HtlcResolutions.IncomingHTLCs))
2✔
753
                if err := binary.Write(&b, endian, numIncoming); err != nil {
2✔
754
                        return err
2✔
755
                }
2✔
UNCOV
756
                for _, htlc := range c.HtlcResolutions.IncomingHTLCs {
×
UNCOV
757
                        err := encodeIncomingResolution(&b, &htlc)
×
758
                        if err != nil {
5✔
759
                                return err
3✔
760
                        }
3✔
UNCOV
761

×
UNCOV
762
                        err = encodeSignDetails(&signDetailsBuf, htlc.SignDetails)
×
763
                        if err != nil {
764
                                return err
3✔
765
                        }
3✔
UNCOV
766
                }
×
UNCOV
767
                numOutgoing := uint32(len(c.HtlcResolutions.OutgoingHTLCs))
×
768
                if err := binary.Write(&b, endian, numOutgoing); err != nil {
769
                        return err
2✔
770
                }
2✔
UNCOV
771
                for _, htlc := range c.HtlcResolutions.OutgoingHTLCs {
×
UNCOV
772
                        err := encodeOutgoingResolution(&b, &htlc)
×
773
                        if err != nil {
6✔
774
                                return err
4✔
775
                        }
4✔
UNCOV
776

×
UNCOV
777
                        err = encodeSignDetails(&signDetailsBuf, htlc.SignDetails)
×
778
                        if err != nil {
779
                                return err
4✔
780
                        }
4✔
UNCOV
781
                }
×
UNCOV
782

×
783
                // Put the resolutions under the resolutionsKey.
784
                err = scopeBucket.Put(resolutionsKey, b.Bytes())
785
                if err != nil {
786
                        return err
2✔
787
                }
2✔
UNCOV
788

×
UNCOV
789
                // We'll put the serialized sign details under its own key to
×
790
                // stay backwards compatible.
791
                err = scopeBucket.Put(
792
                        resolutionsSignDetailsKey, signDetailsBuf.Bytes(),
793
                )
2✔
794
                if err != nil {
2✔
795
                        return err
2✔
796
                }
2✔
UNCOV
797

×
UNCOV
798
                // Write out the anchor resolution if present.
×
799
                if c.AnchorResolution != nil {
800
                        var b bytes.Buffer
801
                        err := encodeAnchorResolution(&b, c.AnchorResolution)
3✔
802
                        if err != nil {
1✔
803
                                return err
1✔
804
                        }
1✔
UNCOV
805

×
UNCOV
806
                        err = scopeBucket.Put(anchorResolutionKey, b.Bytes())
×
807
                        if err != nil {
808
                                return err
1✔
809
                        }
1✔
UNCOV
810
                }
×
UNCOV
811

×
812
                // Write out the breach resolution if present.
813
                if c.BreachResolution != nil {
814
                        var b bytes.Buffer
815
                        err := encodeBreachResolution(&b, c.BreachResolution)
2✔
UNCOV
816
                        if err != nil {
×
817
                                return err
×
818
                        }
×
UNCOV
819

×
UNCOV
820
                        err = scopeBucket.Put(breachResolutionKey, b.Bytes())
×
821
                        if err != nil {
822
                                return err
×
823
                        }
×
UNCOV
824
                }
×
UNCOV
825

×
826
                // If this isn't a taproot channel, then we can exit early here
827
                // as there's no extra data to write.
828
                switch {
829
                case c.AnchorResolution == nil:
830
                        return nil
2✔
831
                case !txscript.IsPayToTaproot(
1✔
832
                        c.AnchorResolution.AnchorSignDescriptor.Output.PkScript,
1✔
833
                ):
834
                        return nil
835
                }
1✔
836

1✔
837
                // With everything else encoded, we'll now populate the taproot
838
                // specific items we need to store for the musig2 channels.
839
                var tb bytes.Buffer
840
                err = encodeTaprootAuxData(&tb, c)
UNCOV
841
                if err != nil {
×
842
                        return err
×
843
                }
×
UNCOV
844

×
UNCOV
845
                return scopeBucket.Put(taprootDataKey, tb.Bytes())
×
846
        })
UNCOV
847
}
×
848

849
// FetchContractResolutions fetches the set of previously stored contract
850
// resolutions from persistent storage.
851
//
852
// NOTE: Part of the ContractResolver interface.
853
func (b *boltArbitratorLog) FetchContractResolutions() (*ContractResolutions, error) {
854
        var c *ContractResolutions
855
        err := kvdb.View(b.db, func(tx kvdb.RTx) error {
6✔
856
                scopeBucket := tx.ReadBucket(b.scopeKey[:])
6✔
857
                if scopeBucket == nil {
12✔
858
                        return errScopeBucketNoExist
6✔
859
                }
9✔
860

3✔
861
                resolutionBytes := scopeBucket.Get(resolutionsKey)
3✔
862
                if resolutionBytes == nil {
863
                        return errNoResolutions
3✔
864
                }
3✔
UNCOV
865

×
UNCOV
866
                resReader := bytes.NewReader(resolutionBytes)
×
867

868
                _, err := io.ReadFull(resReader, c.CommitHash[:])
3✔
869
                if err != nil {
3✔
870
                        return err
3✔
871
                }
3✔
UNCOV
872

×
UNCOV
873
                // First, we'll attempt to read out the commit resolution (if
×
874
                // it exists).
875
                var haveCommitRes bool
876
                err = binary.Read(resReader, endian, &haveCommitRes)
877
                if err != nil {
3✔
878
                        return err
3✔
879
                }
3✔
UNCOV
880
                if haveCommitRes {
×
UNCOV
881
                        c.CommitResolution = &lnwallet.CommitOutputResolution{}
×
882
                        err = decodeCommitResolution(
4✔
883
                                resReader, c.CommitResolution,
1✔
884
                        )
1✔
885
                        if err != nil {
1✔
886
                                return fmt.Errorf("unable to decode "+
1✔
887
                                        "commit res: %w", err)
1✔
888
                        }
×
UNCOV
889
                }
×
UNCOV
890

×
891
                var (
892
                        numIncoming uint32
893
                        numOutgoing uint32
3✔
894
                )
3✔
895

3✔
896
                // Next, we'll read out the incoming and outgoing HTLC
3✔
897
                // resolutions.
3✔
898
                err = binary.Read(resReader, endian, &numIncoming)
3✔
899
                if err != nil {
3✔
900
                        return err
3✔
901
                }
3✔
UNCOV
902
                c.HtlcResolutions.IncomingHTLCs = make([]lnwallet.IncomingHtlcResolution, numIncoming)
×
UNCOV
903
                for i := uint32(0); i < numIncoming; i++ {
×
904
                        err := decodeIncomingResolution(
3✔
905
                                resReader, &c.HtlcResolutions.IncomingHTLCs[i],
6✔
906
                        )
3✔
907
                        if err != nil {
3✔
908
                                return fmt.Errorf("unable to decode "+
3✔
909
                                        "incoming res: %w", err)
3✔
910
                        }
×
UNCOV
911
                }
×
UNCOV
912

×
913
                err = binary.Read(resReader, endian, &numOutgoing)
914
                if err != nil {
915
                        return err
3✔
916
                }
3✔
UNCOV
917
                c.HtlcResolutions.OutgoingHTLCs = make([]lnwallet.OutgoingHtlcResolution, numOutgoing)
×
UNCOV
918
                for i := uint32(0); i < numOutgoing; i++ {
×
919
                        err := decodeOutgoingResolution(
3✔
920
                                resReader, &c.HtlcResolutions.OutgoingHTLCs[i],
8✔
921
                        )
5✔
922
                        if err != nil {
5✔
923
                                return fmt.Errorf("unable to decode "+
5✔
924
                                        "outgoing res: %w", err)
5✔
925
                        }
×
UNCOV
926
                }
×
UNCOV
927

×
928
                // Now we attempt to get the sign details for our HTLC
929
                // resolutions. If not present the channel is of a type that
930
                // doesn't need them. If present there will be SignDetails
931
                // encoded for each HTLC resolution.
932
                signDetailsBytes := scopeBucket.Get(resolutionsSignDetailsKey)
933
                if signDetailsBytes != nil {
934
                        r := bytes.NewReader(signDetailsBytes)
3✔
935

6✔
936
                        // They will be encoded in the same order as the
3✔
937
                        // resolutions: firs incoming HTLCs, then outgoing.
3✔
938
                        for i := uint32(0); i < numIncoming; i++ {
3✔
939
                                htlc := &c.HtlcResolutions.IncomingHTLCs[i]
3✔
940
                                htlc.SignDetails, err = decodeSignDetails(r)
6✔
941
                                if err != nil {
3✔
942
                                        return fmt.Errorf("unable to decode "+
3✔
943
                                                "incoming sign desc: %w", err)
3✔
944
                                }
×
UNCOV
945
                        }
×
UNCOV
946

×
947
                        for i := uint32(0); i < numOutgoing; i++ {
948
                                htlc := &c.HtlcResolutions.OutgoingHTLCs[i]
949
                                htlc.SignDetails, err = decodeSignDetails(r)
8✔
950
                                if err != nil {
5✔
951
                                        return fmt.Errorf("unable to decode "+
5✔
952
                                                "outgoing sign desc: %w", err)
5✔
953
                                }
×
UNCOV
954
                        }
×
UNCOV
955
                }
×
956

957
                anchorResBytes := scopeBucket.Get(anchorResolutionKey)
958
                if anchorResBytes != nil {
959
                        c.AnchorResolution = &lnwallet.AnchorResolution{}
3✔
960
                        resReader := bytes.NewReader(anchorResBytes)
4✔
961
                        err := decodeAnchorResolution(
1✔
962
                                resReader, c.AnchorResolution,
1✔
963
                        )
1✔
964
                        if err != nil {
1✔
965
                                return fmt.Errorf("unable to read anchor "+
1✔
966
                                        "data: %w", err)
1✔
967
                        }
×
UNCOV
968
                }
×
UNCOV
969

×
970
                breachResBytes := scopeBucket.Get(breachResolutionKey)
971
                if breachResBytes != nil {
972
                        c.BreachResolution = &BreachResolution{}
3✔
973
                        resReader := bytes.NewReader(breachResBytes)
3✔
UNCOV
974
                        err := decodeBreachResolution(
×
UNCOV
975
                                resReader, c.BreachResolution,
×
UNCOV
976
                        )
×
UNCOV
977
                        if err != nil {
×
978
                                return fmt.Errorf("unable to read breach "+
×
979
                                        "data: %w", err)
×
980
                        }
×
UNCOV
981
                }
×
UNCOV
982

×
983
                tapCaseBytes := scopeBucket.Get(taprootDataKey)
984
                if tapCaseBytes != nil {
985
                        err = decodeTapRootAuxData(
3✔
986
                                bytes.NewReader(tapCaseBytes), c,
3✔
UNCOV
987
                        )
×
UNCOV
988
                        if err != nil {
×
989
                                return fmt.Errorf("unable to read taproot "+
×
990
                                        "data: %w", err)
×
991
                        }
×
UNCOV
992
                }
×
UNCOV
993
                return nil
×
994
        }, func() {
995
                c = &ContractResolutions{}
3✔
996
        })
6✔
997
        if err != nil {
6✔
998
                return nil, err
6✔
999
        }
9✔
1000

3✔
1001
        return c, err
3✔
1002
}
1003

3✔
1004
// FetchChainActions attempts to fetch the set of previously stored chain
1005
// actions. We'll use this upon restart to properly advance our state machine
1006
// forward.
1007
//
1008
// NOTE: Part of the ContractResolver interface.
1009
func (b *boltArbitratorLog) FetchChainActions() (ChainActionMap, error) {
1010
        var actionsMap ChainActionMap
1011

×
1012
        err := kvdb.View(b.db, func(tx kvdb.RTx) error {
×
1013
                scopeBucket := tx.ReadBucket(b.scopeKey[:])
×
1014
                if scopeBucket == nil {
×
1015
                        return errScopeBucketNoExist
×
1016
                }
×
UNCOV
1017

×
1018
                actionsBucket := scopeBucket.NestedReadBucket(actionsBucketKey)
×
1019
                if actionsBucket == nil {
1020
                        return errNoActions
×
1021
                }
×
UNCOV
1022

×
1023
                return actionsBucket.ForEach(func(action, htlcBytes []byte) error {
×
1024
                        if htlcBytes == nil {
1025
                                return nil
×
1026
                        }
×
UNCOV
1027

×
1028
                        chainAction := ChainAction(action[0])
×
1029

1030
                        htlcReader := bytes.NewReader(htlcBytes)
×
1031
                        htlcs, err := channeldb.DeserializeHtlcs(htlcReader)
×
1032
                        if err != nil {
×
1033
                                return err
×
1034
                        }
×
UNCOV
1035

×
1036
                        actionsMap[chainAction] = htlcs
×
1037

1038
                        return nil
×
UNCOV
1039
                })
×
1040
        }, func() {
×
1041
                actionsMap = make(ChainActionMap)
1042
        })
×
1043
        if err != nil {
×
1044
                return nil, err
×
1045
        }
×
UNCOV
1046

×
1047
        return actionsMap, nil
×
1048
}
UNCOV
1049

×
1050
// InsertConfirmedCommitSet stores the known set of active HTLCs at the time
1051
// channel closure. We'll use this to reconstruct our set of chain actions anew
1052
// based on the confirmed and pending commitment state.
1053
//
1054
// NOTE: Part of the ContractResolver interface.
1055
func (b *boltArbitratorLog) InsertConfirmedCommitSet(c *CommitSet) error {
1056
        return kvdb.Batch(b.db, func(tx kvdb.RwTx) error {
1057
                scopeBucket, err := tx.CreateTopLevelBucket(b.scopeKey[:])
7✔
1058
                if err != nil {
14✔
1059
                        return err
7✔
1060
                }
7✔
UNCOV
1061

×
UNCOV
1062
                var b bytes.Buffer
×
1063
                if err := encodeCommitSet(&b, c); err != nil {
1064
                        return err
7✔
1065
                }
7✔
UNCOV
1066

×
UNCOV
1067
                return scopeBucket.Put(commitSetKey, b.Bytes())
×
1068
        })
1069
}
7✔
1070

1071
// FetchConfirmedCommitSet fetches the known confirmed active HTLC set from the
1072
// database. It takes an optional database transaction, which will be used if it
1073
// is non-nil, otherwise the lookup will be done in its own transaction.
1074
//
1075
// NOTE: Part of the ContractResolver interface.
1076
func (b *boltArbitratorLog) FetchConfirmedCommitSet(tx kvdb.RTx) (*CommitSet, error) {
1077
        if tx != nil {
1078
                return b.fetchConfirmedCommitSet(tx)
19✔
1079
        }
30✔
1080

11✔
1081
        var c *CommitSet
11✔
1082
        err := kvdb.View(b.db, func(tx kvdb.RTx) error {
1083
                var err error
8✔
1084
                c, err = b.fetchConfirmedCommitSet(tx)
16✔
1085
                return err
8✔
1086
        }, func() {
8✔
1087
                c = nil
8✔
1088
        })
16✔
1089
        if err != nil {
8✔
1090
                return nil, err
8✔
1091
        }
9✔
1092

1✔
1093
        return c, nil
1✔
1094
}
1095

7✔
1096
func (b *boltArbitratorLog) fetchConfirmedCommitSet(tx kvdb.RTx) (*CommitSet,
1097
        error) {
1098

1099
        scopeBucket := tx.ReadBucket(b.scopeKey[:])
19✔
1100
        if scopeBucket == nil {
19✔
1101
                return nil, errScopeBucketNoExist
19✔
1102
        }
31✔
1103

12✔
1104
        commitSetBytes := scopeBucket.Get(commitSetKey)
12✔
1105
        if commitSetBytes == nil {
1106
                return nil, errNoCommitSet
7✔
1107
        }
7✔
UNCOV
1108

×
UNCOV
1109
        return decodeCommitSet(bytes.NewReader(commitSetBytes))
×
1110
}
1111

7✔
1112
// WipeHistory is to be called ONLY once *all* contracts have been fully
1113
// resolved, and the channel closure if finalized. This method will delete all
1114
// on-disk state within the persistent log.
1115
//
1116
// NOTE: Part of the ContractResolver interface.
1117
func (b *boltArbitratorLog) WipeHistory() error {
1118
        return kvdb.Update(b.db, func(tx kvdb.RwTx) error {
1119
                scopeBucket, err := tx.CreateTopLevelBucket(b.scopeKey[:])
4✔
1120
                if err != nil {
8✔
1121
                        return err
4✔
1122
                }
4✔
UNCOV
1123

×
UNCOV
1124
                // Once we have the main top-level bucket, we'll delete the key
×
1125
                // that stores the state of the arbitrator.
1126
                if err := scopeBucket.Delete(stateKey[:]); err != nil {
1127
                        return err
1128
                }
4✔
UNCOV
1129

×
UNCOV
1130
                // Next, we'll delete any lingering contract state within the
×
1131
                // contracts bucket by removing the bucket itself.
1132
                err = scopeBucket.DeleteNestedBucket(contractsBucketKey)
1133
                if err != nil && err != kvdb.ErrBucketNotFound {
1134
                        return err
4✔
1135
                }
4✔
UNCOV
1136

×
UNCOV
1137
                // Next, we'll delete storage of any lingering contract
×
1138
                // resolutions.
1139
                if err := scopeBucket.Delete(resolutionsKey); err != nil {
1140
                        return err
1141
                }
4✔
UNCOV
1142

×
UNCOV
1143
                err = scopeBucket.Delete(resolutionsSignDetailsKey)
×
1144
                if err != nil {
1145
                        return err
4✔
1146
                }
4✔
UNCOV
1147

×
UNCOV
1148
                // We'll delete any chain actions that are still stored by
×
1149
                // removing the enclosing bucket.
1150
                err = scopeBucket.DeleteNestedBucket(actionsBucketKey)
1151
                if err != nil && err != kvdb.ErrBucketNotFound {
1152
                        return err
4✔
1153
                }
4✔
UNCOV
1154

×
UNCOV
1155
                // Finally, we'll delete the enclosing bucket itself.
×
1156
                return tx.DeleteTopLevelBucket(b.scopeKey[:])
1157
        }, func() {})
1158
}
4✔
1159

4✔
1160
// checkpointContract is a private method that will be fed into
1161
// ContractResolver instances to checkpoint their state once they reach
1162
// milestones during contract resolution. If the report provided is non-nil,
1163
// it should also be recorded.
1164
func (b *boltArbitratorLog) checkpointContract(c ContractResolver,
1165
        reports ...*channeldb.ResolverReport) error {
1166

1167
        return kvdb.Update(b.db, func(tx kvdb.RwTx) error {
2✔
1168
                contractBucket, err := fetchContractWriteBucket(tx, b.scopeKey[:])
2✔
1169
                if err != nil {
4✔
1170
                        return err
2✔
1171
                }
2✔
UNCOV
1172

×
UNCOV
1173
                if err := b.writeResolver(contractBucket, c); err != nil {
×
1174
                        return err
1175
                }
2✔
UNCOV
1176

×
UNCOV
1177
                for _, report := range reports {
×
1178
                        if err := b.cfg.PutResolverReport(tx, report); err != nil {
1179
                                return err
4✔
1180
                        }
2✔
UNCOV
1181
                }
×
UNCOV
1182

×
1183
                return nil
1184
        }, func() {})
1185
}
2✔
1186

2✔
1187
// encodeSignDetails encodes the given SignDetails struct to the writer.
1188
// SignDetails is allowed to be nil, in which we will encode that it is not
1189
// present.
1190
func encodeSignDetails(w io.Writer, s *input.SignDetails) error {
1191
        // If we don't have sign details, write false and return.
1192
        if s == nil {
39✔
1193
                return binary.Write(w, endian, false)
39✔
1194
        }
67✔
1195

28✔
1196
        // Otherwise write true, and the contents of the SignDetails.
28✔
1197
        if err := binary.Write(w, endian, true); err != nil {
1198
                return err
1199
        }
11✔
UNCOV
1200

×
UNCOV
1201
        err := input.WriteSignDescriptor(w, &s.SignDesc)
×
1202
        if err != nil {
1203
                return err
11✔
1204
        }
11✔
UNCOV
1205
        err = binary.Write(w, endian, uint32(s.SigHashType))
×
UNCOV
1206
        if err != nil {
×
1207
                return err
11✔
1208
        }
11✔
UNCOV
1209

×
UNCOV
1210
        // Write the DER-encoded signature.
×
1211
        b := s.PeerSig.Serialize()
1212
        if err := wire.WriteVarBytes(w, 0, b); err != nil {
1213
                return err
11✔
1214
        }
11✔
UNCOV
1215

×
UNCOV
1216
        return nil
×
1217
}
1218

11✔
1219
// decodeSignDetails extracts a single SignDetails from the reader. It is
1220
// allowed to return nil in case the SignDetails were empty.
1221
func decodeSignDetails(r io.Reader) (*input.SignDetails, error) {
1222
        var present bool
1223
        if err := binary.Read(r, endian, &present); err != nil {
32✔
1224
                return nil, err
32✔
1225
        }
32✔
UNCOV
1226

×
UNCOV
1227
        // Simply return nil if the next SignDetails was not present.
×
1228
        if !present {
1229
                return nil, nil
1230
        }
56✔
1231

24✔
1232
        // Otherwise decode the elements of the SignDetails.
24✔
1233
        s := input.SignDetails{}
1234
        err := input.ReadSignDescriptor(r, &s.SignDesc)
1235
        if err != nil {
8✔
1236
                return nil, err
8✔
1237
        }
8✔
UNCOV
1238

×
UNCOV
1239
        var sigHash uint32
×
1240
        err = binary.Read(r, endian, &sigHash)
1241
        if err != nil {
8✔
1242
                return nil, err
8✔
1243
        }
8✔
UNCOV
1244
        s.SigHashType = txscript.SigHashType(sigHash)
×
UNCOV
1245

×
1246
        // Read DER-encoded signature.
8✔
1247
        rawSig, err := wire.ReadVarBytes(r, 0, 200, "signature")
8✔
1248
        if err != nil {
8✔
1249
                return nil, err
8✔
1250
        }
8✔
UNCOV
1251

×
UNCOV
1252
        s.PeerSig, err = input.ParseSignature(rawSig)
×
1253
        if err != nil {
1254
                return nil, err
8✔
1255
        }
8✔
UNCOV
1256

×
UNCOV
1257
        return &s, nil
×
1258
}
1259

8✔
1260
func encodeIncomingResolution(w io.Writer, i *lnwallet.IncomingHtlcResolution) error {
1261
        if _, err := w.Write(i.Preimage[:]); err != nil {
1262
                return err
12✔
1263
        }
12✔
UNCOV
1264

×
UNCOV
1265
        if i.SignedSuccessTx == nil {
×
1266
                if err := binary.Write(w, endian, false); err != nil {
1267
                        return err
16✔
1268
                }
4✔
UNCOV
1269
        } else {
×
UNCOV
1270
                if err := binary.Write(w, endian, true); err != nil {
×
1271
                        return err
8✔
1272
                }
8✔
UNCOV
1273

×
UNCOV
1274
                if err := i.SignedSuccessTx.Serialize(w); err != nil {
×
1275
                        return err
1276
                }
8✔
UNCOV
1277
        }
×
UNCOV
1278

×
1279
        if err := binary.Write(w, endian, i.CsvDelay); err != nil {
1280
                return err
1281
        }
12✔
UNCOV
1282
        if _, err := w.Write(i.ClaimOutpoint.Hash[:]); err != nil {
×
1283
                return err
×
1284
        }
12✔
UNCOV
1285
        if err := binary.Write(w, endian, i.ClaimOutpoint.Index); err != nil {
×
1286
                return err
×
1287
        }
12✔
UNCOV
1288
        err := input.WriteSignDescriptor(w, &i.SweepSignDesc)
×
UNCOV
1289
        if err != nil {
×
1290
                return err
12✔
1291
        }
12✔
UNCOV
1292

×
UNCOV
1293
        return nil
×
1294
}
1295

12✔
1296
func decodeIncomingResolution(r io.Reader, h *lnwallet.IncomingHtlcResolution) error {
1297
        if _, err := io.ReadFull(r, h.Preimage[:]); err != nil {
1298
                return err
10✔
1299
        }
10✔
UNCOV
1300

×
UNCOV
1301
        var txPresent bool
×
1302
        if err := binary.Read(r, endian, &txPresent); err != nil {
1303
                return err
10✔
1304
        }
10✔
UNCOV
1305
        if txPresent {
×
UNCOV
1306
                h.SignedSuccessTx = &wire.MsgTx{}
×
1307
                if err := h.SignedSuccessTx.Deserialize(r); err != nil {
16✔
1308
                        return err
6✔
1309
                }
6✔
UNCOV
1310
        }
×
UNCOV
1311

×
1312
        err := binary.Read(r, endian, &h.CsvDelay)
1313
        if err != nil {
1314
                return err
10✔
1315
        }
10✔
UNCOV
1316
        _, err = io.ReadFull(r, h.ClaimOutpoint.Hash[:])
×
UNCOV
1317
        if err != nil {
×
1318
                return err
10✔
1319
        }
10✔
UNCOV
1320
        err = binary.Read(r, endian, &h.ClaimOutpoint.Index)
×
UNCOV
1321
        if err != nil {
×
1322
                return err
10✔
1323
        }
10✔
UNCOV
1324

×
UNCOV
1325
        return input.ReadSignDescriptor(r, &h.SweepSignDesc)
×
1326
}
1327

10✔
1328
func encodeOutgoingResolution(w io.Writer, o *lnwallet.OutgoingHtlcResolution) error {
1329
        if err := binary.Write(w, endian, o.Expiry); err != nil {
1330
                return err
27✔
1331
        }
27✔
UNCOV
1332

×
UNCOV
1333
        if o.SignedTimeoutTx == nil {
×
1334
                if err := binary.Write(w, endian, false); err != nil {
1335
                        return err
35✔
1336
                }
8✔
UNCOV
1337
        } else {
×
UNCOV
1338
                if err := binary.Write(w, endian, true); err != nil {
×
1339
                        return err
19✔
1340
                }
19✔
UNCOV
1341

×
UNCOV
1342
                if err := o.SignedTimeoutTx.Serialize(w); err != nil {
×
1343
                        return err
1344
                }
19✔
UNCOV
1345
        }
×
UNCOV
1346

×
1347
        if err := binary.Write(w, endian, o.CsvDelay); err != nil {
1348
                return err
1349
        }
27✔
UNCOV
1350
        if _, err := w.Write(o.ClaimOutpoint.Hash[:]); err != nil {
×
1351
                return err
×
1352
        }
27✔
UNCOV
1353
        if err := binary.Write(w, endian, o.ClaimOutpoint.Index); err != nil {
×
1354
                return err
×
1355
        }
27✔
UNCOV
1356

×
UNCOV
1357
        return input.WriteSignDescriptor(w, &o.SweepSignDesc)
×
1358
}
1359

27✔
1360
func decodeOutgoingResolution(r io.Reader, o *lnwallet.OutgoingHtlcResolution) error {
1361
        err := binary.Read(r, endian, &o.Expiry)
1362
        if err != nil {
22✔
1363
                return err
22✔
1364
        }
22✔
UNCOV
1365

×
UNCOV
1366
        var txPresent bool
×
1367
        if err := binary.Read(r, endian, &txPresent); err != nil {
1368
                return err
22✔
1369
        }
22✔
UNCOV
1370
        if txPresent {
×
UNCOV
1371
                o.SignedTimeoutTx = &wire.MsgTx{}
×
1372
                if err := o.SignedTimeoutTx.Deserialize(r); err != nil {
37✔
1373
                        return err
15✔
1374
                }
15✔
UNCOV
1375
        }
×
UNCOV
1376

×
1377
        err = binary.Read(r, endian, &o.CsvDelay)
1378
        if err != nil {
1379
                return err
22✔
1380
        }
22✔
UNCOV
1381
        _, err = io.ReadFull(r, o.ClaimOutpoint.Hash[:])
×
UNCOV
1382
        if err != nil {
×
1383
                return err
22✔
1384
        }
22✔
UNCOV
1385
        err = binary.Read(r, endian, &o.ClaimOutpoint.Index)
×
UNCOV
1386
        if err != nil {
×
1387
                return err
22✔
1388
        }
22✔
UNCOV
1389

×
UNCOV
1390
        return input.ReadSignDescriptor(r, &o.SweepSignDesc)
×
1391
}
1392

22✔
1393
func encodeCommitResolution(w io.Writer,
1394
        c *lnwallet.CommitOutputResolution) error {
1395

1396
        if _, err := w.Write(c.SelfOutPoint.Hash[:]); err != nil {
2✔
1397
                return err
2✔
1398
        }
2✔
UNCOV
1399
        err := binary.Write(w, endian, c.SelfOutPoint.Index)
×
UNCOV
1400
        if err != nil {
×
1401
                return err
2✔
1402
        }
2✔
UNCOV
1403

×
UNCOV
1404
        err = input.WriteSignDescriptor(w, &c.SelfOutputSignDesc)
×
1405
        if err != nil {
1406
                return err
2✔
1407
        }
2✔
UNCOV
1408

×
UNCOV
1409
        return binary.Write(w, endian, c.MaturityDelay)
×
1410
}
1411

2✔
1412
func decodeCommitResolution(r io.Reader,
1413
        c *lnwallet.CommitOutputResolution) error {
1414

1415
        _, err := io.ReadFull(r, c.SelfOutPoint.Hash[:])
2✔
1416
        if err != nil {
2✔
1417
                return err
2✔
1418
        }
2✔
UNCOV
1419
        err = binary.Read(r, endian, &c.SelfOutPoint.Index)
×
UNCOV
1420
        if err != nil {
×
1421
                return err
2✔
1422
        }
2✔
UNCOV
1423

×
UNCOV
1424
        err = input.ReadSignDescriptor(r, &c.SelfOutputSignDesc)
×
1425
        if err != nil {
1426
                return err
2✔
1427
        }
2✔
UNCOV
1428

×
UNCOV
1429
        return binary.Read(r, endian, &c.MaturityDelay)
×
1430
}
1431

2✔
1432
func encodeAnchorResolution(w io.Writer,
1433
        a *lnwallet.AnchorResolution) error {
1434

1435
        if _, err := w.Write(a.CommitAnchor.Hash[:]); err != nil {
1✔
1436
                return err
1✔
1437
        }
1✔
UNCOV
1438
        err := binary.Write(w, endian, a.CommitAnchor.Index)
×
UNCOV
1439
        if err != nil {
×
1440
                return err
1✔
1441
        }
1✔
UNCOV
1442

×
UNCOV
1443
        return input.WriteSignDescriptor(w, &a.AnchorSignDescriptor)
×
1444
}
1445

1✔
1446
func decodeAnchorResolution(r io.Reader,
1447
        a *lnwallet.AnchorResolution) error {
1448

1449
        _, err := io.ReadFull(r, a.CommitAnchor.Hash[:])
1✔
1450
        if err != nil {
1✔
1451
                return err
1✔
1452
        }
1✔
UNCOV
1453
        err = binary.Read(r, endian, &a.CommitAnchor.Index)
×
UNCOV
1454
        if err != nil {
×
1455
                return err
1✔
1456
        }
1✔
UNCOV
1457

×
UNCOV
1458
        return input.ReadSignDescriptor(r, &a.AnchorSignDescriptor)
×
1459
}
1460

1✔
1461
func encodeBreachResolution(w io.Writer, b *BreachResolution) error {
1462
        if _, err := w.Write(b.FundingOutPoint.Hash[:]); err != nil {
1463
                return err
×
1464
        }
×
UNCOV
1465
        return binary.Write(w, endian, b.FundingOutPoint.Index)
×
UNCOV
1466
}
×
UNCOV
1467

×
1468
func decodeBreachResolution(r io.Reader, b *BreachResolution) error {
1469
        _, err := io.ReadFull(r, b.FundingOutPoint.Hash[:])
UNCOV
1470
        if err != nil {
×
1471
                return err
×
1472
        }
×
UNCOV
1473
        return binary.Read(r, endian, &b.FundingOutPoint.Index)
×
UNCOV
1474
}
×
UNCOV
1475

×
1476
func encodeHtlcSetKey(w io.Writer, h *HtlcSetKey) error {
1477
        err := binary.Write(w, endian, h.IsRemote)
1478
        if err != nil {
23✔
1479
                return err
23✔
1480
        }
23✔
UNCOV
1481
        return binary.Write(w, endian, h.IsPending)
×
UNCOV
1482
}
×
1483

23✔
1484
func encodeCommitSet(w io.Writer, c *CommitSet) error {
1485
        if err := encodeHtlcSetKey(w, c.ConfCommitKey); err != nil {
1486
                return err
7✔
1487
        }
7✔
UNCOV
1488

×
UNCOV
1489
        numSets := uint8(len(c.HtlcSets))
×
1490
        if err := binary.Write(w, endian, numSets); err != nil {
1491
                return err
7✔
1492
        }
7✔
UNCOV
1493

×
UNCOV
1494
        for htlcSetKey, htlcs := range c.HtlcSets {
×
1495
                htlcSetKey := htlcSetKey
1496
                if err := encodeHtlcSetKey(w, &htlcSetKey); err != nil {
23✔
1497
                        return err
16✔
1498
                }
16✔
UNCOV
1499

×
UNCOV
1500
                if err := channeldb.SerializeHtlcs(w, htlcs...); err != nil {
×
1501
                        return err
1502
                }
16✔
UNCOV
1503
        }
×
UNCOV
1504

×
1505
        return nil
1506
}
1507

7✔
1508
func decodeHtlcSetKey(r io.Reader, h *HtlcSetKey) error {
1509
        err := binary.Read(r, endian, &h.IsRemote)
1510
        if err != nil {
23✔
1511
                return err
23✔
1512
        }
23✔
UNCOV
1513

×
UNCOV
1514
        return binary.Read(r, endian, &h.IsPending)
×
1515
}
1516

23✔
1517
func decodeCommitSet(r io.Reader) (*CommitSet, error) {
1518
        c := &CommitSet{
1519
                ConfCommitKey: &HtlcSetKey{},
7✔
1520
                HtlcSets:      make(map[HtlcSetKey][]channeldb.HTLC),
7✔
1521
        }
7✔
1522

7✔
1523
        if err := decodeHtlcSetKey(r, c.ConfCommitKey); err != nil {
7✔
1524
                return nil, err
7✔
1525
        }
7✔
UNCOV
1526

×
UNCOV
1527
        var numSets uint8
×
1528
        if err := binary.Read(r, endian, &numSets); err != nil {
1529
                return nil, err
7✔
1530
        }
7✔
UNCOV
1531

×
UNCOV
1532
        for i := uint8(0); i < numSets; i++ {
×
1533
                var htlcSetKey HtlcSetKey
1534
                if err := decodeHtlcSetKey(r, &htlcSetKey); err != nil {
23✔
1535
                        return nil, err
16✔
1536
                }
16✔
UNCOV
1537

×
UNCOV
1538
                htlcs, err := channeldb.DeserializeHtlcs(r)
×
1539
                if err != nil {
1540
                        return nil, err
16✔
1541
                }
16✔
UNCOV
1542

×
UNCOV
1543
                c.HtlcSets[htlcSetKey] = htlcs
×
1544
        }
1545

16✔
1546
        return c, nil
1547
}
1548

7✔
1549
func encodeTaprootAuxData(w io.Writer, c *ContractResolutions) error {
1550
        tapCase := newTaprootBriefcase()
UNCOV
1551

×
UNCOV
1552
        if c.CommitResolution != nil {
×
UNCOV
1553
                commitResolution := c.CommitResolution
×
UNCOV
1554
                commitSignDesc := commitResolution.SelfOutputSignDesc
×
UNCOV
1555
                //nolint:lll
×
UNCOV
1556
                tapCase.CtrlBlocks.CommitSweepCtrlBlock = commitSignDesc.ControlBlock
×
UNCOV
1557
        }
×
UNCOV
1558

×
UNCOV
1559
        for _, htlc := range c.HtlcResolutions.IncomingHTLCs {
×
UNCOV
1560
                htlc := htlc
×
UNCOV
1561

×
UNCOV
1562
                htlcSignDesc := htlc.SweepSignDesc
×
UNCOV
1563
                ctrlBlock := htlcSignDesc.ControlBlock
×
UNCOV
1564

×
1565
                if ctrlBlock == nil {
1566
                        continue
UNCOV
1567
                }
×
UNCOV
1568

×
UNCOV
1569
                if htlc.SignedSuccessTx != nil {
×
UNCOV
1570
                        resID := newResolverID(
×
UNCOV
1571
                                htlc.SignedSuccessTx.TxIn[0].PreviousOutPoint,
×
UNCOV
1572
                        )
×
UNCOV
1573
                        //nolint:lll
×
UNCOV
1574
                        tapCase.CtrlBlocks.SecondLevelCtrlBlocks[resID] = ctrlBlock
×
1575

1576
                        // For HTLCs we need to go to the second level for, we
UNCOV
1577
                        // also need to store the control block needed to
×
UNCOV
1578
                        // publish the second level transaction.
×
UNCOV
1579
                        if htlc.SignDetails != nil {
×
UNCOV
1580
                                //nolint:lll
×
UNCOV
1581
                                bridgeCtrlBlock := htlc.SignDetails.SignDesc.ControlBlock
×
UNCOV
1582
                                //nolint:lll
×
UNCOV
1583
                                tapCase.CtrlBlocks.IncomingHtlcCtrlBlocks[resID] = bridgeCtrlBlock
×
UNCOV
1584
                        }
×
UNCOV
1585
                } else {
×
UNCOV
1586
                        resID := newResolverID(htlc.ClaimOutpoint)
×
UNCOV
1587
                        //nolint:lll
×
UNCOV
1588
                        tapCase.CtrlBlocks.IncomingHtlcCtrlBlocks[resID] = ctrlBlock
×
UNCOV
1589
                }
×
UNCOV
1590
        }
×
UNCOV
1591
        for _, htlc := range c.HtlcResolutions.OutgoingHTLCs {
×
UNCOV
1592
                htlc := htlc
×
UNCOV
1593

×
UNCOV
1594
                htlcSignDesc := htlc.SweepSignDesc
×
UNCOV
1595
                ctrlBlock := htlcSignDesc.ControlBlock
×
UNCOV
1596

×
UNCOV
1597
                if ctrlBlock == nil {
×
1598
                        continue
UNCOV
1599
                }
×
UNCOV
1600

×
UNCOV
1601
                if htlc.SignedTimeoutTx != nil {
×
UNCOV
1602
                        resID := newResolverID(
×
UNCOV
1603
                                htlc.SignedTimeoutTx.TxIn[0].PreviousOutPoint,
×
UNCOV
1604
                        )
×
UNCOV
1605
                        //nolint:lll
×
UNCOV
1606
                        tapCase.CtrlBlocks.SecondLevelCtrlBlocks[resID] = ctrlBlock
×
1607

1608
                        // For HTLCs we need to go to the second level for, we
UNCOV
1609
                        // also need to store the control block needed to
×
UNCOV
1610
                        // publish the second level transaction.
×
UNCOV
1611
                        //
×
UNCOV
1612
                        //nolint:lll
×
UNCOV
1613
                        if htlc.SignDetails != nil {
×
UNCOV
1614
                                //nolint:lll
×
UNCOV
1615
                                bridgeCtrlBlock := htlc.SignDetails.SignDesc.ControlBlock
×
UNCOV
1616
                                //nolint:lll
×
UNCOV
1617
                                tapCase.CtrlBlocks.OutgoingHtlcCtrlBlocks[resID] = bridgeCtrlBlock
×
UNCOV
1618
                        }
×
UNCOV
1619
                } else {
×
UNCOV
1620
                        resID := newResolverID(htlc.ClaimOutpoint)
×
UNCOV
1621
                        //nolint:lll
×
UNCOV
1622
                        tapCase.CtrlBlocks.OutgoingHtlcCtrlBlocks[resID] = ctrlBlock
×
UNCOV
1623
                }
×
UNCOV
1624
        }
×
UNCOV
1625

×
UNCOV
1626
        if c.AnchorResolution != nil {
×
UNCOV
1627
                anchorSignDesc := c.AnchorResolution.AnchorSignDescriptor
×
UNCOV
1628
                tapCase.TapTweaks.AnchorTweak = anchorSignDesc.TapTweak
×
UNCOV
1629
        }
×
UNCOV
1630

×
UNCOV
1631
        return tapCase.Encode(w)
×
1632
}
1633

UNCOV
1634
func decodeTapRootAuxData(r io.Reader, c *ContractResolutions) error {
×
UNCOV
1635
        tapCase := newTaprootBriefcase()
×
UNCOV
1636
        if err := tapCase.Decode(r); err != nil {
×
1637
                return err
×
1638
        }
UNCOV
1639

×
1640
        if c.CommitResolution != nil {
1641
                c.CommitResolution.SelfOutputSignDesc.ControlBlock =
UNCOV
1642
                        tapCase.CtrlBlocks.CommitSweepCtrlBlock
×
UNCOV
1643
        }
×
UNCOV
1644

×
UNCOV
1645
        for i := range c.HtlcResolutions.IncomingHTLCs {
×
UNCOV
1646
                htlc := c.HtlcResolutions.IncomingHTLCs[i]
×
1647

UNCOV
1648
                var resID resolverID
×
UNCOV
1649
                if htlc.SignedSuccessTx != nil {
×
UNCOV
1650
                        resID = newResolverID(
×
UNCOV
1651
                                htlc.SignedSuccessTx.TxIn[0].PreviousOutPoint,
×
UNCOV
1652
                        )
×
UNCOV
1653

×
UNCOV
1654
                        //nolint:lll
×
1655
                        ctrlBlock := tapCase.CtrlBlocks.SecondLevelCtrlBlocks[resID]
1656
                        htlc.SweepSignDesc.ControlBlock = ctrlBlock
UNCOV
1657

×
UNCOV
1658
                        //nolint:lll
×
UNCOV
1659
                        if htlc.SignDetails != nil {
×
UNCOV
1660
                                bridgeCtrlBlock := tapCase.CtrlBlocks.IncomingHtlcCtrlBlocks[resID]
×
UNCOV
1661
                                htlc.SignDetails.SignDesc.ControlBlock = bridgeCtrlBlock
×
UNCOV
1662
                        }
×
UNCOV
1663
                } else {
×
UNCOV
1664
                        resID = newResolverID(htlc.ClaimOutpoint)
×
UNCOV
1665

×
UNCOV
1666
                        //nolint:lll
×
UNCOV
1667
                        ctrlBlock := tapCase.CtrlBlocks.IncomingHtlcCtrlBlocks[resID]
×
UNCOV
1668
                        htlc.SweepSignDesc.ControlBlock = ctrlBlock
×
UNCOV
1669
                }
×
UNCOV
1670

×
UNCOV
1671
                c.HtlcResolutions.IncomingHTLCs[i] = htlc
×
UNCOV
1672
        }
×
UNCOV
1673
        for i := range c.HtlcResolutions.OutgoingHTLCs {
×
UNCOV
1674
                htlc := c.HtlcResolutions.OutgoingHTLCs[i]
×
UNCOV
1675

×
UNCOV
1676
                var resID resolverID
×
UNCOV
1677
                if htlc.SignedTimeoutTx != nil {
×
UNCOV
1678
                        resID = newResolverID(
×
UNCOV
1679
                                htlc.SignedTimeoutTx.TxIn[0].PreviousOutPoint,
×
UNCOV
1680
                        )
×
UNCOV
1681

×
1682
                        //nolint:lll
UNCOV
1683
                        ctrlBlock := tapCase.CtrlBlocks.SecondLevelCtrlBlocks[resID]
×
1684
                        htlc.SweepSignDesc.ControlBlock = ctrlBlock
UNCOV
1685

×
UNCOV
1686
                        //nolint:lll
×
UNCOV
1687
                        if htlc.SignDetails != nil {
×
UNCOV
1688
                                bridgeCtrlBlock := tapCase.CtrlBlocks.OutgoingHtlcCtrlBlocks[resID]
×
UNCOV
1689
                                htlc.SignDetails.SignDesc.ControlBlock = bridgeCtrlBlock
×
UNCOV
1690
                        }
×
UNCOV
1691
                } else {
×
UNCOV
1692
                        resID = newResolverID(htlc.ClaimOutpoint)
×
UNCOV
1693

×
UNCOV
1694
                        //nolint:lll
×
UNCOV
1695
                        ctrlBlock := tapCase.CtrlBlocks.OutgoingHtlcCtrlBlocks[resID]
×
UNCOV
1696
                        htlc.SweepSignDesc.ControlBlock = ctrlBlock
×
UNCOV
1697
                }
×
UNCOV
1698

×
UNCOV
1699
                c.HtlcResolutions.OutgoingHTLCs[i] = htlc
×
UNCOV
1700
        }
×
UNCOV
1701

×
UNCOV
1702
        if c.AnchorResolution != nil {
×
UNCOV
1703
                c.AnchorResolution.AnchorSignDescriptor.TapTweak =
×
UNCOV
1704
                        tapCase.TapTweaks.AnchorTweak
×
UNCOV
1705
        }
×
UNCOV
1706

×
UNCOV
1707
        return nil
×
UNCOV
1708
}
×
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