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

lightningnetwork / lnd / 16802564426

07 Aug 2025 10:58AM UTC coverage: 57.437% (-9.5%) from 66.938%
16802564426

Pull #9871

github

web-flow
Merge 0e84b7dbb into 8a2128ba4
Pull Request #9871: Add `NoopAdd` HTLCs

48 of 147 new or added lines in 3 files covered. (32.65%)

28319 existing lines in 455 files now uncovered.

99037 of 172428 relevant lines covered (57.44%)

1.78 hits per line

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

42.67
/lnwallet/aux_signer.go
1
package lnwallet
2

3
import (
4
        "github.com/btcsuite/btcd/wire"
5
        "github.com/lightningnetwork/lnd/fn/v2"
6
        "github.com/lightningnetwork/lnd/input"
7
        "github.com/lightningnetwork/lnd/lntypes"
8
        "github.com/lightningnetwork/lnd/lnwallet/chainfee"
9
        "github.com/lightningnetwork/lnd/lnwire"
10
        "github.com/lightningnetwork/lnd/tlv"
11
)
12

13
var (
14
        // htlcCustomSigType is the TLV type that is used to encode the custom
15
        // HTLC signatures within the custom data for an existing HTLC.
16
        htlcCustomSigType tlv.TlvType65543
17

18
        // NoOpHtlcTLVEntry is the TLV that that's used in the update_add_htlc
19
        // message to indicate the presence of a noop HTLC. This has no encoded
20
        // value, its presence is used to indicate that the HTLC is a noop.
21
        NoOpHtlcTLVEntry tlv.TlvType65544
22
)
23

24
// NoOpHtlcTLVType is the (golang) type of the TLV record that's used to signal
25
// that an HTLC should be a noop HTLC.
26
type NoOpHtlcTLVType = tlv.TlvType65544
27

28
// AuxHtlcView is a struct that contains a safe copy of an HTLC view that can
29
// be used by aux components.
30
type AuxHtlcView struct {
31
        // NextHeight is the height of the commitment transaction that will be
32
        // created using this view.
33
        NextHeight uint64
34

35
        // Updates is a Dual of the Local and Remote HTLCs.
36
        Updates lntypes.Dual[[]AuxHtlcDescriptor]
37

38
        // FeePerKw is the fee rate in sat/kw of the commitment transaction.
39
        FeePerKw chainfee.SatPerKWeight
40
}
41

42
// newAuxHtlcView creates a new safe copy of the HTLC view that can be used by
43
// aux components.
44
//
45
// NOTE: This function should only be called while holding the channel's read
46
// lock, since the underlying local/remote payment descriptors are accessed
47
// directly.
48
func newAuxHtlcView(v *HtlcView) AuxHtlcView {
×
49
        return AuxHtlcView{
×
50
                NextHeight: v.NextHeight,
×
51
                Updates: lntypes.Dual[[]AuxHtlcDescriptor]{
×
52
                        Local:  fn.Map(v.Updates.Local, newAuxHtlcDescriptor),
×
53
                        Remote: fn.Map(v.Updates.Remote, newAuxHtlcDescriptor),
×
54
                },
×
55
                FeePerKw: v.FeePerKw,
×
56
        }
×
57
}
×
58

59
// AuxHtlcDescriptor is a struct that contains the information needed to sign or
60
// verify an HTLC for custom channels.
61
type AuxHtlcDescriptor struct {
62
        // ChanID is the ChannelID of the LightningChannel that this
63
        // paymentDescriptor belongs to. We track this here so we can
64
        // reconstruct the Messages that this paymentDescriptor is built from.
65
        ChanID lnwire.ChannelID
66

67
        // RHash is the payment hash for this HTLC. The HTLC can be settled iff
68
        // the preimage to this hash is presented.
69
        RHash PaymentHash
70

71
        // Timeout is the absolute timeout in blocks, after which this HTLC
72
        // expires.
73
        Timeout uint32
74

75
        // Amount is the HTLC amount in milli-satoshis.
76
        Amount lnwire.MilliSatoshi
77

78
        // HtlcIndex is the index within the main update log for this HTLC.
79
        // Entries within the log of type Add will have this field populated,
80
        // as other entries will point to the entry via this counter.
81
        //
82
        // NOTE: This field will only be populated if EntryType is Add.
83
        HtlcIndex uint64
84

85
        // ParentIndex is the HTLC index of the entry that this update settles
86
        // or times out.
87
        //
88
        // NOTE: This field will only be populated if EntryType is Fail or
89
        // Settle.
90
        ParentIndex uint64
91

92
        // EntryType denotes the exact type of the paymentDescriptor. In the
93
        // case of a Timeout, or Settle type, then the Parent field will point
94
        // into the log to the HTLC being modified.
95
        EntryType updateType
96

97
        // CustomRecords also stores the set of optional custom records that
98
        // may have been attached to a sent HTLC.
99
        CustomRecords lnwire.CustomRecords
100

101
        // addCommitHeight[Remote|Local] encodes the height of the commitment
102
        // which included this HTLC on either the remote or local commitment
103
        // chain. This value is used to determine when an HTLC is fully
104
        // "locked-in".
105
        addCommitHeightRemote uint64
106
        addCommitHeightLocal  uint64
107

108
        // removeCommitHeight[Remote|Local] encodes the height of the
109
        // commitment which removed the parent pointer of this
110
        // paymentDescriptor either due to a timeout or a settle. Once both
111
        // these heights are below the tail of both chains, the log entries can
112
        // safely be removed.
113
        removeCommitHeightRemote uint64
114
        removeCommitHeightLocal  uint64
115
}
116

