mirror of
https://github.com/lightningnetwork/lnd.git
synced 2025-06-21 22:32:33 +02:00
features: disallow unsetting of config-set features
This commit is contained in:
parent
4e36e2fd2b
commit
fe7cad2695
@ -7,9 +7,15 @@ import (
|
|||||||
"github.com/lightningnetwork/lnd/lnwire"
|
"github.com/lightningnetwork/lnd/lnwire"
|
||||||
)
|
)
|
||||||
|
|
||||||
// ErrUnknownSet is returned if a proposed feature vector contains a set that
|
var (
|
||||||
// is unknown to LND.
|
// ErrUnknownSet is returned if a proposed feature vector contains a
|
||||||
var ErrUnknownSet = errors.New("unknown feature bit set")
|
// set that is unknown to LND.
|
||||||
|
ErrUnknownSet = errors.New("unknown feature bit set")
|
||||||
|
|
||||||
|
// ErrFeatureConfigured is returned if an attempt is made to unset a
|
||||||
|
// feature that was configured at startup.
|
||||||
|
ErrFeatureConfigured = errors.New("can't unset configured feature")
|
||||||
|
)
|
||||||
|
|
||||||
// Config houses any runtime modifications to the default set descriptors. For
|
// Config houses any runtime modifications to the default set descriptors. For
|
||||||
// our purposes, this typically means disabling certain features to test legacy
|
// our purposes, this typically means disabling certain features to test legacy
|
||||||
@ -61,6 +67,11 @@ type Manager struct {
|
|||||||
// fsets is a static map of feature set to raw feature vectors. Requests
|
// fsets is a static map of feature set to raw feature vectors. Requests
|
||||||
// are fulfilled by cloning these internal feature vectors.
|
// are fulfilled by cloning these internal feature vectors.
|
||||||
fsets map[Set]*lnwire.RawFeatureVector
|
fsets map[Set]*lnwire.RawFeatureVector
|
||||||
|
|
||||||
|
// configFeatures is a set of custom features that were "hard set" in
|
||||||
|
// lnd's config that cannot be updated at runtime (as is the case with
|
||||||
|
// our "standard" features that are defined in LND).
|
||||||
|
configFeatures map[Set]*lnwire.FeatureVector
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewManager creates a new feature Manager, applying any custom modifications
|
// NewManager creates a new feature Manager, applying any custom modifications
|
||||||
@ -99,6 +110,7 @@ func newManager(cfg Config, desc setDesc) (*Manager, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Now, remove any features as directed by the config.
|
// Now, remove any features as directed by the config.
|
||||||
|
configFeatures := make(map[Set]*lnwire.FeatureVector)
|
||||||
for set, raw := range fsets {
|
for set, raw := range fsets {
|
||||||
if cfg.NoTLVOnion {
|
if cfg.NoTLVOnion {
|
||||||
raw.Unset(lnwire.TLVOnionPayloadOptional)
|
raw.Unset(lnwire.TLVOnionPayloadOptional)
|
||||||
@ -177,6 +189,15 @@ func newManager(cfg Config, desc setDesc) (*Manager, error) {
|
|||||||
"feature: %d", err, custom)
|
"feature: %d", err, custom)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Track custom features separately so that we can check that
|
||||||
|
// they aren't unset in subsequent updates. If there is no
|
||||||
|
// entry for the set, the vector will just be empty.
|
||||||
|
configFeatures[set] = lnwire.NewFeatureVector(
|
||||||
|
lnwire.NewRawFeatureVector(cfg.CustomFeatures[set]...),
|
||||||
|
lnwire.Features,
|
||||||
|
)
|
||||||
|
|
||||||
// Ensure that all of our feature sets properly set any
|
// Ensure that all of our feature sets properly set any
|
||||||
// dependent features.
|
// dependent features.
|
||||||
fv := lnwire.NewFeatureVector(raw, lnwire.Features)
|
fv := lnwire.NewFeatureVector(raw, lnwire.Features)
|
||||||
@ -188,7 +209,8 @@ func newManager(cfg Config, desc setDesc) (*Manager, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return &Manager{
|
return &Manager{
|
||||||
fsets: fsets,
|
fsets: fsets,
|
||||||
|
configFeatures: configFeatures,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -248,6 +270,18 @@ func (m *Manager) UpdateFeatureSets(
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If any features were configured for this set, ensure that
|
||||||
|
// they are still set in the new feature vector.
|
||||||
|
if cfgFeat, haveCfgFeat := m.configFeatures[set]; haveCfgFeat {
|
||||||
|
for feature := range cfgFeat.Features() {
|
||||||
|
if !newFeatures.IsSet(feature) {
|
||||||
|
return fmt.Errorf("%w: can't unset: "+
|
||||||
|
"%d", ErrFeatureConfigured,
|
||||||
|
feature)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fv := lnwire.NewFeatureVector(newFeatures, lnwire.Features)
|
fv := lnwire.NewFeatureVector(newFeatures, lnwire.Features)
|
||||||
if err := ValidateDeps(fv); err != nil {
|
if err := ValidateDeps(fv); err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -157,6 +157,7 @@ func TestUpdateFeatureSets(t *testing.T) {
|
|||||||
testCases := []struct {
|
testCases := []struct {
|
||||||
name string
|
name string
|
||||||
features map[Set]*lnwire.RawFeatureVector
|
features map[Set]*lnwire.RawFeatureVector
|
||||||
|
config Config
|
||||||
err error
|
err error
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
@ -211,6 +212,49 @@ func TestUpdateFeatureSets(t *testing.T) {
|
|||||||
),
|
),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: "missing configured feature",
|
||||||
|
features: map[Set]*lnwire.RawFeatureVector{
|
||||||
|
SetInit: lnwire.NewRawFeatureVector(
|
||||||
|
lnwire.DataLossProtectRequired,
|
||||||
|
),
|
||||||
|
SetNodeAnn: lnwire.NewRawFeatureVector(
|
||||||
|
lnwire.DataLossProtectRequired,
|
||||||
|
lnwire.GossipQueriesOptional,
|
||||||
|
),
|
||||||
|
},
|
||||||
|
config: Config{
|
||||||
|
CustomFeatures: map[Set][]lnwire.FeatureBit{
|
||||||
|
SetInit: {
|
||||||
|
lnwire.FeatureBit(333),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
err: ErrFeatureConfigured,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "valid",
|
||||||
|
features: map[Set]*lnwire.RawFeatureVector{
|
||||||
|
SetInit: lnwire.NewRawFeatureVector(
|
||||||
|
lnwire.DataLossProtectRequired,
|
||||||
|
),
|
||||||
|
SetNodeAnn: lnwire.NewRawFeatureVector(
|
||||||
|
lnwire.DataLossProtectRequired,
|
||||||
|
lnwire.GossipQueriesOptional,
|
||||||
|
lnwire.FeatureBit(500),
|
||||||
|
),
|
||||||
|
SetInvoice: lnwire.NewRawFeatureVector(
|
||||||
|
lnwire.FeatureBit(333),
|
||||||
|
),
|
||||||
|
},
|
||||||
|
config: Config{
|
||||||
|
CustomFeatures: map[Set][]lnwire.FeatureBit{
|
||||||
|
SetInvoice: {
|
||||||
|
lnwire.FeatureBit(333),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, testCase := range testCases {
|
for _, testCase := range testCases {
|
||||||
@ -218,7 +262,7 @@ func TestUpdateFeatureSets(t *testing.T) {
|
|||||||
t.Run(testCase.name, func(t *testing.T) {
|
t.Run(testCase.name, func(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
featureMgr, err := newManager(Config{}, setDesc)
|
featureMgr, err := newManager(testCase.config, setDesc)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
err = featureMgr.UpdateFeatureSets(testCase.features)
|
err = featureMgr.UpdateFeatureSets(testCase.features)
|
||||||
@ -231,7 +275,7 @@ func TestUpdateFeatureSets(t *testing.T) {
|
|||||||
actual := featureMgr
|
actual := featureMgr
|
||||||
if err != nil {
|
if err != nil {
|
||||||
originalMgr, err := newManager(
|
originalMgr, err := newManager(
|
||||||
Config{}, setDesc,
|
testCase.config, setDesc,
|
||||||
)
|
)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
expected = originalMgr.fsets
|
expected = originalMgr.fsets
|
||||||
|
Loading…
x
Reference in New Issue
Block a user