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 }