mirror of
https://github.com/lightningnetwork/lnd.git
synced 2024-11-19 09:53:54 +01:00
dad53b3f9a
This reverts commit 717facc202
.
It turns out that we can't do this since it would result in
incompatibility with LDK. The spec has been updated to reallow
optional gossip queries so we revert this commit.
294 lines
6.5 KiB
Go
294 lines
6.5 KiB
Go
package feature
|
|
|
|
import (
|
|
"reflect"
|
|
"testing"
|
|
|
|
"github.com/lightningnetwork/lnd/lnwire"
|
|
"github.com/stretchr/testify/require"
|
|
)
|
|
|
|
type managerTest struct {
|
|
name string
|
|
cfg Config
|
|
}
|
|
|
|
const unknownFeature lnwire.FeatureBit = 30
|
|
|
|
var testSetDesc = setDesc{
|
|
lnwire.DataLossProtectRequired: {
|
|
SetNodeAnn: {}, // I
|
|
},
|
|
lnwire.TLVOnionPayloadRequired: {
|
|
SetInit: {}, // I
|
|
SetNodeAnn: {}, // N
|
|
},
|
|
lnwire.StaticRemoteKeyRequired: {
|
|
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,
|
|
},
|
|
},
|
|
{
|
|
name: "anchors should disable anything dependent on it",
|
|
cfg: Config{
|
|
NoAnchors: 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)
|
|
require.NoError(t, err, "unable to create feature manager")
|
|
|
|
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.TLVOnionPayloadRequired)
|
|
assertUnset(lnwire.TLVOnionPayloadOptional)
|
|
}
|
|
if test.cfg.NoStaticRemoteKey {
|
|
assertUnset(lnwire.StaticRemoteKeyRequired)
|
|
assertUnset(lnwire.StaticRemoteKeyOptional)
|
|
}
|
|
if test.cfg.NoAnchors {
|
|
assertUnset(lnwire.ScriptEnforcedLeaseRequired)
|
|
assertUnset(lnwire.ScriptEnforcedLeaseOptional)
|
|
}
|
|
|
|
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.DataLossProtectRequired)
|
|
if !test.cfg.NoTLVOnion {
|
|
assertSet(lnwire.TLVOnionPayloadRequired)
|
|
}
|
|
if !test.cfg.NoStaticRemoteKey {
|
|
assertSet(lnwire.StaticRemoteKeyRequired)
|
|
}
|
|
}
|
|
|
|
// 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
|
|
config Config
|
|
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),
|
|
),
|
|
},
|
|
},
|
|
{
|
|
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 {
|
|
testCase := testCase
|
|
t.Run(testCase.name, func(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
featureMgr, err := newManager(testCase.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(
|
|
testCase.config, setDesc,
|
|
)
|
|
require.NoError(t, err)
|
|
expected = originalMgr.fsets
|
|
}
|
|
|
|
for set, expectedFeatures := range expected {
|
|
actualSet := actual.GetRaw(set)
|
|
require.True(t,
|
|
actualSet.Equals(expectedFeatures))
|
|
}
|
|
})
|
|
}
|
|
}
|