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

lightningnetwork / lnd / 13211764208

08 Feb 2025 03:08AM UTC coverage: 49.288% (-9.5%) from 58.815%
13211764208

Pull #9489

github

calvinrzachman
itest: verify switchrpc server enforces send then track

We prevent the rpc server from allowing onion dispatches for
attempt IDs which have already been tracked by rpc clients.

This helps protect the client from leaking a duplicate onion
attempt. NOTE: This is not the only method for solving this
issue! The issue could be addressed via careful client side
programming which accounts for the uncertainty and async
nature of dispatching onions to a remote process via RPC.
This would require some lnd ChannelRouter changes for how
we intend to use these RPCs though.
Pull Request #9489: multi: add BuildOnion, SendOnion, and TrackOnion RPCs

474 of 990 new or added lines in 11 files covered. (47.88%)

27321 existing lines in 435 files now uncovered.

101192 of 205306 relevant lines covered (49.29%)

1.54 hits per line

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

0.0
/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.
UNCOV
128
func (h *HTLCEntry) RHashLen() uint64 {
×
UNCOV
129
        if h.RHash == lntypes.ZeroHash {
×
130
                return 0
×
131
        }
×
UNCOV
132
        return 32
×
133
}
134

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

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

UNCOV
147
        return tlv.EBytes32(w, v, buf)
×
148
}
149

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

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

UNCOV
162
        return tlv.DBytes32(r, v, buf, 32)
×
163
}
164

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

×
UNCOV
181
        return tlv.NewStream(
×
UNCOV
182
                tlv.MakeDynamicRecord(
×
UNCOV
183
                        rHashType, &h.RHash, h.RHashLen,
×
UNCOV
184
                        RHashEncoder, RHashDecoder,
×
UNCOV
185
                ),
×
UNCOV
186
                tlv.MakePrimitiveRecord(
×
UNCOV
187
                        refundTimeoutType, &h.RefundTimeout,
×
UNCOV
188
                ),
×
UNCOV
189
                tlv.MakePrimitiveRecord(
×
UNCOV
190
                        outputIndexType, &h.OutputIndex,
×
UNCOV
191
                ),
×
UNCOV
192
                tlv.MakePrimitiveRecord(incomingType, &h.incomingTlv),
×
UNCOV
193
                // We will save 3 bytes if the amount is less or equal to
×
UNCOV
194
                // 4,294,967,295 msat, or roughly 0.043 bitcoin.
×
UNCOV
195
                tlv.MakeBigSizeRecord(amtType, &h.amtTlv),
×
UNCOV
196
        )
×
UNCOV
197
}
×
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,
UNCOV
246
        ourOutputIndex, theirOutputIndex uint32, noAmtData bool) error {
×
UNCOV
247

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

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

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

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

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

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

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

UNCOV
296
        logEntrykey := mig24.MakeLogKey(commit.CommitHeight)
×
UNCOV
297
        return bucket.Put(logEntrykey[:], b.Bytes())
×
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,
UNCOV
303
        updateNum uint64) (RevocationLog, error) {
×
UNCOV
304

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

UNCOV
311
        commitReader := bytes.NewReader(commitBytes)
×
UNCOV
312

×
UNCOV
313
        return deserializeRevocationLog(commitReader)
×
314
}
315

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

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

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

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

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

358
        // Write the HTLCs.
UNCOV
359
        return serializeHTLCEntries(w, rl.HTLCEntries)
×
360
}
361

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

371
                // Patch the amtTlv field.
UNCOV
372
                htlc.amtTlv = uint64(htlc.Amt)
×
UNCOV
373

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

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

UNCOV
386
        return nil
×
387
}
388

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

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

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

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

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

433
        // Read the HTLC entries.
UNCOV
434
        rl.HTLCEntries, err = deserializeHTLCEntries(r)
×
UNCOV
435

×
UNCOV
436
        return rl, err
×
437
}
438

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

×
UNCOV
444
        for {
×
UNCOV
445
                var htlc HTLCEntry
×
UNCOV
446

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

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

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

467
                // Patch the Amt field.
UNCOV
468
                htlc.Amt = btcutil.Amount(htlc.amtTlv)
×
UNCOV
469

×
UNCOV
470
                // Append the entry.
×
UNCOV
471
                htlcs = append(htlcs, &htlc)
×
472
        }
473

UNCOV
474
        return htlcs, nil
×
475
}
476

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

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

UNCOV
494
        return nil
×
495
}
496

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

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

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

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

×
UNCOV
518
        return s.DecodeWithParsedTypes(lr)
×
519
}
520

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

UNCOV
534
        return logBucket, nil
×
535
}
536

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

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

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

550
func putChanRevocationState(chanBucket kvdb.RwBucket,
UNCOV
551
        channel *mig26.OpenChannel) error {
×
UNCOV
552

×
UNCOV
553
        var b bytes.Buffer
×
UNCOV
554
        err := mig.WriteElements(
×
UNCOV
555
                &b, channel.RemoteCurrentRevocation, channel.RevocationProducer,
×
UNCOV
556
                channel.RevocationStore,
×
UNCOV
557
        )
×
UNCOV
558
        if err != nil {
×
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.
UNCOV
566
        if channel.RemoteNextRevocation != nil {
×
567
                err = mig.WriteElements(&b, channel.RemoteNextRevocation)
×
568
                if err != nil {
×
569
                        return err
×
570
                }
×
571
        }
572

UNCOV
573
        return chanBucket.Put(revocationStateKey, b.Bytes())
×
574
}
575

576
func fetchChanRevocationState(chanBucket kvdb.RBucket,
UNCOV
577
        c *mig26.OpenChannel) error {
×
UNCOV
578

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

×
UNCOV
585
        err := mig.ReadElements(
×
UNCOV
586
                r, &c.RemoteCurrentRevocation, &c.RevocationProducer,
×
UNCOV
587
                &c.RevocationStore,
×
UNCOV
588
        )
×
UNCOV
589
        if err != nil {
×
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.
UNCOV
595
        if r.Len() == 0 {
×
UNCOV
596
                return nil
×
UNCOV
597
        }
×
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,
UNCOV
605
        oldLog *mig.ChannelCommitment) (uint32, uint32, error) {
×
UNCOV
606

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

UNCOV
617
        return findOutputIndexesFromRemote(
×
UNCOV
618
                revocationPreimage, chanState, oldLog,
×
UNCOV
619
        )
×
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