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

lightningnetwork / lnd / 15561477203

10 Jun 2025 01:54PM UTC coverage: 58.351% (-10.1%) from 68.487%
15561477203

Pull #9356

github

web-flow
Merge 6440b25db into c6d6d4c0b
Pull Request #9356: lnrpc: add incoming/outgoing channel ids filter to forwarding history request

33 of 36 new or added lines in 2 files covered. (91.67%)

28366 existing lines in 455 files now uncovered.

97715 of 167461 relevant lines covered (58.35%)

1.81 hits per line

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

74.71
/feature/deps.go
1
package feature
2

3
import (
4
        "fmt"
5

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

9
type (
10
        // featureSet contains a set of feature bits.
11
        featureSet map[lnwire.FeatureBit]struct{}
12

13
        // supportedFeatures maps the feature bit from a feature vector to a
14
        // boolean indicating if this features dependencies have already been
15
        // verified. This allows us to short circuit verification if multiple
16
        // features have common dependencies, or map traversal starts verifying
17
        // from the bottom up.
18
        supportedFeatures map[lnwire.FeatureBit]bool
19

20
        // depDesc maps a features to its set of dependent features, which must
21
        // also be present for the vector to be valid. This can be used to
22
        // recursively check the dependency chain for features in a feature
23
        // vector.
24
        depDesc map[lnwire.FeatureBit]featureSet
25
)
26

27
// ErrMissingFeatureDep is an error signaling that a transitive dependency in a
28
// feature vector is not set properly.
29
type ErrMissingFeatureDep struct {
30
        dep lnwire.FeatureBit
31
}
32

33
// NewErrMissingFeatureDep creates a new ErrMissingFeatureDep error.
UNCOV
34
func NewErrMissingFeatureDep(dep lnwire.FeatureBit) ErrMissingFeatureDep {
×
UNCOV
35
        return ErrMissingFeatureDep{dep: dep}
×
UNCOV
36
}
×
37

38
// Error returns a human-readable description of the missing dep error.
39
func (e ErrMissingFeatureDep) Error() string {
×
40
        return fmt.Sprintf("missing feature dependency: %v", e.dep)
×
41
}
×
42

43
// deps is the default set of dependencies for assigned feature bits. If a
44
// feature is not present in the depDesc it is assumed to have no dependencies.
45
//
46
// NOTE: For proper functioning, only the optional variant of feature bits
47
// should be used in the following descriptor. In the future it may be necessary
48
// to distinguish the dependencies for optional and required bits, but for now
49
// the validation code maps required bits to optional ones since it simplifies
50
// the number of constraints.
51
var deps = depDesc{
52
        lnwire.PaymentAddrOptional: {
53
                lnwire.TLVOnionPayloadOptional: {},
54
        },
55
        lnwire.MPPOptional: {
56
                lnwire.PaymentAddrOptional: {},
57
        },
58
        lnwire.AnchorsOptional: {
59
                lnwire.StaticRemoteKeyOptional: {},
60
        },
61
        lnwire.AnchorsZeroFeeHtlcTxOptional: {
62
                lnwire.StaticRemoteKeyOptional: {},
63
        },
64
        lnwire.AMPOptional: {
65
                lnwire.PaymentAddrOptional: {},
66
        },
67
        lnwire.ExplicitChannelTypeOptional: {},
68
        lnwire.ScriptEnforcedLeaseOptional: {
69
                lnwire.ExplicitChannelTypeOptional:  {},
70
                lnwire.AnchorsZeroFeeHtlcTxOptional: {},
71
        },
72
        lnwire.KeysendOptional: {
73
                lnwire.TLVOnionPayloadOptional: {},
74
        },
75
        lnwire.ZeroConfOptional: {
76
                lnwire.ScidAliasOptional: {},
77
        },
78
        lnwire.SimpleTaprootChannelsOptionalStaging: {
79
                lnwire.AnchorsZeroFeeHtlcTxOptional: {},
80
                lnwire.ExplicitChannelTypeOptional:  {},
81
        },
82
        lnwire.SimpleTaprootOverlayChansOptional: {
83
                lnwire.SimpleTaprootChannelsOptionalStaging: {},
84
                lnwire.TLVOnionPayloadOptional:              {},
85
                lnwire.ScidAliasOptional:                    {},
86
        },
87
        lnwire.RouteBlindingOptional: {
88
                lnwire.TLVOnionPayloadOptional: {},
89
        },
90
        lnwire.Bolt11BlindedPathsOptional: {
91
                lnwire.RouteBlindingOptional: {},
92
        },
93
}
94

95
// ValidateDeps asserts that a feature vector sets all features and their
96
// transitive dependencies properly. It assumes that the dependencies between
97
// optional and required features are identical, e.g. if a feature is required
98
// but its dependency is optional, that is sufficient.
99
func ValidateDeps(fv *lnwire.FeatureVector) error {
3✔
100
        features := fv.Features()
3✔
101
        supported := initSupported(features)
3✔
102

3✔
103
        return validateDeps(features, supported)
3✔
104
}
3✔
105

106
// SetBit sets the given feature bit on the given feature bit vector along with
107
// any of its dependencies. If the bit is required, then all the dependencies
108
// are also set to required, otherwise, the optional dependency bits are set.
109
// Existing bits are only upgraded from optional to required but never
110
// downgraded from required to optional.
111
func SetBit(vector *lnwire.FeatureVector,
112
        bit lnwire.FeatureBit) *lnwire.FeatureVector {
3✔
113

3✔
114
        fv := vector.Clone()
3✔
115

3✔
116
        // Get the optional version of the bit since that is what the deps map
3✔
117
        // uses.
3✔
118
        optBit := mapToOptional(bit)
3✔
119

3✔
120
        // If the bit we are setting is optional, then we set it (in its
3✔
121
        // optional form) and also set all its dependents as optional if they
3✔
122
        // are not already set (they may already be set in a required form in
3✔
123
        // which case they should not be overridden).
3✔
124
        if !bit.IsRequired() {
3✔
UNCOV
125
                // Set the bit itself if it does not already exist. We use
×
UNCOV
126
                // SafeSet here so that if the bit already exists in the
×
UNCOV
127
                // required form, then this is not overwritten.
×
UNCOV
128
                _ = fv.SafeSet(bit)
×
UNCOV
129

×
UNCOV
130
                // Do the same for all the dependent bits.
×
UNCOV
131
                for depBit := range deps[optBit] {
×
UNCOV
132
                        fv = SetBit(fv, depBit)
×
UNCOV
133
                }
×
134

UNCOV
135
                return fv
×
136
        }
137

138
        // The bit is required. In this case, we do want to override any
139
        // existing optional bit for both the bit itself and for the dependent
140
        // bits.
141
        fv.Unset(optBit)
3✔
142
        fv.Set(bit)
3✔
143

3✔
144
        // Do the same for all the dependent bits.
3✔
145
        for depBit := range deps[optBit] {
6✔
146
                // The deps map only contains the optional versions of bits, so
3✔
147
                // there is no need to first map the bit to the optional
3✔
148
                // version.
3✔
149
                fv.Unset(depBit)
3✔
150

3✔
151
                // Set the required version of the bit instead.
3✔
152
                fv = SetBit(fv, mapToRequired(depBit))
3✔
153
        }
3✔
154

155
        return fv
3✔
156
}
157

158
// validateDeps is a subroutine that recursively checks that the passed features
159
// have all of their associated dependencies in the supported map.
160
func validateDeps(features featureSet, supported supportedFeatures) error {
3✔
161
        for bit := range features {
6✔
162
                // Convert any required bits to optional.
3✔
163
                bit = mapToOptional(bit)
3✔
164

3✔
165
                // If the supported features doesn't contain the dependency, this
3✔
166
                // vector is invalid.
3✔
167
                checked, ok := supported[bit]
3✔
168
                if !ok {
3✔
UNCOV
169
                        return NewErrMissingFeatureDep(bit)
×
UNCOV
170
                }
×
171

172
                // Alternatively, if we know that this dependency is valid, we
173
                // can short circuit and continue verifying other bits.
174
                if checked {
6✔
175
                        continue
3✔
176
                }
177

178
                // Recursively validate dependencies, since this method ranges
179
                // over the subDeps. This method will return true even if
180
                // subDeps is nil.
181
                subDeps := deps[bit]
3✔
182
                if err := validateDeps(subDeps, supported); err != nil {
3✔
UNCOV
183
                        return err
×
UNCOV
184
                }
×
185

186
                // Once we've confirmed that this feature's dependencies, if
187
                // any, are sound, we record this so other paths taken through
188
                // `bit` return early when inspecting the supported map.
189
                supported[bit] = true
3✔
190
        }
191

192
        return nil
3✔
193
}
194

195
// initSupported sets all bits from the feature vector as supported but not
196
// checked. This signals that the validity of their dependencies has not been
197
// verified. All required bits are mapped to optional to simplify the DAG.
198
func initSupported(features featureSet) supportedFeatures {
3✔
199
        supported := make(supportedFeatures)
3✔
200
        for bit := range features {
6✔
201
                bit = mapToOptional(bit)
3✔
202
                supported[bit] = false
3✔
203
        }
3✔
204

205
        return supported
3✔
206
}
207

208
// mapToOptional returns the optional variant of a given feature bit pair. Our
209
// dependency graph is described using only optional feature bits, which
210
// reduces the number of constraints we need to express in the descriptor.
211
func mapToOptional(bit lnwire.FeatureBit) lnwire.FeatureBit {
3✔
212
        if bit.IsRequired() {
6✔
213
                bit ^= 0x01
3✔
214
        }
3✔
215
        return bit
3✔
216
}
217

218
// mapToRequired returns the required variant of a given feature bit pair.
219
func mapToRequired(bit lnwire.FeatureBit) lnwire.FeatureBit {
3✔
220
        if bit.IsRequired() {
3✔
221
                return bit
×
222
        }
×
223
        bit ^= 0x01
3✔
224

3✔
225
        return bit
3✔
226
}
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