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

lightningnetwork / lnd / 15974418004

30 Jun 2025 01:34PM UTC coverage: 57.801% (+0.05%) from 57.756%
15974418004

Pull #9871

github

web-flow
Merge 8ef8d74db into 01dfee6f8
Pull Request #9871: Add `NoopAdd` HTLCs

36 of 96 new or added lines in 3 files covered. (37.5%)

2254 existing lines in 18 files now uncovered.

98493 of 170401 relevant lines covered (57.8%)

1.79 hits per line

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

63.95
/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
        // NoOpAdd is an update type that adds a new HTLC entry into the log.
47
        // This differs from the normal Add type, in that when settled the
48
        // balance will go back to the sender, rather than be credited for the
49
        // receiver.
50
        NoOpAdd
51
)
52

53
// String returns a human readable string that uniquely identifies the target
54
// update type.
55
func (u updateType) String() string {
3✔
56
        switch u {
3✔
57
        case Add:
3✔
58
                return "Add"
3✔
59
        case Fail:
×
60
                return "Fail"
×
61
        case MalformedFail:
×
62
                return "MalformedFail"
×
63
        case Settle:
×
64
                return "Settle"
×
65
        case FeeUpdate:
×
66
                return "FeeUpdate"
×
NEW
67
        case NoOpAdd:
×
NEW
68
                return "NoopAdd"
×
69
        default:
×
70
                return "<unknown type>"
×
71
        }
72
}
73

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

87
        // RHash is the payment hash for this HTLC. The HTLC can be settled iff
88
        // the preimage to this hash is presented.
89
        RHash PaymentHash
90

91
        // RPreimage is the preimage that settles the HTLC pointed to within the
92
        // log by the ParentIndex.
93
        RPreimage PaymentHash
94

95
        // Timeout is the absolute timeout in blocks, after which this HTLC
96
        // expires.
97
        Timeout uint32
98

99
        // Amount is the HTLC amount in milli-satoshis.
100
        Amount lnwire.MilliSatoshi
101

102
        // LogIndex is the log entry number that his HTLC update has within the
103
        // log. Depending on if IsIncoming is true, this is either an entry the
104
        // remote party added, or one that we added locally.
105
        LogIndex uint64
106

107
        // HtlcIndex is the index within the main update log for this HTLC.
108
        // Entries within the log of type Add will have this field populated,
109
        // as other entries will point to the entry via this counter.
110
        //
111
        // NOTE: This field will only be populate if EntryType is Add.
112
        HtlcIndex uint64
113

114
        // ParentIndex is the HTLC index of the entry that this update settles
115
        // or times out.
116
        //
117
        // NOTE: This field will only be populate if EntryType is Fail or
118
        // Settle.
119
        ParentIndex uint64
120

121
        // SourceRef points to an Add update in a forwarding package owned by
122
        // this channel.
123
        //
124
        // NOTE: This field will only be populated if EntryType is Fail or
125
        // Settle.
126
        SourceRef *channeldb.AddRef
127

128
        // DestRef points to a Fail/Settle update in another link's forwarding
129
        // package.
130
        //
131
        // NOTE: This field will only be populated if EntryType is Fail or
132
        // Settle, and the forwarded Add successfully included in an outgoing
133
        // link's commitment txn.
134
        DestRef *channeldb.SettleFailRef
135

136
        // OpenCircuitKey references the incoming Chan/HTLC ID of an Add HTLC
137
        // packet delivered by the switch.
138
        //
139
        // NOTE: This field is only populated for payment descriptors in the
140
        // *local* update log, and if the Add packet was delivered by the
141
        // switch.
142
        OpenCircuitKey *models.CircuitKey
143

144
        // ClosedCircuitKey references the incoming Chan/HTLC ID of the Add HTLC
145
        // that opened the circuit.
146
        //
147
        // NOTE: This field is only populated for payment descriptors in the
148
        // *local* update log, and if settle/fails have a committed circuit in
149
        // the circuit map.
150
        ClosedCircuitKey *models.CircuitKey
151

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

159
        // remoteOutputIndex is the output index of this HTLC output in the
160
        // commitment transaction of the remote node.
161
        //
162
        // NOTE: If the output is dust from the PoV of the remote commitment
163
        // chain, then this value will be -1.
164
        remoteOutputIndex int32
165

