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

lightningnetwork / lnd / 12349698563

16 Dec 2024 09:29AM UTC coverage: 58.55% (-0.09%) from 58.636%
12349698563

Pull #9357

github

GeorgeTsagk
contractcourt: include custom records on replayed htlc

When notifying the invoice registry for an exit hop htlc we also want to
include its custom records. The channelLink, the other caller of this
method, already populates this field. So we make sure the contest
resolver does so too.
Pull Request #9357: contractcourt: include custom records on replayed htlc

2 of 2 new or added lines in 1 file covered. (100.0%)

262 existing lines in 24 files now uncovered.

134243 of 229278 relevant lines covered (58.55%)

19277.11 hits per line

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

72.87
/channeldb/migration30/revocation_log.go
1
package migration30
2

3
import (
4
        "bytes"
5
        "errors"
6
        "io"
7
        "math"
8

9
        "github.com/btcsuite/btcd/btcutil"
10
        lnwire "github.com/lightningnetwork/lnd/channeldb/migration/lnwire21"
11
        mig24 "github.com/lightningnetwork/lnd/channeldb/migration24"
12
        mig25 "github.com/lightningnetwork/lnd/channeldb/migration25"
13
        mig26 "github.com/lightningnetwork/lnd/channeldb/migration26"
14
        mig "github.com/lightningnetwork/lnd/channeldb/migration_01_to_11"
15
        "github.com/lightningnetwork/lnd/kvdb"
16
        "github.com/lightningnetwork/lnd/lntypes"
17
        "github.com/lightningnetwork/lnd/tlv"
18
)
19

20
const (
21
        // OutputIndexEmpty is used when the output index doesn't exist.
22
        OutputIndexEmpty = math.MaxUint16
23

24
        // A set of tlv type definitions used to serialize the body of
25
        // revocation logs to the database.
26
        //
27
        // NOTE: A migration should be added whenever this list changes.
28
        revLogOurOutputIndexType   tlv.Type = 0
29
        revLogTheirOutputIndexType tlv.Type = 1
30
        revLogCommitTxHashType     tlv.Type = 2
31
        revLogOurBalanceType       tlv.Type = 3
32
        revLogTheirBalanceType     tlv.Type = 4
33
)
34

35
var (
36
        // revocationLogBucketDeprecated is dedicated for storing the necessary
37
        // delta state between channel updates required to re-construct a past
38
        // state in order to punish a counterparty attempting a non-cooperative
39
        // channel closure. This key should be accessed from within the
40
        // sub-bucket of a target channel, identified by its channel point.
41
        //
42
        // Deprecated: This bucket is kept for read-only in case the user
43
        // choose not to migrate the old data.
44
        revocationLogBucketDeprecated = []byte("revocation-log-key")
45

46
        // revocationLogBucket is a sub-bucket under openChannelBucket. This
47
        // sub-bucket is dedicated for storing the minimal info required to
48
        // re-construct a past state in order to punish a counterparty
49
        // attempting a non-cooperative channel closure.
50
        revocationLogBucket = []byte("revocation-log")
51

52
        // revocationStateKey stores their current revocation hash, our
53
        // preimage producer and their preimage store.
54
        revocationStateKey = []byte("revocation-state-key")
55

56
        // ErrNoRevocationsFound is returned when revocation state for a
57
        // particular channel cannot be found.
58
        ErrNoRevocationsFound = errors.New("no revocations found")
59

60
        // ErrLogEntryNotFound is returned when we cannot find a log entry at
61
        // the height requested in the revocation log.
62
        ErrLogEntryNotFound = errors.New("log entry not found")
63

64
        // ErrOutputIndexTooBig is returned when the output index is greater
65
        // than uint16.
66
        ErrOutputIndexTooBig = errors.New("output index is over uint16")
67
)
68

