• 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

66.42
/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.
157
func LegacyDeserializeInvoice(r io.Reader) (Invoice, error) {
2✔
158
        var err error
2✔
159
        invoice := Invoice{}
2✔
160

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

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

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

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

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

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

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

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

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

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

230
        return invoice, nil
2✔
231
}
232

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

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

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

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

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

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

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

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

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

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

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

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

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

311
        return serializeHtlcs(w, i.Htlcs)
2✔
312
}
313

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