feature: add update function for safe feature update

Disallow update of any features that are defined by LND (since
just updating the feature, but not the functionality will result in
strange behavior). All known feature bits should be toggled using
protocol config options.
This commit is contained in:
Carla Kirk-Cohen committed 2023-05-04 10:35:44 -04:00
1 parent 1a9d743e18
commit 5a139fd297
3 files changed
+163

No files matched your search

+110
View File
@@ -135,3 +135,113 @@ func testManager(t *testing.T, test managerTest) {
assertSet(lnwire.StaticRemoteKeyOptional)
}
}
// TestUpdateFeatureSets tests validation of the update of various features in
// each of our sets, asserting that the feature set is not partially modified
// if one set in incorrectly specified.
func TestUpdateFeatureSets(t *testing.T) {
t.Parallel()
// Use a reduced set description to make reasoning about our sets
// easier.
setDesc := setDesc{
lnwire.DataLossProtectRequired: {
SetInit: {}, // I
SetNodeAnn: {}, // N
},
lnwire.GossipQueriesOptional: {
SetNodeAnn: {}, // N
},
}
testCases := []struct {
name string
features map[Set]*lnwire.RawFeatureVector
err error
}{
{
name: "unknown set",
features: map[Set]*lnwire.RawFeatureVector{
setSentinel + 1: lnwire.NewRawFeatureVector(),
},
err: ErrUnknownSet,
},
{
name: "invalid pairwise feature",
features: map[Set]*lnwire.RawFeatureVector{
SetNodeAnn: lnwire.NewRawFeatureVector(
lnwire.FeatureBit(1000),
lnwire.FeatureBit(1001),
),
},
err: lnwire.ErrFeaturePairExists,
},
{
name: "error in one set",
features: map[Set]*lnwire.RawFeatureVector{
SetNodeAnn: lnwire.NewRawFeatureVector(
lnwire.FeatureBit(1000),
lnwire.FeatureBit(1001),
),
SetInit: lnwire.NewRawFeatureVector(
lnwire.DataLossProtectRequired,
),
},
err: lnwire.ErrFeaturePairExists,
},
{
name: "update existing sets ok",
features: map[Set]*lnwire.RawFeatureVector{
SetInit: lnwire.NewRawFeatureVector(
lnwire.DataLossProtectRequired,
lnwire.FeatureBit(1001),
),
SetNodeAnn: lnwire.NewRawFeatureVector(
lnwire.DataLossProtectRequired,
lnwire.GossipQueriesOptional,
lnwire.FeatureBit(1000),
),
},
},
{
name: "update new, valid set ok",
features: map[Set]*lnwire.RawFeatureVector{
SetInvoice: lnwire.NewRawFeatureVector(
lnwire.FeatureBit(1001),
),
},
},
}
for _, testCase := range testCases {
testCase := testCase
t.Run(testCase.name, func(t *testing.T) {
t.Parallel()
featureMgr, err := newManager(Config{}, setDesc)
require.NoError(t, err)
err = featureMgr.UpdateFeatureSets(testCase.features)
require.ErrorIs(t, err, testCase.err)
// Compare the feature manager's sets to the updated
// set if no error was hit, otherwise assert that it
// is unchanged.
expected := testCase.features
actual := featureMgr
if err != nil {
originalMgr, err := newManager(
Config{}, setDesc,
)
require.NoError(t, err)
expected = originalMgr.fsets
}
for set, expectedFeatures := range expected {
actualSet := actual.GetRaw(set)
require.True(t,
actualSet.Equals(expectedFeatures))
}
})
}
}