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

lightningnetwork / lnd / 11216766535

07 Oct 2024 01:37PM UTC coverage: 57.817% (-1.0%) from 58.817%
11216766535

Pull #9148

github

ProofOfKeags
lnwire: remove kickoff feerate from propose/commit
Pull Request #9148: DynComms [2/n]: lnwire: add authenticated wire messages for Dyn*

571 of 879 new or added lines in 16 files covered. (64.96%)

23253 existing lines in 251 files now uncovered.

99022 of 171268 relevant lines covered (57.82%)

38420.67 hits per line

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

64.94
/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
        // CustomFeatures is a set of custom features to advertise in each
67
        // set.
68
        CustomFeatures map[Set][]lnwire.FeatureBit
69
}
70

71
// Manager is responsible for generating feature vectors for different requested
72
// feature sets.
73
type Manager struct {
74
        // fsets is a static map of feature set to raw feature vectors. Requests
75
        // are fulfilled by cloning these internal feature vectors.
76
        fsets map[Set]*lnwire.RawFeatureVector
77

78
        // configFeatures is a set of custom features that were "hard set" in
79
        // lnd's config that cannot be updated at runtime (as is the case with
80
        // our "standard" features that are defined in LND).
81
        configFeatures map[Set]*lnwire.FeatureVector
82
}
83

84
// NewManager creates a new feature Manager, applying any custom modifications
85
// to its feature sets before returning.
86
func NewManager(cfg Config) (*Manager, error) {
87
        return newManager(cfg, defaultSetDesc)
88
}
UNCOV
89

