• 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

64.2
/lnwallet/payment_descriptor.go
1
package lnwallet
2

3
import (
4
        "crypto/sha256"
5

6
        "github.com/lightningnetwork/lnd/channeldb"
7
        "github.com/lightningnetwork/lnd/graph/db/models"
8
        "github.com/lightningnetwork/lnd/input"
9
        "github.com/lightningnetwork/lnd/lntypes"
10
        "github.com/lightningnetwork/lnd/lnwire"
11
)
12

13
// updateType is the exact type of an entry within the shared HTLC log.
14
type updateType uint8
15

16
const (
17
        // Add is an update type that adds a new HTLC entry into the log.
18
        // Either side can add a new pending HTLC by adding a new Add entry
19
        // into their update log.
20
        Add updateType = iota
21

22
        // Fail is an update type which removes a prior HTLC entry from the
23
        // log. Adding a Fail entry to one's log will modify the _remote_
24
        // party's update log once a new commitment view has been evaluated
25
        // which contains the Fail entry.
26
        Fail
27

28
        // MalformedFail is an update type which removes a prior HTLC entry
29
        // from the log. Adding a MalformedFail entry to one's log will modify
30
        // the _remote_ party's update log once a new commitment view has been
31
        // evaluated which contains the MalformedFail entry. The difference
32
        // from Fail type lie in the different data we have to store.
33
        MalformedFail
34

35
        // Settle is an update type which settles a prior HTLC crediting the
36
        // balance of the receiving node. Adding a Settle entry to a log will
37
        // result in the settle entry being removed on the log as well as the
38
        // original add entry from the remote party's log after the next state
39
        // transition.
40
        Settle
41

42
        // FeeUpdate is an update type sent by the channel initiator that
43
        // updates the fee rate used when signing the commitment transaction.
44
        FeeUpdate
45
)
46

47
// String returns a human readable string that uniquely identifies the target
48
// update type.
49
func (u updateType) String() string {
3✔
50
        switch u {
3✔
51
        case Add:
3✔
52
                return "Add"
3✔
53
        case Fail:
×
54
                return "Fail"
×
55
        case MalformedFail:
×
56
                return "MalformedFail"
×
57
        case Settle:
×
58
                return "Settle"
×
59
        case FeeUpdate:
×
60
                return "FeeUpdate"
×
61
        default:
×
62
                return "<unknown type>"
×
63
        }
64
}
65

