123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531 |
- package lnwire
- import (
- "bytes"
- "math"
- "reflect"
- "sort"
- "testing"
- "github.com/stretchr/testify/require"
- )
- var testFeatureNames = map[FeatureBit]string{
- 0: "feature1",
- 3: "feature2",
- 4: "feature3",
- 5: "feature3",
- }
- func TestFeatureVectorSetUnset(t *testing.T) {
- t.Parallel()
- tests := []struct {
- bits []FeatureBit
- expectedFeatures []bool
- }{
- // No features are enabled if no bits are set.
- {
- bits: nil,
- expectedFeatures: []bool{false, false, false, false, false, false, false, false},
- },
- // Test setting an even bit for an even-only bit feature. The
- // corresponding odd bit should not be seen as set.
- {
- bits: []FeatureBit{0},
- expectedFeatures: []bool{true, false, false, false, false, false, false, false},
- },
- // Test setting an odd bit for an even-only bit feature. The
- // corresponding even bit should not be seen as set.
- {
- bits: []FeatureBit{1},
- expectedFeatures: []bool{false, true, false, false, false, false, false, false},
- },
- // Test setting an even bit for an odd-only bit feature. The bit should
- // be seen as set and the odd bit should not.
- {
- bits: []FeatureBit{2},
- expectedFeatures: []bool{false, false, true, false, false, false, false, false},
- },
- // Test setting an odd bit for an odd-only bit feature. The bit should
- // be seen as set and the even bit should not.
- {
- bits: []FeatureBit{3},
- expectedFeatures: []bool{false, false, false, true, false, false, false, false},
- },
- // Test setting an even bit for even-odd pair feature. Both bits in the
- // pair should be seen as set.
- {
- bits: []FeatureBit{4},
- expectedFeatures: []bool{false, false, false, false, true, true, false, false},
- },
- // Test setting an odd bit for even-odd pair feature. Both bits in the
- // pair should be seen as set.
- {
- bits: []FeatureBit{5},
- expectedFeatures: []bool{false, false, false, false, true, true, false, false},
- },
- // Test setting an even bit for an unknown feature. The bit should be
- // seen as set and the odd bit should not.
- {
- bits: []FeatureBit{6},
- expectedFeatures: []bool{false, false, false, false, false, false, true, false},
- },
- // Test setting an odd bit for an unknown feature. The bit should be
- // seen as set and the odd bit should not.
- {
- bits: []FeatureBit{7},
- expectedFeatures: []bool{false, false, false, false, false, false, false, true},
- },
- }
- fv := NewFeatureVector(nil, testFeatureNames)
- for i, test := range tests {
- for _, bit := range test.bits {
- fv.Set(bit)
- }
- for j, expectedSet := range test.expectedFeatures {
- if fv.HasFeature(FeatureBit(j)) != expectedSet {
- t.Errorf("Expectation failed in case %d, bit %d", i, j)
- break
- }
- }
- for _, bit := range test.bits {
- fv.Unset(bit)
- }
- }
- }
- // TestFeatureVectorRequiresFeature tests that if a feature vector only
- // includes a required feature bit (it's even), then the RequiresFeature method
- // will return true for both that bit as well as it's optional counter party.
- func TestFeatureVectorRequiresFeature(t *testing.T) {
- t.Parallel()
- // Create a new feature vector with the features above, and set only
- // the set of required bits. These will be all the even features
- // referenced above.
- fv := NewFeatureVector(nil, testFeatureNames)
- fv.Set(0)
- fv.Set(4)
- // Next we'll query for those exact bits, these should show up as being
- // required.
- require.True(t, fv.RequiresFeature(0))
- require.True(t, fv.RequiresFeature(4))
- // If we query for the odd (optional) counter party to each of the
- // features, the method should still return that the backing feature
- // vector requires the feature to be set.
- require.True(t, fv.RequiresFeature(1))
- require.True(t, fv.RequiresFeature(5))
- }
- func TestFeatureVectorEncodeDecode(t *testing.T) {
- t.Parallel()
- tests := []struct {
- bits []FeatureBit
- expectedEncoded []byte
- }{
- {
- bits: nil,
- expectedEncoded: []byte{0x00, 0x00},
- },
- {
- bits: []FeatureBit{2, 3, 7},
- expectedEncoded: []byte{0x00, 0x01, 0x8C},
- },
- {
- bits: []FeatureBit{2, 3, 8},
- expectedEncoded: []byte{0x00, 0x02, 0x01, 0x0C},
- },
- }
- for i, test := range tests {
- fv := NewRawFeatureVector(test.bits...)
- // Test that Encode produces the correct serialization.
- buffer := new(bytes.Buffer)
- err := fv.Encode(buffer)
- if err != nil {
- t.Errorf("Failed to encode feature vector in case %d: %v", i, err)
- continue
- }
- encoded := buffer.Bytes()
- if !bytes.Equal(encoded, test.expectedEncoded) {
- t.Errorf("Wrong encoding in case %d: got %v, expected %v",
- i, encoded, test.expectedEncoded)
- continue
- }
- // Test that decoding then re-encoding produces the same result.
- fv2 := NewRawFeatureVector()
- err = fv2.Decode(bytes.NewReader(encoded))
- if err != nil {
- t.Errorf("Failed to decode feature vector in case %d: %v", i, err)
- continue
- }
- buffer2 := new(bytes.Buffer)
- err = fv2.Encode(buffer2)
- if err != nil {
- t.Errorf("Failed to re-encode feature vector in case %d: %v",
- i, err)
- continue
- }
- reencoded := buffer2.Bytes()
- if !bytes.Equal(reencoded, test.expectedEncoded) {
- t.Errorf("Wrong re-encoding in case %d: got %v, expected %v",
- i, reencoded, test.expectedEncoded)
- }
- }
- }
- func TestFeatureVectorUnknownFeatures(t *testing.T) {
- t.Parallel()
- tests := []struct {
- bits []FeatureBit
- expectedUnknown []FeatureBit
- }{
- {
- bits: nil,
- expectedUnknown: nil,
- },
- // Since bits {0, 3, 4, 5} are known, and only even bits are considered
- // required (according to the "it's OK to be odd rule"), that leaves
- // {2, 6} as both unknown and required.
- {
- bits: []FeatureBit{0, 1, 2, 3, 4, 5, 6, 7},
- expectedUnknown: []FeatureBit{2, 6},
- },
- }
- for i, test := range tests {
- rawVector := NewRawFeatureVector(test.bits...)
- fv := NewFeatureVector(rawVector, testFeatureNames)
- unknown := fv.UnknownRequiredFeatures()
- // Sort to make comparison independent of order
- sort.Slice(unknown, func(i, j int) bool {
- return unknown[i] < unknown[j]
- })
- if !reflect.DeepEqual(unknown, test.expectedUnknown) {
- t.Errorf("Wrong unknown features in case %d: got %v, expected %v",
- i, unknown, test.expectedUnknown)
- }
- }
- }
- func TestFeatureNames(t *testing.T) {
- t.Parallel()
- tests := []struct {
- bit FeatureBit
- expectedName string
- expectedKnown bool
- }{
- {
- bit: 0,
- expectedName: "feature1",
- expectedKnown: true,
- },
- {
- bit: 1,
- expectedName: "unknown",
- expectedKnown: false,
- },
- {
- bit: 2,
- expectedName: "unknown",
- expectedKnown: false,
- },
- {
- bit: 3,
- expectedName: "feature2",
- expectedKnown: true,
- },
- {
- bit: 4,
- expectedName: "feature3",
- expectedKnown: true,
- },
- {
- bit: 5,
- expectedName: "feature3",
- expectedKnown: true,
- },
- {
- bit: 6,
- expectedName: "unknown",
- expectedKnown: false,
- },
- {
- bit: 7,
- expectedName: "unknown",
- expectedKnown: false,
- },
- }
- fv := NewFeatureVector(nil, testFeatureNames)
- for _, test := range tests {
- name := fv.Name(test.bit)
- if name != test.expectedName {
- t.Errorf("Name for feature bit %d is incorrect: "+
- "expected %s, got %s", test.bit, name, test.expectedName)
- }
- known := fv.IsKnown(test.bit)
- if known != test.expectedKnown {
- t.Errorf("IsKnown for feature bit %d is incorrect: "+
- "expected %v, got %v", test.bit, known, test.expectedKnown)
- }
- }
- }
- // TestIsRequired asserts that feature bits properly return their IsRequired
- // status. We require that even features be required and odd features be
- // optional.
- func TestIsRequired(t *testing.T) {
- optional := FeatureBit(1)
- if optional.IsRequired() {
- t.Fatalf("optional feature should not be required")
- }
- required := FeatureBit(0)
- if !required.IsRequired() {
- t.Fatalf("required feature should be required")
- }
- }
- // TestFeatures asserts that the Features() method on a FeatureVector properly
- // returns the set of feature bits it stores internally.
- func TestFeatures(t *testing.T) {
- tests := []struct {
- name string
- exp map[FeatureBit]struct{}
- }{
- {
- name: "empty",
- exp: map[FeatureBit]struct{}{},
- },
- {
- name: "one",
- exp: map[FeatureBit]struct{}{
- 5: {},
- },
- },
- {
- name: "several",
- exp: map[FeatureBit]struct{}{
- 0: {},
- 5: {},
- 23948: {},
- },
- },
- }
- toRawFV := func(set map[FeatureBit]struct{}) *RawFeatureVector {
- var bits []FeatureBit
- for bit := range set {
- bits = append(bits, bit)
- }
- return NewRawFeatureVector(bits...)
- }
- for _, test := range tests {
- test := test
- t.Run(test.name, func(t *testing.T) {
- fv := NewFeatureVector(
- toRawFV(test.exp), Features,
- )
- if !reflect.DeepEqual(fv.Features(), test.exp) {
- t.Fatalf("feature mismatch, want: %v, got: %v",
- test.exp, fv.Features())
- }
- })
- }
- }
- func TestRawFeatureVectorOnlyContains(t *testing.T) {
- t.Parallel()
- features := []FeatureBit{
- StaticRemoteKeyOptional,
- AnchorsZeroFeeHtlcTxOptional,
- ExplicitChannelTypeRequired,
- }
- fv := NewRawFeatureVector(features...)
- require.True(t, fv.OnlyContains(features...))
- require.False(t, fv.OnlyContains(features[:1]...))
- }
- func TestEqualRawFeatureVectors(t *testing.T) {
- t.Parallel()
- a := NewRawFeatureVector(
- StaticRemoteKeyOptional,
- AnchorsZeroFeeHtlcTxOptional,
- ExplicitChannelTypeRequired,
- )
- b := a.Clone()
- require.True(t, a.Equals(b))
- b.Unset(ExplicitChannelTypeRequired)
- require.False(t, a.Equals(b))
- b.Set(ExplicitChannelTypeOptional)
- require.False(t, a.Equals(b))
- }
- func TestIsEmptyFeatureVector(t *testing.T) {
- t.Parallel()
- fv := NewRawFeatureVector()
- require.True(t, fv.IsEmpty())
- fv.Set(StaticRemoteKeyOptional)
- require.False(t, fv.IsEmpty())
- fv.Unset(StaticRemoteKeyOptional)
- require.True(t, fv.IsEmpty())
- }
- // TestValidatePairs tests that feature vectors can only set the required or
- // optional feature bit in a pair, not both.
- func TestValidatePairs(t *testing.T) {
- t.Parallel()
- rfv := NewRawFeatureVector(
- StaticRemoteKeyOptional,
- StaticRemoteKeyRequired,
- )
- require.Equal(t, ErrFeaturePairExists, rfv.ValidatePairs())
- rfv = NewRawFeatureVector(
- StaticRemoteKeyOptional,
- PaymentAddrRequired,
- )
- require.Nil(t, rfv.ValidatePairs())
- }
- // TestValidateUpdate tests validation of an update to a feature vector.
- func TestValidateUpdate(t *testing.T) {
- t.Parallel()
- testCases := []struct {
- name string
- currentFeatures []FeatureBit
- newFeatures []FeatureBit
- maximumValue FeatureBit
- err error
- }{
- {
- name: "defined feature bit set, can include",
- currentFeatures: []FeatureBit{
- StaticRemoteKeyOptional,
- },
- newFeatures: []FeatureBit{
- StaticRemoteKeyOptional,
- },
- err: nil,
- },
- {
- name: "defined feature bit not already set",
- currentFeatures: []FeatureBit{
- StaticRemoteKeyOptional,
- },
- newFeatures: []FeatureBit{
- StaticRemoteKeyOptional,
- PaymentAddrRequired,
- },
- err: ErrFeatureStandard,
- },
- {
- name: "known feature missing",
- currentFeatures: []FeatureBit{
- StaticRemoteKeyOptional,
- PaymentAddrRequired,
- },
- newFeatures: []FeatureBit{
- StaticRemoteKeyOptional,
- },
- err: ErrFeatureStandard,
- },
- {
- name: "can set unknown feature",
- currentFeatures: []FeatureBit{
- StaticRemoteKeyOptional,
- },
- newFeatures: []FeatureBit{
- StaticRemoteKeyOptional,
- FeatureBit(1001),
- },
- err: nil,
- },
- {
- name: "can unset unknown feature",
- currentFeatures: []FeatureBit{
- StaticRemoteKeyOptional,
- FeatureBit(1001),
- },
- newFeatures: []FeatureBit{
- StaticRemoteKeyOptional,
- },
- err: nil,
- },
- {
- name: "at allowed maximum",
- currentFeatures: []FeatureBit{
- StaticRemoteKeyOptional,
- },
- newFeatures: []FeatureBit{
- StaticRemoteKeyOptional,
- 100,
- },
- maximumValue: 100,
- err: nil,
- },
- {
- name: "above allowed maximum",
- currentFeatures: []FeatureBit{
- StaticRemoteKeyOptional,
- },
- newFeatures: []FeatureBit{
- StaticRemoteKeyOptional,
- 101,
- },
- maximumValue: 100,
- err: ErrFeatureBitMaximum,
- },
- }
- for _, testCase := range testCases {
- testCase := testCase
- t.Run(testCase.name, func(t *testing.T) {
- t.Parallel()
- currentFV := NewRawFeatureVector(
- testCase.currentFeatures...,
- )
- newFV := NewRawFeatureVector(testCase.newFeatures...)
- // Set maximum value if not populated in the test case.
- maximumValue := testCase.maximumValue
- if testCase.maximumValue == 0 {
- maximumValue = math.MaxUint16
- }
- err := currentFV.ValidateUpdate(newFV, maximumValue)
- require.ErrorIs(t, err, testCase.err)
- })
- }
- }
|