69
// HTLCEntry specifies the minimal info needed to be stored on disk for ALL the
70
// historical HTLCs, which is useful for constructing RevocationLog when a
71
// breach is detected.
72
// The actual size of each HTLCEntry varies based on its RHash and Amt(sat),
73
// summarized as follows,
74
//
75
//        | RHash empty | Amt<=252 | Amt<=65,535 | Amt<=4,294,967,295 | otherwise |
76
//        |:-----------:|:--------:|:-----------:|:------------------:|:---------:|
77
//        |     true    |    19    |      21     |         23         |     26    |
78
//        |     false   |    51    |      53     |         55         |     58    |
79
//
80
// So the size varies from 19 bytes to 58 bytes, where most likely to be 23 or
81
// 55 bytes.
82
//
83
// NOTE: all the fields saved to disk use the primitive go types so they can be
84
// made into tlv records without further conversion.
85
type HTLCEntry struct {
86
        // RHash is the payment hash of the HTLC.
87
        RHash [32]byte
88

89
        // RefundTimeout is the absolute timeout on the HTLC that the sender
90
        // must wait before reclaiming the funds in limbo.
91
        RefundTimeout uint32
92

93
        // OutputIndex is the output index for this particular HTLC output
94
        // within the commitment transaction.
95
        //
96
        // NOTE: we use uint16 instead of int32 here to save us 2 bytes, which
97
        // gives us a max number of HTLCs of 65K.
98
        OutputIndex uint16
99

100
        // Incoming denotes whether we're the receiver or the sender of this
101
        // HTLC.
102
        //
103
        // NOTE: this field is the memory representation of the field
104
        // incomingUint.
105
        Incoming bool
106

107
        // Amt is the amount of satoshis this HTLC escrows.
108
        //
109
        // NOTE: this field is the memory representation of the field amtUint.
110
        Amt btcutil.Amount
111

112
        // amtTlv is the uint64 format of Amt. This field is created so we can
113
        // easily make it into a tlv record and save it to disk.
114
        //
115
        // NOTE: we keep this field for accounting purpose only. If the disk
116
        // space becomes an issue, we could delete this field to save us extra
117
        // 8 bytes.
118
        amtTlv uint64
119

120
        // incomingTlv is the uint8 format of Incoming. This field is created
121
        // so we can easily make it into a tlv record and save it to disk.
122
        incomingTlv uint8
123
}
124

125
// RHashLen is used by MakeDynamicRecord to return the size of the RHash.
126
//
127
// NOTE: for zero hash, we return a length 0.
128
func (h *HTLCEntry) RHashLen() uint64 {
2,291✔
129
        if h.RHash == lntypes.ZeroHash {
2,291✔
130
                return 0
×
131
        }
×
132
        return 32
2,291✔
133
}
134

135
// RHashEncoder is the customized encoder which skips encoding the empty hash.
136
func RHashEncoder(w io.Writer, val interface{}, buf *[8]byte) error {
2,291✔
137
        v, ok := val.(*[32]byte)
2,291✔
138
        if !ok {
2,291✔
139
                return tlv.NewTypeForEncodingErr(val, "RHash")
×
140
        }
×
141

142
        // If the value is an empty hash, we will skip encoding it.
143
        if *v == lntypes.ZeroHash {
2,291✔
144
                return nil
×
145
        }
×
146

147
        return tlv.EBytes32(w, v, buf)
2,291✔
148
}
149

150
// RHashDecoder is the customized decoder which skips decoding the empty hash.
151
func RHashDecoder(r io.Reader, val interface{}, buf *[8]byte, l uint64) error {
1,980✔
152
        v, ok := val.(*[32]byte)
1,980✔
153
        if !ok {
1,980✔
154
                return tlv.NewTypeForEncodingErr(val, "RHash")
×
155
        }
×
156

157
        // If the length is zero, we will skip encoding the empty hash.
158
        if l == 0 {
1,980✔
159
                return nil
×
160
        }
×
161

162
        return tlv.DBytes32(r, v, buf, 32)
1,980✔
163
}
164

