/ feature / manager_internal_test.go
manager_internal_test.go
  1  package feature
  2  
  3  import (
  4  	"reflect"
  5  	"testing"
  6  
  7  	"github.com/lightningnetwork/lnd/lnwire"
  8  	"github.com/stretchr/testify/require"
  9  )
 10  
 11  type managerTest struct {
 12  	name string
 13  	cfg  Config
 14  }
 15  
 16  const unknownFeature lnwire.FeatureBit = 30
 17  
 18  var testSetDesc = setDesc{
 19  	lnwire.DataLossProtectRequired: {
 20  		SetNodeAnn: {}, // I
 21  	},
 22  	lnwire.TLVOnionPayloadRequired: {
 23  		SetInit:    {}, // I
 24  		SetNodeAnn: {}, // N
 25  	},
 26  	lnwire.StaticRemoteKeyRequired: {
 27  		SetInit:    {}, // I
 28  		SetNodeAnn: {}, // N
 29  	},
 30  }
 31  
 32  var managerTests = []managerTest{
 33  	{
 34  		name: "default",
 35  		cfg:  Config{},
 36  	},
 37  	{
 38  		name: "no tlv",
 39  		cfg: Config{
 40  			NoTLVOnion: true,
 41  		},
 42  	},
 43  	{
 44  		name: "no static remote key",
 45  		cfg: Config{
 46  			NoStaticRemoteKey: true,
 47  		},
 48  	},
 49  	{
 50  		name: "no tlv or static remote key",
 51  		cfg: Config{
 52  			NoTLVOnion:        true,
 53  			NoStaticRemoteKey: true,
 54  		},
 55  	},
 56  	{
 57  		name: "anchors should disable anything dependent on it",
 58  		cfg: Config{
 59  			NoAnchors: true,
 60  		},
 61  	},
 62  }
 63  
 64  // TestManager asserts basic initialazation and operation of a feature manager,
 65  // including that the proper features are removed in response to config changes.
 66  func TestManager(t *testing.T) {
 67  	for _, test := range managerTests {
 68  		test := test
 69  		t.Run(test.name, func(t *testing.T) {
 70  			testManager(t, test)
 71  		})
 72  	}
 73  }
 74  
 75  func testManager(t *testing.T, test managerTest) {
 76  	m, err := newManager(test.cfg, testSetDesc)
 77  	require.NoError(t, err, "unable to create feature manager")
 78  
 79  	sets := []Set{
 80  		SetInit,
 81  		SetLegacyGlobal,
 82  		SetNodeAnn,
 83  		SetInvoice,
 84  	}
 85  
 86  	for _, set := range sets {
 87  		raw := m.GetRaw(set)
 88  		fv := m.Get(set)
 89  
 90  		fv2 := lnwire.NewFeatureVector(raw, lnwire.Features)
 91  
 92  		if !reflect.DeepEqual(fv, fv2) {
 93  			t.Fatalf("mismatch Get vs GetRaw, raw: %v vs fv: %v",
 94  				fv2, fv)
 95  		}
 96  
 97  		assertUnset := func(bit lnwire.FeatureBit) {
 98  			hasBit := fv.HasFeature(bit) || fv.HasFeature(bit^1)
 99  			if hasBit {
100  				t.Fatalf("bit %v or %v is set", bit, bit^1)
101  			}
102  		}
103  
104  		// Assert that the manager properly unset the configured feature
105  		// bits from all sets.
106  		if test.cfg.NoTLVOnion {
107  			assertUnset(lnwire.TLVOnionPayloadRequired)
108  			assertUnset(lnwire.TLVOnionPayloadOptional)
109  		}
110  		if test.cfg.NoStaticRemoteKey {
111  			assertUnset(lnwire.StaticRemoteKeyRequired)
112  			assertUnset(lnwire.StaticRemoteKeyOptional)
113  		}
114  		if test.cfg.NoAnchors {
115  			assertUnset(lnwire.ScriptEnforcedLeaseRequired)
116  			assertUnset(lnwire.ScriptEnforcedLeaseOptional)
117  		}
118  
119  		assertUnset(unknownFeature)
120  	}
121  
122  	// Do same basic sanity checks on features that are always present.
123  	nodeFeatures := m.Get(SetNodeAnn)
124  
125  	assertSet := func(bit lnwire.FeatureBit) {
126  		has := nodeFeatures.HasFeature(bit)
127  		if !has {
128  			t.Fatalf("node features don't advertised %v", bit)
129  		}
130  	}
131  
132  	assertSet(lnwire.DataLossProtectRequired)
133  	if !test.cfg.NoTLVOnion {
134  		assertSet(lnwire.TLVOnionPayloadRequired)
135  	}
136  	if !test.cfg.NoStaticRemoteKey {
137  		assertSet(lnwire.StaticRemoteKeyRequired)
138  	}
139  }
140  
141  // TestUpdateFeatureSets tests validation of the update of various features in
142  // each of our sets, asserting that the feature set is not partially modified
143  // if one set in incorrectly specified.
144  func TestUpdateFeatureSets(t *testing.T) {
145  	t.Parallel()
146  
147  	// Use a reduced set description to make reasoning about our sets
148  	// easier.
149  	setDesc := setDesc{
150  		lnwire.DataLossProtectRequired: {
151  			SetInit:    {}, // I
152  			SetNodeAnn: {}, // N
153  		},
154  		lnwire.GossipQueriesOptional: {
155  			SetNodeAnn: {}, // N
156  		},
157  	}
158  
159  	testCases := []struct {
160  		name     string
161  		features map[Set]*lnwire.RawFeatureVector
162  		config   Config
163  		err      error
164  	}{
165  		{
166  			name: "unknown set",
167  			features: map[Set]*lnwire.RawFeatureVector{
168  				setSentinel + 1: lnwire.NewRawFeatureVector(),
169  			},
170  			err: ErrUnknownSet,
171  		},
172  		{
173  			name: "invalid pairwise feature",
174  			features: map[Set]*lnwire.RawFeatureVector{
175  				SetNodeAnn: lnwire.NewRawFeatureVector(
176  					lnwire.FeatureBit(1000),
177  					lnwire.FeatureBit(1001),
178  				),
179  			},
180  			err: lnwire.ErrFeaturePairExists,
181  		},
182  		{
183  			name: "error in one set",
184  			features: map[Set]*lnwire.RawFeatureVector{
185  				SetNodeAnn: lnwire.NewRawFeatureVector(
186  					lnwire.FeatureBit(1000),
187  					lnwire.FeatureBit(1001),
188  				),
189  				SetInit: lnwire.NewRawFeatureVector(
190  					lnwire.DataLossProtectRequired,
191  				),
192  			},
193  			err: lnwire.ErrFeaturePairExists,
194  		},
195  		{
196  			name: "update existing sets ok",
197  			features: map[Set]*lnwire.RawFeatureVector{
198  				SetInit: lnwire.NewRawFeatureVector(
199  					lnwire.DataLossProtectRequired,
200  					lnwire.FeatureBit(1001),
201  				),
202  				SetNodeAnn: lnwire.NewRawFeatureVector(
203  					lnwire.DataLossProtectRequired,
204  					lnwire.GossipQueriesOptional,
205  					lnwire.FeatureBit(1000),
206  				),
207  			},
208  		},
209  		{
210  			name: "update new, valid set ok",
211  			features: map[Set]*lnwire.RawFeatureVector{
212  				SetInvoice: lnwire.NewRawFeatureVector(
213  					lnwire.FeatureBit(1001),
214  				),
215  			},
216  		},
217  		{
218  			name: "missing configured feature",
219  			features: map[Set]*lnwire.RawFeatureVector{
220  				SetInit: lnwire.NewRawFeatureVector(
221  					lnwire.DataLossProtectRequired,
222  				),
223  				SetNodeAnn: lnwire.NewRawFeatureVector(
224  					lnwire.DataLossProtectRequired,
225  					lnwire.GossipQueriesOptional,
226  				),
227  			},
228  			config: Config{
229  				CustomFeatures: map[Set][]lnwire.FeatureBit{
230  					SetInit: {
231  						lnwire.FeatureBit(333),
232  					},
233  				},
234  			},
235  			err: ErrFeatureConfigured,
236  		},
237  		{
238  			name: "valid",
239  			features: map[Set]*lnwire.RawFeatureVector{
240  				SetInit: lnwire.NewRawFeatureVector(
241  					lnwire.DataLossProtectRequired,
242  				),
243  				SetNodeAnn: lnwire.NewRawFeatureVector(
244  					lnwire.DataLossProtectRequired,
245  					lnwire.GossipQueriesOptional,
246  					lnwire.FeatureBit(500),
247  				),
248  				SetInvoice: lnwire.NewRawFeatureVector(
249  					lnwire.FeatureBit(333),
250  				),
251  			},
252  			config: Config{
253  				CustomFeatures: map[Set][]lnwire.FeatureBit{
254  					SetInvoice: {
255  						lnwire.FeatureBit(333),
256  					},
257  				},
258  			},
259  		},
260  	}
261  
262  	for _, testCase := range testCases {
263  		testCase := testCase
264  		t.Run(testCase.name, func(t *testing.T) {
265  			t.Parallel()
266  
267  			featureMgr, err := newManager(testCase.config, setDesc)
268  			require.NoError(t, err)
269  
270  			err = featureMgr.UpdateFeatureSets(testCase.features)
271  			require.ErrorIs(t, err, testCase.err)
272  
273  			// Compare the feature manager's sets to the updated
274  			// set if no error was hit, otherwise assert that it
275  			// is unchanged.
276  			expected := testCase.features
277  			actual := featureMgr
278  			if err != nil {
279  				originalMgr, err := newManager(
280  					testCase.config, setDesc,
281  				)
282  				require.NoError(t, err)
283  				expected = originalMgr.fsets
284  			}
285  
286  			for set, expectedFeatures := range expected {
287  				actualSet := actual.GetRaw(set)
288  				require.True(t,
289  					actualSet.Equals(expectedFeatures))
290  			}
291  		})
292  	}
293  }