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

lightningnetwork / lnd / 15561477203

10 Jun 2025 01:54PM UTC coverage: 58.351% (-10.1%) from 68.487%
15561477203

Pull #9356

github

web-flow
Merge 6440b25db into c6d6d4c0b
Pull Request #9356: lnrpc: add incoming/outgoing channel ids filter to forwarding history request

33 of 36 new or added lines in 2 files covered. (91.67%)

28366 existing lines in 455 files now uncovered.

97715 of 167461 relevant lines covered (58.35%)

1.81 hits per line

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

0.0
/channeldb/migration16/migration.go
1
package migration16
2

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

9
        "github.com/btcsuite/btcd/wire"
10
        "github.com/lightningnetwork/lnd/kvdb"
11
)
12

13
var (
14
        paymentsRootBucket = []byte("payments-root-bucket")
15

16
        paymentSequenceKey = []byte("payment-sequence-key")
17

18
        duplicatePaymentsBucket = []byte("payment-duplicate-bucket")
19

20
        paymentsIndexBucket = []byte("payments-index-bucket")
21

22
        byteOrder = binary.BigEndian
23
)
24

25
// paymentIndexType indicates the type of index we have recorded in the payment
26
// indexes bucket.
27
type paymentIndexType uint8
28

29
// paymentIndexTypeHash is a payment index type which indicates that we have
30
// created an index of payment sequence number to payment hash.
31
const paymentIndexTypeHash paymentIndexType = 0
32

33
// paymentIndex stores all the information we require to create an index by
34
// sequence number for a payment.
35
type paymentIndex struct {
36
        // paymentHash is the hash of the payment, which is its key in the
37
        // payment root bucket.
38
        paymentHash []byte
39

40
        // sequenceNumbers is the set of sequence numbers associated with this
41
        // payment hash. There will be more than one sequence number in the
42
        // case where duplicate payments are present.
43
        sequenceNumbers [][]byte
44
}
45

46
// MigrateSequenceIndex migrates the payments db to contain a new bucket which
47
// provides an index from sequence number to payment hash. This is required
48
// for more efficient sequential lookup of payments, which are keyed by payment
49
// hash before this migration.
UNCOV
50
func MigrateSequenceIndex(tx kvdb.RwTx) error {
×
UNCOV
51
        log.Infof("Migrating payments to add sequence number index")
×
UNCOV
52

×
UNCOV
53
        // Get a list of indices we need to write.
×
UNCOV
54
        indexList, err := getPaymentIndexList(tx)
×
UNCOV
55
        if err != nil {
×
56
                return err
×
57
        }
×
58

59
        // Create the top level bucket that we will use to index payments in.
UNCOV
60
        bucket, err := tx.CreateTopLevelBucket(paymentsIndexBucket)
×
UNCOV
61
        if err != nil {
×
62
                return err
×
63
        }
×
64

65
        // Write an index for each of our payments.
UNCOV
66
        for _, index := range indexList {
×
UNCOV
67
                // Write indexes for each of our sequence numbers.
×
UNCOV
68
                for _, seqNr := range index.sequenceNumbers {
×
UNCOV
69
                        err := putIndex(bucket, seqNr, index.paymentHash)
×
UNCOV
70
                        if err != nil {
×
UNCOV
71
                                return err
×
UNCOV
72
                        }
×
73
                }
74
        }
75

UNCOV
76
        return nil
×
77
}
78

79
// putIndex performs a sanity check that ensures we are not writing duplicate
80
// indexes to disk then creates the index provided.
UNCOV
81
func putIndex(bucket kvdb.RwBucket, sequenceNr, paymentHash []byte) error {
×
UNCOV
82
        // Add a sanity check that we do not already have an entry with
×
UNCOV
83
        // this sequence number.
×
UNCOV
84
        existingEntry := bucket.Get(sequenceNr)
×
UNCOV
85
        if existingEntry != nil {
×
UNCOV
86
                return fmt.Errorf("sequence number: %x duplicated",
×
UNCOV
87
                        sequenceNr)
×
UNCOV
88
        }
×
89

UNCOV
90
        bytes, err := serializePaymentIndexEntry(paymentHash)
×
UNCOV
91
        if err != nil {
×
92
                return err
×
93
        }
×
94

UNCOV
95
        return bucket.Put(sequenceNr, bytes)
×
96
}
97

