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

lightningnetwork / lnd / 13236757158

10 Feb 2025 08:39AM UTC coverage: 57.649% (-1.2%) from 58.815%
13236757158

Pull #9493

github

ziggie1984
lncli: for some cmds we don't replace the data of the response.

For some cmds it is not very practical to replace the json output
because we might pipe it into other commands. For example when
creating the route we want to pipe it into sendtoRoute.
Pull Request #9493: For some lncli cmds we should not replace the content with other data

0 of 9 new or added lines in 2 files covered. (0.0%)

19535 existing lines in 252 files now uncovered.

103517 of 179563 relevant lines covered (57.65%)

24878.49 hits per line

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

51.75
/funding/commitment_type_negotiation.go
1
package funding
2

3
import (
4
        "errors"
5

6
        "github.com/lightningnetwork/lnd/lnwallet"
7
        "github.com/lightningnetwork/lnd/lnwire"
8
)
9

10
var (
11
        // errUnsupportedCommitmentType is an error returned when a specific
12
        // channel commitment type is being explicitly negotiated but either
13
        // peer of the channel does not support it.
14
        errUnsupportedChannelType = errors.New("requested channel type " +
15
                "not supported")
16
)
17

18
// negotiateCommitmentType negotiates the commitment type of a newly opened
19
// channel. If a desiredChanType is provided, explicit negotiation for said type
20
// will be attempted if the set of both local and remote features support it.
21
// Otherwise, implicit negotiation will be attempted.
22
//
23
// The returned ChannelType is nil when implicit negotiation is used. An error
24
// is only returned if desiredChanType is not supported.
25
func negotiateCommitmentType(desiredChanType *lnwire.ChannelType, local,
26
        remote *lnwire.FeatureVector) (*lnwire.ChannelType,
27
        lnwallet.CommitmentType, error) {
127✔
28

127✔
29
        // BOLT#2 specifies we MUST use explicit negotiation if both peers
127✔
30
        // signal for it.
127✔
31
        explicitNegotiation := hasFeatures(
127✔
32
                local, remote, lnwire.ExplicitChannelTypeOptional,
127✔
33
        )
127✔
34

127✔
35
        chanTypeRequested := desiredChanType != nil
127✔
36

127✔
37
        switch {
127✔
38
        case explicitNegotiation && chanTypeRequested:
23✔
39
                commitType, err := explicitNegotiateCommitmentType(
23✔
40
                        *desiredChanType, local, remote,
23✔
41
                )
23✔
42

23✔
43
                return desiredChanType, commitType, err
23✔
44

45
        // We don't have a specific channel type requested, so we select a
46
        // default type as if implicit negotiation were used, and then we
47
        // explicitly signal that default type.
48
        case explicitNegotiation && !chanTypeRequested:
3✔
49
                defaultChanType, commitType := implicitNegotiateCommitmentType(
3✔
50
                        local, remote,
3✔
51
                )
3✔
52

3✔
53
                return defaultChanType, commitType, nil
3✔
54

55
        // A specific channel type was requested, but we can't explicitly signal
56
        // it. So if implicit negotiation wouldn't select the desired channel
57
        // type, we must return an error.
58
        case !explicitNegotiation && chanTypeRequested:
2✔
59
                implicitChanType, commitType := implicitNegotiateCommitmentType(
2✔
60
                        local, remote,
2✔
61
                )
2✔
62

2✔
63
                expected := lnwire.RawFeatureVector(*desiredChanType)
2✔
64
                actual := lnwire.RawFeatureVector(*implicitChanType)
2✔
65
                if !expected.Equals(&actual) {
2✔
66
                        return nil, 0, errUnsupportedChannelType
×
67
                }
×
68

69
                return nil, commitType, nil
2✔
70

71
        default: // !explicitNegotiation && !chanTypeRequested
99✔
72
                _, commitType := implicitNegotiateCommitmentType(local, remote)
99✔
73

99✔
74
                return nil, commitType, nil
99✔
75
        }
76
}
77

