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

lightningnetwork / lnd / 11166428937

03 Oct 2024 05:07PM UTC coverage: 58.738% (-0.08%) from 58.817%
11166428937

push

github

web-flow
Merge pull request #8960 from lightningnetwork/0-19-staging-rebased

[custom channels 5/5]: merge custom channel staging branch into master

657 of 875 new or added lines in 29 files covered. (75.09%)

260 existing lines in 20 files now uncovered.

130540 of 222243 relevant lines covered (58.74%)

28084.43 hits per line

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

56.03
/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) {
130✔
28

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

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

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

26✔
43
                return desiredChanType, commitType, err
26✔
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:
6✔
49
                defaultChanType, commitType := implicitNegotiateCommitmentType(
6✔
50
                        local, remote,
6✔
51
                )
6✔
52

6✔
53
                return defaultChanType, commitType, nil
6✔
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) {
26✔
84

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

26✔
87
        switch {
26✔
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
        ):
5✔
136
                if !hasFeatures(
5✔
137
                        local, remote,
5✔
138
                        lnwire.ZeroConfOptional,
5✔
139
                        lnwire.ScriptEnforcedLeaseOptional,
5✔
140
                        lnwire.AnchorsZeroFeeHtlcTxOptional,
5✔
141
                        lnwire.StaticRemoteKeyOptional,
5✔
142
                ) {
5✔
143

×
144
                        return 0, errUnsupportedChannelType
×
145
                }
×
146
                return lnwallet.CommitmentTypeScriptEnforcedLease, nil
5✔
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
        ):
7✔
154
                if !hasFeatures(
7✔
155
                        local, remote,
7✔
156
                        lnwire.ZeroConfOptional,
7✔
157
                        lnwire.AnchorsZeroFeeHtlcTxOptional,
7✔
158
                        lnwire.StaticRemoteKeyOptional,
7✔
159
                ) {
7✔
160

×
161
                        return 0, errUnsupportedChannelType
×
162
                }
×
163
                return lnwallet.CommitmentTypeAnchorsZeroFeeHtlcTx, nil
7✔
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
        ):
5✔
192
                if !hasFeatures(
5✔
193
                        local, remote,
5✔
194
                        lnwire.ScidAliasOptional,
5✔
195
                        lnwire.AnchorsZeroFeeHtlcTxOptional,
5✔
196
                        lnwire.StaticRemoteKeyOptional,
5✔
197
                ) {
5✔
198

×
199
                        return 0, errUnsupportedChannelType
×
200
                }
×
201
                return lnwallet.CommitmentTypeAnchorsZeroFeeHtlcTx, nil
5✔
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,
209
        ):
3✔
210
                if !hasFeatures(
3✔
211
                        local, remote,
3✔
212
                        lnwire.ScriptEnforcedLeaseOptional,
3✔
213
                        lnwire.AnchorsZeroFeeHtlcTxOptional,
3✔
214
                        lnwire.StaticRemoteKeyOptional,
3✔
215
                ) {
3✔
216

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

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

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

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

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

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

3✔
253
                        return 0, errUnsupportedChannelType
3✔
254
                }
3✔
255

256
                return lnwallet.CommitmentTypeSimpleTaproot, nil
5✔
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
        ):
5✔
280

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

×
287
                        return 0, errUnsupportedChannelType
×
288
                }
×
289

290
                return lnwallet.CommitmentTypeSimpleTaproot, nil
5✔
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,
NEW
313
        ):
×
NEW
314

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

×
NEW
320
                        return 0, errUnsupportedChannelType
×
NEW
321
                }
×
322

NEW
323
                return lnwallet.CommitmentTypeSimpleTaprootOverlay, nil
×
324

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

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

×
NEW
337
                        return 0, errUnsupportedChannelType
×
NEW
338
                }
×
339

NEW
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,
NEW
346
        ):
×
NEW
347

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

×
NEW
354
                        return 0, errUnsupportedChannelType
×
NEW
355
                }
×
356

NEW
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,
NEW
364
        ):
×
NEW
365

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

×
NEW
373
                        return 0, errUnsupportedChannelType
×
NEW
374
                }
×
375

NEW
376
                return lnwallet.CommitmentTypeSimpleTaprootOverlay, nil
×
377

378
        // No features, use legacy commitment type.
379
        case channelFeatures.IsEmpty():
5✔
380
                return lnwallet.CommitmentTypeLegacy, nil
5✔
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) {
107✔
393

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

8✔
402
                return &chanType, lnwallet.CommitmentTypeAnchorsZeroFeeHtlcTx
8✔
403
        }
8✔
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) {
107✔
412
                chanType := lnwire.ChannelType(*lnwire.NewRawFeatureVector(
5✔
413
                        lnwire.StaticRemoteKeyRequired,
5✔
414
                ))
5✔
415

5✔
416
                return &chanType, lnwallet.CommitmentTypeTweakless
5✔
417
        }
5✔
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 {
457✔
428

457✔
429
        for _, feature := range features {
943✔
430
                if !local.HasFeature(feature) || !remote.HasFeature(feature) {
885✔
431
                        return false
399✔
432
                }
399✔
433
        }
434
        return true
61✔
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