165
// toTlvStream converts an HTLCEntry record into a tlv representation.
166
func (h *HTLCEntry) toTlvStream() (*tlv.Stream, error) {
8,231✔
167
        const (
8,231✔
168
                // A set of tlv type definitions used to serialize htlc entries
8,231✔
169
                // to the database. We define it here instead of the head of
8,231✔
170
                // the file to avoid naming conflicts.
8,231✔
171
                //
8,231✔
172
                // NOTE: A migration should be added whenever this list
8,231✔
173
                // changes.
8,231✔
174
                rHashType         tlv.Type = 0
8,231✔
175
                refundTimeoutType tlv.Type = 1
8,231✔
176
                outputIndexType   tlv.Type = 2
8,231✔
177
                incomingType      tlv.Type = 3
8,231✔
178
                amtType           tlv.Type = 4
8,231✔
179
        )
8,231✔
180

8,231✔
181
        return tlv.NewStream(
8,231✔
182
                tlv.MakeDynamicRecord(
8,231✔
183
                        rHashType, &h.RHash, h.RHashLen,
8,231✔
184
                        RHashEncoder, RHashDecoder,
8,231✔
185
                ),
8,231✔
186
                tlv.MakePrimitiveRecord(
8,231✔
187
                        refundTimeoutType, &h.RefundTimeout,
8,231✔
188
                ),
8,231✔
189
                tlv.MakePrimitiveRecord(
8,231✔
190
                        outputIndexType, &h.OutputIndex,
8,231✔
191
                ),
8,231✔
192
                tlv.MakePrimitiveRecord(incomingType, &h.incomingTlv),
8,231✔
193
                // We will save 3 bytes if the amount is less or equal to
8,231✔
194
                // 4,294,967,295 msat, or roughly 0.043 bitcoin.
8,231✔
195
                tlv.MakeBigSizeRecord(amtType, &h.amtTlv),
8,231✔
196
        )
8,231✔
197
}
8,231✔
198

199
// RevocationLog stores the info needed to construct a breach retribution. Its
200
// fields can be viewed as a subset of a ChannelCommitment's. In the database,
201
// all historical versions of the RevocationLog are saved using the
202
// CommitHeight as the key.
203
type RevocationLog struct {
204
        // OurOutputIndex specifies our output index in this commitment. In a
205
        // remote commitment transaction, this is the to remote output index.
206
        OurOutputIndex uint16
207

208
        // TheirOutputIndex specifies their output index in this commitment. In
209
        // a remote commitment transaction, this is the to local output index.
210
        TheirOutputIndex uint16
211

212
        // CommitTxHash is the hash of the latest version of the commitment
213
        // state, broadcast able by us.
214
        CommitTxHash [32]byte
215

216
        // HTLCEntries is the set of HTLCEntry's that are pending at this
217
        // particular commitment height.
218
        HTLCEntries []*HTLCEntry
219

220
        // OurBalance is the current available balance within the channel
221
        // directly spendable by us. In other words, it is the value of the
222
        // to_remote output on the remote parties' commitment transaction.
223
        //
224
        // NOTE: this is a pointer so that it is clear if the value is zero or
225
        // nil. Since migration 30 of the channeldb initially did not include
226
        // this field, it could be the case that the field is not present for
227
        // all revocation logs.
228
        OurBalance *lnwire.MilliSatoshi
229

230
        // TheirBalance is the current available balance within the channel
231
        // directly spendable by the remote node. In other words, it is the
232
        // value of the to_local output on the remote parties' commitment.
233
        //
234
        // NOTE: this is a pointer so that it is clear if the value is zero or
235
        // nil. Since migration 30 of the channeldb initially did not include
236
        // this field, it could be the case that the field is not present for
237
        // all revocation logs.
238
        TheirBalance *lnwire.MilliSatoshi
239
}
240

