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{} {
return p.quit
}
func (p *mockPeer) LocalGlobalFeatures() *lnwire.FeatureVector {
func (p *mockPeer) LocalFeatures() *lnwire.FeatureVector {
return nil
}
func (p *mockPeer) RemoteGlobalFeatures() *lnwire.FeatureVector {
func (p *mockPeer) RemoteFeatures() *lnwire.FeatureVector {
return nil
}

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

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

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

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

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

@ -143,6 +143,17 @@ func NewRawFeatureVector(bits ...FeatureBit) *RawFeatureVector {
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.
func (fv *RawFeatureVector) Clone() *RawFeatureVector {
newFeatures := NewRawFeatureVector()

@ -7,20 +7,26 @@ import "io"
// diagnosis where features are incompatible. Each node MUST wait to receive
// init before sending any other messages.
type Init struct {
// GlobalFeatures is feature vector which affects HTLCs and thus are
// also advertised to other nodes.
// GlobalFeatures is a legacy feature vector used for backwards
// compatibility with older nodes. Any features defined here should be
// merged with those presented in Features.
GlobalFeatures *RawFeatureVector
// LocalFeatures is feature vector which only affect the protocol
// between two nodes.
LocalFeatures *RawFeatureVector
// Features is a feature vector containing a the features supported by
// the remote node.
//
// 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.
func NewInitMessage(gf *RawFeatureVector, lf *RawFeatureVector) *Init {
func NewInitMessage(gf *RawFeatureVector, f *RawFeatureVector) *Init {
return &Init{
GlobalFeatures: gf,
LocalFeatures: lf,
Features: f,
}
}
@ -35,7 +41,7 @@ var _ Message = (*Init)(nil)
func (msg *Init) Decode(r io.Reader, pver uint32) error {
return ReadElements(r,
&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 {
return WriteElements(w,
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.
outgoingCltvRejectDelta uint32
// remoteLocalFeatures is the local feature vector received from the
// peer during the connection handshake.
remoteLocalFeatures *lnwire.FeatureVector
// remoteGlobalFeatures is the global feature vector received from the
// peer during the connection handshake.
remoteGlobalFeatures *lnwire.FeatureVector
// remoteFeatures is the feature vector received from the peer during
// the connection handshake.
remoteFeatures *lnwire.FeatureVector
// failedChannels is a set that tracks channels we consider `failed`.
// 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
// 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",
p.pubKeyBytes[:])
@ -2395,54 +2391,55 @@ func (p *peer) WipeChannel(chanPoint *wire.OutPoint) error {
// handleInitMsg handles the incoming init message which contains global and
// local features vectors. If feature vectors are incompatible then disconnect.
func (p *peer) handleInitMsg(msg *lnwire.Init) error {
p.remoteLocalFeatures = lnwire.NewFeatureVector(
msg.LocalFeatures, lnwire.LocalFeatures,
)
p.remoteGlobalFeatures = lnwire.NewFeatureVector(
msg.GlobalFeatures, lnwire.GlobalFeatures,
// First, merge any features from the legacy global features field into
// those presented in the local features fields.
err := msg.Features.Merge(msg.GlobalFeatures)
if err != nil {
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
// didn't set any required bits that we don't know of.
unknownLocalFeatures := p.remoteLocalFeatures.UnknownRequiredFeatures()
if len(unknownLocalFeatures) > 0 {
err := fmt.Errorf("Peer set unknown local feature bits: %v",
unknownLocalFeatures)
return err
}
unknownGlobalFeatures := p.remoteGlobalFeatures.UnknownRequiredFeatures()
if len(unknownGlobalFeatures) > 0 {
err := fmt.Errorf("Peer set unknown global feature bits: %v",
unknownGlobalFeatures)
unknownFeatures := p.remoteFeatures.UnknownRequiredFeatures()
if len(unknownFeatures) > 0 {
err := fmt.Errorf("peer set unknown feature bits: %v",
unknownFeatures)
return err
}
// 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.
switch {
case !p.remoteLocalFeatures.HasFeature(lnwire.DataLossProtectRequired):
case !p.remoteFeatures.HasFeature(lnwire.DataLossProtectRequired):
return fmt.Errorf("data loss protection required")
}
return nil
}
// LocalGlobalFeatures returns the set of global features that has been
// advertised by the local node. This allows sub-systems that use this
// interface to gate their behavior off the set of negotiated feature bits.
// LocalFeatures returns the set of global features that has been advertised by
// the local node. This allows sub-systems that use this interface to gate their
// behavior off the set of negotiated feature bits.
//
// NOTE: Part of the lnpeer.Peer interface.
func (p *peer) LocalGlobalFeatures() *lnwire.FeatureVector {
func (p *peer) LocalFeatures() *lnwire.FeatureVector {
return p.features
}
// RemoteGlobalFeatures returns the set of global features that has been
// advertised by the remote node. This allows sub-systems that use this
// interface to gate their behavior off the set of negotiated feature bits.
// RemoteFeatures returns the set of global features that has been advertised by
// the remote node. This allows sub-systems that use this interface to gate
// their behavior off the set of negotiated feature bits.
//
// NOTE: Part of the lnpeer.Peer interface.
func (p *peer) RemoteGlobalFeatures() *lnwire.FeatureVector {
return p.remoteGlobalFeatures
func (p *peer) RemoteFeatures() *lnwire.FeatureVector {
return p.remoteFeatures
}
// sendInitMsg sends init message to remote peer which contains our currently