-
Notifications
You must be signed in to change notification settings - Fork 2.3k
flat features #3685
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
Merged
Merged
flat features #3685
Changes from all commits
Commits
Show all changes
5 commits
Select commit
Hold shift + click to select a range
90e36ca
lnwire/features: add unified Features namespace
cfromknecht fe566e1
feature: add new feature pkg to manage feature sets
cfromknecht 6c86075
peer+server: use feature manager to generate feature vectors
cfromknecht 16318c5
multi: merge local+global features from remote peer
cfromknecht 5e27b50
multi: remove LocalFeatures and GlobalFeatures
cfromknecht File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,32 @@ | ||
| package feature | ||
|
|
||
| import "github.com/lightningnetwork/lnd/lnwire" | ||
|
|
||
| // setDesc describes which feature bits should be advertised in which feature | ||
| // sets. | ||
| type setDesc map[lnwire.FeatureBit]map[Set]struct{} | ||
|
|
||
| // defaultSetDesc are the default set descriptors for generating feature | ||
| // vectors. Each set is annotated with the corresponding identifier from BOLT 9 | ||
| // indicating where it should be advertised. | ||
| var defaultSetDesc = setDesc{ | ||
| lnwire.DataLossProtectRequired: { | ||
| SetInit: {}, // I | ||
| SetNodeAnn: {}, // N | ||
| }, | ||
| lnwire.GossipQueriesOptional: { | ||
| SetInit: {}, // I | ||
| SetNodeAnn: {}, // N | ||
| }, | ||
| lnwire.TLVOnionPayloadOptional: { | ||
| SetInit: {}, // I | ||
| SetNodeAnn: {}, // N | ||
| SetInvoice: {}, // 9 | ||
| SetLegacyGlobal: {}, | ||
| }, | ||
| lnwire.StaticRemoteKeyOptional: { | ||
| SetInit: {}, // I | ||
| SetNodeAnn: {}, // N | ||
| SetLegacyGlobal: {}, | ||
| }, | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,97 @@ | ||
| package feature | ||
|
|
||
| import ( | ||
| "fmt" | ||
|
|
||
| "github.com/lightningnetwork/lnd/lnwire" | ||
| ) | ||
|
|
||
| // Config houses any runtime modifications to the default set descriptors. For | ||
| // our purposes, this typically means disabling certain features to test legacy | ||
| // protocol interoperability or functionality. | ||
| type Config struct { | ||
| // NoTLVOnion unsets any optional or required TLVOnionPaylod bits from | ||
| // all feature sets. | ||
| NoTLVOnion bool | ||
|
|
||
| // NoStaticRemoteKey unsets any optional or required StaticRemoteKey | ||
| // bits from all feature sets. | ||
| NoStaticRemoteKey bool | ||
| } | ||
|
|
||
| // Manager is responsible for generating feature vectors for different requested | ||
| // feature sets. | ||
| type Manager struct { | ||
| // fsets is a static map of feature set to raw feature vectors. Requests | ||
| // are fulfilled by cloning these interal feature vectors. | ||
| fsets map[Set]*lnwire.RawFeatureVector | ||
| } | ||
|
|
||
| // NewManager creates a new feature Manager, applying any custom modifications | ||
| // to its feature sets before returning. | ||
| func NewManager(cfg Config) (*Manager, error) { | ||
| return newManager(cfg, defaultSetDesc) | ||
| } | ||
|
|
||
| // newManager creates a new feeature Manager, applying any custom modifications | ||
|
cfromknecht marked this conversation as resolved.
Outdated
|
||
| // to its feature sets before returning. This method accepts the setDesc as its | ||
| // own parameter so that it can be unit tested. | ||
| func newManager(cfg Config, desc setDesc) (*Manager, error) { | ||
| // First build the default feature vector for all known sets. | ||
| fsets := make(map[Set]*lnwire.RawFeatureVector) | ||
| for bit, sets := range desc { | ||
| for set := range sets { | ||
| // Fetch the feature vector for this set, allocating a | ||
| // new one if it doesn't exist. | ||
| fv, ok := fsets[set] | ||
| if !ok { | ||
| fv = lnwire.NewRawFeatureVector() | ||
| } | ||
|
|
||
| // Set the configured bit on the feature vector, | ||
| // ensuring that we don't set two feature bits for the | ||
| // same pair. | ||
| err := fv.SafeSet(bit) | ||
| if err != nil { | ||
| return nil, fmt.Errorf("unable to set "+ | ||
| "%v in %v: %v", bit, set, err) | ||
| } | ||
|
|
||
| // Write the updated feature vector under its set. | ||
| fsets[set] = fv | ||
| } | ||
| } | ||
|
|
||
| // Now, remove any features as directed by the config. | ||
| for _, fv := range fsets { | ||
| if cfg.NoTLVOnion { | ||
| fv.Unset(lnwire.TLVOnionPayloadOptional) | ||
| fv.Unset(lnwire.TLVOnionPayloadRequired) | ||
| } | ||
| if cfg.NoStaticRemoteKey { | ||
| fv.Unset(lnwire.StaticRemoteKeyOptional) | ||
| fv.Unset(lnwire.StaticRemoteKeyRequired) | ||
| } | ||
| } | ||
|
|
||
| return &Manager{ | ||
| fsets: fsets, | ||
| }, nil | ||
| } | ||
|
|
||
| // GetRaw returns a raw feature vector for the passed set. If no set is known, | ||
| // an empty raw feature vector is returned. | ||
| func (m *Manager) GetRaw(set Set) *lnwire.RawFeatureVector { | ||
| if fv, ok := m.fsets[set]; ok { | ||
| return fv.Clone() | ||
| } | ||
|
|
||
| return lnwire.NewRawFeatureVector() | ||
| } | ||
|
|
||
| // Get returns a feature vector for the passed set. If no set is known, an empty | ||
| // feature vector is returned. | ||
| func (m *Manager) Get(set Set) *lnwire.FeatureVector { | ||
| raw := m.GetRaw(set) | ||
| return lnwire.NewFeatureVector(raw, lnwire.Features) | ||
| } | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,128 @@ | ||
| package feature | ||
|
|
||
| import ( | ||
| "reflect" | ||
| "testing" | ||
|
|
||
| "github.com/lightningnetwork/lnd/lnwire" | ||
| ) | ||
|
|
||
| type managerTest struct { | ||
| name string | ||
| cfg Config | ||
| } | ||
|
|
||
| const unknownFeature lnwire.FeatureBit = 30 | ||
|
|
||
| var testSetDesc = setDesc{ | ||
| lnwire.DataLossProtectRequired: { | ||
| SetNodeAnn: {}, // I | ||
| }, | ||
| lnwire.TLVOnionPayloadOptional: { | ||
| SetInit: {}, // I | ||
| SetNodeAnn: {}, // N | ||
| }, | ||
| lnwire.StaticRemoteKeyOptional: { | ||
| SetInit: {}, // I | ||
| SetNodeAnn: {}, // N | ||
| }, | ||
| } | ||
|
|
||
| var managerTests = []managerTest{ | ||
| { | ||
| name: "default", | ||
| cfg: Config{}, | ||
| }, | ||
| { | ||
| name: "no tlv", | ||
| cfg: Config{ | ||
| NoTLVOnion: true, | ||
| }, | ||
| }, | ||
| { | ||
| name: "no static remote key", | ||
| cfg: Config{ | ||
| NoStaticRemoteKey: true, | ||
| }, | ||
| }, | ||
| { | ||
| name: "no tlv or static remote key", | ||
| cfg: Config{ | ||
| NoTLVOnion: true, | ||
| NoStaticRemoteKey: true, | ||
| }, | ||
| }, | ||
| } | ||
|
|
||
| // TestManager asserts basic initialazation and operation of a feature manager, | ||
| // including that the proper features are removed in response to config changes. | ||
| func TestManager(t *testing.T) { | ||
| for _, test := range managerTests { | ||
| test := test | ||
| t.Run(test.name, func(t *testing.T) { | ||
| testManager(t, test) | ||
| }) | ||
| } | ||
| } | ||
|
|
||
| func testManager(t *testing.T, test managerTest) { | ||
| m, err := newManager(test.cfg, testSetDesc) | ||
| if err != nil { | ||
| t.Fatalf("unable to create feature manager: %v", err) | ||
| } | ||
|
|
||
| sets := []Set{ | ||
| SetInit, | ||
| SetLegacyGlobal, | ||
| SetNodeAnn, | ||
| SetInvoice, | ||
| } | ||
|
|
||
| for _, set := range sets { | ||
| raw := m.GetRaw(set) | ||
| fv := m.Get(set) | ||
|
|
||
| fv2 := lnwire.NewFeatureVector(raw, lnwire.Features) | ||
|
|
||
| if !reflect.DeepEqual(fv, fv2) { | ||
| t.Fatalf("mismatch Get vs GetRaw, raw: %v vs fv: %v", | ||
| fv2, fv) | ||
| } | ||
|
|
||
| assertUnset := func(bit lnwire.FeatureBit) { | ||
| hasBit := fv.HasFeature(bit) || fv.HasFeature(bit^1) | ||
| if hasBit { | ||
| t.Fatalf("bit %v or %v is set", bit, bit^1) | ||
| } | ||
| } | ||
|
|
||
| // Assert that the manager properly unset the configured feature | ||
| // bits from all sets. | ||
| if test.cfg.NoTLVOnion { | ||
| assertUnset(lnwire.TLVOnionPayloadOptional) | ||
| } | ||
| if test.cfg.NoStaticRemoteKey { | ||
| assertUnset(lnwire.StaticRemoteKeyOptional) | ||
| } | ||
|
|
||
| assertUnset(unknownFeature) | ||
| } | ||
|
|
||
| // Do same basic sanity checks on features that are always present. | ||
| nodeFeatures := m.Get(SetNodeAnn) | ||
|
|
||
| assertSet := func(bit lnwire.FeatureBit) { | ||
| has := nodeFeatures.HasFeature(bit) | ||
| if !has { | ||
| t.Fatalf("node features don't advertised %v", bit) | ||
| } | ||
| } | ||
|
|
||
| assertSet(lnwire.DataLossProtectOptional) | ||
| if !test.cfg.NoTLVOnion { | ||
| assertSet(lnwire.TLVOnionPayloadRequired) | ||
| } | ||
| if !test.cfg.NoStaticRemoteKey { | ||
| assertSet(lnwire.StaticRemoteKeyOptional) | ||
| } | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,41 @@ | ||
| package feature | ||
|
|
||
| // Set is an enum identifying various feature sets, which separates the single | ||
| // feature namespace into distinct categories depending what context a feature | ||
| // vector is being used. | ||
| type Set uint8 | ||
|
|
||
| const ( | ||
| // SetInit identifies features that should be sent in an Init message to | ||
| // a remote peer. | ||
| SetInit Set = iota | ||
|
|
||
| // SetLegacyGlobal identifies features that should be set in the legacy | ||
| // GlobalFeatures field of an Init message, which maintains backwards | ||
| // compatibility with nodes that haven't implemented flat features. | ||
| SetLegacyGlobal | ||
|
|
||
| // SetNodeAnn identifies features that should be advertised on node | ||
| // announcements. | ||
| SetNodeAnn | ||
|
|
||
| // SetInvoice identifies features that should be advertised on invoices | ||
| // generated by the daemon. | ||
| SetInvoice | ||
| ) | ||
|
|
||
| // String returns a human-readable description of a Set. | ||
| func (s Set) String() string { | ||
| switch s { | ||
| case SetInit: | ||
| return "SetInit" | ||
| case SetLegacyGlobal: | ||
| return "SetLegacyGlobal" | ||
| case SetNodeAnn: | ||
| return "SetNodeAnn" | ||
| case SetInvoice: | ||
| return "SetInvoice" | ||
| default: | ||
| return "SetUnknown" | ||
| } | ||
| } |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.