commit
b222b6e625
@ -157,8 +157,9 @@ func (d *databaseChannelGraph) addRandChannel(node1, node2 *btcec.PublicKey,
|
|||||||
IP: bytes.Repeat([]byte("a"), 16),
|
IP: bytes.Repeat([]byte("a"), 16),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Features: lnwire.NewFeatureVector(nil,
|
Features: lnwire.NewFeatureVector(
|
||||||
lnwire.GlobalFeatures),
|
nil, lnwire.Features,
|
||||||
|
),
|
||||||
AuthSigBytes: testSig.Serialize(),
|
AuthSigBytes: testSig.Serialize(),
|
||||||
}
|
}
|
||||||
graphNode.AddPubKey(pub)
|
graphNode.AddPubKey(pub)
|
||||||
@ -183,7 +184,9 @@ func (d *databaseChannelGraph) addRandChannel(node1, node2 *btcec.PublicKey,
|
|||||||
IP: bytes.Repeat([]byte("a"), 16),
|
IP: bytes.Repeat([]byte("a"), 16),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Features: lnwire.NewFeatureVector(nil, lnwire.GlobalFeatures),
|
Features: lnwire.NewFeatureVector(
|
||||||
|
nil, lnwire.Features,
|
||||||
|
),
|
||||||
AuthSigBytes: testSig.Serialize(),
|
AuthSigBytes: testSig.Serialize(),
|
||||||
}
|
}
|
||||||
dbNode.AddPubKey(nodeKey)
|
dbNode.AddPubKey(nodeKey)
|
||||||
@ -287,7 +290,9 @@ func (d *databaseChannelGraph) addRandNode() (*btcec.PublicKey, error) {
|
|||||||
IP: bytes.Repeat([]byte("a"), 16),
|
IP: bytes.Repeat([]byte("a"), 16),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
Features: lnwire.NewFeatureVector(nil, lnwire.GlobalFeatures),
|
Features: lnwire.NewFeatureVector(
|
||||||
|
nil, lnwire.Features,
|
||||||
|
),
|
||||||
AuthSigBytes: testSig.Serialize(),
|
AuthSigBytes: testSig.Serialize(),
|
||||||
}
|
}
|
||||||
dbNode.AddPubKey(nodeKey)
|
dbNode.AddPubKey(nodeKey)
|
||||||
|
@ -3506,7 +3506,7 @@ func deserializeLightningNode(r io.Reader) (LightningNode, error) {
|
|||||||
return LightningNode{}, err
|
return LightningNode{}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
fv := lnwire.NewFeatureVector(nil, lnwire.GlobalFeatures)
|
fv := lnwire.NewFeatureVector(nil, lnwire.Features)
|
||||||
err = fv.Decode(r)
|
err = fv.Decode(r)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return LightningNode{}, err
|
return LightningNode{}, err
|
||||||
|
@ -36,7 +36,7 @@ var (
|
|||||||
_, _ = testSig.R.SetString("63724406601629180062774974542967536251589935445068131219452686511677818569431", 10)
|
_, _ = testSig.R.SetString("63724406601629180062774974542967536251589935445068131219452686511677818569431", 10)
|
||||||
_, _ = testSig.S.SetString("18801056069249825825291287104931333862866033135609736119018462340006816851118", 10)
|
_, _ = testSig.S.SetString("18801056069249825825291287104931333862866033135609736119018462340006816851118", 10)
|
||||||
|
|
||||||
testFeatures = lnwire.NewFeatureVector(nil, lnwire.GlobalFeatures)
|
testFeatures = lnwire.NewFeatureVector(nil, lnwire.Features)
|
||||||
)
|
)
|
||||||
|
|
||||||
func createLightningNode(db *DB, priv *btcec.PrivateKey) (*LightningNode, error) {
|
func createLightningNode(db *DB, priv *btcec.PrivateKey) (*LightningNode, error) {
|
||||||
|
@ -744,7 +744,7 @@ func deserializeLightningNode(r io.Reader) (LightningNode, error) {
|
|||||||
return LightningNode{}, err
|
return LightningNode{}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
fv := lnwire.NewFeatureVector(nil, lnwire.GlobalFeatures)
|
fv := lnwire.NewFeatureVector(nil, nil)
|
||||||
err = fv.Decode(r)
|
err = fv.Decode(r)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return LightningNode{}, err
|
return LightningNode{}, err
|
||||||
|
@ -25,7 +25,7 @@ var (
|
|||||||
_, _ = testSig.R.SetString("63724406601629180062774974542967536251589935445068131219452686511677818569431", 10)
|
_, _ = testSig.R.SetString("63724406601629180062774974542967536251589935445068131219452686511677818569431", 10)
|
||||||
_, _ = testSig.S.SetString("18801056069249825825291287104931333862866033135609736119018462340006816851118", 10)
|
_, _ = testSig.S.SetString("18801056069249825825291287104931333862866033135609736119018462340006816851118", 10)
|
||||||
|
|
||||||
testFeatures = lnwire.NewFeatureVector(nil, lnwire.GlobalFeatures)
|
testFeatures = lnwire.NewFeatureVector(nil, nil)
|
||||||
)
|
)
|
||||||
|
|
||||||
func createLightningNode(db *DB, priv *btcec.PrivateKey) (*LightningNode, error) {
|
func createLightningNode(db *DB, priv *btcec.PrivateKey) (*LightningNode, error) {
|
||||||
|
@ -1459,9 +1459,7 @@ func (d *AuthenticatedGossiper) addNode(msg *lnwire.NodeAnnouncement) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
timestamp := time.Unix(int64(msg.Timestamp), 0)
|
timestamp := time.Unix(int64(msg.Timestamp), 0)
|
||||||
features := lnwire.NewFeatureVector(
|
features := lnwire.NewFeatureVector(msg.Features, lnwire.Features)
|
||||||
msg.Features, lnwire.GlobalFeatures,
|
|
||||||
)
|
|
||||||
node := &channeldb.LightningNode{
|
node := &channeldb.LightningNode{
|
||||||
HaveNodeAnnouncement: true,
|
HaveNodeAnnouncement: true,
|
||||||
LastUpdate: timestamp,
|
LastUpdate: timestamp,
|
||||||
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
32
feature/default_sets.go
Normal file
32
feature/default_sets.go
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
package feature
|
||||||
|
|
||||||
|
import "github.com/lightningnetwork/lnd/lnwire"
|
||||||
|
|
||||||
|
// setDesc describes which feature bits should be advertised in which feature
|
||||||
|
// sets.
|
||||||
|
type setDesc map[lnwire.FeatureBit]map[Set]struct{}
|
||||||
|
|
||||||
|
// defaultSetDesc are the default set descriptors for generating feature
|
||||||
|
// vectors. Each set is annotated with the corresponding identifier from BOLT 9
|
||||||
|
// indicating where it should be advertised.
|
||||||
|
var defaultSetDesc = setDesc{
|
||||||
|
lnwire.DataLossProtectRequired: {
|
||||||
|
SetInit: {}, // I
|
||||||
|
SetNodeAnn: {}, // N
|
||||||
|
},
|
||||||
|
lnwire.GossipQueriesOptional: {
|
||||||
|
SetInit: {}, // I
|
||||||
|
SetNodeAnn: {}, // N
|
||||||
|
},
|
||||||
|
lnwire.TLVOnionPayloadOptional: {
|
||||||
|
SetInit: {}, // I
|
||||||
|
SetNodeAnn: {}, // N
|
||||||
|
SetInvoice: {}, // 9
|
||||||
|
SetLegacyGlobal: {},
|
||||||
|
},
|
||||||
|
lnwire.StaticRemoteKeyOptional: {
|
||||||
|
SetInit: {}, // I
|
||||||
|
SetNodeAnn: {}, // N
|
||||||
|
SetLegacyGlobal: {},
|
||||||
|
},
|
||||||
|
}
|
97
feature/manager.go
Normal file
97
feature/manager.go
Normal file
@ -0,0 +1,97 @@
|
|||||||
|
package feature
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"github.com/lightningnetwork/lnd/lnwire"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Config houses any runtime modifications to the default set descriptors. For
|
||||||
|
// our purposes, this typically means disabling certain features to test legacy
|
||||||
|
// protocol interoperability or functionality.
|
||||||
|
type Config struct {
|
||||||
|
// NoTLVOnion unsets any optional or required TLVOnionPaylod bits from
|
||||||
|
// all feature sets.
|
||||||
|
NoTLVOnion bool
|
||||||
|
|
||||||
|
// NoStaticRemoteKey unsets any optional or required StaticRemoteKey
|
||||||
|
// bits from all feature sets.
|
||||||
|
NoStaticRemoteKey bool
|
||||||
|
}
|
||||||
|
|
||||||
|
// Manager is responsible for generating feature vectors for different requested
|
||||||
|
// feature sets.
|
||||||
|
type Manager struct {
|
||||||
|
// fsets is a static map of feature set to raw feature vectors. Requests
|
||||||
|
// are fulfilled by cloning these interal feature vectors.
|
||||||
|
fsets map[Set]*lnwire.RawFeatureVector
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewManager creates a new feature Manager, applying any custom modifications
|
||||||
|
// to its feature sets before returning.
|
||||||
|
func NewManager(cfg Config) (*Manager, error) {
|
||||||
|
return newManager(cfg, defaultSetDesc)
|
||||||
|
}
|
||||||
|
|
||||||
|
// newManager creates a new feeature Manager, applying any custom modifications
|
||||||
|
// to its feature sets before returning. This method accepts the setDesc as its
|
||||||
|
// own parameter so that it can be unit tested.
|
||||||
|
func newManager(cfg Config, desc setDesc) (*Manager, error) {
|
||||||
|
// First build the default feature vector for all known sets.
|
||||||
|
fsets := make(map[Set]*lnwire.RawFeatureVector)
|
||||||
|
for bit, sets := range desc {
|
||||||
|
for set := range sets {
|
||||||
|
// Fetch the feature vector for this set, allocating a
|
||||||
|
// new one if it doesn't exist.
|
||||||
|
fv, ok := fsets[set]
|
||||||
|
if !ok {
|
||||||
|
fv = lnwire.NewRawFeatureVector()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set the configured bit on the feature vector,
|
||||||
|
// ensuring that we don't set two feature bits for the
|
||||||
|
// same pair.
|
||||||
|
err := fv.SafeSet(bit)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("unable to set "+
|
||||||
|
"%v in %v: %v", bit, set, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Write the updated feature vector under its set.
|
||||||
|
fsets[set] = fv
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Now, remove any features as directed by the config.
|
||||||
|
for _, fv := range fsets {
|
||||||
|
if cfg.NoTLVOnion {
|
||||||
|
fv.Unset(lnwire.TLVOnionPayloadOptional)
|
||||||
|
fv.Unset(lnwire.TLVOnionPayloadRequired)
|
||||||
|
}
|
||||||
|
if cfg.NoStaticRemoteKey {
|
||||||
|
fv.Unset(lnwire.StaticRemoteKeyOptional)
|
||||||
|
fv.Unset(lnwire.StaticRemoteKeyRequired)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return &Manager{
|
||||||
|
fsets: fsets,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetRaw returns a raw feature vector for the passed set. If no set is known,
|
||||||
|
// an empty raw feature vector is returned.
|
||||||
|
func (m *Manager) GetRaw(set Set) *lnwire.RawFeatureVector {
|
||||||
|
if fv, ok := m.fsets[set]; ok {
|
||||||
|
return fv.Clone()
|
||||||
|
}
|
||||||
|
|
||||||
|
return lnwire.NewRawFeatureVector()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get returns a feature vector for the passed set. If no set is known, an empty
|
||||||
|
// feature vector is returned.
|
||||||
|
func (m *Manager) Get(set Set) *lnwire.FeatureVector {
|
||||||
|
raw := m.GetRaw(set)
|
||||||
|
return lnwire.NewFeatureVector(raw, lnwire.Features)
|
||||||
|
}
|
128
feature/manager_internal_test.go
Normal file
128
feature/manager_internal_test.go
Normal file
@ -0,0 +1,128 @@
|
|||||||
|
package feature
|
||||||
|
|
||||||
|
import (
|
||||||
|
"reflect"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/lightningnetwork/lnd/lnwire"
|
||||||
|
)
|
||||||
|
|
||||||
|
type managerTest struct {
|
||||||
|
name string
|
||||||
|
cfg Config
|
||||||
|
}
|
||||||
|
|
||||||
|
const unknownFeature lnwire.FeatureBit = 30
|
||||||
|
|
||||||
|
var testSetDesc = setDesc{
|
||||||
|
lnwire.DataLossProtectRequired: {
|
||||||
|
SetNodeAnn: {}, // I
|
||||||
|
},
|
||||||
|
lnwire.TLVOnionPayloadOptional: {
|
||||||
|
SetInit: {}, // I
|
||||||
|
SetNodeAnn: {}, // N
|
||||||
|
},
|
||||||
|
lnwire.StaticRemoteKeyOptional: {
|
||||||
|
SetInit: {}, // I
|
||||||
|
SetNodeAnn: {}, // N
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
var managerTests = []managerTest{
|
||||||
|
{
|
||||||
|
name: "default",
|
||||||
|
cfg: Config{},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "no tlv",
|
||||||
|
cfg: Config{
|
||||||
|
NoTLVOnion: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "no static remote key",
|
||||||
|
cfg: Config{
|
||||||
|
NoStaticRemoteKey: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "no tlv or static remote key",
|
||||||
|
cfg: Config{
|
||||||
|
NoTLVOnion: true,
|
||||||
|
NoStaticRemoteKey: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
// TestManager asserts basic initialazation and operation of a feature manager,
|
||||||
|
// including that the proper features are removed in response to config changes.
|
||||||
|
func TestManager(t *testing.T) {
|
||||||
|
for _, test := range managerTests {
|
||||||
|
test := test
|
||||||
|
t.Run(test.name, func(t *testing.T) {
|
||||||
|
testManager(t, test)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func testManager(t *testing.T, test managerTest) {
|
||||||
|
m, err := newManager(test.cfg, testSetDesc)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unable to create feature manager: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
sets := []Set{
|
||||||
|
SetInit,
|
||||||
|
SetLegacyGlobal,
|
||||||
|
SetNodeAnn,
|
||||||
|
SetInvoice,
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, set := range sets {
|
||||||
|
raw := m.GetRaw(set)
|
||||||
|
fv := m.Get(set)
|
||||||
|
|
||||||
|
fv2 := lnwire.NewFeatureVector(raw, lnwire.Features)
|
||||||
|
|
||||||
|
if !reflect.DeepEqual(fv, fv2) {
|
||||||
|
t.Fatalf("mismatch Get vs GetRaw, raw: %v vs fv: %v",
|
||||||
|
fv2, fv)
|
||||||
|
}
|
||||||
|
|
||||||
|
assertUnset := func(bit lnwire.FeatureBit) {
|
||||||
|
hasBit := fv.HasFeature(bit) || fv.HasFeature(bit^1)
|
||||||
|
if hasBit {
|
||||||
|
t.Fatalf("bit %v or %v is set", bit, bit^1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Assert that the manager properly unset the configured feature
|
||||||
|
// bits from all sets.
|
||||||
|
if test.cfg.NoTLVOnion {
|
||||||
|
assertUnset(lnwire.TLVOnionPayloadOptional)
|
||||||
|
}
|
||||||
|
if test.cfg.NoStaticRemoteKey {
|
||||||
|
assertUnset(lnwire.StaticRemoteKeyOptional)
|
||||||
|
}
|
||||||
|
|
||||||
|
assertUnset(unknownFeature)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Do same basic sanity checks on features that are always present.
|
||||||
|
nodeFeatures := m.Get(SetNodeAnn)
|
||||||
|
|
||||||
|
assertSet := func(bit lnwire.FeatureBit) {
|
||||||
|
has := nodeFeatures.HasFeature(bit)
|
||||||
|
if !has {
|
||||||
|
t.Fatalf("node features don't advertised %v", bit)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
assertSet(lnwire.DataLossProtectOptional)
|
||||||
|
if !test.cfg.NoTLVOnion {
|
||||||
|
assertSet(lnwire.TLVOnionPayloadRequired)
|
||||||
|
}
|
||||||
|
if !test.cfg.NoStaticRemoteKey {
|
||||||
|
assertSet(lnwire.StaticRemoteKeyOptional)
|
||||||
|
}
|
||||||
|
}
|
41
feature/set.go
Normal file
41
feature/set.go
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
package feature
|
||||||
|
|
||||||
|
// Set is an enum identifying various feature sets, which separates the single
|
||||||
|
// feature namespace into distinct categories depending what context a feature
|
||||||
|
// vector is being used.
|
||||||
|
type Set uint8
|
||||||
|
|
||||||
|
const (
|
||||||
|
// SetInit identifies features that should be sent in an Init message to
|
||||||
|
// a remote peer.
|
||||||
|
SetInit Set = iota
|
||||||
|
|
||||||
|
// SetLegacyGlobal identifies features that should be set in the legacy
|
||||||
|
// GlobalFeatures field of an Init message, which maintains backwards
|
||||||
|
// compatibility with nodes that haven't implemented flat features.
|
||||||
|
SetLegacyGlobal
|
||||||
|
|
||||||
|
// SetNodeAnn identifies features that should be advertised on node
|
||||||
|
// announcements.
|
||||||
|
SetNodeAnn
|
||||||
|
|
||||||
|
// SetInvoice identifies features that should be advertised on invoices
|
||||||
|
// generated by the daemon.
|
||||||
|
SetInvoice
|
||||||
|
)
|
||||||
|
|
||||||
|
// String returns a human-readable description of a Set.
|
||||||
|
func (s Set) String() string {
|
||||||
|
switch s {
|
||||||
|
case SetInit:
|
||||||
|
return "SetInit"
|
||||||
|
case SetLegacyGlobal:
|
||||||
|
return "SetLegacyGlobal"
|
||||||
|
case SetNodeAnn:
|
||||||
|
return "SetNodeAnn"
|
||||||
|
case SetInvoice:
|
||||||
|
return "SetInvoice"
|
||||||
|
default:
|
||||||
|
return "SetUnknown"
|
||||||
|
}
|
||||||
|
}
|
@ -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
|
|
||||||
}
|
}
|
||||||
|
@ -2,10 +2,17 @@ package lnwire
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
// ErrFeaturePairExists signals an error in feature vector construction
|
||||||
|
// where the opposing bit in a feature pair has already been set.
|
||||||
|
ErrFeaturePairExists = errors.New("feature pair exists")
|
||||||
|
)
|
||||||
|
|
||||||
// FeatureBit represents a feature that can be enabled in either a local or
|
// FeatureBit represents a feature that can be enabled in either a local or
|
||||||
// global feature vector at a specific bit position. Feature bits follow the
|
// global feature vector at a specific bit position. Feature bits follow the
|
||||||
// "it's OK to be odd" rule, where features at even bit positions must be known
|
// "it's OK to be odd" rule, where features at even bit positions must be known
|
||||||
@ -78,24 +85,15 @@ const (
|
|||||||
maxAllowedSize = 32764
|
maxAllowedSize = 32764
|
||||||
)
|
)
|
||||||
|
|
||||||
// LocalFeatures is a mapping of known connection-local feature bits to a
|
// Features is a mapping of known feature bits to a descriptive name. All known
|
||||||
// descriptive name. All known local feature bits must be assigned a name in
|
// feature bits must be assigned a name in this mapping, and feature bit pairs
|
||||||
// this mapping. Local features are those which are only sent to the peer and
|
// must be assigned together for correct behavior.
|
||||||
// not advertised to the entire network. A full description of these feature
|
var Features = map[FeatureBit]string{
|
||||||
// bits is provided in the BOLT-09 specification.
|
|
||||||
var LocalFeatures = map[FeatureBit]string{
|
|
||||||
DataLossProtectRequired: "data-loss-protect",
|
DataLossProtectRequired: "data-loss-protect",
|
||||||
DataLossProtectOptional: "data-loss-protect",
|
DataLossProtectOptional: "data-loss-protect",
|
||||||
InitialRoutingSync: "initial-routing-sync",
|
InitialRoutingSync: "initial-routing-sync",
|
||||||
GossipQueriesRequired: "gossip-queries",
|
GossipQueriesRequired: "gossip-queries",
|
||||||
GossipQueriesOptional: "gossip-queries",
|
GossipQueriesOptional: "gossip-queries",
|
||||||
}
|
|
||||||
|
|
||||||
// GlobalFeatures is a mapping of known global feature bits to a descriptive
|
|
||||||
// name. All known global feature bits must be assigned a name in this mapping.
|
|
||||||
// Global features are those which are advertised to the entire network. A full
|
|
||||||
// description of these feature bits is provided in the BOLT-09 specification.
|
|
||||||
var GlobalFeatures = map[FeatureBit]string{
|
|
||||||
TLVOnionPayloadRequired: "tlv-onion",
|
TLVOnionPayloadRequired: "tlv-onion",
|
||||||
TLVOnionPayloadOptional: "tlv-onion",
|
TLVOnionPayloadOptional: "tlv-onion",
|
||||||
StaticRemoteKeyOptional: "static-remote-key",
|
StaticRemoteKeyOptional: "static-remote-key",
|
||||||
@ -121,6 +119,26 @@ 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.
|
||||||
|
func (fv *RawFeatureVector) Clone() *RawFeatureVector {
|
||||||
|
newFeatures := NewRawFeatureVector()
|
||||||
|
for bit := range fv.features {
|
||||||
|
newFeatures.Set(bit)
|
||||||
|
}
|
||||||
|
return newFeatures
|
||||||
|
}
|
||||||
|
|
||||||
// IsSet returns whether a particular feature bit is enabled in the vector.
|
// IsSet returns whether a particular feature bit is enabled in the vector.
|
||||||
func (fv *RawFeatureVector) IsSet(feature FeatureBit) bool {
|
func (fv *RawFeatureVector) IsSet(feature FeatureBit) bool {
|
||||||
return fv.features[feature]
|
return fv.features[feature]
|
||||||
@ -131,6 +149,20 @@ func (fv *RawFeatureVector) Set(feature FeatureBit) {
|
|||||||
fv.features[feature] = true
|
fv.features[feature] = true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SafeSet sets the chosen feature bit in the feature vector, but returns an
|
||||||
|
// error if the opposing feature bit is already set. This ensures both that we
|
||||||
|
// are creating properly structured feature vectors, and in some cases, that
|
||||||
|
// peers are sending properly encoded ones, i.e. it can't be both optional and
|
||||||
|
// required.
|
||||||
|
func (fv *RawFeatureVector) SafeSet(feature FeatureBit) error {
|
||||||
|
if _, ok := fv.features[feature^1]; ok {
|
||||||
|
return ErrFeaturePairExists
|
||||||
|
}
|
||||||
|
|
||||||
|
fv.Set(feature)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// Unset marks a feature as disabled in the vector.
|
// Unset marks a feature as disabled in the vector.
|
||||||
func (fv *RawFeatureVector) Unset(feature FeatureBit) {
|
func (fv *RawFeatureVector) Unset(feature FeatureBit) {
|
||||||
delete(fv.features, feature)
|
delete(fv.features, feature)
|
||||||
|
@ -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,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
87
peer.go
87
peer.go
@ -190,21 +190,24 @@ type peer struct {
|
|||||||
|
|
||||||
server *server
|
server *server
|
||||||
|
|
||||||
// localFeatures is the set of local features that we advertised to the
|
// features is the set of features that we advertised to the remote
|
||||||
// remote node.
|
// node.
|
||||||
localFeatures *lnwire.RawFeatureVector
|
features *lnwire.FeatureVector
|
||||||
|
|
||||||
|
// legacyFeatures is the set of features that we advertised to the remote
|
||||||
|
// node for backwards compatibility. Nodes that have not implemented
|
||||||
|
// flat featurs will still be able to read our feature bits from the
|
||||||
|
// legacy global field, but we will also advertise everything in the
|
||||||
|
// default features field.
|
||||||
|
legacyFeatures *lnwire.FeatureVector
|
||||||
|
|
||||||
// outgoingCltvRejectDelta defines the number of blocks before expiry of
|
// outgoingCltvRejectDelta defines the number of blocks before expiry of
|
||||||
// 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
|
||||||
@ -234,7 +237,7 @@ var _ lnpeer.Peer = (*peer)(nil)
|
|||||||
// pointer to the main server.
|
// pointer to the main server.
|
||||||
func newPeer(conn net.Conn, connReq *connmgr.ConnReq, server *server,
|
func newPeer(conn net.Conn, connReq *connmgr.ConnReq, server *server,
|
||||||
addr *lnwire.NetAddress, inbound bool,
|
addr *lnwire.NetAddress, inbound bool,
|
||||||
localFeatures *lnwire.RawFeatureVector,
|
features, legacyFeatures *lnwire.FeatureVector,
|
||||||
chanActiveTimeout time.Duration,
|
chanActiveTimeout time.Duration,
|
||||||
outgoingCltvRejectDelta uint32) (
|
outgoingCltvRejectDelta uint32) (
|
||||||
*peer, error) {
|
*peer, error) {
|
||||||
@ -252,7 +255,8 @@ func newPeer(conn net.Conn, connReq *connmgr.ConnReq, server *server,
|
|||||||
|
|
||||||
server: server,
|
server: server,
|
||||||
|
|
||||||
localFeatures: localFeatures,
|
features: features,
|
||||||
|
legacyFeatures: legacyFeatures,
|
||||||
|
|
||||||
outgoingCltvRejectDelta: outgoingCltvRejectDelta,
|
outgoingCltvRejectDelta: outgoingCltvRejectDelta,
|
||||||
|
|
||||||
@ -399,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[:])
|
||||||
|
|
||||||
@ -2387,62 +2391,63 @@ 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.server.globalFeatures
|
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
|
||||||
// supported local and global features.
|
// supported local and global features.
|
||||||
func (p *peer) sendInitMsg() error {
|
func (p *peer) sendInitMsg() error {
|
||||||
msg := lnwire.NewInitMessage(
|
msg := lnwire.NewInitMessage(
|
||||||
p.server.globalFeatures.RawFeatureVector,
|
p.legacyFeatures.RawFeatureVector,
|
||||||
p.localFeatures,
|
p.features.RawFeatureVector,
|
||||||
)
|
)
|
||||||
|
|
||||||
return p.writeMessage(msg)
|
return p.writeMessage(msg)
|
||||||
|
@ -28,7 +28,7 @@ var (
|
|||||||
Port: 9000}
|
Port: 9000}
|
||||||
testAddrs = []net.Addr{testAddr}
|
testAddrs = []net.Addr{testAddr}
|
||||||
|
|
||||||
testFeatures = lnwire.NewFeatureVector(nil, lnwire.GlobalFeatures)
|
testFeatures = lnwire.NewFeatureVector(nil, lnwire.Features)
|
||||||
|
|
||||||
testHash = [32]byte{
|
testHash = [32]byte{
|
||||||
0xb7, 0x94, 0x38, 0x5f, 0x2d, 0x1e, 0xf7, 0xab,
|
0xb7, 0x94, 0x38, 0x5f, 0x2d, 0x1e, 0xf7, 0xab,
|
||||||
|
39
server.go
39
server.go
@ -35,6 +35,7 @@ import (
|
|||||||
"github.com/lightningnetwork/lnd/channelnotifier"
|
"github.com/lightningnetwork/lnd/channelnotifier"
|
||||||
"github.com/lightningnetwork/lnd/contractcourt"
|
"github.com/lightningnetwork/lnd/contractcourt"
|
||||||
"github.com/lightningnetwork/lnd/discovery"
|
"github.com/lightningnetwork/lnd/discovery"
|
||||||
|
"github.com/lightningnetwork/lnd/feature"
|
||||||
"github.com/lightningnetwork/lnd/htlcswitch"
|
"github.com/lightningnetwork/lnd/htlcswitch"
|
||||||
"github.com/lightningnetwork/lnd/htlcswitch/hop"
|
"github.com/lightningnetwork/lnd/htlcswitch/hop"
|
||||||
"github.com/lightningnetwork/lnd/input"
|
"github.com/lightningnetwork/lnd/input"
|
||||||
@ -232,9 +233,9 @@ type server struct {
|
|||||||
|
|
||||||
readPool *pool.Read
|
readPool *pool.Read
|
||||||
|
|
||||||
// globalFeatures feature vector which affects HTLCs and thus are also
|
// featureMgr dispatches feature vectors for various contexts within the
|
||||||
// advertised to other nodes.
|
// daemon.
|
||||||
globalFeatures *lnwire.FeatureVector
|
featureMgr *feature.Manager
|
||||||
|
|
||||||
// currentNodeAnn is the node announcement that has been broadcast to
|
// currentNodeAnn is the node announcement that has been broadcast to
|
||||||
// the network upon startup, if the attributes of the node (us) has
|
// the network upon startup, if the attributes of the node (us) has
|
||||||
@ -369,6 +370,14 @@ func newServer(listenAddrs []net.Addr, chanDB *channeldb.DB,
|
|||||||
readBufferPool, cfg.Workers.Read, pool.DefaultWorkerTimeout,
|
readBufferPool, cfg.Workers.Read, pool.DefaultWorkerTimeout,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
featureMgr, err := feature.NewManager(feature.Config{
|
||||||
|
NoTLVOnion: cfg.LegacyProtocol.LegacyOnion(),
|
||||||
|
NoStaticRemoteKey: cfg.LegacyProtocol.LegacyCommitment(),
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
s := &server{
|
s := &server{
|
||||||
chanDB: chanDB,
|
chanDB: chanDB,
|
||||||
cc: cc,
|
cc: cc,
|
||||||
@ -405,9 +414,7 @@ func newServer(listenAddrs []net.Addr, chanDB *channeldb.DB,
|
|||||||
peerConnectedListeners: make(map[string][]chan<- lnpeer.Peer),
|
peerConnectedListeners: make(map[string][]chan<- lnpeer.Peer),
|
||||||
peerDisconnectedListeners: make(map[string][]chan<- struct{}),
|
peerDisconnectedListeners: make(map[string][]chan<- struct{}),
|
||||||
|
|
||||||
globalFeatures: lnwire.NewFeatureVector(
|
featureMgr: featureMgr,
|
||||||
globalFeatures, lnwire.GlobalFeatures,
|
|
||||||
),
|
|
||||||
quit: make(chan struct{}),
|
quit: make(chan struct{}),
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -594,7 +601,7 @@ func newServer(listenAddrs []net.Addr, chanDB *channeldb.DB,
|
|||||||
LastUpdate: time.Now(),
|
LastUpdate: time.Now(),
|
||||||
Addresses: selfAddrs,
|
Addresses: selfAddrs,
|
||||||
Alias: nodeAlias.String(),
|
Alias: nodeAlias.String(),
|
||||||
Features: s.globalFeatures,
|
Features: s.featureMgr.Get(feature.SetNodeAnn),
|
||||||
Color: color,
|
Color: color,
|
||||||
}
|
}
|
||||||
copy(selfNode.PubKeyBytes[:], privKey.PubKey().SerializeCompressed())
|
copy(selfNode.PubKeyBytes[:], privKey.PubKey().SerializeCompressed())
|
||||||
@ -1965,7 +1972,7 @@ func (s *server) initTorController() error {
|
|||||||
Addresses: newNodeAnn.Addresses,
|
Addresses: newNodeAnn.Addresses,
|
||||||
Alias: newNodeAnn.Alias.String(),
|
Alias: newNodeAnn.Alias.String(),
|
||||||
Features: lnwire.NewFeatureVector(
|
Features: lnwire.NewFeatureVector(
|
||||||
newNodeAnn.Features, lnwire.GlobalFeatures,
|
newNodeAnn.Features, lnwire.Features,
|
||||||
),
|
),
|
||||||
Color: newNodeAnn.RGBColor,
|
Color: newNodeAnn.RGBColor,
|
||||||
AuthSigBytes: newNodeAnn.Signature.ToSignatureBytes(),
|
AuthSigBytes: newNodeAnn.Signature.ToSignatureBytes(),
|
||||||
@ -2728,14 +2735,10 @@ func (s *server) peerConnected(conn net.Conn, connReq *connmgr.ConnReq,
|
|||||||
ChainNet: activeNetParams.Net,
|
ChainNet: activeNetParams.Net,
|
||||||
}
|
}
|
||||||
|
|
||||||
// With the brontide connection established, we'll now craft the local
|
// With the brontide connection established, we'll now craft the feature
|
||||||
// feature vector to advertise to the remote node.
|
// vectors to advertise to the remote node.
|
||||||
localFeatures := lnwire.NewRawFeatureVector()
|
initFeatures := s.featureMgr.Get(feature.SetInit)
|
||||||
|
legacyFeatures := s.featureMgr.Get(feature.SetLegacyGlobal)
|
||||||
// We'll signal that we understand the data loss protection feature,
|
|
||||||
// and also that we support the new gossip query features.
|
|
||||||
localFeatures.Set(lnwire.DataLossProtectRequired)
|
|
||||||
localFeatures.Set(lnwire.GossipQueriesOptional)
|
|
||||||
|
|
||||||
// Now that we've established a connection, create a peer, and it to the
|
// Now that we've established a connection, create a peer, and it to the
|
||||||
// set of currently active peers. Configure the peer with the incoming
|
// set of currently active peers. Configure the peer with the incoming
|
||||||
@ -2744,8 +2747,8 @@ func (s *server) peerConnected(conn net.Conn, connReq *connmgr.ConnReq,
|
|||||||
// htlcs, an extra block is added to prevent the channel from being
|
// htlcs, an extra block is added to prevent the channel from being
|
||||||
// closed when the htlc is outstanding and a new block comes in.
|
// closed when the htlc is outstanding and a new block comes in.
|
||||||
p, err := newPeer(
|
p, err := newPeer(
|
||||||
conn, connReq, s, peerAddr, inbound, localFeatures,
|
conn, connReq, s, peerAddr, inbound, initFeatures,
|
||||||
cfg.ChanEnableTimeout,
|
legacyFeatures, cfg.ChanEnableTimeout,
|
||||||
defaultOutgoingCltvRejectDelta,
|
defaultOutgoingCltvRejectDelta,
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
Loading…
Reference in New Issue
Block a user