66
// paymentDescriptor represents a commitment state update which either adds,
67
// settles, or removes an HTLC. paymentDescriptors encapsulate all necessary
68
// metadata w.r.t to an HTLC, and additional data pairing a settle message to
69
// the original added HTLC.
70
//
71
// TODO(roasbeef): LogEntry interface??
72
//   - need to separate attrs for cancel/add/settle/feeupdate
73
type paymentDescriptor struct {
74
        // ChanID is the ChannelID of the LightningChannel that this
75
        // paymentDescriptor belongs to. We track this here so we can
76
        // reconstruct the Messages that this paymentDescriptor is built from.
77
        ChanID lnwire.ChannelID
78

79
        // RHash is the payment hash for this HTLC. The HTLC can be settled iff
80
        // the preimage to this hash is presented.
81
        RHash PaymentHash
82

83
        // RPreimage is the preimage that settles the HTLC pointed to within the
84
        // log by the ParentIndex.
85
        RPreimage PaymentHash
86

87
        // Timeout is the absolute timeout in blocks, after which this HTLC
88
        // expires.
89
        Timeout uint32
90

91
        // Amount is the HTLC amount in milli-satoshis.
92
        Amount lnwire.MilliSatoshi
93

94
        // LogIndex is the log entry number that his HTLC update has within the
95
        // log. Depending on if IsIncoming is true, this is either an entry the
96
        // remote party added, or one that we added locally.
97
        LogIndex uint64
98

99
        // HtlcIndex is the index within the main update log for this HTLC.
100
        // Entries within the log of type Add will have this field populated,
101
        // as other entries will point to the entry via this counter.
102
        //
103
        // NOTE: This field will only be populate if EntryType is Add.
104
        HtlcIndex uint64
105

106
        // ParentIndex is the HTLC index of the entry that this update settles
107
        // or times out.
108
        //
109
        // NOTE: This field will only be populate if EntryType is Fail or
110
        // Settle.
111
        ParentIndex uint64
112

113
        // SourceRef points to an Add update in a forwarding package owned by
114
        // this channel.
115
        //
116
        // NOTE: This field will only be populated if EntryType is Fail or
117
        // Settle.
118
        SourceRef *channeldb.AddRef
119

120
        // DestRef points to a Fail/Settle update in another link's forwarding
121
        // package.
122
        //
123
        // NOTE: This field will only be populated if EntryType is Fail or
124
        // Settle, and the forwarded Add successfully included in an outgoing
125
        // link's commitment txn.
126
        DestRef *channeldb.SettleFailRef
127

128
        // OpenCircuitKey references the incoming Chan/HTLC ID of an Add HTLC
129
        // packet delivered by the switch.
130
        //
131
        // NOTE: This field is only populated for payment descriptors in the
132
        // *local* update log, and if the Add packet was delivered by the
133
        // switch.
134
        OpenCircuitKey *models.CircuitKey
135

136
        // ClosedCircuitKey references the incoming Chan/HTLC ID of the Add HTLC
137
        // that opened the circuit.
138
        //
139
        // NOTE: This field is only populated for payment descriptors in the
140
        // *local* update log, and if settle/fails have a committed circuit in
141
        // the circuit map.
142
        ClosedCircuitKey *models.CircuitKey
143

144
        // localOutputIndex is the output index of this HTLc output in the
145
        // commitment transaction of the local node.
146
        //
147
        // NOTE: If the output is dust from the PoV of the local commitment
148
        // chain, then this value will be -1.
149
        localOutputIndex int32
150

151
        // remoteOutputIndex is the output index of this HTLC output in the
152
        // commitment transaction of the remote node.
153
        //
154
        // NOTE: If the output is dust from the PoV of the remote commitment
155
        // chain, then this value will be -1.
156
        remoteOutputIndex int32
157

158
        // sig is the signature for the second-level HTLC transaction that
159
        // spends the version of this HTLC on the commitment transaction of the
160
        // local node. This signature is generated by the remote node and
161
        // stored by the local node in the case that local node needs to
162
        // broadcast their commitment transaction.
163
        sig input.Signature
164

165
        // addCommitHeight[Remote|Local] encodes the height of the commitment
166
        // which included this HTLC on either the remote or local commitment
167
        // chain. This value is used to determine when an HTLC is fully
168
        // "locked-in".
169
        addCommitHeights lntypes.Dual[uint64]
170

171
        // removeCommitHeight[Remote|Local] encodes the height of the
172
        // commitment which removed the parent pointer of this
173
        // paymentDescriptor either due to a timeout or a settle. Once both
174
        // these heights are below the tail of both chains, the log entries can
175
        // safely be removed.
176
        removeCommitHeights lntypes.Dual[uint64]
177

178
        // OnionBlob is an opaque blob which is used to complete multi-hop
179
        // routing.
180
        //
181
        // NOTE: Populated only on add payment descriptor entry types.
182
        OnionBlob [lnwire.OnionPacketSize]byte
183

184
        // ShaOnionBlob is a sha of the onion blob.
185
        //
186
        // NOTE: Populated only in payment descriptor with MalformedFail type.
187
        ShaOnionBlob [sha256.Size]byte
188

189
        // FailReason stores the reason why a particular payment was canceled.
190
        //
191
        // NOTE: Populate only in fail payment descriptor entry types.
192
        FailReason []byte
193

194
        // FailCode stores the code why a particular payment was canceled.
195
        //
196
        // NOTE: Populated only in payment descriptor with MalformedFail type.
197
        FailCode lnwire.FailCode
198

199
        // [our|their|]PkScript are the raw public key scripts that encodes the
200
        // redemption rules for this particular HTLC. These fields will only be
201
        // populated iff the EntryType of this paymentDescriptor is Add.
202
        // ourPkScript is the ourPkScript from the context of our local
203
        // commitment chain. theirPkScript is the latest pkScript from the
204
        // context of the remote commitment chain.
205
        //
206
        // NOTE: These values may change within the logs themselves, however,
207
        // they'll stay consistent within the commitment chain entries
208
        // themselves.
209
        ourPkScript        []byte
210
        ourWitnessScript   []byte
211
        theirPkScript      []byte
212
        theirWitnessScript []byte
213

214
        // EntryType denotes the exact type of the paymentDescriptor. In the
215
        // case of a Timeout, or Settle type, then the Parent field will point
216
        // into the log to the HTLC being modified.
217
        EntryType updateType
218

219
        // isForwarded denotes if an incoming HTLC has been forwarded to any
220
        // possible upstream peers in the route.
221
        isForwarded bool
222

223
        // BlindingPoint is an optional ephemeral key used in route blinding.
224
        // This value is set for nodes that are relaying payments inside of a
225
        // blinded route (ie, not the introduction node) from update_add_htlc's
226
        // TLVs.
227
        BlindingPoint lnwire.BlindingPointRecord
228

229
        // CustomRecords also stores the set of optional custom records that
230
        // may have been attached to a sent HTLC.
231
        CustomRecords lnwire.CustomRecords
232
}
233