98
// serializePaymentIndexEntry serializes a payment hash typed index. The value
99
// produced contains a payment index type (which can be used in future to
100
// signal different payment index types) and the payment hash.
UNCOV
101
func serializePaymentIndexEntry(hash []byte) ([]byte, error) {
×
UNCOV
102
        var b bytes.Buffer
×
UNCOV
103

×
UNCOV
104
        err := binary.Write(&b, byteOrder, paymentIndexTypeHash)
×
UNCOV
105
        if err != nil {
×
106
                return nil, err
×
107
        }
×
108

UNCOV
109
        if err := wire.WriteVarBytes(&b, 0, hash); err != nil {
×
110
                return nil, err
×
111
        }
×
112

UNCOV
113
        return b.Bytes(), nil
×
114
}
115

116
// getPaymentIndexList gets a list of indices we need to write for our current
117
// set of payments.
UNCOV
118
func getPaymentIndexList(tx kvdb.RTx) ([]paymentIndex, error) {
×
UNCOV
119
        // Iterate over all payments and store their indexing keys. This is
×
UNCOV
120
        // needed, because no modifications are allowed inside a Bucket.ForEach
×
UNCOV
121
        // loop.
×
UNCOV
122
        paymentsBucket := tx.ReadBucket(paymentsRootBucket)
×
UNCOV
123
        if paymentsBucket == nil {
×
124
                return nil, nil
×
125
        }
×
126

UNCOV
127
        var indexList []paymentIndex
×
UNCOV
128
        err := paymentsBucket.ForEach(func(k, v []byte) error {
×
UNCOV
129
                // Get the bucket which contains the payment, fail if the key
×
UNCOV
130
                // does not have a bucket.
×
UNCOV
131
                bucket := paymentsBucket.NestedReadBucket(k)
×
UNCOV
132
                if bucket == nil {
×
133
                        return fmt.Errorf("non bucket element in " +
×
134
                                "payments bucket")
×
135
                }
×
UNCOV
136
                seqBytes := bucket.Get(paymentSequenceKey)
×
UNCOV
137
                if seqBytes == nil {
×
138
                        return fmt.Errorf("nil sequence number bytes")
×
139
                }
×
140

UNCOV
141
                seqNrs, err := fetchSequenceNumbers(bucket)
×
UNCOV
142
                if err != nil {
×
143
                        return err
×
144
                }
×
145

146
                // Create an index object with our payment hash and sequence
147
                // numbers and append it to our set of indexes.
UNCOV
148
                index := paymentIndex{
×
UNCOV
149
                        paymentHash:     k,
×
UNCOV
150
                        sequenceNumbers: seqNrs,
×
UNCOV
151
                }
×
UNCOV
152

×
UNCOV
153
                indexList = append(indexList, index)
×
UNCOV
154
                return nil
×
155
        })
UNCOV
156
        if err != nil {
×
157
                return nil, err
×
158
        }
×
159

UNCOV
160
        return indexList, nil
×
161
}
162

163
// fetchSequenceNumbers fetches all the sequence numbers associated with a
164
// payment, including those belonging to any duplicate payments.
UNCOV
165
func fetchSequenceNumbers(paymentBucket kvdb.RBucket) ([][]byte, error) {
×
UNCOV
166
        seqNum := paymentBucket.Get(paymentSequenceKey)
×
UNCOV
167
        if seqNum == nil {
×
168
                return nil, errors.New("expected sequence number")
×
169
        }
×
170

UNCOV
171
        sequenceNumbers := [][]byte{seqNum}
×
UNCOV
172

×
UNCOV
173
        // Get the duplicate payments bucket, if it has no duplicates, just
×
UNCOV
174
        // return early with the payment sequence number.
×
UNCOV
175
        duplicates := paymentBucket.NestedReadBucket(duplicatePaymentsBucket)
×
UNCOV
176
        if duplicates == nil {
×
UNCOV
177
                return sequenceNumbers, nil
×
UNCOV
178
        }
×
179

180
        // If we do have duplicated, they are keyed by sequence number, so we
181
        // iterate through the duplicates bucket and add them to our set of
182
        // sequence numbers.
UNCOV
183
        if err := duplicates.ForEach(func(k, v []byte) error {
×
UNCOV
184
                sequenceNumbers = append(sequenceNumbers, k)
×
UNCOV
185
                return nil
×
UNCOV
186
        }); err != nil {
×
187
                return nil, err
×
188
        }
×
189

UNCOV
190
        return sequenceNumbers, nil
×
191
}
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