117
// AddHeight returns the height at which the HTLC was added to the commitment
118
// chain. The height is returned based on the chain the HTLC is being added to
119
// (local or remote chain).
120
func (a *AuxHtlcDescriptor) AddHeight(
121
        whoseCommitChain lntypes.ChannelParty) uint64 {
×
122

×
123
        if whoseCommitChain.IsRemote() {
×
124
                return a.addCommitHeightRemote
×
125
        }
×
126

127
        return a.addCommitHeightLocal
×
128
}
129

130
// IsAdd checks if the entry type of the Aux HTLC Descriptor is an add type.
NEW
131
func (a *AuxHtlcDescriptor) IsAdd() bool {
×
NEW
132
        switch a.EntryType {
×
NEW
133
        case Add:
×
NEW
134
                fallthrough
×
NEW
135
        case NoOpAdd:
×
NEW
136
                return true
×
NEW
137
        default:
×
NEW
138
                return false
×
139
        }
140
}
141

142
// RemoveHeight returns the height at which the HTLC was removed from the
143
// commitment chain. The height is returned based on the chain the HTLC is being
144
// removed from (local or remote chain).
145
func (a *AuxHtlcDescriptor) RemoveHeight(
146
        whoseCommitChain lntypes.ChannelParty) uint64 {
×
147

×
148
        if whoseCommitChain.IsRemote() {
×
149
                return a.removeCommitHeightRemote
×
150
        }
×
151

152
        return a.removeCommitHeightLocal
×
153
}
154

155
// newAuxHtlcDescriptor creates a new AuxHtlcDescriptor from a payment
156
// descriptor.
157
//
158
// NOTE: This function should only be called while holding the channel's read
159
// lock, since the underlying payment descriptors are accessed directly.
160
func newAuxHtlcDescriptor(p *paymentDescriptor) AuxHtlcDescriptor {
3✔
161
        return AuxHtlcDescriptor{
3✔
162
                ChanID:                   p.ChanID,
3✔
163
                RHash:                    p.RHash,
3✔
164
                Timeout:                  p.Timeout,
3✔
165
                Amount:                   p.Amount,
3✔
166
                HtlcIndex:                p.HtlcIndex,
3✔
167
                ParentIndex:              p.ParentIndex,
3✔
168
                EntryType:                p.EntryType,
3✔
169
                CustomRecords:            p.CustomRecords.Copy(),
3✔
170
                addCommitHeightRemote:    p.addCommitHeights.Remote,
3✔
171
                addCommitHeightLocal:     p.addCommitHeights.Local,
3✔
172
                removeCommitHeightRemote: p.removeCommitHeights.Remote,
3✔
173
                removeCommitHeightLocal:  p.removeCommitHeights.Local,
3✔
174
        }
3✔
175
}
3✔
176

177
// BaseAuxJob is a struct that contains the common fields that are shared among
178
// the aux sign/verify jobs.
179
type BaseAuxJob struct {
180
        // OutputIndex is the output index of the HTLC on the commitment
181
        // transaction being signed.
182
        //
183
        // NOTE: If the output is dust from the PoV of the commitment chain,
184
        // then this value will be -1.
185
        OutputIndex int32
186

187
        // KeyRing is the commitment key ring that contains the keys needed to
188
        // generate the second level HTLC signatures.
189
        KeyRing CommitmentKeyRing
190

191
        // HTLC is the HTLC that is being signed or verified.
192
        HTLC AuxHtlcDescriptor
193

194
        // Incoming is a boolean that indicates if the HTLC is incoming or
195
        // outgoing.
196
        Incoming bool
197

198
        // CommitBlob is the commitment transaction blob that contains the aux
199
        // information for this channel.
200
        CommitBlob fn.Option[tlv.Blob]
201

202
        // HtlcLeaf is the aux tap leaf that corresponds to the HTLC being
203
        // signed/verified.
204
        HtlcLeaf input.AuxTapLeaf
205
}
206

