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

lightningnetwork / lnd / 13211764208

08 Feb 2025 03:08AM UTC coverage: 49.288% (-9.5%) from 58.815%
13211764208

Pull #9489

github

calvinrzachman
itest: verify switchrpc server enforces send then track

We prevent the rpc server from allowing onion dispatches for
attempt IDs which have already been tracked by rpc clients.

This helps protect the client from leaking a duplicate onion
attempt. NOTE: This is not the only method for solving this
issue! The issue could be addressed via careful client side
programming which accounts for the uncertainty and async
nature of dispatching onions to a remote process via RPC.
This would require some lnd ChannelRouter changes for how
we intend to use these RPCs though.
Pull Request #9489: multi: add BuildOnion, SendOnion, and TrackOnion RPCs

474 of 990 new or added lines in 11 files covered. (47.88%)

27321 existing lines in 435 files now uncovered.

101192 of 205306 relevant lines covered (49.29%)

1.54 hits per line

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

0.0
/channeldb/migration12/invoices.go
1
package migration12
2

3
import (
4
        "bytes"
5
        "encoding/binary"
6
        "io"
7
        "time"
8

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

15
const (
16
        // MaxMemoSize is maximum size of the memo field within invoices stored
17
        // in the database.
18
        MaxMemoSize = 1024
19

20
        // maxReceiptSize is the maximum size of the payment receipt stored
21
        // within the database along side incoming/outgoing invoices.
22
        maxReceiptSize = 1024
23

24
        // MaxPaymentRequestSize is the max size of a payment request for
25
        // this invoice.
26
        // TODO(halseth): determine the max length payment request when field
27
        // lengths are final.
28
        MaxPaymentRequestSize = 4096
29

30
        memoType        tlv.Type = 0
31
        payReqType      tlv.Type = 1
32
        createTimeType  tlv.Type = 2
33
        settleTimeType  tlv.Type = 3
34
        addIndexType    tlv.Type = 4
35
        settleIndexType tlv.Type = 5
36
        preimageType    tlv.Type = 6
37
        valueType       tlv.Type = 7
38
        cltvDeltaType   tlv.Type = 8
39
        expiryType      tlv.Type = 9
40
        paymentAddrType tlv.Type = 10
41
        featuresType    tlv.Type = 11
42
        invStateType    tlv.Type = 12
43
        amtPaidType     tlv.Type = 13
44
)
45

46
var (
47
        // invoiceBucket is the name of the bucket within the database that
48
        // stores all data related to invoices no matter their final state.
49
        // Within the invoice bucket, each invoice is keyed by its invoice ID
50
        // which is a monotonically increasing uint32.
51
        invoiceBucket = []byte("invoices")
52

53
        // Big endian is the preferred byte order, due to cursor scans over
54
        // integer keys iterating in order.
55
        byteOrder = binary.BigEndian
56
)
57

58
// ContractState describes the state the invoice is in.
59
type ContractState uint8
60

61
// ContractTerm is a companion struct to the Invoice struct. This struct houses
62
// the necessary conditions required before the invoice can be considered fully
63
// settled by the payee.
64
type ContractTerm struct {
65
        // PaymentPreimage is the preimage which is to be revealed in the
66
        // occasion that an HTLC paying to the hash of this preimage is
67
        // extended.
68
        PaymentPreimage lntypes.Preimage
69

70
        // Value is the expected amount of milli-satoshis to be paid to an HTLC
71
        // which can be satisfied by the above preimage.
72
        Value lnwire.MilliSatoshi
73

74
        // State describes the state the invoice is in.
75
        State ContractState
76

77
        // PaymentAddr is a randomly generated value include in the MPP record
78
        // by the sender to prevent probing of the receiver.
79
        PaymentAddr [32]byte
80

81
        // Features is the feature vectors advertised on the payment request.
82
        Features *lnwire.FeatureVector
83
}
84

85
// Invoice is a payment invoice generated by a payee in order to request
86
// payment for some good or service. The inclusion of invoices within Lightning
87
// creates a payment work flow for merchants very similar to that of the
88
// existing financial system within PayPal, etc.  Invoices are added to the
89
// database when a payment is requested, then can be settled manually once the
90
// payment is received at the upper layer. For record keeping purposes,
91
// invoices are never deleted from the database, instead a bit is toggled
92
// denoting the invoice has been fully settled. Within the database, all
93
// invoices must have a unique payment hash which is generated by taking the
94
// sha256 of the payment preimage.
95
type Invoice struct {
96
        // Memo is an optional memo to be stored along side an invoice.  The
97
        // memo may contain further details pertaining to the invoice itself,
98
        // or any other message which fits within the size constraints.
99
        Memo []byte
100

101
        // PaymentRequest is an optional field where a payment request created
102
        // for this invoice can be stored.
103
        PaymentRequest []byte
104

105
        // FinalCltvDelta is the minimum required number of blocks before htlc
106
        // expiry when the invoice is accepted.
107
        FinalCltvDelta int32
108

109
        // Expiry defines how long after creation this invoice should expire.
110
        Expiry time.Duration
111

112
        // CreationDate is the exact time the invoice was created.
113
        CreationDate time.Time
114

115
        // SettleDate is the exact time the invoice was settled.
116
        SettleDate time.Time
117

118
        // Terms are the contractual payment terms of the invoice. Once all the
119
        // terms have been satisfied by the payer, then the invoice can be
120
        // considered fully fulfilled.
121
        //
122
        // TODO(roasbeef): later allow for multiple terms to fulfill the final
123
        // invoice: payment fragmentation, etc.
124
        Terms ContractTerm
125

126
        // AddIndex is an auto-incrementing integer that acts as a
127
        // monotonically increasing sequence number for all invoices created.
128
        // Clients can then use this field as a "checkpoint" of sorts when
129
        // implementing a streaming RPC to notify consumers of instances where
130
        // an invoice has been added before they re-connected.
131
        //
132
        // NOTE: This index starts at 1.
133
        AddIndex uint64
134

135
        // SettleIndex is an auto-incrementing integer that acts as a
136
        // monotonically increasing sequence number for all settled invoices.
137
        // Clients can then use this field as a "checkpoint" of sorts when
138
        // implementing a streaming RPC to notify consumers of instances where
139
        // an invoice has been settled before they re-connected.
140
        //
141
        // NOTE: This index starts at 1.
142
        SettleIndex uint64
143

144
        // AmtPaid is the final amount that we ultimately accepted for pay for
145
        // this invoice. We specify this value independently as it's possible
146
        // that the invoice originally didn't specify an amount, or the sender
147
        // overpaid.
148
        AmtPaid lnwire.MilliSatoshi
149

150
        // Htlcs records all htlcs that paid to this invoice. Some of these
151
        // htlcs may have been marked as canceled.
152
        Htlcs []byte
153
}
154

155
// LegacyDeserializeInvoice decodes an invoice from the passed io.Reader using
156
// the pre-TLV serialization.
UNCOV
157
func LegacyDeserializeInvoice(r io.Reader) (Invoice, error) {
×
UNCOV
158
        var err error
×
UNCOV
159
        invoice := Invoice{}
×
UNCOV
160

×
UNCOV
161
        // TODO(roasbeef): use read full everywhere
×
UNCOV
162
        invoice.Memo, err = wire.ReadVarBytes(r, 0, MaxMemoSize, "")
×
UNCOV
163
        if err != nil {
×
164
                return invoice, err
×
165
        }
×
UNCOV
166
        _, err = wire.ReadVarBytes(r, 0, maxReceiptSize, "")
×
UNCOV
167
        if err != nil {
×
168
                return invoice, err
×
169
        }
×
170

UNCOV
171
        invoice.PaymentRequest, err = wire.ReadVarBytes(r, 0, MaxPaymentRequestSize, "")
×
UNCOV
172
        if err != nil {
×
173
                return invoice, err
×
174
        }
×
175

UNCOV
176
        if err := binary.Read(r, byteOrder, &invoice.FinalCltvDelta); err != nil {
×
177
                return invoice, err
×
178
        }
×
179

UNCOV
180
        var expiry int64
×
UNCOV
181
        if err := binary.Read(r, byteOrder, &expiry); err != nil {
×
182
                return invoice, err
×
183
        }
×
UNCOV
184
        invoice.Expiry = time.Duration(expiry)
×
UNCOV
185

×
UNCOV
186
        birthBytes, err := wire.ReadVarBytes(r, 0, 300, "birth")
×
UNCOV
187
        if err != nil {
×
188
                return invoice, err
×
189
        }
×
UNCOV
190
        if err := invoice.CreationDate.UnmarshalBinary(birthBytes); err != nil {
×
191
                return invoice, err
×
192
        }
×
193

UNCOV
194
        settledBytes, err := wire.ReadVarBytes(r, 0, 300, "settled")
×
UNCOV
195
        if err != nil {
×
196
                return invoice, err
×
197
        }
×
UNCOV
198
        if err := invoice.SettleDate.UnmarshalBinary(settledBytes); err != nil {
×
199
                return invoice, err
×
200
        }
×
201

UNCOV
202
        if _, err := io.ReadFull(r, invoice.Terms.PaymentPreimage[:]); err != nil {
×
203
                return invoice, err
×
204
        }
×
UNCOV
205
        var scratch [8]byte
×
UNCOV
206
        if _, err := io.ReadFull(r, scratch[:]); err != nil {
×
207
                return invoice, err
×
208
        }
×
UNCOV
209
        invoice.Terms.Value = lnwire.MilliSatoshi(byteOrder.Uint64(scratch[:]))
×
UNCOV
210

×
UNCOV
211
        if err := binary.Read(r, byteOrder, &invoice.Terms.State); err != nil {
×
212
                return invoice, err
×
213
        }
×
214

UNCOV
215
        if err := binary.Read(r, byteOrder, &invoice.AddIndex); err != nil {
×
216
                return invoice, err
×
217
        }
×
UNCOV
218
        if err := binary.Read(r, byteOrder, &invoice.SettleIndex); err != nil {
×
219
                return invoice, err
×
220
        }
×
UNCOV
221
        if err := binary.Read(r, byteOrder, &invoice.AmtPaid); err != nil {
×
222
                return invoice, err
×
223
        }
×
224

UNCOV
225
        invoice.Htlcs, err = deserializeHtlcs(r)
×
UNCOV
226
        if err != nil {
×
227
                return Invoice{}, err
×
228
        }
×
229

UNCOV
230
        return invoice, nil
×
231
}
232

233
// deserializeHtlcs reads a list of invoice htlcs from a reader and returns it
234
// as a flattened byte slice.
UNCOV
235
func deserializeHtlcs(r io.Reader) ([]byte, error) {
×
UNCOV
236
        var b bytes.Buffer
×
UNCOV
237
        _, err := io.Copy(&b, r)
×
UNCOV
238
        return b.Bytes(), err
×
UNCOV
239
}
×
240

241
// SerializeInvoice serializes an invoice to a writer.
242
//
243
// nolint: dupl
UNCOV
244
func SerializeInvoice(w io.Writer, i *Invoice) error {
×
UNCOV
245
        creationDateBytes, err := i.CreationDate.MarshalBinary()
×
UNCOV
246
        if err != nil {
×
247
                return err
×
248
        }
×
249

UNCOV
250
        settleDateBytes, err := i.SettleDate.MarshalBinary()
×
UNCOV
251
        if err != nil {
×
252
                return err
×
253
        }
×
254

UNCOV
255
        var fb bytes.Buffer
×
UNCOV
256
        err = i.Terms.Features.EncodeBase256(&fb)
×
UNCOV
257
        if err != nil {
×
258
                return err
×
259
        }
×
UNCOV
260
        featureBytes := fb.Bytes()
×
UNCOV
261

×
UNCOV
262
        preimage := [32]byte(i.Terms.PaymentPreimage)
×
UNCOV
263
        value := uint64(i.Terms.Value)
×
UNCOV
264
        cltvDelta := uint32(i.FinalCltvDelta)
×
UNCOV
265
        expiry := uint64(i.Expiry)
×
UNCOV
266

×
UNCOV
267
        amtPaid := uint64(i.AmtPaid)
×
UNCOV
268
        state := uint8(i.Terms.State)
×
UNCOV
269

×
UNCOV
270
        tlvStream, err := tlv.NewStream(
×
UNCOV
271
                // Memo and payreq.
×
UNCOV
272
                tlv.MakePrimitiveRecord(memoType, &i.Memo),
×
UNCOV
273
                tlv.MakePrimitiveRecord(payReqType, &i.PaymentRequest),
×
UNCOV
274

×
UNCOV
275
                // Add/settle metadata.
×
UNCOV
276
                tlv.MakePrimitiveRecord(createTimeType, &creationDateBytes),
×
UNCOV
277
                tlv.MakePrimitiveRecord(settleTimeType, &settleDateBytes),
×
UNCOV
278
                tlv.MakePrimitiveRecord(addIndexType, &i.AddIndex),
×
UNCOV
279
                tlv.MakePrimitiveRecord(settleIndexType, &i.SettleIndex),
×
UNCOV
280

×
UNCOV
281
                // Terms.
×
UNCOV
282
                tlv.MakePrimitiveRecord(preimageType, &preimage),
×
UNCOV
283
                tlv.MakePrimitiveRecord(valueType, &value),
×
UNCOV
284
                tlv.MakePrimitiveRecord(cltvDeltaType, &cltvDelta),
×
UNCOV
285
                tlv.MakePrimitiveRecord(expiryType, &expiry),
×
UNCOV
286
                tlv.MakePrimitiveRecord(paymentAddrType, &i.Terms.PaymentAddr),
×
UNCOV
287
                tlv.MakePrimitiveRecord(featuresType, &featureBytes),
×
UNCOV
288

×
UNCOV
289
                // Invoice state.
×
UNCOV
290
                tlv.MakePrimitiveRecord(invStateType, &state),
×
UNCOV
291
                tlv.MakePrimitiveRecord(amtPaidType, &amtPaid),
×
UNCOV
292
        )
×
UNCOV
293
        if err != nil {
×
294
                return err
×
295
        }
×
296

UNCOV
297
        var b bytes.Buffer
×
UNCOV
298
        if err = tlvStream.Encode(&b); err != nil {
×
299
                return err
×
300
        }
×
301

UNCOV
302
        err = binary.Write(w, byteOrder, uint64(b.Len()))
×
UNCOV
303
        if err != nil {
×
304
                return err
×
305
        }
×
306

UNCOV
307
        if _, err = w.Write(b.Bytes()); err != nil {
×
308
                return err
×
309
        }
×
310

UNCOV
311
        return serializeHtlcs(w, i.Htlcs)
×
312
}
313

314
// serializeHtlcs writes a serialized list of invoice htlcs into a writer.
UNCOV
315
func serializeHtlcs(w io.Writer, htlcs []byte) error {
×
UNCOV
316
        _, err := w.Write(htlcs)
×
UNCOV
317
        return err
×
UNCOV
318
}
×
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