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

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

9
        bitcoinCfg "github.com/btcsuite/btcd/chaincfg"
10
        "github.com/btcsuite/btcd/wire"
11
        lnwire "github.com/lightningnetwork/lnd/channeldb/migration/lnwire21"
12
        "github.com/lightningnetwork/lnd/channeldb/migration_01_to_11/zpay32"
13
        "github.com/lightningnetwork/lnd/kvdb"
14
        litecoinCfg "github.com/ltcsuite/ltcd/chaincfg"
15
)
16

17
// MigrateInvoices adds invoice htlcs and a separate cltv delta field to the
18
// invoices.
UNCOV
19
func MigrateInvoices(tx kvdb.RwTx) error {
×
UNCOV
20
        log.Infof("Migrating invoices to new invoice format")
×
UNCOV
21

×
UNCOV
22
        invoiceB := tx.ReadWriteBucket(invoiceBucket)
×
UNCOV
23
        if invoiceB == nil {
×
24
                return nil
×
25
        }
×
26

27
        // Iterate through the entire key space of the top-level invoice bucket.
28
        // If key with a non-nil value stores the next invoice ID which maps to
29
        // the corresponding invoice. Store those keys first, because it isn't
30
        // safe to modify the bucket inside a ForEach loop.
UNCOV
31
        var invoiceKeys [][]byte
×
UNCOV
32
        err := invoiceB.ForEach(func(k, v []byte) error {
×
UNCOV
33
                if v == nil {
×
34
                        return nil
×
35
                }
×
36

UNCOV
37
                invoiceKeys = append(invoiceKeys, k)
×
UNCOV
38

×
UNCOV
39
                return nil
×
40
        })
UNCOV
41
        if err != nil {
×
42
                return err
×
43
        }
×
44

UNCOV
45
        nets := []*bitcoinCfg.Params{
×
UNCOV
46
                &bitcoinCfg.MainNetParams, &bitcoinCfg.SimNetParams,
×
UNCOV
47
                &bitcoinCfg.RegressionNetParams, &bitcoinCfg.TestNet3Params,
×
UNCOV
48
        }
×
UNCOV
49

×
UNCOV
50
        ltcNets := []*litecoinCfg.Params{
×
UNCOV
51
                &litecoinCfg.MainNetParams, &litecoinCfg.SimNetParams,
×
UNCOV
52
                &litecoinCfg.RegressionNetParams, &litecoinCfg.TestNet4Params,
×
UNCOV
53
        }
×
UNCOV
54
        for _, net := range ltcNets {
×
UNCOV
55
                var convertedNet bitcoinCfg.Params
×
UNCOV
56
                convertedNet.Bech32HRPSegwit = net.Bech32HRPSegwit
×
UNCOV
57
                nets = append(nets, &convertedNet)
×
UNCOV
58
        }
×
59

60
        // Iterate over all stored keys and migrate the invoices.
UNCOV
61
        for _, k := range invoiceKeys {
×
UNCOV
62
                v := invoiceB.Get(k)
×
UNCOV
63

×
UNCOV
64
                // Deserialize the invoice with the deserializing function that
×
UNCOV
65
                // was in use for this version of the database.
×
UNCOV
66
                invoiceReader := bytes.NewReader(v)
×
UNCOV
67
                invoice, err := deserializeInvoiceLegacy(invoiceReader)
×
UNCOV
68
                if err != nil {
×
69
                        return err
×
70
                }
×
71

UNCOV
72
                if invoice.Terms.State == ContractAccepted {
×
UNCOV
73
                        return fmt.Errorf("cannot upgrade with invoice(s) " +
×
UNCOV
74
                                "in accepted state, see release notes")
×
UNCOV
75
                }
×
76

77
                // Try to decode the payment request for every possible net to
78
                // avoid passing a the active network to channeldb. This would
79
                // be a layering violation, while this migration is only running
80
                // once and will likely be removed in the future.
UNCOV
81
                var payReq *zpay32.Invoice
×
UNCOV
82
                for _, net := range nets {
×
UNCOV
83
                        payReq, err = zpay32.Decode(
×
UNCOV
84
                                string(invoice.PaymentRequest), net,
×
UNCOV
85
                        )
×
UNCOV
86
                        if err == nil {
×
UNCOV
87
                                break
×
88
                        }
89
                }
UNCOV
90
                if payReq == nil {
×
91
                        return fmt.Errorf("cannot decode payreq")
×
92
                }
×
UNCOV
93
                invoice.FinalCltvDelta = int32(payReq.MinFinalCLTVExpiry())
×
UNCOV
94
                invoice.Expiry = payReq.Expiry()
×
UNCOV
95

×
UNCOV
96
                // Serialize the invoice in the new format and use it to replace
×
UNCOV
97
                // the old invoice in the database.
×
UNCOV
98
                var buf bytes.Buffer
×
UNCOV
99
                if err := serializeInvoice(&buf, &invoice); err != nil {
×
100
                        return err
×
101
                }
×
102

UNCOV
103
                err = invoiceB.Put(k, buf.Bytes())
×
UNCOV
104
                if err != nil {
×
105
                        return err
×
106
                }
×
107
        }
108

UNCOV
109
        log.Infof("Migration of invoices completed!")
×
UNCOV
110
        return nil
×
111
}
112

