• 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/migration_01_to_11/migration_10_route_tlv_records.go
1
package migration_01_to_11
2

3
import (
4
        "bytes"
5
        "io"
6

7
        "github.com/lightningnetwork/lnd/kvdb"
8
)
9

10
// MigrateRouteSerialization migrates the way we serialize routes across the
11
// entire database. At the time of writing of this migration, this includes our
12
// payment attempts, as well as the payment results in mission control.
UNCOV
13
func MigrateRouteSerialization(tx kvdb.RwTx) error {
×
UNCOV
14
        // First, we'll do all the payment attempts.
×
UNCOV
15
        rootPaymentBucket := tx.ReadWriteBucket(paymentsRootBucket)
×
UNCOV
16
        if rootPaymentBucket == nil {
×
17
                return nil
×
18
        }
×
19

20
        // As we can't mutate a bucket while we're iterating over it with
21
        // ForEach, we'll need to collect all the known payment hashes in
22
        // memory first.
UNCOV
23
        var payHashes [][]byte
×
UNCOV
24
        err := rootPaymentBucket.ForEach(func(k, v []byte) error {
×
UNCOV
25
                if v != nil {
×
26
                        return nil
×
27
                }
×
28

UNCOV
29
                payHashes = append(payHashes, k)
×
UNCOV
30
                return nil
×
31
        })
UNCOV
32
        if err != nil {
×
33
                return err
×
34
        }
×
35

36
        // Now that we have all the payment hashes, we can carry out the
37
        // migration itself.
UNCOV
38
        for _, payHash := range payHashes {
×
UNCOV
39
                payHashBucket := rootPaymentBucket.NestedReadWriteBucket(payHash)
×
UNCOV
40

×
UNCOV
41
                // First, we'll migrate the main (non duplicate) payment to
×
UNCOV
42
                // this hash.
×
UNCOV
43
                err := migrateAttemptEncoding(tx, payHashBucket)
×
UNCOV
44
                if err != nil {
×
45
                        return err
×
46
                }
×
47

48
                // Now that we've migrated the main payment, we'll also check
49
                // for any duplicate payments to the same payment hash.
UNCOV
50
                dupBucket := payHashBucket.NestedReadWriteBucket(paymentDuplicateBucket)
×
UNCOV
51

×
UNCOV
52
                // If there's no dup bucket, then we can move on to the next
×
UNCOV
53
                // payment.
×
UNCOV
54
                if dupBucket == nil {
×
UNCOV
55
                        continue
×
56
                }
57

58
                // Otherwise, we'll now iterate through all the duplicate pay
59
                // hashes and migrate those.
UNCOV
60
                var dupSeqNos [][]byte
×
UNCOV
61
                err = dupBucket.ForEach(func(k, v []byte) error {
×
UNCOV
62
                        dupSeqNos = append(dupSeqNos, k)
×
UNCOV
63
                        return nil
×
UNCOV
64
                })
×
UNCOV
65
                if err != nil {
×
66
                        return err
×
67
                }
×
68

69
                // Now in this second pass, we'll re-serialize their duplicate
70
                // payment attempts under the new encoding.
UNCOV
71
                for _, seqNo := range dupSeqNos {
×
UNCOV
72
                        dupPayHashBucket := dupBucket.NestedReadWriteBucket(seqNo)
×
UNCOV
73
                        err := migrateAttemptEncoding(tx, dupPayHashBucket)
×
UNCOV
74
                        if err != nil {
×
75
                                return err
×
76
                        }
×
77
                }
78
        }
79

UNCOV
80
        log.Infof("Migration of route/hop serialization complete!")
×
UNCOV
81

×
UNCOV
82
        log.Infof("Migrating to new mission control store by clearing " +
×
UNCOV
83
                "existing data")
×
UNCOV
84

×
UNCOV
85
        resultsKey := []byte("missioncontrol-results")
×
UNCOV
86
        err = tx.DeleteTopLevelBucket(resultsKey)
×
UNCOV
87
        if err != nil && err != kvdb.ErrBucketNotFound {
×
88
                return err
×
89
        }
×
90

UNCOV
91
        log.Infof("Migration to new mission control completed!")
×
UNCOV
92

×
UNCOV
93
        return nil
×
94
}
95

96
// migrateAttemptEncoding migrates payment attempts using the legacy format to
97
// the new format.
UNCOV
98
func migrateAttemptEncoding(tx kvdb.RwTx, payHashBucket kvdb.RwBucket) error {
×
UNCOV
99
        payAttemptBytes := payHashBucket.Get(paymentAttemptInfoKey)
×
UNCOV
100
        if payAttemptBytes == nil {
×
101
                return nil
×
102
        }
×
103

104
        // For our migration, we'll first read out the existing payment attempt
105
        // using the legacy serialization of the attempt.
UNCOV
106
        payAttemptReader := bytes.NewReader(payAttemptBytes)
×
UNCOV
107
        payAttempt, err := deserializePaymentAttemptInfoLegacy(
×
UNCOV
108
                payAttemptReader,
×
UNCOV
109
        )
×
UNCOV
110
        if err != nil {
×
111
                return err
×
112
        }
×
113

114
        // Now that we have the old attempts, we'll explicitly mark this as
115
        // needing a legacy payload, since after this migration, the modern
116
        // payload will be the default if signalled.
UNCOV
117
        for _, hop := range payAttempt.Route.Hops {
×
UNCOV
118
                hop.LegacyPayload = true
×
UNCOV
119
        }
×
120

121
        // Finally, we'll write out the payment attempt using the new encoding.
UNCOV
122
        var b bytes.Buffer
×
UNCOV
123
        err = serializePaymentAttemptInfo(&b, payAttempt)
×
UNCOV
124
        if err != nil {
×
125
                return err
×
126
        }
×
127

UNCOV
128
        return payHashBucket.Put(paymentAttemptInfoKey, b.Bytes())
×
129
}
130

