From f12ec12c26340bbca6d7e137c50ceb4d5da22cd4 Mon Sep 17 00:00:00 2001 From: Elle Mouton Date: Mon, 4 Nov 2024 10:17:20 +0200 Subject: [PATCH] multi: add a `--gossip.no-sync` option When set, LND will not advertise the gossip queries feature bit and it will not initiate gossip syncing with any peer. --- discovery/gossiper.go | 31 +++++++++++++++++++++++++++++++ feature/manager.go | 7 +++++++ lncfg/gossip.go | 2 ++ peer/brontide.go | 8 ++++++++ sample-lnd.conf | 4 ++++ server.go | 2 ++ 6 files changed, 54 insertions(+) diff --git a/discovery/gossiper.go b/discovery/gossiper.go index 41e58c404ed..3bd704f986c 100644 --- a/discovery/gossiper.go +++ b/discovery/gossiper.go @@ -74,6 +74,13 @@ var ( // the remote peer. ErrGossipSyncerNotFound = errors.New("gossip syncer not found") + // ErrUnexpectedGossipQueries is an error that is returned if we receive + // gossip queries from a peer when we have disabled gossip syncing and + // in other words have not advertised that we support gossip queries. + ErrUnexpectedGossipQueries = errors.New( + "unexpected gossip queries received", + ) + // emptyPubkey is used to compare compressed pubkeys against an empty // byte array. emptyPubkey [33]byte @@ -359,6 +366,11 @@ type Config struct { // updates for a channel and returns true if the channel should be // considered a zombie based on these timestamps. IsStillZombieChannel func(time.Time, time.Time) bool + + // NoGossipSync is true if gossip syncing has been disabled. It + // indicates that we have not advertised the gossip queries feature bit, + // and so we should not receive any gossip queries from our peers. + NoGossipSync bool } // processedNetworkMsg is a wrapper around networkMsg and a boolean. It is @@ -810,6 +822,25 @@ func (d *AuthenticatedGossiper) ProcessRemoteAnnouncement(msg lnwire.Message, errChan := make(chan error, 1) + // If gossip syncing has been disabled, we expect not to receive any + // gossip queries from our peer. + if d.cfg.NoGossipSync { + switch m := msg.(type) { + case *lnwire.QueryShortChanIDs, + *lnwire.QueryChannelRange, + *lnwire.ReplyChannelRange, + *lnwire.ReplyShortChanIDsEnd, + *lnwire.GossipTimestampRange: + + log.Warnf("Gossip syncing was disabled, "+ + "skipping message: %v", m) + errChan <- ErrUnexpectedGossipQueries + + return errChan + default: + } + } + // For messages in the known set of channel series queries, we'll // dispatch the message directly to the GossipSyncer, and skip the main // processing loop. diff --git a/feature/manager.go b/feature/manager.go index 89f1d4b6bce..9409458bf0b 100644 --- a/feature/manager.go +++ b/feature/manager.go @@ -66,6 +66,9 @@ type Config struct { // NoTaprootOverlay unsets the taproot overlay channel feature bits. NoTaprootOverlay bool + // NoGossipQueries unsets the gossip queries feature bit. + NoGossipQueries bool + // CustomFeatures is a set of custom features to advertise in each // set. CustomFeatures map[Set][]lnwire.FeatureBit @@ -199,6 +202,10 @@ func newManager(cfg Config, desc setDesc) (*Manager, error) { raw.Unset(lnwire.SimpleTaprootOverlayChansOptional) raw.Unset(lnwire.SimpleTaprootOverlayChansRequired) } + if cfg.NoGossipQueries { + raw.Unset(lnwire.GossipQueriesOptional) + raw.Unset(lnwire.GossipQueriesRequired) + } for _, custom := range cfg.CustomFeatures[set] { if custom > set.Maximum() { return nil, fmt.Errorf("feature bit: %v "+ diff --git a/lncfg/gossip.go b/lncfg/gossip.go index a2c82a7aa80..54ac4258829 100644 --- a/lncfg/gossip.go +++ b/lncfg/gossip.go @@ -18,6 +18,8 @@ type Gossip struct { ChannelUpdateInterval time.Duration `long:"channel-update-interval" description:"The interval used to determine how often lnd should allow a burst of new updates for a specific channel and direction."` SubBatchDelay time.Duration `long:"sub-batch-delay" description:"The duration to wait before sending the next announcement batch if there are multiple. Use a small value if there are a lot announcements and they need to be broadcast quickly."` + + NoSync bool `long:"no-sync" description:"If set, lnd will not request graph updates from its peers and wont advertise the gossip queries feature bit. This is useful if LND has been provided with an external graph source that it may use for pathfinding."` } // Parse the pubkeys for the pinned syncers. diff --git a/peer/brontide.go b/peer/brontide.go index 2b7853673ae..e35e7a63125 100644 --- a/peer/brontide.go +++ b/peer/brontide.go @@ -425,6 +425,9 @@ type Config struct { // used to modify the way the co-op close transaction is constructed. AuxChanCloser fn.Option[chancloser.AuxChanCloser] + // NoGossipSync is true if we should not sync gossip with this peer. + NoGossipSync bool + // Quit is the server's quit channel. If this is closed, we halt operation. Quit chan struct{} } @@ -864,6 +867,11 @@ func (p *Brontide) Start() error { // initGossipSync initializes either a gossip syncer or an initial routing // dump, depending on the negotiated synchronization method. func (p *Brontide) initGossipSync() { + // If gossip syncing has explicitly been disabled, we'll exit early. + if p.cfg.NoGossipSync { + return + } + // If the remote peer knows of the new gossip queries feature, then // we'll create a new gossipSyncer in the AuthenticatedGossiper for it. if p.remoteFeatures.HasFeature(lnwire.GossipQueriesOptional) { diff --git a/sample-lnd.conf b/sample-lnd.conf index 6d64603e8f6..9eaff599b64 100644 --- a/sample-lnd.conf +++ b/sample-lnd.conf @@ -1699,6 +1699,10 @@ ; be broadcast quickly. ; gossip.sub-batch-delay=5s +; If set, LND will not request graph updates from its peers and wont advertise +; the gossip queries feature bit. This is useful if LND has been provided with +; an external graph source that it may use for pathfinding. +; gossip.no-sync=false [invoices] diff --git a/server.go b/server.go index 28511dc48c4..993e00c468a 100644 --- a/server.go +++ b/server.go @@ -578,6 +578,7 @@ func newServer(cfg *Config, listenAddrs []net.Addr, NoTaprootChans: !cfg.ProtocolOptions.TaprootChans, NoTaprootOverlay: !cfg.ProtocolOptions.TaprootOverlayChans, NoRouteBlinding: cfg.ProtocolOptions.NoRouteBlinding(), + NoGossipQueries: cfg.Gossip.NoSync, }) if err != nil { return nil, err @@ -4188,6 +4189,7 @@ func (s *server) peerConnected(conn net.Conn, connReq *connmgr.ConnReq, MsgRouter: s.implCfg.MsgRouter, AuxChanCloser: s.implCfg.AuxChanCloser, AuxResolver: s.implCfg.AuxContractResolver, + NoGossipSync: s.cfg.Gossip.NoSync, } copy(pCfg.PubKeyBytes[:], peerAddr.IdentityKey.SerializeCompressed())