241
// putRevocationLog uses the fields `CommitTx` and `Htlcs` from a
242
// ChannelCommitment to construct a revocation log entry and saves them to
243
// disk. It also saves our output index and their output index, which are
244
// useful when creating breach retribution.
245
func putRevocationLog(bucket kvdb.RwBucket, commit *mig.ChannelCommitment,
246
        ourOutputIndex, theirOutputIndex uint32, noAmtData bool) error {
2,013✔
247

2,013✔
248
        // Sanity check that the output indexes can be safely converted.
2,013✔
249
        if ourOutputIndex > math.MaxUint16 {
2,013✔
250
                return ErrOutputIndexTooBig
×
251
        }
×
252
        if theirOutputIndex > math.MaxUint16 {
2,013✔
253
                return ErrOutputIndexTooBig
×
254
        }
×
255

256
        rl := &RevocationLog{
2,013✔
257
                OurOutputIndex:   uint16(ourOutputIndex),
2,013✔
258
                TheirOutputIndex: uint16(theirOutputIndex),
2,013✔
259
                CommitTxHash:     commit.CommitTx.TxHash(),
2,013✔
260
                HTLCEntries:      make([]*HTLCEntry, 0, len(commit.Htlcs)),
2,013✔
261
        }
2,013✔
262

2,013✔
263
        if !noAmtData {
2,013✔
UNCOV
264
                rl.OurBalance = &commit.LocalBalance
×
UNCOV
265
                rl.TheirBalance = &commit.RemoteBalance
×
UNCOV
266
        }
×
267

268
        for _, htlc := range commit.Htlcs {
2,702✔
269
                // Skip dust HTLCs.
689✔
270
                if htlc.OutputIndex < 0 {
689✔
271
                        continue
×
272
                }
273

274
                // Sanity check that the output indexes can be safely
275
                // converted.
276
                if htlc.OutputIndex > math.MaxUint16 {
689✔
277
                        return ErrOutputIndexTooBig
×
278
                }
×
279

280
                entry := &HTLCEntry{
689✔
281
                        RHash:         htlc.RHash,
689✔
282
                        RefundTimeout: htlc.RefundTimeout,
689✔
283
                        Incoming:      htlc.Incoming,
689✔
284
                        OutputIndex:   uint16(htlc.OutputIndex),
689✔
285
                        Amt:           htlc.Amt.ToSatoshis(),
689✔
286
                }
689✔
287
                rl.HTLCEntries = append(rl.HTLCEntries, entry)
689✔
288
        }
289

290
        var b bytes.Buffer
2,013✔
291
        err := serializeRevocationLog(&b, rl)
2,013✔
292
        if err != nil {
2,013✔
293
                return err
×
294
        }
×
295

296
        logEntrykey := mig24.MakeLogKey(commit.CommitHeight)
2,013✔
297
        return bucket.Put(logEntrykey[:], b.Bytes())
2,013✔
298
}
299

300
// fetchRevocationLog queries the revocation log bucket to find an log entry.
301
// Return an error if not found.
302
func fetchRevocationLog(log kvdb.RBucket,
303
        updateNum uint64) (RevocationLog, error) {
3,960✔
304

3,960✔
305
        logEntrykey := mig24.MakeLogKey(updateNum)
3,960✔
306
        commitBytes := log.Get(logEntrykey[:])
3,960✔
307
        if commitBytes == nil {
3,960✔
308
                return RevocationLog{}, ErrLogEntryNotFound
×
309
        }
×
310

311
        commitReader := bytes.NewReader(commitBytes)
3,960✔
312

3,960✔
313
        return deserializeRevocationLog(commitReader)
3,960✔
314
}
315