UNCOV
131
func deserializePaymentAttemptInfoLegacy(r io.Reader) (*PaymentAttemptInfo, error) {
×
UNCOV
132
        a := &PaymentAttemptInfo{}
×
UNCOV
133
        err := ReadElements(r, &a.PaymentID, &a.SessionKey)
×
UNCOV
134
        if err != nil {
×
135
                return nil, err
×
136
        }
×
UNCOV
137
        a.Route, err = deserializeRouteLegacy(r)
×
UNCOV
138
        if err != nil {
×
139
                return nil, err
×
140
        }
×
UNCOV
141
        return a, nil
×
142
}
143

UNCOV
144
func serializePaymentAttemptInfoLegacy(w io.Writer, a *PaymentAttemptInfo) error {
×
UNCOV
145
        if err := WriteElements(w, a.PaymentID, a.SessionKey); err != nil {
×
146
                return err
×
147
        }
×
148

UNCOV
149
        if err := serializeRouteLegacy(w, a.Route); err != nil {
×
150
                return err
×
151
        }
×
152

UNCOV
153
        return nil
×
154
}
155

UNCOV
156
func deserializeHopLegacy(r io.Reader) (*Hop, error) {
×
UNCOV
157
        h := &Hop{}
×
UNCOV
158

×
UNCOV
159
        var pub []byte
×
UNCOV
160
        if err := ReadElements(r, &pub); err != nil {
×
161
                return nil, err
×
162
        }
×
UNCOV
163
        copy(h.PubKeyBytes[:], pub)
×
UNCOV
164

×
UNCOV
165
        if err := ReadElements(r,
×
UNCOV
166
                &h.ChannelID, &h.OutgoingTimeLock, &h.AmtToForward,
×
UNCOV
167
        ); err != nil {
×
168
                return nil, err
×
169
        }
×
170

UNCOV
171
        return h, nil
×
172
}
173

UNCOV
174
func serializeHopLegacy(w io.Writer, h *Hop) error {
×
UNCOV
175
        if err := WriteElements(w,
×
UNCOV
176
                h.PubKeyBytes[:], h.ChannelID, h.OutgoingTimeLock,
×
UNCOV
177
                h.AmtToForward,
×
UNCOV
178
        ); err != nil {
×
179
                return err
×
180
        }
×
181

UNCOV
182
        return nil
×
183
}
184

UNCOV
185
func deserializeRouteLegacy(r io.Reader) (Route, error) {
×
UNCOV
186
        rt := Route{}
×
UNCOV
187
        if err := ReadElements(r,
×
UNCOV
188
                &rt.TotalTimeLock, &rt.TotalAmount,
×
UNCOV
189
        ); err != nil {
×
190
                return rt, err
×
191
        }
×
192

UNCOV
193
        var pub []byte
×
UNCOV
194
        if err := ReadElements(r, &pub); err != nil {
×
195
                return rt, err
×
196
        }
×
UNCOV
197
        copy(rt.SourcePubKey[:], pub)
×
UNCOV
198

×
UNCOV
199
        var numHops uint32
×
UNCOV
200
        if err := ReadElements(r, &numHops); err != nil {
×
201
                return rt, err
×
202
        }
×
203

UNCOV
204
        var hops []*Hop
×
UNCOV
205
        for i := uint32(0); i < numHops; i++ {
×
UNCOV
206
                hop, err := deserializeHopLegacy(r)
×
UNCOV
207
                if err != nil {
×
208
                        return rt, err
×
209
                }
×
UNCOV
210
                hops = append(hops, hop)
×
211
        }
UNCOV
212
        rt.Hops = hops
×
UNCOV
213

×
UNCOV
214
        return rt, nil
×
215
}
216

UNCOV
217
func serializeRouteLegacy(w io.Writer, r Route) error {
×
UNCOV
218
        if err := WriteElements(w,
×
UNCOV
219
                r.TotalTimeLock, r.TotalAmount, r.SourcePubKey[:],
×
UNCOV
220
        ); err != nil {
×
221
                return err
×
222
        }
×
223

UNCOV
224
        if err := WriteElements(w, uint32(len(r.Hops))); err != nil {
×
225
                return err
×
226
        }
×
227

UNCOV
228
        for _, h := range r.Hops {
×
UNCOV
229
                if err := serializeHopLegacy(w, h); err != nil {
×
230
                        return err
×
231
                }
×
232
        }
233

UNCOV
234
        return nil
×
235
}
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