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

lightningnetwork / lnd / 11292787765

11 Oct 2024 12:58PM UTC coverage: 49.179% (-9.5%) from 58.716%
11292787765

push

github

web-flow
Merge pull request #9168 from feelancer21/fix-lncli-wallet-proto

lnrpc: fix lncli documentation tags in walletkit.proto

97369 of 197987 relevant lines covered (49.18%)

1.04 hits per line

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

0.0
/channeldb/migration32/mission_control_store.go
1
package migration32
2

3
import (
4
        "bytes"
5
        "io"
6
        "math"
7
        "time"
8

9
        "github.com/btcsuite/btcd/wire"
10
        lnwire "github.com/lightningnetwork/lnd/channeldb/migration/lnwire21"
11
)
12

13
const (
14
        // unknownFailureSourceIdx is the database encoding of an unknown error
15
        // source.
16
        unknownFailureSourceIdx = -1
17
)
18

19
var (
20
        // resultsKey is the fixed key under which the attempt results are
21
        // stored.
22
        resultsKey = []byte("missioncontrol-results")
23
)
24

25
// paymentResultCommon holds the fields that are shared by the old and new
26
// payment result encoding.
27
type paymentResultCommon struct {
28
        id                 uint64
29
        timeFwd, timeReply time.Time
30
        success            bool
31
        failureSourceIdx   *int
32
        failure            lnwire.FailureMessage
33
}
34

35
// paymentResultOld is the information that becomes available when a payment
36
// attempt completes.
37
type paymentResultOld struct {
38
        paymentResultCommon
39
        route *Route
40
}
41

42
// deserializeOldResult deserializes a payment result using the old encoding.
43
func deserializeOldResult(k, v []byte) (*paymentResultOld, error) {
×
44
        // Parse payment id.
×
45
        result := paymentResultOld{
×
46
                paymentResultCommon: paymentResultCommon{
×
47
                        id: byteOrder.Uint64(k[8:]),
×
48
                },
×
49
        }
×
50

×
51
        r := bytes.NewReader(v)
×
52

×
53
        // Read timestamps, success status and failure source index.
×
54
        var (
×
55
                timeFwd, timeReply uint64
×
56
                dbFailureSourceIdx int32
×
57
        )
×
58

×
59
        err := ReadElements(
×
60
                r, &timeFwd, &timeReply, &result.success, &dbFailureSourceIdx,
×
61
        )
×
62
        if err != nil {
×
63
                return nil, err
×
64
        }
×
65

66
        // Convert time stamps to local time zone for consistent logging.
67
        result.timeFwd = time.Unix(0, int64(timeFwd)).Local()
×
68
        result.timeReply = time.Unix(0, int64(timeReply)).Local()
×
69

×
70
        // Convert from unknown index magic number to nil value.
×
71
        if dbFailureSourceIdx != unknownFailureSourceIdx {
×
72
                failureSourceIdx := int(dbFailureSourceIdx)
×
73
                result.failureSourceIdx = &failureSourceIdx
×
74
        }
×
75

76
        // Read route.
77
        route, err := DeserializeRoute(r)
×
78
        if err != nil {
×
79
                return nil, err
×
80
        }
×
81
        result.route = &route
×
82

×
83
        // Read failure.
×
84
        failureBytes, err := wire.ReadVarBytes(r, 0, math.MaxUint16, "failure")
×
85
        if err != nil {
×
86
                return nil, err
×
87
        }
×
88
        if len(failureBytes) > 0 {
×
89
                result.failure, err = lnwire.DecodeFailureMessage(
×
90
                        bytes.NewReader(failureBytes), 0,
×
91
                )
×
92
                if err != nil {
×
93
                        return nil, err
×
94
                }
×
95
        }
96

97
        return &result, nil
×
98
}
99

100
// convertPaymentResult converts a paymentResultOld to a paymentResultNew.
101
func convertPaymentResult(old *paymentResultOld) *paymentResultNew {
×
102
        return &paymentResultNew{
×
103
                paymentResultCommon: old.paymentResultCommon,
×
104
                route:               extractMCRoute(old.route),
×
105
        }
×
106
}
×
107

