multi: merge local+global features from remote peer

This commit is contained in:
Conner Fromknecht 2019-11-08 05:31:47 -08:00
parent 6c86075354
commit 16318c5a41
No known key found for this signature in database
GPG Key ID: E7D737B67FA592C7
9 changed files with 75 additions and 62 deletions

@ -56,10 +56,10 @@ func (p *mockPeer) Address() net.Addr { return nil }
func (p *mockPeer) QuitSignal() <-chan struct{} { func (p *mockPeer) QuitSignal() <-chan struct{} {
return p.quit return p.quit
} }
func (p *mockPeer) LocalGlobalFeatures() *lnwire.FeatureVector { func (p *mockPeer) LocalFeatures() *lnwire.FeatureVector {
return nil return nil
} }
func (p *mockPeer) RemoteGlobalFeatures() *lnwire.FeatureVector { func (p *mockPeer) RemoteFeatures() *lnwire.FeatureVector {
return nil return nil
} }

@ -1205,10 +1205,10 @@ func (f *fundingManager) handleFundingOpen(fmsg *fundingOpenMsg) {
// negotiated the new tweakless commitment format. This is only the // negotiated the new tweakless commitment format. This is only the
// case if *both* us and the remote peer are signaling the proper // case if *both* us and the remote peer are signaling the proper
// feature bit. // feature bit.
localTweakless := fmsg.peer.LocalGlobalFeatures().HasFeature( localTweakless := fmsg.peer.LocalFeatures().HasFeature(
lnwire.StaticRemoteKeyOptional, lnwire.StaticRemoteKeyOptional,
) )
remoteTweakless := fmsg.peer.RemoteGlobalFeatures().HasFeature( remoteTweakless := fmsg.peer.RemoteFeatures().HasFeature(
lnwire.StaticRemoteKeyOptional, lnwire.StaticRemoteKeyOptional,
) )
tweaklessCommitment := localTweakless && remoteTweakless tweaklessCommitment := localTweakless && remoteTweakless
@ -2780,10 +2780,10 @@ func (f *fundingManager) handleInitFundingMsg(msg *initFundingMsg) {
// negotiated the new tweakless commitment format. This is only the // negotiated the new tweakless commitment format. This is only the
// case if *both* us and the remote peer are signaling the proper // case if *both* us and the remote peer are signaling the proper
// feature bit. // feature bit.
localTweakless := msg.peer.LocalGlobalFeatures().HasFeature( localTweakless := msg.peer.LocalFeatures().HasFeature(
lnwire.StaticRemoteKeyOptional, lnwire.StaticRemoteKeyOptional,
) )
remoteTweakless := msg.peer.RemoteGlobalFeatures().HasFeature( remoteTweakless := msg.peer.RemoteFeatures().HasFeature(
lnwire.StaticRemoteKeyOptional, lnwire.StaticRemoteKeyOptional,
) )
tweaklessCommitment := localTweakless && remoteTweakless tweaklessCommitment := localTweakless && remoteTweakless

@ -184,11 +184,11 @@ func (n *testNode) QuitSignal() <-chan struct{} {
return n.shutdownChannel return n.shutdownChannel
} }
func (n *testNode) LocalGlobalFeatures() *lnwire.FeatureVector { func (n *testNode) LocalFeatures() *lnwire.FeatureVector {
return lnwire.NewFeatureVector(nil, nil) return lnwire.NewFeatureVector(nil, nil)
} }
func (n *testNode) RemoteGlobalFeatures() *lnwire.FeatureVector { func (n *testNode) RemoteFeatures() *lnwire.FeatureVector {
return lnwire.NewFeatureVector(nil, nil) return lnwire.NewFeatureVector(nil, nil)
} }

@ -1653,10 +1653,10 @@ func (m *mockPeer) IdentityKey() *btcec.PublicKey {
func (m *mockPeer) Address() net.Addr { func (m *mockPeer) Address() net.Addr {
return nil return nil
} }
func (m *mockPeer) LocalGlobalFeatures() *lnwire.FeatureVector { func (m *mockPeer) LocalFeatures() *lnwire.FeatureVector {
return nil return nil
} }
func (m *mockPeer) RemoteGlobalFeatures() *lnwire.FeatureVector { func (m *mockPeer) RemoteFeatures() *lnwire.FeatureVector {
return nil return nil
} }

@ -607,11 +607,11 @@ func (s *mockServer) WipeChannel(*wire.OutPoint) error {
return nil return nil
} }
func (s *mockServer) LocalGlobalFeatures() *lnwire.FeatureVector { func (s *mockServer) LocalFeatures() *lnwire.FeatureVector {
return nil return nil
} }
func (s *mockServer) RemoteGlobalFeatures() *lnwire.FeatureVector { func (s *mockServer) RemoteFeatures() *lnwire.FeatureVector {
return nil return nil
} }

@ -47,15 +47,14 @@ type Peer interface {
// implementation exits. // implementation exits.
QuitSignal() <-chan struct{} QuitSignal() <-chan struct{}
// LocalGlobalFeatures returns the set of global features that has been // LocalFeatures returns the set of features that has been advertised by
// advertised by the local peer. This allows sub-systems that use this // the us to the remote peer. This allows sub-systems that use this
// interface to gate their behavior off the set of negotiated feature // interface to gate their behavior off the set of negotiated feature
// bits. // bits.
LocalGlobalFeatures() *lnwire.FeatureVector LocalFeatures() *lnwire.FeatureVector
// RemoteGlobalFeatures returns the set of global features that has // RemoteFeatures returns the set of features that has been advertised
// been advertised by the remote peer. This allows sub-systems that use // by the remote peer. This allows sub-systems that use this interface
// this interface to gate their behavior off the set of negotiated // to gate their behavior off the set of negotiated feature bits.
// feature bits. RemoteFeatures() *lnwire.FeatureVector
RemoteGlobalFeatures() *lnwire.FeatureVector
} }