166
        // sig is the signature for the second-level HTLC transaction that
167
        // spends the version of this HTLC on the commitment transaction of the
168
        // local node. This signature is generated by the remote node and
169
        // stored by the local node in the case that local node needs to
170
        // broadcast their commitment transaction.
171
        sig input.Signature
172

173
        // addCommitHeight[Remote|Local] encodes the height of the commitment
174
        // which included this HTLC on either the remote or local commitment
175
        // chain. This value is used to determine when an HTLC is fully
176
        // "locked-in".
177
        addCommitHeights lntypes.Dual[uint64]
178

179
        // removeCommitHeight[Remote|Local] encodes the height of the
180
        // commitment which removed the parent pointer of this
181
        // paymentDescriptor either due to a timeout or a settle. Once both
182
        // these heights are below the tail of both chains, the log entries can
183
        // safely be removed.
184
        removeCommitHeights lntypes.Dual[uint64]
185

186
        // OnionBlob is an opaque blob which is used to complete multi-hop
187
        // routing.
188
        //
189
        // NOTE: Populated only on add payment descriptor entry types.
190
        OnionBlob [lnwire.OnionPacketSize]byte
191

192
        // ShaOnionBlob is a sha of the onion blob.
193
        //
194
        // NOTE: Populated only in payment descriptor with MalformedFail type.
195
        ShaOnionBlob [sha256.Size]byte
196

197
        // FailReason stores the reason why a particular payment was canceled.
198
        //
199
        // NOTE: Populate only in fail payment descriptor entry types.
200
        FailReason []byte
201

202
        // FailCode stores the code why a particular payment was canceled.
203
        //
204
        // NOTE: Populated only in payment descriptor with MalformedFail type.
205
        FailCode lnwire.FailCode
206

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

222
        // EntryType denotes the exact type of the paymentDescriptor. In the
223
        // case of a Timeout, or Settle type, then the Parent field will point
224
        // into the log to the HTLC being modified.
225
        EntryType updateType
226

227
        // isForwarded denotes if an incoming HTLC has been forwarded to any
228
        // possible upstream peers in the route.
229
        isForwarded bool
230

231
        // BlindingPoint is an optional ephemeral key used in route blinding.
232
        // This value is set for nodes that are relaying payments inside of a
233
        // blinded route (ie, not the introduction node) from update_add_htlc's
234
        // TLVs.
235
        BlindingPoint lnwire.BlindingPointRecord
236

237
        // CustomRecords also stores the set of optional custom records that
238
        // may have been attached to a sent HTLC.
239
        CustomRecords lnwire.CustomRecords
240
}
241

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

289
        return channeldb.LogUpdate{
3✔
290
                LogIndex:  pd.LogIndex,
3✔
291
                UpdateMsg: msg,
3✔
292
        }
3✔
293
}
294

295
// setCommitHeight updates the appropriate addCommitHeight and/or
296
// removeCommitHeight for whoseCommitChain and locks it in at nextHeight.
297
func (pd *paymentDescriptor) setCommitHeight(
298
        whoseCommitChain lntypes.ChannelParty, nextHeight uint64) {
3✔
299

3✔
300
        switch pd.EntryType {
3✔
301
        case Add, NoOpAdd:
3✔
302
                pd.addCommitHeights.SetForParty(
3✔
303
                        whoseCommitChain, nextHeight,
3✔
304
                )
3✔
305
        case Settle, Fail, MalformedFail:
3✔
306
                pd.removeCommitHeights.SetForParty(
3✔
307
                        whoseCommitChain, nextHeight,
3✔
308
                )
3✔
309
        case FeeUpdate:
×
310
                // Fee updates are applied for all commitments
×
311
                // after they are sent/received, so we consider
×
312
                // them being added and removed at the same
×
313
                // height.
×
314
                pd.addCommitHeights.SetForParty(
×
315
                        whoseCommitChain, nextHeight,
×
316
                )
×
317
                pd.removeCommitHeights.SetForParty(
×
318
                        whoseCommitChain, nextHeight,
×
319
                )
×
320
        }
321
}
322

323
// isAdd returns true if the paymentDescriptor is of type Add.
324
func (pd *paymentDescriptor) isAdd() bool {
3✔
325
        return pd.EntryType == Add || pd.EntryType == NoOpAdd
3✔
326
}
3✔
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