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

lightningnetwork / lnd / 13586005509

28 Feb 2025 10:14AM UTC coverage: 68.629% (+9.9%) from 58.77%
13586005509

Pull #9521

github

web-flow
Merge 37d3a70a5 into 8532955b3
Pull Request #9521: unit: remove GOACC, use Go 1.20 native coverage functionality

129950 of 189351 relevant lines covered (68.63%)

23726.46 hits per line

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

70.37
/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.
13
func MigrateRouteSerialization(tx kvdb.RwTx) error {
1✔
14
        // First, we'll do all the payment attempts.
1✔
15
        rootPaymentBucket := tx.ReadWriteBucket(paymentsRootBucket)
1✔
16
        if rootPaymentBucket == nil {
1✔
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.
23
        var payHashes [][]byte
1✔
24
        err := rootPaymentBucket.ForEach(func(k, v []byte) error {
4✔
25
                if v != nil {
3✔
26
                        return nil
×
27
                }
×
28

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

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

3✔
41
                // First, we'll migrate the main (non duplicate) payment to
3✔
42
                // this hash.
3✔
43
                err := migrateAttemptEncoding(tx, payHashBucket)
3✔
44
                if err != nil {
3✔
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.
50
                dupBucket := payHashBucket.NestedReadWriteBucket(paymentDuplicateBucket)
3✔
51

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

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

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

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

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

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

91
        log.Infof("Migration to new mission control completed!")
1✔
92

1✔
93
        return nil
1✔
94
}
95

96
// migrateAttemptEncoding migrates payment attempts using the legacy format to
97
// the new format.
98
func migrateAttemptEncoding(tx kvdb.RwTx, payHashBucket kvdb.RwBucket) error {
4✔
99
        payAttemptBytes := payHashBucket.Get(paymentAttemptInfoKey)
4✔
100
        if payAttemptBytes == nil {
4✔
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.
106
        payAttemptReader := bytes.NewReader(payAttemptBytes)
4✔
107
        payAttempt, err := deserializePaymentAttemptInfoLegacy(
4✔
108
                payAttemptReader,
4✔
109
        )
4✔
110
        if err != nil {
4✔
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.
117
        for _, hop := range payAttempt.Route.Hops {
12✔
118
                hop.LegacyPayload = true
8✔
119
        }
8✔
120

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

128
        return payHashBucket.Put(paymentAttemptInfoKey, b.Bytes())
4✔
129
}
130

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

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

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

153
        return nil
4✔
154
}
155

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

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

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

171
        return h, nil
8✔
172
}
173

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

182
        return nil
8✔
183
}
184

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

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

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

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

4✔
214
        return rt, nil
4✔
215
}
216

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

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

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

234
        return nil
4✔
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