78
// explicitNegotiateCommitmentType attempts to explicitly negotiate for a
79
// specific channel type. Since the channel type is comprised of a set of even
80
// feature bits, we also make sure each feature is supported by both peers. An
81
// error is returned if either peer does not support said channel type.
82
func explicitNegotiateCommitmentType(channelType lnwire.ChannelType, local,
83
        remote *lnwire.FeatureVector) (lnwallet.CommitmentType, error) {
23✔
84

23✔
85
        channelFeatures := lnwire.RawFeatureVector(channelType)
23✔
86

23✔
87
        switch {
23✔
88
        // Lease script enforcement + anchors zero fee + static remote key +
89
        // zero conf + scid alias features only.
90
        case channelFeatures.OnlyContains(
91
                lnwire.ZeroConfRequired,
92
                lnwire.ScidAliasRequired,
93
                lnwire.ScriptEnforcedLeaseRequired,
94
                lnwire.AnchorsZeroFeeHtlcTxRequired,
95
                lnwire.StaticRemoteKeyRequired,
96
        ):
×
97
                if !hasFeatures(
×
98
                        local, remote,
×
99
                        lnwire.ZeroConfOptional,
×
100
                        lnwire.ScriptEnforcedLeaseOptional,
×
101
                        lnwire.AnchorsZeroFeeHtlcTxOptional,
×
102
                        lnwire.StaticRemoteKeyOptional,
×
103
                ) {
×
104

×
105
                        return 0, errUnsupportedChannelType
×
106
                }
×
107
                return lnwallet.CommitmentTypeScriptEnforcedLease, nil
×
108

109
        // Anchors zero fee + static remote key + zero conf + scid alias
110
        // features only.
111
        case channelFeatures.OnlyContains(
112
                lnwire.ZeroConfRequired,
113
                lnwire.ScidAliasRequired,
114
                lnwire.AnchorsZeroFeeHtlcTxRequired,
115
                lnwire.StaticRemoteKeyRequired,
116
        ):
×
117
                if !hasFeatures(
×
118
                        local, remote,
×
119
                        lnwire.ZeroConfOptional,
×
120
                        lnwire.AnchorsZeroFeeHtlcTxOptional,
×
121
                        lnwire.StaticRemoteKeyOptional,
×
122
                ) {
×
123

×
124
                        return 0, errUnsupportedChannelType
×
125
                }
×
126
                return lnwallet.CommitmentTypeAnchorsZeroFeeHtlcTx, nil
×
127

128
        // Lease script enforcement + anchors zero fee + static remote key +
129
        // zero conf features only.
130
        case channelFeatures.OnlyContains(
131
                lnwire.ZeroConfRequired,
132
                lnwire.ScriptEnforcedLeaseRequired,
133
                lnwire.AnchorsZeroFeeHtlcTxRequired,
134
                lnwire.StaticRemoteKeyRequired,
135
        ):
2✔
136
                if !hasFeatures(
2✔
137
                        local, remote,
2✔
138
                        lnwire.ZeroConfOptional,
2✔
139
                        lnwire.ScriptEnforcedLeaseOptional,
2✔
140
                        lnwire.AnchorsZeroFeeHtlcTxOptional,
2✔
141
                        lnwire.StaticRemoteKeyOptional,
2✔
142
                ) {
2✔
143

×
144
                        return 0, errUnsupportedChannelType
×
145
                }
×
146
                return lnwallet.CommitmentTypeScriptEnforcedLease, nil
2✔
147

148
        // Anchors zero fee + static remote key + zero conf features only.
149
        case channelFeatures.OnlyContains(
150
                lnwire.ZeroConfRequired,
151
                lnwire.AnchorsZeroFeeHtlcTxRequired,
152
                lnwire.StaticRemoteKeyRequired,
153
        ):
4✔
154
                if !hasFeatures(
4✔
155
                        local, remote,
4✔
156
                        lnwire.ZeroConfOptional,
4✔
157
                        lnwire.AnchorsZeroFeeHtlcTxOptional,
4✔
158
                        lnwire.StaticRemoteKeyOptional,
4✔
159
                ) {
4✔
160

×
161
                        return 0, errUnsupportedChannelType
×
162
                }
×
163
                return lnwallet.CommitmentTypeAnchorsZeroFeeHtlcTx, nil
4✔
164

165
        // Lease script enforcement + anchors zero fee + static remote key +
166
        // option-scid-alias features only.
167
        case channelFeatures.OnlyContains(
168
                lnwire.ScidAliasRequired,
169
                lnwire.ScriptEnforcedLeaseRequired,
170
                lnwire.AnchorsZeroFeeHtlcTxRequired,
171
                lnwire.StaticRemoteKeyRequired,
172
        ):
2✔
173
                if !hasFeatures(
2✔
174
                        local, remote,
2✔
175
                        lnwire.ScidAliasOptional,
2✔
176
                        lnwire.ScriptEnforcedLeaseOptional,
2✔
177
                        lnwire.AnchorsZeroFeeHtlcTxOptional,
2✔
178
                        lnwire.StaticRemoteKeyOptional,
2✔
179
                ) {
2✔
180

×
181
                        return 0, errUnsupportedChannelType
×
182
                }
×
183
                return lnwallet.CommitmentTypeScriptEnforcedLease, nil
2✔
184

185
        // Anchors zero fee + static remote key + option-scid-alias features
186
        // only.
187
        case channelFeatures.OnlyContains(
188
                lnwire.ScidAliasRequired,
189
                lnwire.AnchorsZeroFeeHtlcTxRequired,
190
                lnwire.StaticRemoteKeyRequired,
191
        ):
2✔
192
                if !hasFeatures(
2✔
193
                        local, remote,
2✔
194
                        lnwire.ScidAliasOptional,
2✔
195
                        lnwire.AnchorsZeroFeeHtlcTxOptional,
2✔
196
                        lnwire.StaticRemoteKeyOptional,
2✔
197
                ) {
2✔
198

×
199
                        return 0, errUnsupportedChannelType
×
200
                }
×
201
                return lnwallet.CommitmentTypeAnchorsZeroFeeHtlcTx, nil
2✔
202

203
        // Lease script enforcement + anchors zero fee + static remote key
204
        // features only.
205
        case channelFeatures.OnlyContains(
206
                lnwire.ScriptEnforcedLeaseRequired,
207
                lnwire.AnchorsZeroFeeHtlcTxRequired,
208
                lnwire.StaticRemoteKeyRequired,
UNCOV
209
        ):
×
UNCOV
210
                if !hasFeatures(
×
UNCOV
211
                        local, remote,
×
UNCOV
212
                        lnwire.ScriptEnforcedLeaseOptional,
×
UNCOV
213
                        lnwire.AnchorsZeroFeeHtlcTxOptional,
×
UNCOV
214
                        lnwire.StaticRemoteKeyOptional,
×
UNCOV
215
                ) {
×
216

×
217
                        return 0, errUnsupportedChannelType
×
218
                }
×
UNCOV
219
                return lnwallet.CommitmentTypeScriptEnforcedLease, nil
×
220

221
        // Anchors zero fee + static remote key features only.
222
        case channelFeatures.OnlyContains(
223
                lnwire.AnchorsZeroFeeHtlcTxRequired,
224
                lnwire.StaticRemoteKeyRequired,
225
        ):
5✔
226
                if !hasFeatures(
5✔
227
                        local, remote,
5✔
228
                        lnwire.AnchorsZeroFeeHtlcTxOptional,
5✔
229
                        lnwire.StaticRemoteKeyOptional,
5✔
230
                ) {
7✔
231

2✔
232
                        return 0, errUnsupportedChannelType
2✔
233
                }
2✔
234
                return lnwallet.CommitmentTypeAnchorsZeroFeeHtlcTx, nil
3✔
235

236
        // Static remote key feature only.
237
        case channelFeatures.OnlyContains(lnwire.StaticRemoteKeyRequired):
2✔
238
                if !hasFeatures(local, remote, lnwire.StaticRemoteKeyOptional) {
2✔
239
                        return 0, errUnsupportedChannelType
×
240
                }
×
241
                return lnwallet.CommitmentTypeTweakless, nil
2✔
242

243
        // Simple taproot channels only.
244
        case channelFeatures.OnlyContains(
245
                lnwire.SimpleTaprootChannelsRequiredStaging,
246
        ):
2✔
247

2✔
248
                if !hasFeatures(
2✔
249
                        local, remote,
2✔
250
                        lnwire.SimpleTaprootChannelsOptionalStaging,
2✔
251
                ) {
2✔
UNCOV
252

×
UNCOV
253
                        return 0, errUnsupportedChannelType
×
UNCOV
254
                }
×
255

256
                return lnwallet.CommitmentTypeSimpleTaproot, nil
2✔
257

258
        // Simple taproot channels with scid only.
259
        case channelFeatures.OnlyContains(
260
                lnwire.SimpleTaprootChannelsRequiredStaging,
261
                lnwire.ScidAliasRequired,
262
        ):
×
263

×
264
                if !hasFeatures(
×
265
                        local, remote,
×
266
                        lnwire.SimpleTaprootChannelsOptionalStaging,
×
267
                        lnwire.ScidAliasOptional,
×
268
                ) {
×
269

×
270
                        return 0, errUnsupportedChannelType
×
271
                }
×
272

273
                return lnwallet.CommitmentTypeSimpleTaproot, nil
×
274

275
        // Simple taproot channels with zero conf only.
276
        case channelFeatures.OnlyContains(
277
                lnwire.SimpleTaprootChannelsRequiredStaging,
278
                lnwire.ZeroConfRequired,
279
        ):
2✔
280

2✔
281
                if !hasFeatures(
2✔
282
                        local, remote,
2✔
283
                        lnwire.SimpleTaprootChannelsOptionalStaging,
2✔
284
                        lnwire.ZeroConfOptional,
2✔
285
                ) {
2✔
286

×
287
                        return 0, errUnsupportedChannelType
×
288
                }
×
289

290
                return lnwallet.CommitmentTypeSimpleTaproot, nil
2✔
291

292
        // Simple taproot channels with scid and zero conf.
293
        case channelFeatures.OnlyContains(
294
                lnwire.SimpleTaprootChannelsRequiredStaging,
295
                lnwire.ZeroConfRequired,
296
                lnwire.ScidAliasRequired,
297
        ):
×
298

×
299
                if !hasFeatures(
×
300
                        local, remote,
×
301
                        lnwire.SimpleTaprootChannelsOptionalStaging,
×
302
                        lnwire.ZeroConfOptional,
×
303
                ) {
×
304

×
305
                        return 0, errUnsupportedChannelType
×
306
                }
×
307

308
                return lnwallet.CommitmentTypeSimpleTaproot, nil
×
309

310
        // Simple taproot channels overlay only.
311
        case channelFeatures.OnlyContains(
312
                lnwire.SimpleTaprootOverlayChansRequired,
313
        ):
×
314

×
315
                if !hasFeatures(
×
316
                        local, remote,
×
317
                        lnwire.SimpleTaprootOverlayChansOptional,
×
318
                ) {
×
319

×
320
                        return 0, errUnsupportedChannelType
×
321
                }
×
322

323
                return lnwallet.CommitmentTypeSimpleTaprootOverlay, nil
×
324

325
        // Simple taproot overlay channels with scid only.
326
        case channelFeatures.OnlyContains(
327
                lnwire.SimpleTaprootOverlayChansRequired,
328
                lnwire.ScidAliasRequired,
329
        ):
×
330

×
331
                if !hasFeatures(
×
332
                        local, remote,
×
333
                        lnwire.SimpleTaprootOverlayChansOptional,
×
334
                        lnwire.ScidAliasOptional,
×
335
                ) {
×
336

×
337
                        return 0, errUnsupportedChannelType
×
338
                }
×
339

340
                return lnwallet.CommitmentTypeSimpleTaprootOverlay, nil
×
341

342
        // Simple taproot overlay channels with zero conf only.
343
        case channelFeatures.OnlyContains(
344
                lnwire.SimpleTaprootOverlayChansRequired,
345
                lnwire.ZeroConfRequired,
346
        ):
×
347

×
348
                if !hasFeatures(
×
349
                        local, remote,
×
350
                        lnwire.SimpleTaprootOverlayChansOptional,
×
351
                        lnwire.ZeroConfOptional,
×
352
                ) {
×
353

×
354
                        return 0, errUnsupportedChannelType
×
355
                }
×
356

357
                return lnwallet.CommitmentTypeSimpleTaprootOverlay, nil
×
358

359
        // Simple taproot overlay channels with scid and zero conf.
360
        case channelFeatures.OnlyContains(
361
                lnwire.SimpleTaprootOverlayChansRequired,
362
                lnwire.ZeroConfRequired,
363
                lnwire.ScidAliasRequired,
364
        ):
×
365

×
366
                if !hasFeatures(
×
367
                        local, remote,
×
368
                        lnwire.SimpleTaprootOverlayChansOptional,
×
369
                        lnwire.ZeroConfOptional,
×
370
                        lnwire.ScidAliasOptional,
×
371
                ) {
×
372

×
373
                        return 0, errUnsupportedChannelType
×
374
                }
×
375

376
                return lnwallet.CommitmentTypeSimpleTaprootOverlay, nil
×
377

378
        // No features, use legacy commitment type.
379
        case channelFeatures.IsEmpty():
2✔
380
                return lnwallet.CommitmentTypeLegacy, nil
2✔
381

382
        default:
×
383
                return 0, errUnsupportedChannelType
×
384
        }
385
}
386