234
// toLogUpdate recovers the underlying LogUpdate from the paymentDescriptor.
235
// This operation is lossy and will forget some extra information tracked by the
236
// paymentDescriptor but the function is total in that all paymentDescriptors
237
// can be converted back to LogUpdates.
238
func (pd *paymentDescriptor) toLogUpdate() channeldb.LogUpdate {
3✔
239
        var msg lnwire.Message
3✔
240
        switch pd.EntryType {
3✔
241
        case Add:
3✔
242
                msg = &lnwire.UpdateAddHTLC{
3✔
243
                        ChanID:        pd.ChanID,
3✔
244
                        ID:            pd.HtlcIndex,
3✔
245
                        Amount:        pd.Amount,
3✔
246
                        PaymentHash:   pd.RHash,
3✔
247
                        Expiry:        pd.Timeout,
3✔
248
                        OnionBlob:     pd.OnionBlob,
3✔
249
                        BlindingPoint: pd.BlindingPoint,
3✔
250
                        CustomRecords: pd.CustomRecords.Copy(),
3✔
251
                }
3✔
252
        case Settle:
3✔
253
                msg = &lnwire.UpdateFulfillHTLC{
3✔
254
                        ChanID:          pd.ChanID,
3✔
255
                        ID:              pd.ParentIndex,
3✔
256
                        PaymentPreimage: pd.RPreimage,
3✔
257
                }
3✔
258
        case Fail:
3✔
259
                msg = &lnwire.UpdateFailHTLC{
3✔
260
                        ChanID: pd.ChanID,
3✔
261
                        ID:     pd.ParentIndex,
3✔
262
                        Reason: pd.FailReason,
3✔
263
                }
3✔
264
        case MalformedFail:
3✔
265
                msg = &lnwire.UpdateFailMalformedHTLC{
3✔
266
                        ChanID:       pd.ChanID,
3✔
267
                        ID:           pd.ParentIndex,
3✔
268
                        ShaOnionBlob: pd.ShaOnionBlob,
3✔
269
                        FailureCode:  pd.FailCode,
3✔
270
                }
3✔
UNCOV
271
        case FeeUpdate:
×
UNCOV
272
                // The Amount field holds the feerate denominated in
×
UNCOV
273
                // msat. Since feerates are only denominated in sat/kw,
×
UNCOV
274
                // we can convert it without loss of precision.
×
UNCOV
275
                msg = &lnwire.UpdateFee{
×
UNCOV
276
                        ChanID:   pd.ChanID,
×
UNCOV
277
                        FeePerKw: uint32(pd.Amount.ToSatoshis()),
×
UNCOV
278
                }
×
279
        }
280

281
        return channeldb.LogUpdate{
3✔
282
                LogIndex:  pd.LogIndex,
3✔
283
                UpdateMsg: msg,
3✔
284
        }
3✔
285
}
286

287
// setCommitHeight updates the appropriate addCommitHeight and/or
288
// removeCommitHeight for whoseCommitChain and locks it in at nextHeight.
289
func (pd *paymentDescriptor) setCommitHeight(
290
        whoseCommitChain lntypes.ChannelParty, nextHeight uint64) {
3✔
291

3✔
292
        switch pd.EntryType {
3✔
293
        case Add:
3✔
294
                pd.addCommitHeights.SetForParty(
3✔
295
                        whoseCommitChain, nextHeight,
3✔
296
                )
3✔
297
        case Settle, Fail, MalformedFail:
3✔
298
                pd.removeCommitHeights.SetForParty(
3✔
299
                        whoseCommitChain, nextHeight,
3✔
300
                )
3✔
UNCOV
301
        case FeeUpdate:
×
UNCOV
302
                // Fee updates are applied for all commitments
×
UNCOV
303
                // after they are sent/received, so we consider
×
UNCOV
304
                // them being added and removed at the same
×
UNCOV
305
                // height.
×
UNCOV
306
                pd.addCommitHeights.SetForParty(
×
UNCOV
307
                        whoseCommitChain, nextHeight,
×
UNCOV
308
                )
×
UNCOV
309
                pd.removeCommitHeights.SetForParty(
×
UNCOV
310
                        whoseCommitChain, nextHeight,
×
UNCOV
311
                )
×
312
        }
313
}
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