207
// AuxSigJob is a struct that contains all the information needed to sign an
208
// HTLC for custom channels.
209
type AuxSigJob struct {
210
        // SignDesc is the sign desc for this HTLC.
211
        SignDesc input.SignDescriptor
212

213
        BaseAuxJob
214

215
        // Resp is a channel that will be used to send the result of the sign
216
        // job. This channel MUST be buffered.
217
        Resp chan AuxSigJobResp
218

219
        // Cancel is a channel that is closed by the caller if they wish to
220
        // abandon all pending sign jobs part of a single batch. This should
221
        // never be closed by the validator.
222
        Cancel <-chan struct{}
223
}
224

225
// NewAuxSigJob creates a new AuxSigJob.
226
func NewAuxSigJob(sigJob SignJob, keyRing CommitmentKeyRing, incoming bool,
227
        htlc AuxHtlcDescriptor, commitBlob fn.Option[tlv.Blob],
228
        htlcLeaf input.AuxTapLeaf, cancelChan <-chan struct{}) AuxSigJob {
3✔
229

3✔
230
        return AuxSigJob{
3✔
231
                SignDesc: sigJob.SignDesc,
3✔
232
                BaseAuxJob: BaseAuxJob{
3✔
233
                        OutputIndex: sigJob.OutputIndex,
3✔
234
                        KeyRing:     keyRing,
3✔
235
                        HTLC:        htlc,
3✔
236
                        Incoming:    incoming,
3✔
237
                        CommitBlob:  commitBlob,
3✔
238
                        HtlcLeaf:    htlcLeaf,
3✔
239
                },
3✔
240
                Resp:   make(chan AuxSigJobResp, 1),
3✔
241
                Cancel: cancelChan,
3✔
242
        }
3✔
243
}
3✔
244

245
// AuxSigJobResp is a struct that contains the result of a sign job.
246
type AuxSigJobResp struct {
247
        // SigBlob is the signature blob that was generated for the HTLC. This
248
        // is an opaque TLV field that may contain the signature and other data.
249
        SigBlob fn.Option[tlv.Blob]
250

251
        // HtlcIndex is the index of the HTLC that was signed.
252
        HtlcIndex uint64
253

254
        // Err is the error that occurred when executing the specified
255
        // signature job. In the case that no error occurred, this value will
256
        // be nil.
257
        Err error
258
}
259

260
// AuxVerifyJob is a struct that contains all the information needed to verify
261
// an HTLC for custom channels.
262
type AuxVerifyJob struct {
263
        // SigBlob is the signature blob that was generated for the HTLC. This
264
        // is an opaque TLV field that may contain the signature and other data.
265
        SigBlob fn.Option[tlv.Blob]
266

267
        BaseAuxJob
268
}
269

270
// NewAuxVerifyJob creates a new AuxVerifyJob.
271
func NewAuxVerifyJob(sig fn.Option[tlv.Blob], keyRing CommitmentKeyRing,
272
        incoming bool, htlc AuxHtlcDescriptor, commitBlob fn.Option[tlv.Blob],
UNCOV
273
        htlcLeaf input.AuxTapLeaf) AuxVerifyJob {
×
UNCOV
274

×
UNCOV
275
        return AuxVerifyJob{
×
UNCOV
276
                SigBlob: sig,
×
UNCOV
277
                BaseAuxJob: BaseAuxJob{
×
UNCOV
278
                        KeyRing:    keyRing,
×
UNCOV
279
                        HTLC:       htlc,
×
UNCOV
280
                        Incoming:   incoming,
×
UNCOV
281
                        CommitBlob: commitBlob,
×
UNCOV
282
                        HtlcLeaf:   htlcLeaf,
×
UNCOV
283
                },
×
UNCOV
284
        }
×
UNCOV
285
}
×
286

287
// AuxSigner is an interface that is used to sign and verify HTLCs for custom
288
// channels. It is similar to the existing SigPool, but uses opaque blobs to
289
// shuffle around signature information and other metadata.
290
type AuxSigner interface {
291
        // SubmitSecondLevelSigBatch takes a batch of aux sign jobs and
292
        // processes them asynchronously.
293
        SubmitSecondLevelSigBatch(chanState AuxChanState, commitTx *wire.MsgTx,
294
                sigJob []AuxSigJob) error
295

296
        // PackSigs takes a series of aux signatures and packs them into a
297
        // single blob that can be sent alongside the CommitSig messages.
298
        PackSigs([]fn.Option[tlv.Blob]) fn.Result[fn.Option[tlv.Blob]]
299

300
        // UnpackSigs takes a packed blob of signatures and returns the
301
        // original signatures for each HTLC, keyed by HTLC index.
302
        UnpackSigs(fn.Option[tlv.Blob]) fn.Result[[]fn.Option[tlv.Blob]]
303

304
        // VerifySecondLevelSigs attempts to synchronously verify a batch of aux
305
        // sig jobs.
306
        VerifySecondLevelSigs(chanState AuxChanState, commitTx *wire.MsgTx,
307
                verifyJob []AuxVerifyJob) error
308
}
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