387
// implicitNegotiateCommitmentType negotiates the commitment type of a channel
388
// implicitly by choosing the latest type supported by the local and remote
389
// features.
390
func implicitNegotiateCommitmentType(local,
391
        remote *lnwire.FeatureVector) (*lnwire.ChannelType,
392
        lnwallet.CommitmentType) {
104✔
393

104✔
394
        // If both peers are signalling support for anchor commitments with
104✔
395
        // zero-fee HTLC transactions, we'll use this type.
104✔
396
        if hasFeatures(local, remote, lnwire.AnchorsZeroFeeHtlcTxOptional) {
109✔
397
                chanType := lnwire.ChannelType(*lnwire.NewRawFeatureVector(
5✔
398
                        lnwire.AnchorsZeroFeeHtlcTxRequired,
5✔
399
                        lnwire.StaticRemoteKeyRequired,
5✔
400
                ))
5✔
401

5✔
402
                return &chanType, lnwallet.CommitmentTypeAnchorsZeroFeeHtlcTx
5✔
403
        }
5✔
404

405
        // Since we don't want to support the "legacy" anchor type, we will fall
406
        // back to static remote key if the nodes don't support the zero fee
407
        // HTLC tx anchor type.
408
        //
409
        // If both nodes are signaling the proper feature bit for tweakless
410
        // commitments, we'll use that.
411
        if hasFeatures(local, remote, lnwire.StaticRemoteKeyOptional) {
101✔
412
                chanType := lnwire.ChannelType(*lnwire.NewRawFeatureVector(
2✔
413
                        lnwire.StaticRemoteKeyRequired,
2✔
414
                ))
2✔
415

2✔
416
                return &chanType, lnwallet.CommitmentTypeTweakless
2✔
417
        }
2✔
418

419
        // Otherwise we'll fall back to the legacy type.
420
        chanType := lnwire.ChannelType(*lnwire.NewRawFeatureVector())
97✔
421
        return &chanType, lnwallet.CommitmentTypeLegacy
97✔
422
}
423

424
// hasFeatures determines whether a set of features is supported by both the set
425
// of local and remote features.
426
func hasFeatures(local, remote *lnwire.FeatureVector,
427
        features ...lnwire.FeatureBit) bool {
454✔
428

454✔
429
        for _, feature := range features {
937✔
430
                if !local.HasFeature(feature) || !remote.HasFeature(feature) {
879✔
431
                        return false
396✔
432
                }
396✔
433
        }
434
        return true
58✔
435
}
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