UNCOV
113
func deserializeInvoiceLegacy(r io.Reader) (Invoice, error) {
×
UNCOV
114
        var err error
×
UNCOV
115
        invoice := Invoice{}
×
UNCOV
116

×
UNCOV
117
        // TODO(roasbeef): use read full everywhere
×
UNCOV
118
        invoice.Memo, err = wire.ReadVarBytes(r, 0, MaxMemoSize, "")
×
UNCOV
119
        if err != nil {
×
120
                return invoice, err
×
121
        }
×
UNCOV
122
        invoice.Receipt, err = wire.ReadVarBytes(r, 0, MaxReceiptSize, "")
×
UNCOV
123
        if err != nil {
×
124
                return invoice, err
×
125
        }
×
126

UNCOV
127
        invoice.PaymentRequest, err = wire.ReadVarBytes(r, 0, MaxPaymentRequestSize, "")
×
UNCOV
128
        if err != nil {
×
129
                return invoice, err
×
130
        }
×
131

UNCOV
132
        birthBytes, err := wire.ReadVarBytes(r, 0, 300, "birth")
×
UNCOV
133
        if err != nil {
×
134
                return invoice, err
×
135
        }
×
UNCOV
136
        if err := invoice.CreationDate.UnmarshalBinary(birthBytes); err != nil {
×
137
                return invoice, err
×
138
        }
×
139

UNCOV
140
        settledBytes, err := wire.ReadVarBytes(r, 0, 300, "settled")
×
UNCOV
141
        if err != nil {
×
142
                return invoice, err
×
143
        }
×
UNCOV
144
        if err := invoice.SettleDate.UnmarshalBinary(settledBytes); err != nil {
×
145
                return invoice, err
×
146
        }
×
147

UNCOV
148
        if _, err := io.ReadFull(r, invoice.Terms.PaymentPreimage[:]); err != nil {
×
149
                return invoice, err
×
150
        }
×
UNCOV
151
        var scratch [8]byte
×
UNCOV
152
        if _, err := io.ReadFull(r, scratch[:]); err != nil {
×
153
                return invoice, err
×
154
        }
×
UNCOV
155
        invoice.Terms.Value = lnwire.MilliSatoshi(byteOrder.Uint64(scratch[:]))
×
UNCOV
156

×
UNCOV
157
        if err := binary.Read(r, byteOrder, &invoice.Terms.State); err != nil {
×
158
                return invoice, err
×
159
        }
×
160

UNCOV
161
        if err := binary.Read(r, byteOrder, &invoice.AddIndex); err != nil {
×
162
                return invoice, err
×
163
        }
×
UNCOV
164
        if err := binary.Read(r, byteOrder, &invoice.SettleIndex); err != nil {
×
165
                return invoice, err
×
166
        }
×
UNCOV
167
        if err := binary.Read(r, byteOrder, &invoice.AmtPaid); err != nil {
×
168
                return invoice, err
×
169
        }
×
170

UNCOV
171
        return invoice, nil
×
172
}
173

174
// serializeInvoiceLegacy serializes an invoice in the format of the previous db
175
// version.
UNCOV
176
func serializeInvoiceLegacy(w io.Writer, i *Invoice) error {
×
UNCOV
177
        if err := wire.WriteVarBytes(w, 0, i.Memo[:]); err != nil {
×
178
                return err
×
179
        }
×
UNCOV
180
        if err := wire.WriteVarBytes(w, 0, i.Receipt[:]); err != nil {
×
181
                return err
×
182
        }
×
UNCOV
183
        if err := wire.WriteVarBytes(w, 0, i.PaymentRequest[:]); err != nil {
×
184
                return err
×
185
        }
×
186

UNCOV
187
        birthBytes, err := i.CreationDate.MarshalBinary()
×
UNCOV
188
        if err != nil {
×
189
                return err
×
190
        }
×
191

UNCOV
192
        if err := wire.WriteVarBytes(w, 0, birthBytes); err != nil {
×
193
                return err
×
194
        }
×
195

UNCOV
196
        settleBytes, err := i.SettleDate.MarshalBinary()
×
UNCOV
197
        if err != nil {
×
198
                return err
×
199
        }
×
200

UNCOV
201
        if err := wire.WriteVarBytes(w, 0, settleBytes); err != nil {
×
202
                return err
×
203
        }
×
204

UNCOV
205
        if _, err := w.Write(i.Terms.PaymentPreimage[:]); err != nil {
×
206
                return err
×
207
        }
×
208

UNCOV
209
        var scratch [8]byte
×
UNCOV
210
        byteOrder.PutUint64(scratch[:], uint64(i.Terms.Value))
×
UNCOV
211
        if _, err := w.Write(scratch[:]); err != nil {
×
212
                return err
×
213
        }
×
214

UNCOV
215
        if err := binary.Write(w, byteOrder, i.Terms.State); err != nil {
×
216
                return err
×
217
        }
×
218

UNCOV
219
        if err := binary.Write(w, byteOrder, i.AddIndex); err != nil {
×
220
                return err
×
221
        }
×
UNCOV
222
        if err := binary.Write(w, byteOrder, i.SettleIndex); err != nil {
×
223
                return err
×
224
        }
×
UNCOV
225
        if err := binary.Write(w, byteOrder, int64(i.AmtPaid)); err != nil {
×
226
                return err
×
227
        }
×
228

UNCOV
229
        return nil
×
230
}
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