316
// serializeRevocationLog serializes a RevocationLog record based on tlv
317
// format.
318
func serializeRevocationLog(w io.Writer, rl *RevocationLog) error {
4,839✔
319
        // Add the tlv records for all non-optional fields.
4,839✔
320
        records := []tlv.Record{
4,839✔
321
                tlv.MakePrimitiveRecord(
4,839✔
322
                        revLogOurOutputIndexType, &rl.OurOutputIndex,
4,839✔
323
                ),
4,839✔
324
                tlv.MakePrimitiveRecord(
4,839✔
325
                        revLogTheirOutputIndexType, &rl.TheirOutputIndex,
4,839✔
326
                ),
4,839✔
327
                tlv.MakePrimitiveRecord(
4,839✔
328
                        revLogCommitTxHashType, &rl.CommitTxHash,
4,839✔
329
                ),
4,839✔
330
        }
4,839✔
331

4,839✔
332
        // Now we add any optional fields that are non-nil.
4,839✔
333
        if rl.OurBalance != nil {
4,839✔
UNCOV
334
                lb := uint64(*rl.OurBalance)
×
UNCOV
335
                records = append(records, tlv.MakeBigSizeRecord(
×
UNCOV
336
                        revLogOurBalanceType, &lb,
×
UNCOV
337
                ))
×
UNCOV
338
        }
×
339

340
        if rl.TheirBalance != nil {
4,839✔
UNCOV
341
                rb := uint64(*rl.TheirBalance)
×
UNCOV
342
                records = append(records, tlv.MakeBigSizeRecord(
×
UNCOV
343
                        revLogTheirBalanceType, &rb,
×
UNCOV
344
                ))
×
UNCOV
345
        }
×
346

347
        // Create the tlv stream.
348
        tlvStream, err := tlv.NewStream(records...)
4,839✔
349
        if err != nil {
4,839✔
350
                return err
×
351
        }
×
352

353
        // Write the tlv stream.
354
        if err := writeTlvStream(w, tlvStream); err != nil {
4,839✔
355
                return err
×
356
        }
×
357

358
        // Write the HTLCs.
359
        return serializeHTLCEntries(w, rl.HTLCEntries)
4,839✔
360
}
361

362
// serializeHTLCEntries serializes a list of HTLCEntry records based on tlv
363
// format.
364
func serializeHTLCEntries(w io.Writer, htlcs []*HTLCEntry) error {
4,839✔
365
        for _, htlc := range htlcs {
7,130✔
366
                // Patch the incomingTlv field.
2,291✔
367
                if htlc.Incoming {
2,316✔
368
                        htlc.incomingTlv = 1
25✔
369
                }
25✔
370

371
                // Patch the amtTlv field.
372
                htlc.amtTlv = uint64(htlc.Amt)
2,291✔
373

2,291✔
374
                // Create the tlv stream.
2,291✔
375
                tlvStream, err := htlc.toTlvStream()
2,291✔
376
                if err != nil {
2,291✔
377
                        return err
×
378
                }
×
379

380
                // Write the tlv stream.
381
                if err := writeTlvStream(w, tlvStream); err != nil {
2,291✔
382
                        return err
×
383
                }
×
384
        }
385

386
        return nil
4,839✔
387
}
388

389
// deserializeRevocationLog deserializes a RevocationLog based on tlv format.
390
func deserializeRevocationLog(r io.Reader) (RevocationLog, error) {
3,960✔
391
        var (
3,960✔
392
                rl            RevocationLog
3,960✔
393
                localBalance  uint64
3,960✔
394
                remoteBalance uint64
3,960✔
395
        )
3,960✔
396

3,960✔
397
        // Create the tlv stream.
3,960✔
398
        tlvStream, err := tlv.NewStream(
3,960✔
399
                tlv.MakePrimitiveRecord(
3,960✔
400
                        revLogOurOutputIndexType, &rl.OurOutputIndex,
3,960✔
401
                ),
3,960✔
402
                tlv.MakePrimitiveRecord(
3,960✔
403
                        revLogTheirOutputIndexType, &rl.TheirOutputIndex,
3,960✔
404
                ),
3,960✔
405
                tlv.MakePrimitiveRecord(
3,960✔
406
                        revLogCommitTxHashType, &rl.CommitTxHash,
3,960✔
407
                ),
3,960✔
408
                tlv.MakeBigSizeRecord(revLogOurBalanceType, &localBalance),
3,960✔
409
                tlv.MakeBigSizeRecord(
3,960✔
410
                        revLogTheirBalanceType, &remoteBalance,
3,960✔
411
                ),
3,960✔
412
        )
3,960✔
413
        if err != nil {
3,960✔
414
                return rl, err
×
415
        }
×
416

417
        // Read the tlv stream.
418
        parsedTypes, err := readTlvStream(r, tlvStream)
3,960✔
419
        if err != nil {
3,960✔
420
                return rl, err
×
421
        }
×
422

423
        if t, ok := parsedTypes[revLogOurBalanceType]; ok && t == nil {
3,960✔
UNCOV
424
                lb := lnwire.MilliSatoshi(localBalance)
×
UNCOV
425
                rl.OurBalance = &lb
×
UNCOV
426
        }
×
427

428
        if t, ok := parsedTypes[revLogTheirBalanceType]; ok && t == nil {
3,960✔
UNCOV
429
                rb := lnwire.MilliSatoshi(remoteBalance)
×
UNCOV
430
                rl.TheirBalance = &rb
×
UNCOV
431
        }
×
432

433
        // Read the HTLC entries.
434
        rl.HTLCEntries, err = deserializeHTLCEntries(r)
3,960✔
435

3,960✔
436
        return rl, err
3,960✔
437
}
438

