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:
Olaoluwa Osuntokun 2018-10-24 17:10:42 -07:00 committed by GitHub
commit d67c1fdcaa
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 110 additions and 71 deletions

@ -89,7 +89,7 @@ func (c *chanSeries) UpdatesInHorizon(chain chainhash.Hash,
return nil, err
}
for _, nodeAnn := range nodeAnnsInHorizon {
nodeUpdate, err := makeNodeAnn(&nodeAnn)
nodeUpdate, err := nodeAnn.NodeAnnouncement(true)
if err != nil {
return nil, err
}
@ -151,25 +151,6 @@ func (c *chanSeries) FilterChannelRange(chain chainhash.Hash,
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
// 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
@ -221,7 +202,7 @@ func (c *chanSeries) FetchChanAnns(chain chainhash.Hash,
nodePub := channel.Policy1.Node.PubKeyBytes
hasNodeAnn := channel.Policy1.Node.HaveNodeAnnouncement
if _, ok := nodePubsSent[nodePub]; !ok && hasNodeAnn {
nodeAnn, err := makeNodeAnn(channel.Policy1.Node)
nodeAnn, err := channel.Policy1.Node.NodeAnnouncement(true)
if err != nil {
return nil, err
}
@ -238,7 +219,7 @@ func (c *chanSeries) FetchChanAnns(chain chainhash.Hash,
nodePub := channel.Policy2.Node.PubKeyBytes
hasNodeAnn := channel.Policy2.Node.HaveNodeAnnouncement
if _, ok := nodePubsSent[nodePub]; !ok && hasNodeAnn {
nodeAnn, err := makeNodeAnn(channel.Policy2.Node)
nodeAnn, err := channel.Policy2.Node.NodeAnnouncement(true)
if err != nil {
return nil, err
}

@ -1767,6 +1767,43 @@ func (l *LightningNode) AddPubKey(key *btcec.PublicKey) {
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
// key. If the node isn't found in the database, then ErrGraphNodeNotFound is
// returned.

@ -270,27 +270,6 @@ func (d *AuthenticatedGossiper) SynchronizeNode(syncPeer lnpeer.Peer) error {
// containing all the messages to be sent to the target peer.
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
// announcement more than one time as one node may have many channel
// anns we'll need to send.
@ -330,7 +309,7 @@ func (d *AuthenticatedGossiper) SynchronizeNode(syncPeer lnpeer.Peer) error {
nodePub := e1.Node.PubKeyBytes
hasNodeAnn := e1.Node.HaveNodeAnnouncement
if _, ok := nodePubsSent[nodePub]; !ok && hasNodeAnn {
nodeAnn, err := makeNodeAnn(e1.Node)
nodeAnn, err := e1.Node.NodeAnnouncement(true)
if err != nil {
return err
}
@ -352,7 +331,7 @@ func (d *AuthenticatedGossiper) SynchronizeNode(syncPeer lnpeer.Peer) error {
nodePub := e2.Node.PubKeyBytes
hasNodeAnn := e2.Node.HaveNodeAnnouncement
if _, ok := nodePubsSent[nodePub]; !ok && hasNodeAnn {
nodeAnn, err := makeNodeAnn(e2.Node)
nodeAnn, err := e2.Node.NodeAnnouncement(true)
if err != nil {
return err
}

@ -7858,6 +7858,8 @@ func testNodeAnnouncement(net *lntest.NetworkHarness, t *harnessTest) {
advertisedAddrs := []string{
"192.168.1.1:8333",
"[2001:db8:85a3:8d3:1319:8a2e:370:7348]:8337",
"bkb6azqggsaiskzi.onion:9735",
"fomvuglh6h6vcag73xo5t5gv56ombih3zr2xvplkpbfd7wrog4swjwid.onion:1234",
}
var lndArgs []string

@ -229,7 +229,8 @@ func (b *BtcdFeeEstimator) fetchEstimate(confTarget uint32) (SatPerKWeight, erro
// Finally, we'll enforce our fee floor.
if satPerKw < b.minFeePerKW {
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
}

@ -440,14 +440,19 @@ func newServer(listenAddrs []net.Addr, chanDB *channeldb.DB, cc *chainControl,
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)
if err != nil {
srvrLog.Errorf("unable to parse color: %v\n", 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
if alias == "" {
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())
// If our information has changed since our last boot, then we'll
// re-sign our node announcement so a fresh authenticated version of it
// can be propagated throughout the network upon startup.
//
// TODO(roasbeef): don't always set timestamp above to _now.
nodeAnn := &lnwire.NodeAnnouncement{
Timestamp: uint32(selfNode.LastUpdate.Unix()),
Addresses: selfNode.Addresses,
NodeID: selfNode.PubKeyBytes,
Alias: nodeAlias,
Features: selfNode.Features.RawFeatureVector,
RGBColor: color,
// Based on the disk representation of the node announcement generated
// above, we'll generate a node announcement that can go out on the
// network so we can properly sign it.
nodeAnn, err := selfNode.NodeAnnouncement(false)
if err != nil {
return nil, fmt.Errorf("unable to gen self node ann: %v", err)
}
// With the announcement generated, we'll sign it to properly
// authenticate the message on the network.
authSig, err := discovery.SignAnnouncement(
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 "+
"self node announcement: %v", err)
}
selfNode.AuthSigBytes = authSig.Serialize()
s.currentNodeAnn = nodeAnn
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)
nodeAnn.Signature, err = lnwire.NewSigFromRawSignature(
selfNode.AuthSigBytes,
)
if err != nil {
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{
Graph: chanGraph,
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
// 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
}
@ -1526,27 +1556,36 @@ func (s *server) genNodeAnnouncement(refresh bool,
s.mu.Lock()
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 {
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 {
update(s.currentNodeAnn)
}
// We'll now update the timestamp, ensuring that with each update, the
// timestamp monotonically increases.
newStamp := uint32(time.Now().Unix())
if newStamp <= s.currentNodeAnn.Timestamp {
newStamp = s.currentNodeAnn.Timestamp + 1
}
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(
s.nodeSigner, s.identityPriv.PubKey(), s.currentNodeAnn,
)
if err != nil {
return lnwire.NodeAnnouncement{}, err
}
s.currentNodeAnn.Signature, err = lnwire.NewSigFromSignature(sig)
if err != nil {
return lnwire.NodeAnnouncement{}, err