@ -143,6 +143,17 @@ func NewRawFeatureVector(bits ...FeatureBit) *RawFeatureVector {
return fv return fv
} }
// Merges sets all feature bits in other on the receiver's feature vector.
func (fv *RawFeatureVector) Merge(other *RawFeatureVector) error {
for bit := range other.features {
err := fv.SafeSet(bit)
if err != nil {
return err
}
}
return nil
}
// Clone makes a copy of a feature vector. // Clone makes a copy of a feature vector.
func (fv *RawFeatureVector) Clone() *RawFeatureVector { func (fv *RawFeatureVector) Clone() *RawFeatureVector {
newFeatures := NewRawFeatureVector() newFeatures := NewRawFeatureVector()

@ -7,20 +7,26 @@ import "io"
// diagnosis where features are incompatible. Each node MUST wait to receive // diagnosis where features are incompatible. Each node MUST wait to receive
// init before sending any other messages. // init before sending any other messages.
type Init struct { type Init struct {
// GlobalFeatures is feature vector which affects HTLCs and thus are // GlobalFeatures is a legacy feature vector used for backwards
// also advertised to other nodes. // compatibility with older nodes. Any features defined here should be
// merged with those presented in Features.
GlobalFeatures *RawFeatureVector GlobalFeatures *RawFeatureVector
// LocalFeatures is feature vector which only affect the protocol // Features is a feature vector containing a the features supported by
// between two nodes. // the remote node.
LocalFeatures *RawFeatureVector //
// NOTE: Older nodes may place some features in GlobalFeatures, but all
// new features are to be added in Features. When handling an Init
// message, any GlobalFeatures should be merged into the unified
// Features field.
Features *RawFeatureVector
} }
// NewInitMessage creates new instance of init message object. // NewInitMessage creates new instance of init message object.
func NewInitMessage(gf *RawFeatureVector, lf *RawFeatureVector) *Init { func NewInitMessage(gf *RawFeatureVector, f *RawFeatureVector) *Init {
return &Init{ return &Init{
GlobalFeatures: gf, GlobalFeatures: gf,
LocalFeatures: lf, Features: f,
} }
} }
@ -35,7 +41,7 @@ var _ Message = (*Init)(nil)
func (msg *Init) Decode(r io.Reader, pver uint32) error { func (msg *Init) Decode(r io.Reader, pver uint32) error {
return ReadElements(r, return ReadElements(r,
&msg.GlobalFeatures, &msg.GlobalFeatures,
&msg.LocalFeatures, &msg.Features,
) )
} }
@ -46,7 +52,7 @@ func (msg *Init) Decode(r io.Reader, pver uint32) error {
func (msg *Init) Encode(w io.Writer, pver uint32) error { func (msg *Init) Encode(w io.Writer, pver uint32) error {
return WriteElements(w, return WriteElements(w,
msg.GlobalFeatures, msg.GlobalFeatures,
msg.LocalFeatures, msg.Features,
) )
} }

63
peer.go

@ -205,13 +205,9 @@ type peer struct {
// an htlc where we don't offer an htlc anymore. // an htlc where we don't offer an htlc anymore.
outgoingCltvRejectDelta uint32 outgoingCltvRejectDelta uint32
// remoteLocalFeatures is the local feature vector received from the // remoteFeatures is the feature vector received from the peer during
// peer during the connection handshake. // the connection handshake.
remoteLocalFeatures *lnwire.FeatureVector remoteFeatures *lnwire.FeatureVector
// remoteGlobalFeatures is the global feature vector received from the
// peer during the connection handshake.
remoteGlobalFeatures *lnwire.FeatureVector
// failedChannels is a set that tracks channels we consider `failed`. // failedChannels is a set that tracks channels we consider `failed`.
// This is a temporary measure until we have implemented real failure // This is a temporary measure until we have implemented real failure
@ -407,7 +403,7 @@ func (p *peer) initGossipSync() {
// If the remote peer knows of the new gossip queries feature, then // If the remote peer knows of the new gossip queries feature, then
// we'll create a new gossipSyncer in the AuthenticatedGossiper for it. // we'll create a new gossipSyncer in the AuthenticatedGossiper for it.
case p.remoteLocalFeatures.HasFeature(lnwire.GossipQueriesOptional): case p.remoteFeatures.HasFeature(lnwire.GossipQueriesOptional):
srvrLog.Infof("Negotiated chan series queries with %x", srvrLog.Infof("Negotiated chan series queries with %x",
p.pubKeyBytes[:]) p.pubKeyBytes[:])
@ -2395,54 +2391,55 @@ func (p *peer) WipeChannel(chanPoint *wire.OutPoint) error {
// handleInitMsg handles the incoming init message which contains global and // handleInitMsg handles the incoming init message which contains global and
// local features vectors. If feature vectors are incompatible then disconnect. // local features vectors. If feature vectors are incompatible then disconnect.
func (p *peer) handleInitMsg(msg *lnwire.Init) error { func (p *peer) handleInitMsg(msg *lnwire.Init) error {
p.remoteLocalFeatures = lnwire.NewFeatureVector( // First, merge any features from the legacy global features field into
msg.LocalFeatures, lnwire.LocalFeatures, // those presented in the local features fields.
) err := msg.Features.Merge(msg.GlobalFeatures)
p.remoteGlobalFeatures = lnwire.NewFeatureVector( if err != nil {
msg.GlobalFeatures, lnwire.GlobalFeatures, return fmt.Errorf("unable to merge legacy global featues: %v",
err)
}
// Then, finalize the remote feature vector providing the flatteneed
// feature bit namespace.
p.remoteFeatures = lnwire.NewFeatureVector(
msg.Features, lnwire.Features,
) )
// Now that we have their features loaded, we'll ensure that they // Now that we have their features loaded, we'll ensure that they
// didn't set any required bits that we don't know of. // didn't set any required bits that we don't know of.
unknownLocalFeatures := p.remoteLocalFeatures.UnknownRequiredFeatures() unknownFeatures := p.remoteFeatures.UnknownRequiredFeatures()
if len(unknownLocalFeatures) > 0 { if len(unknownFeatures) > 0 {
err := fmt.Errorf("Peer set unknown local feature bits: %v", err := fmt.Errorf("peer set unknown feature bits: %v",
unknownLocalFeatures) unknownFeatures)
return err
}
unknownGlobalFeatures := p.remoteGlobalFeatures.UnknownRequiredFeatures()
if len(unknownGlobalFeatures) > 0 {
err := fmt.Errorf("Peer set unknown global feature bits: %v",
unknownGlobalFeatures)
return err return err
} }
// Now that we know we understand their requirements, we'll check to // Now that we know we understand their requirements, we'll check to
// see if they don't support anything that we deem to be mandatory. // see if they don't support anything that we deem to be mandatory.
switch { switch {
case !p.remoteLocalFeatures.HasFeature(lnwire.DataLossProtectRequired): case !p.remoteFeatures.HasFeature(lnwire.DataLossProtectRequired):
return fmt.Errorf("data loss protection required") return fmt.Errorf("data loss protection required")
} }
return nil return nil
} }
// LocalGlobalFeatures returns the set of global features that has been // LocalFeatures returns the set of global features that has been advertised by
// advertised by the local node. This allows sub-systems that use this // the local node. This allows sub-systems that use this interface to gate their
// interface to gate their behavior off the set of negotiated feature bits. // behavior off the set of negotiated feature bits.
// //
// NOTE: Part of the lnpeer.Peer interface. // NOTE: Part of the lnpeer.Peer interface.
func (p *peer) LocalGlobalFeatures() *lnwire.FeatureVector { func (p *peer) LocalFeatures() *lnwire.FeatureVector {
return p.features return p.features
} }
// RemoteGlobalFeatures returns the set of global features that has been // RemoteFeatures returns the set of global features that has been advertised by
// advertised by the remote node. This allows sub-systems that use this // the remote node. This allows sub-systems that use this interface to gate
// interface to gate their behavior off the set of negotiated feature bits. // their behavior off the set of negotiated feature bits.
// //
// NOTE: Part of the lnpeer.Peer interface. // NOTE: Part of the lnpeer.Peer interface.
func (p *peer) RemoteGlobalFeatures() *lnwire.FeatureVector { func (p *peer) RemoteFeatures() *lnwire.FeatureVector {
return p.remoteGlobalFeatures return p.remoteFeatures
} }
// sendInitMsg sends init message to remote peer which contains our currently // sendInitMsg sends init message to remote peer which contains our currently