439
// deserializeHTLCEntries deserializes a list of HTLC entries based on tlv
440
// format.
441
func deserializeHTLCEntries(r io.Reader) ([]*HTLCEntry, error) {
3,960✔
442
        var htlcs []*HTLCEntry
3,960✔
443

3,960✔
444
        for {
9,900✔
445
                var htlc HTLCEntry
5,940✔
446

5,940✔
447
                // Create the tlv stream.
5,940✔
448
                tlvStream, err := htlc.toTlvStream()
5,940✔
449
                if err != nil {
5,940✔
450
                        return nil, err
×
451
                }
×
452

453
                // Read the HTLC entry.
454
                if _, err := readTlvStream(r, tlvStream); err != nil {
9,900✔
455
                        // We've reached the end when hitting an EOF.
3,960✔
456
                        if err == io.ErrUnexpectedEOF {
7,920✔
457
                                break
3,960✔
458
                        }
459
                        return nil, err
×
460
                }
461

462
                // Patch the Incoming field.
463
                if htlc.incomingTlv == 1 {
1,980✔
464
                        htlc.Incoming = true
×
465
                }
×
466

467
                // Patch the Amt field.
468
                htlc.Amt = btcutil.Amount(htlc.amtTlv)
1,980✔
469

1,980✔
470
                // Append the entry.
1,980✔
471
                htlcs = append(htlcs, &htlc)
1,980✔
472
        }
473

474
        return htlcs, nil
3,960✔
475
}
476

477
// writeTlvStream is a helper function that encodes the tlv stream into the
478
// writer.
479
func writeTlvStream(w io.Writer, s *tlv.Stream) error {
7,130✔
480
        var b bytes.Buffer
7,130✔
481
        if err := s.Encode(&b); err != nil {
7,130✔
482
                return err
×
483
        }
×
484
        // Write the stream's length as a varint.
485
        err := tlv.WriteVarInt(w, uint64(b.Len()), &[8]byte{})
7,130✔
486
        if err != nil {
7,130✔
487
                return err
×
488
        }
×
489

490
        if _, err = w.Write(b.Bytes()); err != nil {
7,130✔
491
                return err
×
492
        }
×
493

494
        return nil
7,130✔
495
}
496

497
// readTlvStream is a helper function that decodes the tlv stream from the
498
// reader.
499
func readTlvStream(r io.Reader, s *tlv.Stream) (tlv.TypeMap, error) {
9,900✔
500
        var bodyLen uint64
9,900✔
501

9,900✔
502
        // Read the stream's length.
9,900✔
503
        bodyLen, err := tlv.ReadVarInt(r, &[8]byte{})
9,900✔
504
        switch {
9,900✔
505
        // We'll convert any EOFs to ErrUnexpectedEOF, since this results in an
506
        // invalid record.
507
        case err == io.EOF:
3,960✔
508
                return nil, io.ErrUnexpectedEOF
3,960✔
509

510
        // Other unexpected errors.
511
        case err != nil:
×
512
                return nil, err
×
513
        }
514

515
        // TODO(yy): add overflow check.
516
        lr := io.LimitReader(r, int64(bodyLen))
5,940✔
517

5,940✔
518
        return s.DecodeWithParsedTypes(lr)
5,940✔
519
}
520

