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

lightningnetwork / lnd / 13035292482

29 Jan 2025 03:59PM UTC coverage: 49.3% (-9.5%) from 58.777%
13035292482

Pull #9456

github

mohamedawnallah
docs: update release-notes-0.19.0.md

In this commit, we warn users about the removal
of RPCs `SendToRoute`, `SendToRouteSync`, `SendPayment`,
and `SendPaymentSync` in the next release 0.20.
Pull Request #9456: lnrpc+docs: deprecate warning `SendToRoute`, `SendToRouteSync`, `SendPayment`, and `SendPaymentSync` in Release 0.19

100634 of 204126 relevant lines covered (49.3%)

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.
128
func (h *HTLCEntry) RHashLen() uint64 {
×
129
        if h.RHash == lntypes.ZeroHash {
×
130
                return 0
×
131
        }
×
132
        return 32
×
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 {
×
137
        v, ok := val.(*[32]byte)
×
138
        if !ok {
×
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 {
×
144
                return nil
×
145
        }
×
146

147
        return tlv.EBytes32(w, v, buf)
×
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 {
×
152
        v, ok := val.(*[32]byte)
×
153
        if !ok {
×
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 {
×
159
                return nil
×
160
        }
×
161

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

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

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

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

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

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

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

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

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

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

296
        logEntrykey := mig24.MakeLogKey(commit.CommitHeight)
×
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,
303
        updateNum uint64) (RevocationLog, error) {
×
304

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

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

×
313
        return deserializeRevocationLog(commitReader)
×
314
}
315

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

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

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.
348
        tlvStream, err := tlv.NewStream(records...)
×
349
        if err != nil {
×
350
                return err
×
351
        }
×
352

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

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

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

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

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

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

386
        return nil
×
387
}
388

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

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

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

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

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.
434
        rl.HTLCEntries, err = deserializeHTLCEntries(r)
×
435

×
436
        return rl, err
×
437
}
438

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

×
444
        for {
×
445
                var htlc HTLCEntry
×
446

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

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

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

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

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

474
        return htlcs, nil
×
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 {
×
480
        var b bytes.Buffer
×
481
        if err := s.Encode(&b); err != nil {
×
482
                return err
×
483
        }
×
484
        // Write the stream's length as a varint.
485
        err := tlv.WriteVarInt(w, uint64(b.Len()), &[8]byte{})
×
486
        if err != nil {
×
487
                return err
×
488
        }
×
489

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

494
        return nil
×
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) {
×
500
        var bodyLen uint64
×
501

×
502
        // Read the stream's length.
×
503
        bodyLen, err := tlv.ReadVarInt(r, &[8]byte{})
×
504
        switch {
×
505
        // We'll convert any EOFs to ErrUnexpectedEOF, since this results in an
506
        // invalid record.
507
        case err == io.EOF:
×
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.
516
        lr := io.LimitReader(r, int64(bodyLen))
×
517

×
518
        return s.DecodeWithParsedTypes(lr)
×
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) {
×
524
        logBucket := chanBucket.NestedReadBucket(revocationLogBucket)
×
525
        if logBucket == nil {
×
526
                logBucket = chanBucket.NestedReadBucket(
×
527
                        revocationLogBucketDeprecated,
×
528
                )
×
529
                if logBucket == nil {
×
530
                        return nil, mig25.ErrNoPastDeltas
×
531
                }
×
532
        }
533

534
        return logBucket, nil
×
535
}
536

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

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

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

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

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

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

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

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

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

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

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