2017-02-16 15:31:19 +03:00
|
|
|
package lnwire
|
|
|
|
|
|
|
|
import (
|
|
|
|
"encoding/binary"
|
|
|
|
"io"
|
|
|
|
"math"
|
2017-02-23 02:53:12 +03:00
|
|
|
|
|
|
|
"github.com/go-errors/errors"
|
2017-02-16 15:31:19 +03:00
|
|
|
)
|
|
|
|
|
|
|
|
// featureFlag represent the status of the feature optional/required and needed
|
|
|
|
// to allow future incompatible changes, or backward compatible changes.
|
|
|
|
type featureFlag uint8
|
|
|
|
|
2017-02-23 02:53:12 +03:00
|
|
|
// String returns the string representation for the featureFlag.
|
2017-02-16 15:31:19 +03:00
|
|
|
func (f featureFlag) String() string {
|
|
|
|
switch f {
|
|
|
|
case OptionalFlag:
|
|
|
|
return "optional"
|
|
|
|
case RequiredFlag:
|
|
|
|
return "required"
|
|
|
|
default:
|
|
|
|
return "<unknown>"
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-03-16 22:11:53 +03:00
|
|
|
// featureName represent the name of the feature and needed in order to have
|
|
|
|
// the compile errors if we specify wrong feature name.
|
2017-02-16 15:31:19 +03:00
|
|
|
type featureName string
|
|
|
|
|
|
|
|
const (
|
2017-03-16 22:11:53 +03:00
|
|
|
// OptionalFlag represent the feature which we already have but it
|
|
|
|
// isn't required yet, and if remote peer doesn't have this feature we
|
|
|
|
// may turn it off without disconnecting with peer.
|
2017-02-16 15:31:19 +03:00
|
|
|
OptionalFlag featureFlag = 2 // 0b10
|
|
|
|
|
|
|
|
// RequiredFlag represent the features which is required for proper
|
|
|
|
// peer interaction, we disconnect with peer if it doesn't have this
|
|
|
|
// particular feature.
|
|
|
|
RequiredFlag featureFlag = 1 // 0b01
|
|
|
|
|
|
|
|
// flagMask is a mask which is needed to extract feature flag value.
|
|
|
|
flagMask = 3 // 0b11
|
|
|
|
|
|
|
|
// flagBitsSize represent the size of the feature flag in bits. For
|
|
|
|
// more information read the init message specification.
|
|
|
|
flagBitsSize = 2
|
|
|
|
|
|
|
|
// maxAllowedSize is a maximum allowed size of feature vector.
|
2017-03-16 22:11:53 +03:00
|
|
|
//
|
2017-02-16 15:31:19 +03:00
|
|
|
// NOTE: Within the protocol, the maximum allowed message size is 65535
|
2017-03-16 22:11:53 +03:00
|
|
|
// bytes. Adding the overhead from the crypto protocol (the 2-byte
|
|
|
|
// packet length and 16-byte MAC), we arrive at 65569 bytes. Accounting
|
|
|
|
// for the overhead within the feature message to signal the type of
|
|
|
|
// the message, that leaves 65567 bytes for the init message itself.
|
|
|
|
// Next, we reserve 4-bytes to encode the lengths of both the local and
|
|
|
|
// global feature vectors, so 65563 for the global and local features.
|
|
|
|
// Knocking off one byte for the sake of the calculation, that leads to
|
|
|
|
// a max allowed size of 32781 bytes for each feature vector, or 131124
|
|
|
|
// different features.
|
2017-02-16 15:31:19 +03:00
|
|
|
maxAllowedSize = 32781
|
|
|
|
)
|
|
|
|
|
2017-02-17 17:28:11 +03:00
|
|
|
// Feature represent the feature which is used on stage of initialization of
|
|
|
|
// feature vector. Initial feature flags might be changed dynamically later.
|
|
|
|
type Feature struct {
|
|
|
|
Name featureName
|
|
|
|
Flag featureFlag
|
|
|
|
}
|
|
|
|
|
2017-03-16 22:11:53 +03:00
|
|
|
// FeatureVector represents the global/local feature vector. With this
|
|
|
|
// structure you may set/get the feature by name and compare feature vector
|
|
|
|
// with remote one.
|
2017-02-16 15:31:19 +03:00
|
|
|
type FeatureVector struct {
|
2017-02-17 17:28:11 +03:00
|
|
|
// featuresMap is the map which stores the correspondence between
|
|
|
|
// feature name and its index within feature vector. Index within
|
2017-03-16 22:11:53 +03:00
|
|
|
// feature vector and actual binary position of feature are different
|
|
|
|
// things)
|
2017-02-17 17:28:11 +03:00
|
|
|
featuresMap map[featureName]int // name -> index
|
|
|
|
|
|
|
|
// flags is the map which stores the correspondence between feature
|
|
|
|
// index and its flag.
|
|
|
|
flags map[int]featureFlag // index -> flag
|
2017-02-16 15:31:19 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
// NewFeatureVector creates new instance of feature vector.
|
2017-02-17 17:28:11 +03:00
|
|
|
func NewFeatureVector(features []Feature) *FeatureVector {
|
|
|
|
featuresMap := make(map[featureName]int)
|
|
|
|
flags := make(map[int]featureFlag)
|
|
|
|
|
|
|
|
for index, feature := range features {
|
|
|
|
featuresMap[feature.Name] = index
|
|
|
|
flags[index] = feature.Flag
|
|
|
|
}
|
|
|
|
|
2017-02-16 15:31:19 +03:00
|
|
|
return &FeatureVector{
|
2017-02-17 17:28:11 +03:00
|
|
|
featuresMap: featuresMap,
|
|
|
|
flags: flags,
|
2017-02-16 15:31:19 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// SetFeatureFlag assign flag to the feature.
|
|
|
|
func (f *FeatureVector) SetFeatureFlag(name featureName, flag featureFlag) error {
|
2017-02-17 17:28:11 +03:00
|
|
|
position, ok := f.featuresMap[name]
|
2017-02-16 15:31:19 +03:00
|
|
|
if !ok {
|
|
|
|
return errors.Errorf("can't find feature with name: %v", name)
|
|
|
|
}
|
|
|
|
|
|
|
|
f.flags[position] = flag
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2017-02-17 17:28:11 +03:00
|
|
|
// serializedSize returns the number of bytes which is needed to represent
|
|
|
|
// feature vector in byte format.
|
|
|
|
func (f *FeatureVector) serializedSize() uint16 {
|
2017-02-16 15:31:19 +03:00
|
|
|
return uint16(math.Ceil(float64(flagBitsSize*len(f.flags)) / 8))
|
|
|
|
}
|
|
|
|
|
|
|
|
// NewFeatureVectorFromReader decodes the feature vector from binary
|
2017-03-16 22:11:53 +03:00
|
|
|
// representation and creates the instance of it. Every feature decoded as 2
|
|
|
|
// bits where odd bit determine whether the feature is "optional" and even bit
|
|
|
|
// told us whether the feature is "required". The even/odd semantic allows
|
|
|
|
// future incompatible changes, or backward compatible changes. Bits generally
|
|
|
|
// assigned in pairs, so that optional features can later become compulsory.
|
2017-02-16 15:31:19 +03:00
|
|
|
func NewFeatureVectorFromReader(r io.Reader) (*FeatureVector, error) {
|
|
|
|
f := &FeatureVector{
|
2017-02-17 17:28:11 +03:00
|
|
|
flags: make(map[int]featureFlag),
|
2017-02-16 15:31:19 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
getFlag := func(data []byte, position int) featureFlag {
|
|
|
|
byteNumber := uint(position / 8)
|
|
|
|
bitNumber := uint(position % 8)
|
|
|
|
|
|
|
|
return featureFlag((data[byteNumber] >> bitNumber) & flagMask)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Read the length of the feature vector.
|
|
|
|
var l [2]byte
|
2017-04-20 02:07:11 +03:00
|
|
|
if _, err := io.ReadFull(r, l[:]); err != nil {
|
2017-02-16 15:31:19 +03:00
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
length := binary.BigEndian.Uint16(l[:])
|
|
|
|
|
|
|
|
// Read the feature vector data.
|
|
|
|
data := make([]byte, length)
|
2017-04-20 02:07:11 +03:00
|
|
|
if _, err := io.ReadFull(r, data[:]); err != nil {
|
2017-02-16 15:31:19 +03:00
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
// Initialize feature vector.
|
|
|
|
bitsNumber := len(data) * 8
|
|
|
|
for position := 0; position <= bitsNumber-flagBitsSize; position += flagBitsSize {
|
|
|
|
flag := getFlag(data, position)
|
|
|
|
switch flag {
|
|
|
|
case OptionalFlag, RequiredFlag:
|
|
|
|
// Every feature/flag takes 2 bits, so in order to get
|
|
|
|
// the feature/flag index we should divide position
|
|
|
|
// on 2.
|
|
|
|
index := position / flagBitsSize
|
|
|
|
f.flags[index] = flag
|
|
|
|
default:
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return f, nil
|
|
|
|
}
|
|
|
|
|
2017-03-16 22:11:53 +03:00
|
|
|
// Encode encodes the features vector into bytes representation, every feature
|
|
|
|
// encoded as 2 bits where odd bit determine whether the feature is "optional"
|
|
|
|
// and even bit told us whether the feature is "required". The even/odd
|
|
|
|
// semantic allows future incompatible changes, or backward compatible changes.
|
|
|
|
// Bits generally assigned in pairs, so that optional features can later become
|
|
|
|
// compulsory.
|
2017-02-16 15:31:19 +03:00
|
|
|
func (f *FeatureVector) Encode(w io.Writer) error {
|
|
|
|
setFlag := func(data []byte, position int, flag featureFlag) {
|
|
|
|
byteNumber := uint(position / 8)
|
|
|
|
bitNumber := uint(position % 8)
|
|
|
|
|
|
|
|
data[byteNumber] |= (byte(flag) << bitNumber)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Write length of feature vector.
|
|
|
|
var l [2]byte
|
2017-02-17 17:28:11 +03:00
|
|
|
length := f.serializedSize()
|
2017-02-16 15:31:19 +03:00
|
|
|
binary.BigEndian.PutUint16(l[:], length)
|
|
|
|
if _, err := w.Write(l[:]); err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
// Generate the data and write it.
|
|
|
|
data := make([]byte, length)
|
|
|
|
for index, flag := range f.flags {
|
2017-03-16 22:11:53 +03:00
|
|
|
// Every feature takes 2 bits, so in order to get the feature
|
|
|
|
// bits position we should multiply index by 2.
|
2017-02-16 15:31:19 +03:00
|
|
|
position := index * flagBitsSize
|
|
|
|
setFlag(data, position, flag)
|
|
|
|
}
|
|
|
|
|
2017-02-23 21:59:50 +03:00
|
|
|
_, err := w.Write(data)
|
|
|
|
return err
|
2017-02-16 15:31:19 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
// Compare checks that features are compatible and returns the features which
|
|
|
|
// were present in both remote and local feature vectors. If remote/local node
|
|
|
|
// doesn't have the feature and local/remote node require it than such vectors
|
|
|
|
// are incompatible.
|
2017-02-23 22:56:47 +03:00
|
|
|
func (f *FeatureVector) Compare(f2 *FeatureVector) (*SharedFeatures, error) {
|
|
|
|
shared := newSharedFeatures(f.Copy())
|
2017-02-16 15:31:19 +03:00
|
|
|
|
2017-02-23 22:56:47 +03:00
|
|
|
for index, flag := range f.flags {
|
|
|
|
if _, exist := f2.flags[index]; !exist {
|
2017-02-16 15:31:19 +03:00
|
|
|
switch flag {
|
|
|
|
case RequiredFlag:
|
|
|
|
return nil, errors.New("Remote node hasn't " +
|
|
|
|
"locally required feature")
|
|
|
|
case OptionalFlag:
|
|
|
|
// If feature is optional and remote side
|
|
|
|
// haven't it than it might be safely disabled.
|
2017-02-17 17:28:11 +03:00
|
|
|
delete(shared.flags, index)
|
2017-02-16 15:31:19 +03:00
|
|
|
continue
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// If feature exists on both sides than such feature might be
|
|
|
|
// considered as active.
|
|
|
|
shared.flags[index] = flag
|
|
|
|
}
|
|
|
|
|
2017-02-23 22:56:47 +03:00
|
|
|
for index, flag := range f2.flags {
|
|
|
|
if _, exist := f.flags[index]; !exist {
|
2017-02-16 15:31:19 +03:00
|
|
|
switch flag {
|
|
|
|
case RequiredFlag:
|
|
|
|
return nil, errors.New("Local node hasn't " +
|
|
|
|
"locally required feature")
|
|
|
|
case OptionalFlag:
|
|
|
|
// If feature is optional and local side
|
|
|
|
// haven't it than it might be safely disabled.
|
2017-02-17 17:28:11 +03:00
|
|
|
delete(shared.flags, index)
|
2017-02-16 15:31:19 +03:00
|
|
|
continue
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// If feature exists on both sides than such feature might be
|
|
|
|
// considered as active.
|
|
|
|
shared.flags[index] = flag
|
|
|
|
}
|
|
|
|
|
|
|
|
return shared, nil
|
|
|
|
}
|
|
|
|
|
2017-02-17 17:28:11 +03:00
|
|
|
// Copy generate new distinct instance of the feature vector.
|
|
|
|
func (f *FeatureVector) Copy() *FeatureVector {
|
|
|
|
features := make([]Feature, len(f.featuresMap))
|
|
|
|
|
|
|
|
for name, index := range f.featuresMap {
|
|
|
|
features[index] = Feature{
|
|
|
|
Name: name,
|
|
|
|
Flag: f.flags[index],
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return NewFeatureVector(features)
|
|
|
|
}
|
|
|
|
|
2017-03-16 22:11:53 +03:00
|
|
|
// SharedFeatures is a product of comparison of two features vector which
|
|
|
|
// consist of features which are present in both local and remote features
|
|
|
|
// vectors.
|
2017-02-16 15:31:19 +03:00
|
|
|
type SharedFeatures struct {
|
|
|
|
*FeatureVector
|
|
|
|
}
|
|
|
|
|
2017-02-17 17:28:11 +03:00
|
|
|
// newSharedFeatures creates new shared features instance.
|
|
|
|
func newSharedFeatures(f *FeatureVector) *SharedFeatures {
|
|
|
|
return &SharedFeatures{f}
|
2017-02-16 15:31:19 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
// IsActive checks is feature active or not, it might be disabled during
|
2017-03-16 22:11:53 +03:00
|
|
|
// comparision with remote feature vector if it was optional and remote peer
|
|
|
|
// doesn't support it.
|
2017-02-16 15:31:19 +03:00
|
|
|
func (f *SharedFeatures) IsActive(name featureName) bool {
|
2017-02-17 17:28:11 +03:00
|
|
|
index, ok := f.featuresMap[name]
|
2017-02-16 15:31:19 +03:00
|
|
|
if !ok {
|
|
|
|
// If we even have no such feature in feature map, than it
|
|
|
|
// can't be active in any circumstances.
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
2017-02-17 17:28:11 +03:00
|
|
|
_, exist := f.flags[index]
|
2017-02-16 15:31:19 +03:00
|
|
|
return exist
|
|
|
|
}
|