mirror of
https://github.com/lightningnetwork/lnd.git
synced 2025-05-06 18:00:25 +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"
|
||||
)
|
||||
|
||||
// ErrUnknownSet is returned if a proposed feature vector contains a set that
|
||||
// is unknown to LND.
|
||||
var ErrUnknownSet = errors.New("unknown feature bit set")
|
||||
var (
|
||||
// ErrUnknownSet is returned if a proposed feature vector contains a
|
||||
// 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
|
||||
// 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
|
||||
// are fulfilled by cloning these internal feature vectors.
|
||||
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
|
||||
@ -99,6 +110,7 @@ func newManager(cfg Config, desc setDesc) (*Manager, error) {
|
||||
}
|
||||
|
||||
// Now, remove any features as directed by the config.
|
||||
configFeatures := make(map[Set]*lnwire.FeatureVector)
|
||||
for set, raw := range fsets {
|
||||
if cfg.NoTLVOnion {
|
||||
raw.Unset(lnwire.TLVOnionPayloadOptional)
|
||||
@ -177,6 +189,15 @@ func newManager(cfg Config, desc setDesc) (*Manager, error) {
|
||||
"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
|
||||
// dependent features.
|
||||
fv := lnwire.NewFeatureVector(raw, lnwire.Features)
|
||||
@ -188,7 +209,8 @@ func newManager(cfg Config, desc setDesc) (*Manager, error) {
|
||||
}
|
||||
|
||||
return &Manager{
|
||||
fsets: fsets,
|
||||
fsets: fsets,
|
||||
configFeatures: configFeatures,
|
||||
}, nil
|
||||
}
|
||||
|
||||
@ -248,6 +270,18 @@ func (m *Manager) UpdateFeatureSets(
|
||||
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)
|
||||
if err := ValidateDeps(fv); err != nil {
|
||||
return err
|
||||
|
@ -157,6 +157,7 @@ func TestUpdateFeatureSets(t *testing.T) {
|
||||
testCases := []struct {
|
||||
name string
|
||||
features map[Set]*lnwire.RawFeatureVector
|
||||
config Config
|
||||
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 {
|
||||
@ -218,7 +262,7 @@ func TestUpdateFeatureSets(t *testing.T) {
|
||||
t.Run(testCase.name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
featureMgr, err := newManager(Config{}, setDesc)
|
||||
featureMgr, err := newManager(testCase.config, setDesc)
|
||||
require.NoError(t, err)
|
||||
|
||||
err = featureMgr.UpdateFeatureSets(testCase.features)
|
||||
@ -231,7 +275,7 @@ func TestUpdateFeatureSets(t *testing.T) {
|
||||
actual := featureMgr
|
||||
if err != nil {
|
||||
originalMgr, err := newManager(
|
||||
Config{}, setDesc,
|
||||
testCase.config, setDesc,
|
||||
)
|
||||
require.NoError(t, err)
|
||||
expected = originalMgr.fsets
|
||||
|
Loading…
x
Reference in New Issue
Block a user