lnwire: add new RequiresFeature method

In this commit, we add a new RequiresFeature method to the feature
vector struct. This method allows us to check if the set of features
we're examining *require* that the even portion of a bit pair be set.
This can be used to check if new behavior should be allowed (after we
flip new bits to be required) for existing contexts.
This commit is contained in:
Olaoluwa Osuntokun 2020-11-24 19:54:35 -08:00
parent 82ccab606c
commit baeceb2a0b
No known key found for this signature in database
GPG Key ID: 3BBD59E99B280306
2 changed files with 43 additions and 1 deletions

@ -398,6 +398,20 @@ func (fv *FeatureVector) HasFeature(feature FeatureBit) bool {
(fv.isFeatureBitPair(feature) && fv.IsSet(feature^1)) (fv.isFeatureBitPair(feature) && fv.IsSet(feature^1))
} }
// RequiresFeature returns true if the referenced feature vector *requires*
// that the given required bit be set. This method can be used with both
// optional and required feature bits as a parameter.
func (fv *FeatureVector) RequiresFeature(feature FeatureBit) bool {
// If we weren't passed a required feature bit, then we'll flip the
// lowest bit to query for the required version of the feature. This
// lets callers pass in both the optional and required bits.
if !feature.IsRequired() {
feature ^= 1
}
return fv.IsSet(feature)
}
// UnknownRequiredFeatures returns a list of feature bits set in the vector // UnknownRequiredFeatures returns a list of feature bits set in the vector
// that are unknown and in an even bit position. Feature bits with an even // that are unknown and in an even bit position. Feature bits with an even
// index must be known to a node receiving the feature vector in a message. // index must be known to a node receiving the feature vector in a message.

@ -5,6 +5,8 @@ import (
"reflect" "reflect"
"sort" "sort"
"testing" "testing"
"github.com/stretchr/testify/require"
) )
var testFeatureNames = map[FeatureBit]string{ var testFeatureNames = map[FeatureBit]string{
@ -87,6 +89,7 @@ func TestFeatureVectorSetUnset(t *testing.T) {
t.Errorf("Expectation failed in case %d, bit %d", i, j) t.Errorf("Expectation failed in case %d, bit %d", i, j)
break break
} }
} }
for _, bit := range test.bits { for _, bit := range test.bits {
@ -95,6 +98,31 @@ func TestFeatureVectorSetUnset(t *testing.T) {
} }
} }
// 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) { func TestFeatureVectorEncodeDecode(t *testing.T) {
t.Parallel() t.Parallel()
@ -277,7 +305,7 @@ func TestIsRequired(t *testing.T) {
} }
// TestFeatures asserts that the Features() method on a FeatureVector properly // TestFeatures asserts that the Features() method on a FeatureVector properly
// returns the set of feature bits it stores internallly. // returns the set of feature bits it stores internally.
func TestFeatures(t *testing.T) { func TestFeatures(t *testing.T) {
tests := []struct { tests := []struct {
name string name string