108
// paymentResultNew is the information that becomes available when a payment
109
// attempt completes.
110
type paymentResultNew struct {
111
        paymentResultCommon
112
        route *mcRoute
113
}
114

115
// extractMCRoute extracts the fields required by MC from the Route struct to
116
// create the more minimal mcRoute struct.
117
func extractMCRoute(route *Route) *mcRoute {
×
118
        return &mcRoute{
×
119
                sourcePubKey: route.SourcePubKey,
×
120
                totalAmount:  route.TotalAmount,
×
121
                hops:         extractMCHops(route.Hops),
×
122
        }
×
123
}
×
124

125
// extractMCHops extracts the Hop fields that MC actually uses from a slice of
126
// Hops.
127
func extractMCHops(hops []*Hop) []*mcHop {
×
128
        mcHops := make([]*mcHop, len(hops))
×
129
        for i, hop := range hops {
×
130
                mcHops[i] = extractMCHop(hop)
×
131
        }
×
132

133
        return mcHops
×
134
}
135

136
// extractMCHop extracts the Hop fields that MC actually uses from a Hop.
137
func extractMCHop(hop *Hop) *mcHop {
×
138
        return &mcHop{
×
139
                channelID:        hop.ChannelID,
×
140
                pubKeyBytes:      hop.PubKeyBytes,
×
141
                amtToFwd:         hop.AmtToForward,
×
142
                hasBlindingPoint: hop.BlindingPoint != nil,
×
143
                hasCustomRecords: len(hop.CustomRecords) > 0,
×
144
        }
×
145
}
×
146

147
// mcRoute holds the bare minimum info about a payment attempt route that MC
148
// requires.
149
type mcRoute struct {
150
        sourcePubKey Vertex
151
        totalAmount  lnwire.MilliSatoshi
152
        hops         []*mcHop
153
}
154

155
// mcHop holds the bare minimum info about a payment attempt route hop that MC
156
// requires.
157
type mcHop struct {
158
        channelID        uint64
159
        pubKeyBytes      Vertex
160
        amtToFwd         lnwire.MilliSatoshi
161
        hasBlindingPoint bool
162
        hasCustomRecords bool
163
}
164

165
// serializeOldResult serializes a payment result and returns a key and value
166
// byte slice to insert into the bucket.
167
func serializeOldResult(rp *paymentResultOld) ([]byte, []byte, error) {
×
168
        // Write timestamps, success status, failure source index and route.
×
169
        var b bytes.Buffer
×
170
        var dbFailureSourceIdx int32
×
171
        if rp.failureSourceIdx == nil {
×
172
                dbFailureSourceIdx = unknownFailureSourceIdx
×
173
        } else {
×
174
                dbFailureSourceIdx = int32(*rp.failureSourceIdx)
×
175
        }
×
176
        err := WriteElements(
×
177
                &b,
×
178
                uint64(rp.timeFwd.UnixNano()),
×
179
                uint64(rp.timeReply.UnixNano()),
×
180
                rp.success, dbFailureSourceIdx,
×
181
        )
×
182
        if err != nil {
×
183
                return nil, nil, err
×
184
        }
×
185

186
        if err := SerializeRoute(&b, *rp.route); err != nil {
×
187
                return nil, nil, err
×
188
        }
×
189

190
        // Write failure. If there is no failure message, write an empty
191
        // byte slice.
192
        var failureBytes bytes.Buffer
×
193
        if rp.failure != nil {
×
194
                err := lnwire.EncodeFailureMessage(&failureBytes, rp.failure, 0)
×
195
                if err != nil {
×
196
                        return nil, nil, err
×
197
                }
×
198
        }
199
        err = wire.WriteVarBytes(&b, 0, failureBytes.Bytes())
×
200
        if err != nil {
×
201
                return nil, nil, err
×
202
        }
×
203
        // Compose key that identifies this result.
204
        key := getResultKeyOld(rp)
×
205

×
206
        return key, b.Bytes(), nil
×
207
}
208

