Merge pull request #1954 from Roasbeef/tor-node-ann-fixes
server: ensure each time we update a node ann we also update the on-disk version
This commit is contained in:
commit
d67c1fdcaa
@ -89,7 +89,7 @@ func (c *chanSeries) UpdatesInHorizon(chain chainhash.Hash,
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
for _, nodeAnn := range nodeAnnsInHorizon {
|
for _, nodeAnn := range nodeAnnsInHorizon {
|
||||||
nodeUpdate, err := makeNodeAnn(&nodeAnn)
|
nodeUpdate, err := nodeAnn.NodeAnnouncement(true)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -151,25 +151,6 @@ func (c *chanSeries) FilterChannelRange(chain chainhash.Hash,
|
|||||||
return chanResp, nil
|
return chanResp, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func makeNodeAnn(n *channeldb.LightningNode) (*lnwire.NodeAnnouncement, error) {
|
|
||||||
alias, _ := lnwire.NewNodeAlias(n.Alias)
|
|
||||||
|
|
||||||
wireSig, err := lnwire.NewSigFromRawSignature(n.AuthSigBytes)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return &lnwire.NodeAnnouncement{
|
|
||||||
Signature: wireSig,
|
|
||||||
Timestamp: uint32(n.LastUpdate.Unix()),
|
|
||||||
Addresses: n.Addresses,
|
|
||||||
NodeID: n.PubKeyBytes,
|
|
||||||
Features: n.Features.RawFeatureVector,
|
|
||||||
RGBColor: n.Color,
|
|
||||||
Alias: alias,
|
|
||||||
ExtraOpaqueData: n.ExtraOpaqueData,
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// FetchChanAnns returns a full set of channel announcements as well as their
|
// FetchChanAnns returns a full set of channel announcements as well as their
|
||||||
// updates that match the set of specified short channel ID's. We'll use this
|
// updates that match the set of specified short channel ID's. We'll use this
|
||||||
// to reply to a QueryShortChanIDs message sent by a remote peer. The response
|
// to reply to a QueryShortChanIDs message sent by a remote peer. The response
|
||||||
@ -221,7 +202,7 @@ func (c *chanSeries) FetchChanAnns(chain chainhash.Hash,
|
|||||||
nodePub := channel.Policy1.Node.PubKeyBytes
|
nodePub := channel.Policy1.Node.PubKeyBytes
|
||||||
hasNodeAnn := channel.Policy1.Node.HaveNodeAnnouncement
|
hasNodeAnn := channel.Policy1.Node.HaveNodeAnnouncement
|
||||||
if _, ok := nodePubsSent[nodePub]; !ok && hasNodeAnn {
|
if _, ok := nodePubsSent[nodePub]; !ok && hasNodeAnn {
|
||||||
nodeAnn, err := makeNodeAnn(channel.Policy1.Node)
|
nodeAnn, err := channel.Policy1.Node.NodeAnnouncement(true)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -238,7 +219,7 @@ func (c *chanSeries) FetchChanAnns(chain chainhash.Hash,
|
|||||||
nodePub := channel.Policy2.Node.PubKeyBytes
|
nodePub := channel.Policy2.Node.PubKeyBytes
|
||||||
hasNodeAnn := channel.Policy2.Node.HaveNodeAnnouncement
|
hasNodeAnn := channel.Policy2.Node.HaveNodeAnnouncement
|
||||||
if _, ok := nodePubsSent[nodePub]; !ok && hasNodeAnn {
|
if _, ok := nodePubsSent[nodePub]; !ok && hasNodeAnn {
|
||||||
nodeAnn, err := makeNodeAnn(channel.Policy2.Node)
|
nodeAnn, err := channel.Policy2.Node.NodeAnnouncement(true)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -1767,6 +1767,43 @@ func (l *LightningNode) AddPubKey(key *btcec.PublicKey) {
|
|||||||
copy(l.PubKeyBytes[:], key.SerializeCompressed())
|
copy(l.PubKeyBytes[:], key.SerializeCompressed())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NodeAnnouncement retrieves the latest node announcement of the node.
|
||||||
|
func (l *LightningNode) NodeAnnouncement(signed bool) (*lnwire.NodeAnnouncement,
|
||||||
|
error) {
|
||||||
|
|
||||||
|
if !l.HaveNodeAnnouncement {
|
||||||
|
return nil, fmt.Errorf("node does not have node announcement")
|
||||||
|
}
|
||||||
|
|
||||||
|
alias, err := lnwire.NewNodeAlias(l.Alias)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
nodeAnn := &lnwire.NodeAnnouncement{
|
||||||
|
Features: l.Features.RawFeatureVector,
|
||||||
|
NodeID: l.PubKeyBytes,
|
||||||
|
RGBColor: l.Color,
|
||||||
|
Alias: alias,
|
||||||
|
Addresses: l.Addresses,
|
||||||
|
Timestamp: uint32(l.LastUpdate.Unix()),
|
||||||
|
ExtraOpaqueData: l.ExtraOpaqueData,
|
||||||
|
}
|
||||||
|
|
||||||
|
if !signed {
|
||||||
|
return nodeAnn, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
sig, err := lnwire.NewSigFromRawSignature(l.AuthSigBytes)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
nodeAnn.Signature = sig
|
||||||
|
|
||||||
|
return nodeAnn, nil
|
||||||
|
}
|
||||||
|
|
||||||
// FetchLightningNode attempts to look up a target node by its identity public
|
// FetchLightningNode attempts to look up a target node by its identity public
|
||||||
// key. If the node isn't found in the database, then ErrGraphNodeNotFound is
|
// key. If the node isn't found in the database, then ErrGraphNodeNotFound is
|
||||||
// returned.
|
// returned.
|
||||||
|
@ -270,27 +270,6 @@ func (d *AuthenticatedGossiper) SynchronizeNode(syncPeer lnpeer.Peer) error {
|
|||||||
// containing all the messages to be sent to the target peer.
|
// containing all the messages to be sent to the target peer.
|
||||||
var announceMessages []lnwire.Message
|
var announceMessages []lnwire.Message
|
||||||
|
|
||||||
makeNodeAnn := func(n *channeldb.LightningNode) (
|
|
||||||
*lnwire.NodeAnnouncement, error) {
|
|
||||||
|
|
||||||
alias, _ := lnwire.NewNodeAlias(n.Alias)
|
|
||||||
|
|
||||||
wireSig, err := lnwire.NewSigFromRawSignature(n.AuthSigBytes)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return &lnwire.NodeAnnouncement{
|
|
||||||
Signature: wireSig,
|
|
||||||
Timestamp: uint32(n.LastUpdate.Unix()),
|
|
||||||
Addresses: n.Addresses,
|
|
||||||
NodeID: n.PubKeyBytes,
|
|
||||||
Features: n.Features.RawFeatureVector,
|
|
||||||
RGBColor: n.Color,
|
|
||||||
Alias: alias,
|
|
||||||
ExtraOpaqueData: n.ExtraOpaqueData,
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// We'll use this map to ensure we don't send the same node
|
// We'll use this map to ensure we don't send the same node
|
||||||
// announcement more than one time as one node may have many channel
|
// announcement more than one time as one node may have many channel
|
||||||
// anns we'll need to send.
|
// anns we'll need to send.
|
||||||
@ -330,7 +309,7 @@ func (d *AuthenticatedGossiper) SynchronizeNode(syncPeer lnpeer.Peer) error {
|
|||||||
nodePub := e1.Node.PubKeyBytes
|
nodePub := e1.Node.PubKeyBytes
|
||||||
hasNodeAnn := e1.Node.HaveNodeAnnouncement
|
hasNodeAnn := e1.Node.HaveNodeAnnouncement
|
||||||
if _, ok := nodePubsSent[nodePub]; !ok && hasNodeAnn {
|
if _, ok := nodePubsSent[nodePub]; !ok && hasNodeAnn {
|
||||||
nodeAnn, err := makeNodeAnn(e1.Node)
|
nodeAnn, err := e1.Node.NodeAnnouncement(true)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -352,7 +331,7 @@ func (d *AuthenticatedGossiper) SynchronizeNode(syncPeer lnpeer.Peer) error {
|
|||||||
nodePub := e2.Node.PubKeyBytes
|
nodePub := e2.Node.PubKeyBytes
|
||||||
hasNodeAnn := e2.Node.HaveNodeAnnouncement
|
hasNodeAnn := e2.Node.HaveNodeAnnouncement
|
||||||
if _, ok := nodePubsSent[nodePub]; !ok && hasNodeAnn {
|
if _, ok := nodePubsSent[nodePub]; !ok && hasNodeAnn {
|
||||||
nodeAnn, err := makeNodeAnn(e2.Node)
|
nodeAnn, err := e2.Node.NodeAnnouncement(true)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -7858,6 +7858,8 @@ func testNodeAnnouncement(net *lntest.NetworkHarness, t *harnessTest) {
|
|||||||
advertisedAddrs := []string{
|
advertisedAddrs := []string{
|
||||||
"192.168.1.1:8333",
|
"192.168.1.1:8333",
|
||||||
"[2001:db8:85a3:8d3:1319:8a2e:370:7348]:8337",
|
"[2001:db8:85a3:8d3:1319:8a2e:370:7348]:8337",
|
||||||
|
"bkb6azqggsaiskzi.onion:9735",
|
||||||
|
"fomvuglh6h6vcag73xo5t5gv56ombih3zr2xvplkpbfd7wrog4swjwid.onion:1234",
|
||||||
}
|
}
|
||||||
|
|
||||||
var lndArgs []string
|
var lndArgs []string
|
||||||
|
@ -229,7 +229,8 @@ func (b *BtcdFeeEstimator) fetchEstimate(confTarget uint32) (SatPerKWeight, erro
|
|||||||
// Finally, we'll enforce our fee floor.
|
// Finally, we'll enforce our fee floor.
|
||||||
if satPerKw < b.minFeePerKW {
|
if satPerKw < b.minFeePerKW {
|
||||||
walletLog.Debugf("Estimated fee rate of %v sat/kw is too low, "+
|
walletLog.Debugf("Estimated fee rate of %v sat/kw is too low, "+
|
||||||
"using fee floor of %v sat/kw instead", b.minFeePerKW)
|
"using fee floor of %v sat/kw instead", satPerKw,
|
||||||
|
b.minFeePerKW)
|
||||||
satPerKw = b.minFeePerKW
|
satPerKw = b.minFeePerKW
|
||||||
}
|
}
|
||||||
|
|
||||||
|
89
server.go
89
server.go
@ -440,14 +440,19 @@ func newServer(listenAddrs []net.Addr, chanDB *channeldb.DB, cc *chainControl,
|
|||||||
|
|
||||||
chanGraph := chanDB.ChannelGraph()
|
chanGraph := chanDB.ChannelGraph()
|
||||||
|
|
||||||
// Parse node color from configuration.
|
// We'll now reconstruct a node announcement based on our current
|
||||||
|
// configuration so we can send it out as a sort of heart beat within
|
||||||
|
// the network.
|
||||||
|
//
|
||||||
|
// We'll start by parsing the node color from configuration.
|
||||||
color, err := parseHexColor(cfg.Color)
|
color, err := parseHexColor(cfg.Color)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
srvrLog.Errorf("unable to parse color: %v\n", err)
|
srvrLog.Errorf("unable to parse color: %v\n", err)
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// If no alias is provided, default to first 10 characters of public key
|
// If no alias is provided, default to first 10 characters of public
|
||||||
|
// key.
|
||||||
alias := cfg.Alias
|
alias := cfg.Alias
|
||||||
if alias == "" {
|
if alias == "" {
|
||||||
alias = hex.EncodeToString(serializedPubKey[:10])
|
alias = hex.EncodeToString(serializedPubKey[:10])
|
||||||
@ -466,19 +471,16 @@ func newServer(listenAddrs []net.Addr, chanDB *channeldb.DB, cc *chainControl,
|
|||||||
}
|
}
|
||||||
copy(selfNode.PubKeyBytes[:], privKey.PubKey().SerializeCompressed())
|
copy(selfNode.PubKeyBytes[:], privKey.PubKey().SerializeCompressed())
|
||||||
|
|
||||||
// If our information has changed since our last boot, then we'll
|
// Based on the disk representation of the node announcement generated
|
||||||
// re-sign our node announcement so a fresh authenticated version of it
|
// above, we'll generate a node announcement that can go out on the
|
||||||
// can be propagated throughout the network upon startup.
|
// network so we can properly sign it.
|
||||||
//
|
nodeAnn, err := selfNode.NodeAnnouncement(false)
|
||||||
// TODO(roasbeef): don't always set timestamp above to _now.
|
if err != nil {
|
||||||
nodeAnn := &lnwire.NodeAnnouncement{
|
return nil, fmt.Errorf("unable to gen self node ann: %v", err)
|
||||||
Timestamp: uint32(selfNode.LastUpdate.Unix()),
|
|
||||||
Addresses: selfNode.Addresses,
|
|
||||||
NodeID: selfNode.PubKeyBytes,
|
|
||||||
Alias: nodeAlias,
|
|
||||||
Features: selfNode.Features.RawFeatureVector,
|
|
||||||
RGBColor: color,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// With the announcement generated, we'll sign it to properly
|
||||||
|
// authenticate the message on the network.
|
||||||
authSig, err := discovery.SignAnnouncement(
|
authSig, err := discovery.SignAnnouncement(
|
||||||
s.nodeSigner, s.identityPriv.PubKey(), nodeAnn,
|
s.nodeSigner, s.identityPriv.PubKey(), nodeAnn,
|
||||||
)
|
)
|
||||||
@ -486,18 +488,21 @@ func newServer(listenAddrs []net.Addr, chanDB *channeldb.DB, cc *chainControl,
|
|||||||
return nil, fmt.Errorf("unable to generate signature for "+
|
return nil, fmt.Errorf("unable to generate signature for "+
|
||||||
"self node announcement: %v", err)
|
"self node announcement: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
selfNode.AuthSigBytes = authSig.Serialize()
|
selfNode.AuthSigBytes = authSig.Serialize()
|
||||||
s.currentNodeAnn = nodeAnn
|
nodeAnn.Signature, err = lnwire.NewSigFromRawSignature(
|
||||||
|
selfNode.AuthSigBytes,
|
||||||
if err := chanGraph.SetSourceNode(selfNode); err != nil {
|
)
|
||||||
return nil, fmt.Errorf("can't set self node: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
nodeAnn.Signature, err = lnwire.NewSigFromRawSignature(selfNode.AuthSigBytes)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Finally, we'll update the representation on disk, and update our
|
||||||
|
// cached in-memory version as well.
|
||||||
|
if err := chanGraph.SetSourceNode(selfNode); err != nil {
|
||||||
|
return nil, fmt.Errorf("can't set self node: %v", err)
|
||||||
|
}
|
||||||
|
s.currentNodeAnn = nodeAnn
|
||||||
|
|
||||||
s.chanRouter, err = routing.New(routing.Config{
|
s.chanRouter, err = routing.New(routing.Config{
|
||||||
Graph: chanGraph,
|
Graph: chanGraph,
|
||||||
Chain: cc.chainIO,
|
Chain: cc.chainIO,
|
||||||
@ -1512,7 +1517,32 @@ func (s *server) initTorController() error {
|
|||||||
|
|
||||||
// Now that the onion service has been created, we'll add the onion
|
// Now that the onion service has been created, we'll add the onion
|
||||||
// address it can be reached at to our list of advertised addresses.
|
// address it can be reached at to our list of advertised addresses.
|
||||||
s.currentNodeAnn.Addresses = append(s.currentNodeAnn.Addresses, addr)
|
newNodeAnn, err := s.genNodeAnnouncement(
|
||||||
|
true, func(currentAnn *lnwire.NodeAnnouncement) {
|
||||||
|
currentAnn.Addresses = append(currentAnn.Addresses, addr)
|
||||||
|
},
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("Unable to generate new node "+
|
||||||
|
"announcement: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Finally, we'll update the on-disk version of our announcement so it
|
||||||
|
// will eventually propagate to nodes in the network.
|
||||||
|
selfNode := &channeldb.LightningNode{
|
||||||
|
HaveNodeAnnouncement: true,
|
||||||
|
LastUpdate: time.Unix(int64(newNodeAnn.Timestamp), 0),
|
||||||
|
Addresses: newNodeAnn.Addresses,
|
||||||
|
Alias: newNodeAnn.Alias.String(),
|
||||||
|
Features: lnwire.NewFeatureVector(
|
||||||
|
newNodeAnn.Features, lnwire.GlobalFeatures,
|
||||||
|
),
|
||||||
|
Color: newNodeAnn.RGBColor,
|
||||||
|
AuthSigBytes: newNodeAnn.Signature.ToSignatureBytes(),
|
||||||
|
}
|
||||||
|
if err := s.chanDB.ChannelGraph().SetSourceNode(selfNode); err != nil {
|
||||||
|
return fmt.Errorf("can't set self node: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@ -1526,27 +1556,36 @@ func (s *server) genNodeAnnouncement(refresh bool,
|
|||||||
s.mu.Lock()
|
s.mu.Lock()
|
||||||
defer s.mu.Unlock()
|
defer s.mu.Unlock()
|
||||||
|
|
||||||
|
// If we don't need to refresh the announcement, then we can return a
|
||||||
|
// copy of our cached version.
|
||||||
if !refresh {
|
if !refresh {
|
||||||
return *s.currentNodeAnn, nil
|
return *s.currentNodeAnn, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Now that we know we need to update our copy, we'll apply all the
|
||||||
|
// function updates that'll mutate the current version of our node
|
||||||
|
// announcement.
|
||||||
for _, update := range updates {
|
for _, update := range updates {
|
||||||
update(s.currentNodeAnn)
|
update(s.currentNodeAnn)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// We'll now update the timestamp, ensuring that with each update, the
|
||||||
|
// timestamp monotonically increases.
|
||||||
newStamp := uint32(time.Now().Unix())
|
newStamp := uint32(time.Now().Unix())
|
||||||
if newStamp <= s.currentNodeAnn.Timestamp {
|
if newStamp <= s.currentNodeAnn.Timestamp {
|
||||||
newStamp = s.currentNodeAnn.Timestamp + 1
|
newStamp = s.currentNodeAnn.Timestamp + 1
|
||||||
}
|
}
|
||||||
|
|
||||||
s.currentNodeAnn.Timestamp = newStamp
|
s.currentNodeAnn.Timestamp = newStamp
|
||||||
|
|
||||||
|
// Now that the announcement is fully updated, we'll generate a new
|
||||||
|
// signature over the announcement to ensure nodes on the network
|
||||||
|
// accepted the new authenticated announcement.
|
||||||
sig, err := discovery.SignAnnouncement(
|
sig, err := discovery.SignAnnouncement(
|
||||||
s.nodeSigner, s.identityPriv.PubKey(), s.currentNodeAnn,
|
s.nodeSigner, s.identityPriv.PubKey(), s.currentNodeAnn,
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return lnwire.NodeAnnouncement{}, err
|
return lnwire.NodeAnnouncement{}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
s.currentNodeAnn.Signature, err = lnwire.NewSigFromSignature(sig)
|
s.currentNodeAnn.Signature, err = lnwire.NewSigFromSignature(sig)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return lnwire.NodeAnnouncement{}, err
|
return lnwire.NodeAnnouncement{}, err
|
||||||
|
Loading…
Reference in New Issue
Block a user