521
// fetchLogBucket returns a read bucket by visiting both the new and the old
522
// bucket.
523
func fetchLogBucket(chanBucket kvdb.RBucket) (kvdb.RBucket, error) {
3,960✔
524
        logBucket := chanBucket.NestedReadBucket(revocationLogBucket)
3,960✔
525
        if logBucket == nil {
3,960✔
526
                logBucket = chanBucket.NestedReadBucket(
×
527
                        revocationLogBucketDeprecated,
×
528
                )
×
529
                if logBucket == nil {
×
530
                        return nil, mig25.ErrNoPastDeltas
×
531
                }
×
532
        }
533

534
        return logBucket, nil
3,960✔
535
}
536

537
// putOldRevocationLog saves a revocation log using the old format.
538
func putOldRevocationLog(log kvdb.RwBucket,
539
        commit *mig.ChannelCommitment) error {
3,994✔
540

3,994✔
541
        var b bytes.Buffer
3,994✔
542
        if err := mig.SerializeChanCommit(&b, commit); err != nil {
3,994✔
543
                return err
×
544
        }
×
545

546
        logEntrykey := mig24.MakeLogKey(commit.CommitHeight)
3,994✔
547
        return log.Put(logEntrykey[:], b.Bytes())
3,994✔
548
}
549

550
func putChanRevocationState(chanBucket kvdb.RwBucket,
551
        channel *mig26.OpenChannel) error {
2,659✔
552

2,659✔
553
        var b bytes.Buffer
2,659✔
554
        err := mig.WriteElements(
2,659✔
555
                &b, channel.RemoteCurrentRevocation, channel.RevocationProducer,
2,659✔
556
                channel.RevocationStore,
2,659✔
557
        )
2,659✔
558
        if err != nil {
2,659✔
559
                return err
×
560
        }
×
561

562
        // TODO(roasbeef): don't keep producer on disk
563

564
        // If the next revocation is present, which is only the case after the
565
        // FundingLocked message has been sent, then we'll write it to disk.
566
        if channel.RemoteNextRevocation != nil {
2,659✔
567
                err = mig.WriteElements(&b, channel.RemoteNextRevocation)
×
568
                if err != nil {
×
569
                        return err
×
570
                }
×
571
        }
572

573
        return chanBucket.Put(revocationStateKey, b.Bytes())
2,659✔
574
}
575

576
func fetchChanRevocationState(chanBucket kvdb.RBucket,
577
        c *mig26.OpenChannel) error {
1,884✔
578

1,884✔
579
        revBytes := chanBucket.Get(revocationStateKey)
1,884✔
580
        if revBytes == nil {
1,884✔
581
                return ErrNoRevocationsFound
×
582
        }
×
583
        r := bytes.NewReader(revBytes)
1,884✔
584

1,884✔
585
        err := mig.ReadElements(
1,884✔
586
                r, &c.RemoteCurrentRevocation, &c.RevocationProducer,
1,884✔
587
                &c.RevocationStore,
1,884✔
588
        )
1,884✔
589
        if err != nil {
1,884✔
590
                return err
×
591
        }
×
592

593
        // If there aren't any bytes left in the buffer, then we don't yet have
594
        // the next remote revocation, so we can exit early here.
595
        if r.Len() == 0 {
3,768✔
596
                return nil
1,884✔
597
        }
1,884✔
598

599
        // Otherwise we'll read the next revocation for the remote party which
600
        // is always the last item within the buffer.
601
        return mig.ReadElements(r, &c.RemoteNextRevocation)
×
602
}
603

604
func findOutputIndexes(chanState *mig26.OpenChannel,
605
        oldLog *mig.ChannelCommitment) (uint32, uint32, error) {
2,826✔
606

2,826✔
607
        // With the state number broadcast known, we can now derive/restore the
2,826✔
608
        // proper revocation preimage necessary to sweep the remote party's
2,826✔
609
        // output.
2,826✔
610
        revocationPreimage, err := chanState.RevocationStore.LookUp(
2,826✔
611
                oldLog.CommitHeight,
2,826✔
612
        )
2,826✔
613
        if err != nil {
2,826✔
614
                return 0, 0, err
×
615
        }
×
616

617
        return findOutputIndexesFromRemote(
2,826✔
618
                revocationPreimage, chanState, oldLog,
2,826✔
619
        )
2,826✔
620
}
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