209
// getResultKeyOld returns a byte slice representing a unique key for this
210
// payment result.
211
func getResultKeyOld(rp *paymentResultOld) []byte {
×
212
        var keyBytes [8 + 8 + 33]byte
×
213

×
214
        // Identify records by a combination of time, payment id and sender pub
×
215
        // key. This allows importing mission control data from an external
×
216
        // source without key collisions and keeps the records sorted
×
217
        // chronologically.
×
218
        byteOrder.PutUint64(keyBytes[:], uint64(rp.timeReply.UnixNano()))
×
219
        byteOrder.PutUint64(keyBytes[8:], rp.id)
×
220
        copy(keyBytes[16:], rp.route.SourcePubKey[:])
×
221

×
222
        return keyBytes[:]
×
223
}
×
224

225
// serializeNewResult serializes a payment result and returns a key and value
226
// byte slice to insert into the bucket.
227
func serializeNewResult(rp *paymentResultNew) ([]byte, []byte, error) {
×
228
        // Write timestamps, success status, failure source index and route.
×
229
        var b bytes.Buffer
×
230

×
231
        var dbFailureSourceIdx int32
×
232
        if rp.failureSourceIdx == nil {
×
233
                dbFailureSourceIdx = unknownFailureSourceIdx
×
234
        } else {
×
235
                dbFailureSourceIdx = int32(*rp.failureSourceIdx)
×
236
        }
×
237

238
        err := WriteElements(
×
239
                &b,
×
240
                uint64(rp.timeFwd.UnixNano()),
×
241
                uint64(rp.timeReply.UnixNano()),
×
242
                rp.success, dbFailureSourceIdx,
×
243
        )
×
244
        if err != nil {
×
245
                return nil, nil, err
×
246
        }
×
247

248
        if err := serializeMCRoute(&b, rp.route); err != nil {
×
249
                return nil, nil, err
×
250
        }
×
251

252
        // Write failure. If there is no failure message, write an empty
253
        // byte slice.
254
        var failureBytes bytes.Buffer
×
255
        if rp.failure != nil {
×
256
                err := lnwire.EncodeFailureMessage(&failureBytes, rp.failure, 0)
×
257
                if err != nil {
×
258
                        return nil, nil, err
×
259
                }
×
260
        }
261
        err = wire.WriteVarBytes(&b, 0, failureBytes.Bytes())
×
262
        if err != nil {
×
263
                return nil, nil, err
×
264
        }
×
265

266
        // Compose key that identifies this result.
267
        key := getResultKeyNew(rp)
×
268

×
269
        return key, b.Bytes(), nil
×
270
}
271

272
// getResultKeyNew returns a byte slice representing a unique key for this
273
// payment result.
274
func getResultKeyNew(rp *paymentResultNew) []byte {
×
275
        var keyBytes [8 + 8 + 33]byte
×
276

×
277
        // Identify records by a combination of time, payment id and sender pub
×
278
        // key. This allows importing mission control data from an external
×
279
        // source without key collisions and keeps the records sorted
×
280
        // chronologically.
×
281
        byteOrder.PutUint64(keyBytes[:], uint64(rp.timeReply.UnixNano()))
×
282
        byteOrder.PutUint64(keyBytes[8:], rp.id)
×
283
        copy(keyBytes[16:], rp.route.sourcePubKey[:])
×
284

×
285
        return keyBytes[:]
×
286
}
×
287

288
// serializeMCRoute serializes an mcRoute and writes the bytes to the given
289
// io.Writer.
290
func serializeMCRoute(w io.Writer, r *mcRoute) error {
×
291
        if err := WriteElements(
×
292
                w, r.totalAmount, r.sourcePubKey[:],
×
293
        ); err != nil {
×
294
                return err
×
295
        }
×
296

297
        if err := WriteElements(w, uint32(len(r.hops))); err != nil {
×
298
                return err
×
299
        }
×
300

301
        for _, h := range r.hops {
×
302
                if err := serializeNewHop(w, h); err != nil {
×
303
                        return err
×
304
                }
×
305
        }
306

307
        return nil
×
308
}
309

310
// serializeMCRoute serializes an mcHop and writes the bytes to the given
311
// io.Writer.
312
func serializeNewHop(w io.Writer, h *mcHop) error {
×
313
        return WriteElements(w,
×
314
                h.pubKeyBytes[:],
×
315
                h.channelID,
×
316
                h.amtToFwd,
×
317
                h.hasBlindingPoint,
×
318
                h.hasCustomRecords,
×
319
        )
×
320
}
×
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