×
UNCOV
90
// newManager creates a new feature Manager, applying any custom modifications
×
UNCOV
91
// to its feature sets before returning. This method accepts the setDesc as its
×
92
// own parameter so that it can be unit tested.
93
func newManager(cfg Config, desc setDesc) (*Manager, error) {
94
        // First build the default feature vector for all known sets.
95
        fsets := make(map[Set]*lnwire.RawFeatureVector)
96
        for bit, sets := range desc {
16✔
97
                for set := range sets {
16✔
98
                        // Fetch the feature vector for this set, allocating a
16✔
99
                        // new one if it doesn't exist.
53✔
100
                        fv, ok := fsets[set]
95✔
101
                        if !ok {
58✔
102
                                fv = lnwire.NewRawFeatureVector()
58✔
103
                        }
58✔
104

90✔
105
                        // Set the configured bit on the feature vector,
32✔
106
                        // ensuring that we don't set two feature bits for the
32✔
107
                        // same pair.
108
                        err := fv.SafeSet(bit)
109
                        if err != nil {
110
                                return nil, fmt.Errorf("unable to set "+
111
                                        "%v in %v: %v", bit, set, err)
58✔
112
                        }
58✔
UNCOV
113

×
UNCOV
114
                        // Write the updated feature vector under its set.
×
UNCOV
115
                        fsets[set] = fv
×
116
                }
117
        }
118

58✔
119
        // Now, remove any features as directed by the config.
120
        configFeatures := make(map[Set]*lnwire.FeatureVector)
121
        for set, raw := range fsets {
122
                if cfg.NoTLVOnion {
123
                        raw.Unset(lnwire.TLVOnionPayloadOptional)
16✔
124
                        raw.Unset(lnwire.TLVOnionPayloadRequired)
48✔
125
                        raw.Unset(lnwire.PaymentAddrOptional)
36✔
126
                        raw.Unset(lnwire.PaymentAddrRequired)
4✔
127
                        raw.Unset(lnwire.MPPOptional)
4✔
128
                        raw.Unset(lnwire.MPPRequired)
4✔
129
                        raw.Unset(lnwire.RouteBlindingOptional)
4✔
130
                        raw.Unset(lnwire.RouteBlindingRequired)
4✔
131
                        raw.Unset(lnwire.Bolt11BlindedPathsOptional)
4✔
132
                        raw.Unset(lnwire.Bolt11BlindedPathsRequired)
4✔
133
                        raw.Unset(lnwire.AMPOptional)
4✔
134
                        raw.Unset(lnwire.AMPRequired)
4✔
135
                        raw.Unset(lnwire.KeysendOptional)
4✔
136
                        raw.Unset(lnwire.KeysendRequired)
4✔
137
                }
4✔
138
                if cfg.NoStaticRemoteKey {
4✔
139
                        raw.Unset(lnwire.StaticRemoteKeyOptional)
4✔
140
                        raw.Unset(lnwire.StaticRemoteKeyRequired)
4✔
141
                }
36✔
142
                if cfg.NoAnchors {
4✔
143
                        raw.Unset(lnwire.AnchorsZeroFeeHtlcTxOptional)
4✔
144
                        raw.Unset(lnwire.AnchorsZeroFeeHtlcTxRequired)
4✔
145

34✔
146
                        // If anchors are disabled, then we also need to
2✔
147
                        // disable all other features that depend on it as
2✔
148
                        // well, as otherwise we may create an invalid feature
2✔
149
                        // bit set.
2✔
150
                        for bit, depFeatures := range deps {
2✔
151
                                for depFeature := range depFeatures {
2✔
152
                                        switch {
2✔
153
                                        case depFeature == lnwire.AnchorsZeroFeeHtlcTxRequired:
28✔
154
                                                fallthrough
58✔
155
                                        case depFeature == lnwire.AnchorsZeroFeeHtlcTxOptional:
32✔
UNCOV
156
                                                raw.Unset(bit)
×
UNCOV
157
                                        }
×
158
                                }
4✔
159
                        }
4✔
160
                }
161
                if cfg.NoWumbo {
162
                        raw.Unset(lnwire.WumboChannelsOptional)
163
                        raw.Unset(lnwire.WumboChannelsRequired)
164
                }
32✔
UNCOV
165
                if cfg.NoScriptEnforcementLease {
×
UNCOV
166
                        raw.Unset(lnwire.ScriptEnforcedLeaseOptional)
×
UNCOV
167
                        raw.Unset(lnwire.ScriptEnforcedLeaseRequired)
×
168
                }
32✔
UNCOV
169
                if cfg.NoKeysend {
×
170
                        raw.Unset(lnwire.KeysendOptional)
×
171
                        raw.Unset(lnwire.KeysendRequired)
×
172
                }
32✔
UNCOV
173
                if cfg.NoOptionScidAlias {
×
UNCOV
174
                        raw.Unset(lnwire.ScidAliasOptional)
×
UNCOV
175
                        raw.Unset(lnwire.ScidAliasRequired)
×
176
                }
32✔
UNCOV
177
                if cfg.NoZeroConf {
×
UNCOV
178
                        raw.Unset(lnwire.ZeroConfOptional)
×
UNCOV
179
                        raw.Unset(lnwire.ZeroConfRequired)
×
180
                }
32✔
UNCOV
181
                if cfg.NoAnySegwit {
×
UNCOV
182
                        raw.Unset(lnwire.ShutdownAnySegwitOptional)
×
UNCOV
183
                        raw.Unset(lnwire.ShutdownAnySegwitRequired)
×
184
                }
32✔
UNCOV
185
                if cfg.NoTaprootChans {
×
UNCOV
186
                        raw.Unset(lnwire.SimpleTaprootChannelsOptionalStaging)
×
UNCOV
187
                        raw.Unset(lnwire.SimpleTaprootChannelsRequiredStaging)
×
188
                }
32✔
UNCOV
189
                if cfg.NoRouteBlinding {
×
UNCOV
190
                        raw.Unset(lnwire.RouteBlindingOptional)
×
UNCOV
191
                        raw.Unset(lnwire.RouteBlindingRequired)
×
192
                        raw.Unset(lnwire.Bolt11BlindedPathsOptional)
32✔
UNCOV
193
                        raw.Unset(lnwire.Bolt11BlindedPathsRequired)
×
UNCOV
194
                }
×
UNCOV
195
                for _, custom := range cfg.CustomFeatures[set] {
×
UNCOV
196
                        if custom > set.Maximum() {
×
197
                                return nil, fmt.Errorf("feature bit: %v "+
×
198
                                        "exceeds set: %v maximum: %v", custom,
32✔
199
                                        set, set.Maximum())
×
200
                        }
×
UNCOV
201

×
202
                        if raw.IsSet(custom) {
34✔
203
                                return nil, fmt.Errorf("feature bit: %v "+
2✔
204
                                        "already set", custom)
×
205
                        }
×
UNCOV
206

×
UNCOV
207
                        if err := raw.SafeSet(custom); err != nil {
×
208
                                return nil, fmt.Errorf("%w: could not set "+
209
                                        "feature: %d", err, custom)
2✔
210
                        }
×
UNCOV
211
                }
×
UNCOV
212

×
213
                // Track custom features separately so that we can check that
214
                // they aren't unset in subsequent updates. If there is no
2✔
UNCOV
215
                // entry for the set, the vector will just be empty.
×
UNCOV
216
                configFeatures[set] = lnwire.NewFeatureVector(
×
UNCOV
217
                        lnwire.NewRawFeatureVector(cfg.CustomFeatures[set]...),
×
218
                        lnwire.Features,
219
                )
220

221
                // Ensure that all of our feature sets properly set any
222
                // dependent features.
223
                fv := lnwire.NewFeatureVector(raw, lnwire.Features)
32✔
224
                err := ValidateDeps(fv)
32✔
225
                if err != nil {
32✔
226
                        return nil, fmt.Errorf("invalid feature set %v: %w",
32✔
227
                                set, err)
32✔
228
                }
32✔
229
        }
32✔
230

32✔
231
        return &Manager{
32✔
232
                fsets:          fsets,
32✔
UNCOV
233
                configFeatures: configFeatures,
×
UNCOV
234
        }, nil
×
UNCOV
235
}
×
236

