-
Notifications
You must be signed in to change notification settings - Fork 2.2k
multi: Add ability to set custom node announcement feature bits in config #7168
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
25e8968
3cfd8a6
e4990e9
771ee02
f8991ca
a4f07c2
779d470
0133ffc
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -248,36 +248,25 @@ func (s *Server) updateFeatures(currentfeatures *lnwire.RawFeatureVector, | |
updates []*UpdateFeatureAction) (*lnwire.RawFeatureVector, | ||
*lnrpc.Op, error) { | ||
|
||
ops := &lnrpc.Op{Entity: "features"} | ||
raw := currentfeatures.Clone() | ||
var ( | ||
ops = &lnrpc.Op{Entity: "features"} | ||
add []lnwire.FeatureBit | ||
remove []lnwire.FeatureBit | ||
) | ||
|
||
for _, update := range updates { | ||
bit := lnwire.FeatureBit(update.FeatureBit) | ||
|
||
switch update.Action { | ||
case UpdateAction_ADD: | ||
if raw.IsSet(bit) { | ||
return nil, nil, fmt.Errorf( | ||
"invalid add action for bit %v, "+ | ||
"bit is already set", | ||
update.FeatureBit, | ||
) | ||
} | ||
raw.Set(bit) | ||
add = append(add, bit) | ||
ops.Actions = append( | ||
ops.Actions, | ||
fmt.Sprintf("%s set", lnwire.Features[bit]), | ||
) | ||
|
||
case UpdateAction_REMOVE: | ||
if !raw.IsSet(bit) { | ||
return nil, nil, fmt.Errorf( | ||
"invalid remove action for bit %v, "+ | ||
"bit is already unset", | ||
update.FeatureBit, | ||
) | ||
} | ||
raw.Unset(bit) | ||
remove = append(remove, bit) | ||
ops.Actions = append( | ||
ops.Actions, | ||
fmt.Sprintf("%s unset", lnwire.Features[bit]), | ||
|
@@ -292,7 +281,13 @@ func (s *Server) updateFeatures(currentfeatures *lnwire.RawFeatureVector, | |
} | ||
} | ||
|
||
// Validate our new SetNodeAnn. | ||
raw, err := lnwire.MergeFeatureVector( | ||
currentfeatures, add, remove, s.cfg.ConfigFeatures, | ||
) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think you could call this a more 'external' approach to managing the feature bits. Would this have been possible as an extension of There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Going to take a look at moving this into the feature manager. The existing API only advertises custom features in gossip (not peer init), but I think that it makes sense to update it to do both. Seems like it'll simplify things a bit as well 🤞 |
||
if err != nil { | ||
return nil, nil, err | ||
} | ||
|
||
fv := lnwire.NewFeatureVector(raw, lnwire.Features) | ||
if err := feature.ValidateDeps(fv); err != nil { | ||
return nil, nil, fmt.Errorf( | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -3,13 +3,31 @@ package lnwire | |
import ( | ||
"encoding/binary" | ||
"errors" | ||
"fmt" | ||
"io" | ||
) | ||
|
||
var ( | ||
// ErrFeaturePairExists signals an error in feature vector construction | ||
// where the opposing bit in a feature pair has already been set. | ||
ErrFeaturePairExists = errors.New("feature pair exists") | ||
|
||
// ErrFeatureStandard is returned when attempts to modify LND's known | ||
// set of features are made. | ||
ErrFeatureStandard = errors.New("feature is used in standard " + | ||
"protocol set") | ||
|
||
// ErrFeatureSet is returned when an attempt to set a feature bit that | ||
// is already active is made. | ||
ErrFeatureSet = errors.New("feature bit already set") | ||
|
||
// ErrFeatureNotSet is returned when an attempt to un-set a feature bit | ||
// this is not active is made. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. %s/this/that |
||
ErrFeatureNotSet = errors.New("feature bit not set") | ||
|
||
// ErrFeatureConfigured is returned when an attempt to un-set a feature | ||
// that was set in lnd's config is made. | ||
ErrFeatureConfigured = errors.New("feature bit set in config") | ||
) | ||
|
||
// FeatureBit represents a feature that can be enabled in either a local or | ||
|
@@ -621,3 +639,64 @@ func (fv *FeatureVector) Clone() *FeatureVector { | |
features := fv.RawFeatureVector.Clone() | ||
return NewFeatureVector(features, fv.featureNames) | ||
} | ||
|
||
// MergeFeatureVector accepts a list of feature bits to add and remove, | ||
// validates that they may be modified (are not known to LND, set/unset actions | ||
// are logical for the current vector) and returns a merged vector. The merge | ||
// function also accepts a map of feature bits that were set at a config level. | ||
// These features are considered "hard-set", so will also trigger an error if | ||
// we attempt to modify them. | ||
func MergeFeatureVector(current *RawFeatureVector, add, remove []FeatureBit, | ||
configured []FeatureBit) (*RawFeatureVector, error) { | ||
|
||
if current == nil { | ||
return nil, errors.New("nil feature vector not allowed") | ||
} | ||
|
||
configuredBits := make(map[FeatureBit]struct{}, len(configured)) | ||
for _, bit := range configured { | ||
configuredBits[bit] = struct{}{} | ||
} | ||
|
||
// Make a copy of the current vector so that we don't mutate it. | ||
raw := current.Clone() | ||
for _, bit := range add { | ||
if _, set := configuredBits[bit]; set { | ||
return nil, fmt.Errorf("can't add feature bit %d: %w", | ||
bit, ErrFeatureConfigured) | ||
} | ||
|
||
if name, known := Features[bit]; known { | ||
return nil, fmt.Errorf("can't set feature "+ | ||
"bit %d (%v): %w", bit, name, | ||
ErrFeatureStandard) | ||
} | ||
|
||
if raw.IsSet(bit) { | ||
return nil, fmt.Errorf("invalid add action for bit "+ | ||
"%d: %w", bit, ErrFeatureSet) | ||
} | ||
raw.Set(bit) | ||
} | ||
|
||
for _, bit := range remove { | ||
if _, set := configuredBits[bit]; set { | ||
return nil, fmt.Errorf("can't remove feature bit %d: "+ | ||
"%w", bit, ErrFeatureConfigured) | ||
} | ||
|
||
if name, known := Features[bit]; known { | ||
return nil, fmt.Errorf("can't unset feature "+ | ||
"bit %d (%v): %w", bit, name, | ||
ErrFeatureStandard) | ||
} | ||
|
||
if !raw.IsSet(bit) { | ||
return nil, fmt.Errorf("invalid remove action for "+ | ||
"bit %d: %w", bit, ErrFeatureNotSet) | ||
} | ||
raw.Unset(bit) | ||
} | ||
|
||
return raw, nil | ||
} |
Uh oh!
There was an error while loading. Please reload this page.