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

lightningnetwork / lnd / 13536249039

26 Feb 2025 03:42AM UTC coverage: 57.462% (-1.4%) from 58.835%
13536249039

Pull #8453

github

Roasbeef
peer: update chooseDeliveryScript to gen script if needed

In this commit, we update `chooseDeliveryScript` to generate a new
script if needed. This allows us to fold in a few other lines that
always followed this function into this expanded function.

The tests have been updated accordingly.
Pull Request #8453: [4/4] - multi: integrate new rbf coop close FSM into the existing peer flow

275 of 1318 new or added lines in 22 files covered. (20.86%)

19521 existing lines in 257 files now uncovered.

103858 of 180741 relevant lines covered (57.46%)

24750.23 hits per line

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

63.04
/feature/manager.go
1
package feature
2

3
import (
4
        "errors"
5
        "fmt"
6

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

10
var (
11
        // ErrUnknownSet is returned if a proposed feature vector contains a
12
        // set that is unknown to LND.
13
        ErrUnknownSet = errors.New("unknown feature bit set")
14

15
        // ErrFeatureConfigured is returned if an attempt is made to unset a
16
        // feature that was configured at startup.
17
        ErrFeatureConfigured = errors.New("can't unset configured feature")
18
)
19

20
// Config houses any runtime modifications to the default set descriptors. For
21
// our purposes, this typically means disabling certain features to test legacy
22
// protocol interoperability or functionality.
23
type Config struct {
24
        // NoTLVOnion unsets any optional or required TLVOnionPaylod bits from
25
        // all feature sets.
26
        NoTLVOnion bool
27

28
        // NoStaticRemoteKey unsets any optional or required StaticRemoteKey
29
        // bits from all feature sets.
30
        NoStaticRemoteKey bool
31

32
        // NoAnchors unsets any bits signaling support for anchor outputs.
33
        NoAnchors bool
34

35
        // NoWumbo unsets any bits signalling support for wumbo channels.
36
        NoWumbo bool
37

38
        // NoTaprootChans unsets any bits signaling support for taproot
39
        // channels.
40
        NoTaprootChans bool
41

42
        // NoScriptEnforcementLease unsets any bits signaling support for script
43
        // enforced leases.
44
        NoScriptEnforcementLease bool
45

46
        // NoKeysend unsets any bits signaling support for accepting keysend
47
        // payments.
48
        NoKeysend bool
49

50
        // NoOptionScidAlias unsets any bits signalling support for
51
        // option_scid_alias. This also implicitly disables zero-conf channels.
52
        NoOptionScidAlias bool
53

54
        // NoZeroConf unsets any bits signalling support for zero-conf
55
        // channels. This should be used instead of NoOptionScidAlias to still
56
        // keep option-scid-alias support.
57
        NoZeroConf bool
58

59
        // NoAnySegwit unsets any bits that signal support for using other
60
        // segwit witness versions for co-op closes.
61
        NoAnySegwit bool
62

63
        // NoRouteBlinding unsets route blinding feature bits.
64
        NoRouteBlinding bool
65

66
        // NoQuiescence unsets quiescence feature bits.
67
        NoQuiescence bool
68

69
        // NoTaprootOverlay unsets the taproot overlay channel feature bits.
70
        NoTaprootOverlay bool
71

72
        // NoExperimentalEndorsement unsets any bits that signal support for
73
        // forwarding experimental endorsement.
74
        NoExperimentalEndorsement bool
75

76
        // NoRbfCoopClose unsets any bits that signal support for using RBF for
77
        // coop close.
78
        NoRbfCoopClose bool
79

80
        // CustomFeatures is a set of custom features to advertise in each
81
        // set.
82
        CustomFeatures map[Set][]lnwire.FeatureBit
83
}
84

85
// Manager is responsible for generating feature vectors for different requested
86
// feature sets.
87
type Manager struct {
88
        // fsets is a static map of feature set to raw feature vectors. Requests
89
        // are fulfilled by cloning these internal feature vectors.
90
        fsets map[Set]*lnwire.RawFeatureVector
91

92
        // configFeatures is a set of custom features that were "hard set" in
93
        // lnd's config that cannot be updated at runtime (as is the case with
94
        // our "standard" features that are defined in LND).
95
        configFeatures map[Set]*lnwire.FeatureVector
96
}
97

98
// NewManager creates a new feature Manager, applying any custom modifications
99
// to its feature sets before returning.
UNCOV
100
func NewManager(cfg Config) (*Manager, error) {
×
UNCOV
101
        return newManager(cfg, defaultSetDesc)
×
UNCOV
102
}
×
103

104
// newManager creates a new feature Manager, applying any custom modifications
105
// to its feature sets before returning. This method accepts the setDesc as its
106
// own parameter so that it can be unit tested.
107
func newManager(cfg Config, desc setDesc) (*Manager, error) {
16✔
108
        // First build the default feature vector for all known sets.
16✔
109
        fsets := make(map[Set]*lnwire.RawFeatureVector)
16✔
110
        for bit, sets := range desc {
53✔
111
                for set := range sets {
95✔
112
                        // Fetch the feature vector for this set, allocating a
58✔
113
                        // new one if it doesn't exist.
58✔
114
                        fv, ok := fsets[set]
58✔
115
                        if !ok {
90✔
116
                                fv = lnwire.NewRawFeatureVector()
32✔
117
                        }
32✔
118

119
                        // Set the configured bit on the feature vector,
120
                        // ensuring that we don't set two feature bits for the
121
                        // same pair.
122
                        err := fv.SafeSet(bit)
58✔
123
                        if err != nil {
58✔
124
                                return nil, fmt.Errorf("unable to set "+
×
125
                                        "%v in %v: %v", bit, set, err)
×
126
                        }
×
127

128
                        // Write the updated feature vector under its set.
129
                        fsets[set] = fv
58✔
130
                }
131
        }
132

133
        // Now, remove any features as directed by the config.
134
        configFeatures := make(map[Set]*lnwire.FeatureVector)
16✔
135
        for set, raw := range fsets {
48✔
136
                if cfg.NoTLVOnion {
36✔
137
                        raw.Unset(lnwire.TLVOnionPayloadOptional)
4✔
138
                        raw.Unset(lnwire.TLVOnionPayloadRequired)
4✔
139
                        raw.Unset(lnwire.PaymentAddrOptional)
4✔
140
                        raw.Unset(lnwire.PaymentAddrRequired)
4✔
141
                        raw.Unset(lnwire.MPPOptional)
4✔
142
                        raw.Unset(lnwire.MPPRequired)
4✔
143
                        raw.Unset(lnwire.RouteBlindingOptional)
4✔
144
                        raw.Unset(lnwire.RouteBlindingRequired)
4✔
145
                        raw.Unset(lnwire.Bolt11BlindedPathsOptional)
4✔
146
                        raw.Unset(lnwire.Bolt11BlindedPathsRequired)
4✔
147
                        raw.Unset(lnwire.AMPOptional)
4✔
148
                        raw.Unset(lnwire.AMPRequired)
4✔
149
                        raw.Unset(lnwire.KeysendOptional)
4✔
150
                        raw.Unset(lnwire.KeysendRequired)
4✔
151
                }
4✔
152
                if cfg.NoStaticRemoteKey {
36✔
153
                        raw.Unset(lnwire.StaticRemoteKeyOptional)
4✔
154
                        raw.Unset(lnwire.StaticRemoteKeyRequired)
4✔
155
                }
4✔
156
                if cfg.NoAnchors {
34✔
157
                        raw.Unset(lnwire.AnchorsZeroFeeHtlcTxOptional)
2✔
158
                        raw.Unset(lnwire.AnchorsZeroFeeHtlcTxRequired)
2✔
159

2✔
160
                        // If anchors are disabled, then we also need to
2✔
161
                        // disable all other features that depend on it as
2✔
162
                        // well, as otherwise we may create an invalid feature
2✔
163
                        // bit set.
2✔
164
                        for bit, depFeatures := range deps {
28✔
165
                                for depFeature := range depFeatures {
58✔
166
                                        switch {
32✔
167
                                        case depFeature == lnwire.AnchorsZeroFeeHtlcTxRequired:
×
168
                                                fallthrough
×
169
                                        case depFeature == lnwire.AnchorsZeroFeeHtlcTxOptional:
4✔
170
                                                raw.Unset(bit)
4✔
171
                                        }
172
                                }
173
                        }
174
                }
175
                if cfg.NoWumbo {
32✔
UNCOV
176
                        raw.Unset(lnwire.WumboChannelsOptional)
×
UNCOV
177
                        raw.Unset(lnwire.WumboChannelsRequired)
×
UNCOV
178
                }
×
179
                if cfg.NoScriptEnforcementLease {
32✔
UNCOV
180
                        raw.Unset(lnwire.ScriptEnforcedLeaseOptional)
×
UNCOV
181
                        raw.Unset(lnwire.ScriptEnforcedLeaseRequired)
×
UNCOV
182
                }
×
183
                if cfg.NoKeysend {
32✔
184
                        raw.Unset(lnwire.KeysendOptional)
×
185
                        raw.Unset(lnwire.KeysendRequired)
×
186
                }
×
187
                if cfg.NoOptionScidAlias {
32✔
UNCOV
188
                        raw.Unset(lnwire.ScidAliasOptional)
×
UNCOV
189
                        raw.Unset(lnwire.ScidAliasRequired)
×
UNCOV
190
                }
×
191
                if cfg.NoZeroConf {
32✔
UNCOV
192
                        raw.Unset(lnwire.ZeroConfOptional)
×
UNCOV
193
                        raw.Unset(lnwire.ZeroConfRequired)
×
UNCOV
194
                }
×
195
                if cfg.NoAnySegwit {
32✔
UNCOV
196
                        raw.Unset(lnwire.ShutdownAnySegwitOptional)
×
UNCOV
197
                        raw.Unset(lnwire.ShutdownAnySegwitRequired)
×
UNCOV
198
                }
×
199
                if cfg.NoTaprootChans {
32✔
UNCOV
200
                        raw.Unset(lnwire.SimpleTaprootChannelsOptionalStaging)
×
UNCOV
201
                        raw.Unset(lnwire.SimpleTaprootChannelsRequiredStaging)
×
UNCOV
202
                }
×
203
                if cfg.NoRouteBlinding {
32✔
UNCOV
204
                        raw.Unset(lnwire.RouteBlindingOptional)
×
UNCOV
205
                        raw.Unset(lnwire.RouteBlindingRequired)
×
UNCOV
206
                        raw.Unset(lnwire.Bolt11BlindedPathsOptional)
×
UNCOV
207
                        raw.Unset(lnwire.Bolt11BlindedPathsRequired)
×
UNCOV
208
                }
×
209
                if cfg.NoQuiescence {
32✔
210
                        raw.Unset(lnwire.QuiescenceOptional)
×
211
                }
×
212
                if cfg.NoTaprootOverlay {
32✔
UNCOV
213
                        raw.Unset(lnwire.SimpleTaprootOverlayChansOptional)
×
UNCOV
214
                        raw.Unset(lnwire.SimpleTaprootOverlayChansRequired)
×
UNCOV
215
                }
×
216
                if cfg.NoExperimentalEndorsement {
32✔
UNCOV
217
                        raw.Unset(lnwire.ExperimentalEndorsementOptional)
×
UNCOV
218
                        raw.Unset(lnwire.ExperimentalEndorsementRequired)
×
UNCOV
219
                }
×
220
                if cfg.NoRbfCoopClose {
32✔
NEW
221
                        raw.Unset(lnwire.RbfCoopCloseOptionalStaging)
×
NEW
222
                }
×
223

224
                for _, custom := range cfg.CustomFeatures[set] {
34✔
225
                        if custom > set.Maximum() {
2✔
226
                                return nil, fmt.Errorf("feature bit: %v "+
×
227
                                        "exceeds set: %v maximum: %v", custom,
×
228
                                        set, set.Maximum())
×
229
                        }
×
230

231
                        if raw.IsSet(custom) {
2✔
232
                                return nil, fmt.Errorf("feature bit: %v "+
×
233
                                        "already set", custom)
×
234
                        }
×
235

236
                        if err := raw.SafeSet(custom); err != nil {
2✔
237
                                return nil, fmt.Errorf("%w: could not set "+
×
238
                                        "feature: %d", err, custom)
×
239
                        }
×
240
                }
241

242
                // Track custom features separately so that we can check that
243
                // they aren't unset in subsequent updates. If there is no
244
                // entry for the set, the vector will just be empty.
245
                configFeatures[set] = lnwire.NewFeatureVector(
32✔
246
                        lnwire.NewRawFeatureVector(cfg.CustomFeatures[set]...),
32✔
247
                        lnwire.Features,
32✔
248
                )
32✔
249

32✔
250
                // Ensure that all of our feature sets properly set any
32✔
251
                // dependent features.
32✔
252
                fv := lnwire.NewFeatureVector(raw, lnwire.Features)
32✔
253
                err := ValidateDeps(fv)
32✔
254
                if err != nil {
32✔
255
                        return nil, fmt.Errorf("invalid feature set %v: %w",
×
256
                                set, err)
×
257
                }
×
258
        }
259

260
        return &Manager{
16✔
261
                fsets:          fsets,
16✔
262
                configFeatures: configFeatures,
16✔
263
        }, nil
16✔
264
}
265

266
// GetRaw returns a raw feature vector for the passed set. If no set is known,
267
// an empty raw feature vector is returned.
268
func (m *Manager) GetRaw(set Set) *lnwire.RawFeatureVector {
67✔
269
        if fv, ok := m.fsets[set]; ok {
112✔
270
                return fv.Clone()
45✔
271
        }
45✔
272

273
        return lnwire.NewRawFeatureVector()
22✔
274
}
275

276
// setRaw sets a new raw feature vector for the given set.
277
func (m *Manager) setRaw(set Set, raw *lnwire.RawFeatureVector) {
6✔
278
        m.fsets[set] = raw
6✔
279
}
6✔
280

281
// Get returns a feature vector for the passed set. If no set is known, an empty
282
// feature vector is returned.
283
func (m *Manager) Get(set Set) *lnwire.FeatureVector {
33✔
284
        raw := m.GetRaw(set)
33✔
285
        return lnwire.NewFeatureVector(raw, lnwire.Features)
33✔
286
}
33✔
287

288
// ListSets returns a list of the feature sets that our node supports.
UNCOV
289
func (m *Manager) ListSets() []Set {
×
UNCOV
290
        var sets []Set
×
UNCOV
291

×
UNCOV
292
        for set := range m.fsets {
×
UNCOV
293
                sets = append(sets, set)
×
UNCOV
294
        }
×
295

UNCOV
296
        return sets
×
297
}
298

299
// UpdateFeatureSets accepts a map of new feature vectors for each of the
300
// manager's known sets, validates that the update can be applied and modifies
301
// the feature manager's internal state. If a set is not included in the update
302
// map, it is left unchanged. The feature vectors provided are expected to
303
// include the current set of features, updated with desired bits added/removed.
304
func (m *Manager) UpdateFeatureSets(
305
        updates map[Set]*lnwire.RawFeatureVector) error {
7✔
306

7✔
307
        for set, newFeatures := range updates {
18✔
308
                if !set.valid() {
12✔
309
                        return fmt.Errorf("%w: set: %d", ErrUnknownSet, set)
1✔
310
                }
1✔
311

312
                if err := newFeatures.ValidatePairs(); err != nil {
12✔
313
                        return err
2✔
314
                }
2✔
315

316
                if err := m.Get(set).ValidateUpdate(
8✔
317
                        newFeatures, set.Maximum(),
8✔
318
                ); err != nil {
8✔
UNCOV
319
                        return err
×
UNCOV
320
                }
×
321

322
                // If any features were configured for this set, ensure that
323
                // they are still set in the new feature vector.
324
                if cfgFeat, haveCfgFeat := m.configFeatures[set]; haveCfgFeat {
14✔
325
                        for feature := range cfgFeat.Features() {
7✔
326
                                if !newFeatures.IsSet(feature) {
2✔
327
                                        return fmt.Errorf("%w: can't unset: "+
1✔
328
                                                "%d", ErrFeatureConfigured,
1✔
329
                                                feature)
1✔
330
                                }
1✔
331
                        }
332
                }
333

334
                fv := lnwire.NewFeatureVector(newFeatures, lnwire.Features)
7✔
335
                if err := ValidateDeps(fv); err != nil {
7✔
336
                        return err
×
337
                }
×
338
        }
339

340
        // Only update the current feature sets once every proposed set has
341
        // passed validation so that we don't partially update any sets then
342
        // fail out on a later set's validation.
343
        for set, features := range updates {
9✔
344
                m.setRaw(set, features.Clone())
6✔
345
        }
6✔
346

347
        return nil
3✔
348
}
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