237
// GetRaw returns a raw feature vector for the passed set. If no set is known,
238
// an empty raw feature vector is returned.
16✔
239
func (m *Manager) GetRaw(set Set) *lnwire.RawFeatureVector {
16✔
240
        if fv, ok := m.fsets[set]; ok {
16✔
241
                return fv.Clone()
16✔
242
        }
243

244
        return lnwire.NewRawFeatureVector()
245
}
246

67✔
247
// setRaw sets a new raw feature vector for the given set.
112✔
248
func (m *Manager) setRaw(set Set, raw *lnwire.RawFeatureVector) {
45✔
249
        m.fsets[set] = raw
45✔
250
}
251

22✔
252
// Get returns a feature vector for the passed set. If no set is known, an empty
253
// feature vector is returned.
254
func (m *Manager) Get(set Set) *lnwire.FeatureVector {
255
        raw := m.GetRaw(set)
6✔
256
        return lnwire.NewFeatureVector(raw, lnwire.Features)
6✔
257
}
6✔
258

259
// ListSets returns a list of the feature sets that our node supports.
260
func (m *Manager) ListSets() []Set {
261
        var sets []Set
33✔
262

33✔
263
        for set := range m.fsets {
33✔
264
                sets = append(sets, set)
33✔
265
        }
266

UNCOV
267
        return sets
×
UNCOV
268
}
×
UNCOV
269

×
UNCOV
270
// UpdateFeatureSets accepts a map of new feature vectors for each of the
×
UNCOV
271
// manager's known sets, validates that the update can be applied and modifies
×
UNCOV
272
// the feature manager's internal state. If a set is not included in the update
×
273
// map, it is left unchanged. The feature vectors provided are expected to
UNCOV
274
// include the current set of features, updated with desired bits added/removed.
×
275
func (m *Manager) UpdateFeatureSets(
276
        updates map[Set]*lnwire.RawFeatureVector) error {
277

278
        for set, newFeatures := range updates {
279
                if !set.valid() {
280
                        return fmt.Errorf("%w: set: %d", ErrUnknownSet, set)
281
                }
282

283
                if err := newFeatures.ValidatePairs(); err != nil {
7✔
284
                        return err
7✔
285
                }
18✔
286

12✔
287
                if err := m.Get(set).ValidateUpdate(
1✔
288
                        newFeatures, set.Maximum(),
1✔
289
                ); err != nil {
290
                        return err
12✔
291
                }
2✔
292

2✔
293
                // If any features were configured for this set, ensure that
294
                // they are still set in the new feature vector.
8✔
295
                if cfgFeat, haveCfgFeat := m.configFeatures[set]; haveCfgFeat {
8✔
296
                        for feature := range cfgFeat.Features() {
8✔
UNCOV
297
                                if !newFeatures.IsSet(feature) {
×
UNCOV
298
                                        return fmt.Errorf("%w: can't unset: "+
×
299
                                                "%d", ErrFeatureConfigured,
300
                                                feature)
301
                                }
302
                        }
14✔
303
                }
7✔
304

2✔
305
                fv := lnwire.NewFeatureVector(newFeatures, lnwire.Features)
1✔
306
                if err := ValidateDeps(fv); err != nil {
1✔
307
                        return err
1✔
308
                }
1✔
309
        }
310

311
        // Only update the current feature sets once every proposed set has
312
        // passed validation so that we don't partially update any sets then
7✔
313
        // fail out on a later set's validation.
7✔
UNCOV
314
        for set, features := range updates {
×
UNCOV
315
                m.setRaw(set, features.Clone())
×
316
        }
317

318
        return nil
319
}
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