github.com/decred/dcrlnd@v0.7.6/discovery/syncer.go (about)

     1  package discovery
     2  
     3  import (
     4  	"errors"
     5  	"fmt"
     6  	"math"
     7  	"math/rand"
     8  	"sort"
     9  	"sync"
    10  	"sync/atomic"
    11  	"time"
    12  
    13  	"github.com/decred/dcrd/chaincfg/chainhash"
    14  	"github.com/decred/dcrlnd/lnpeer"
    15  	"github.com/decred/dcrlnd/lnwire"
    16  	"golang.org/x/time/rate"
    17  )
    18  
    19  // SyncerType encapsulates the different types of syncing mechanisms for a
    20  // gossip syncer.
    21  type SyncerType uint8
    22  
    23  const (
    24  	// ActiveSync denotes that a gossip syncer:
    25  	//
    26  	// 1. Should not attempt to synchronize with the remote peer for
    27  	//    missing channels.
    28  	// 2. Should respond to queries from the remote peer.
    29  	// 3. Should receive new updates from the remote peer.
    30  	//
    31  	// They are started in a chansSynced state in order to accomplish their
    32  	// responsibilities above.
    33  	ActiveSync SyncerType = iota
    34  
    35  	// PassiveSync denotes that a gossip syncer:
    36  	//
    37  	// 1. Should not attempt to synchronize with the remote peer for
    38  	//    missing channels.
    39  	// 2. Should respond to queries from the remote peer.
    40  	// 3. Should not receive new updates from the remote peer.
    41  	//
    42  	// They are started in a chansSynced state in order to accomplish their
    43  	// responsibilities above.
    44  	PassiveSync
    45  
    46  	// PinnedSync denotes an ActiveSync that doesn't count towards the
    47  	// default active syncer limits and is always active throughout the
    48  	// duration of the peer's connection. Each pinned syncer will begin by
    49  	// performing a historical sync to ensure we are well synchronized with
    50  	// their routing table.
    51  	PinnedSync
    52  )
    53  
    54  // String returns a human readable string describing the target SyncerType.
    55  func (t SyncerType) String() string {
    56  	switch t {
    57  	case ActiveSync:
    58  		return "ActiveSync"
    59  	case PassiveSync:
    60  		return "PassiveSync"
    61  	case PinnedSync:
    62  		return "PinnedSync"
    63  	default:
    64  		return fmt.Sprintf("unknown sync type %d", t)
    65  	}
    66  }
    67  
    68  // IsActiveSync returns true if the SyncerType should set a GossipTimestampRange
    69  // allowing new gossip messages to be received from the peer.
    70  func (t SyncerType) IsActiveSync() bool {
    71  	switch t {
    72  	case ActiveSync, PinnedSync:
    73  		return true
    74  	default:
    75  		return false
    76  	}
    77  }
    78  
    79  // syncerState is an enum that represents the current state of the GossipSyncer.
    80  // As the syncer is a state machine, we'll gate our actions based off of the
    81  // current state and the next incoming message.
    82  type syncerState uint32
    83  
    84  const (
    85  	// syncingChans is the default state of the GossipSyncer. We start in
    86  	// this state when a new peer first connects and we don't yet know if
    87  	// we're fully synchronized.
    88  	syncingChans syncerState = iota
    89  
    90  	// waitingQueryRangeReply is the second main phase of the GossipSyncer.
    91  	// We enter this state after we send out our first QueryChannelRange
    92  	// reply. We'll stay in this state until the remote party sends us a
    93  	// ReplyShortChanIDsEnd message that indicates they've responded to our
    94  	// query entirely. After this state, we'll transition to
    95  	// waitingQueryChanReply after we send out requests for all the new
    96  	// chan ID's to us.
    97  	waitingQueryRangeReply
    98  
    99  	// queryNewChannels is the third main phase of the GossipSyncer.  In
   100  	// this phase we'll send out all of our QueryShortChanIDs messages in
   101  	// response to the new channels that we don't yet know about.
   102  	queryNewChannels
   103  
   104  	// waitingQueryChanReply is the fourth main phase of the GossipSyncer.
   105  	// We enter this phase once we've sent off a query chink to the remote
   106  	// peer.  We'll stay in this phase until we receive a
   107  	// ReplyShortChanIDsEnd message which indicates that the remote party
   108  	// has responded to all of our requests.
   109  	waitingQueryChanReply
   110  
   111  	// chansSynced is the terminal stage of the GossipSyncer. Once we enter
   112  	// this phase, we'll send out our update horizon, which filters out the
   113  	// set of channel updates that we're interested in. In this state,
   114  	// we'll be able to accept any outgoing messages from the
   115  	// AuthenticatedGossiper, and decide if we should forward them to our
   116  	// target peer based on its update horizon.
   117  	chansSynced
   118  
   119  	// syncerIdle is a state in which the gossip syncer can handle external
   120  	// requests to transition or perform historical syncs. It is used as the
   121  	// initial state for pinned syncers, as well as a fallthrough case for
   122  	// chansSynced allowing fully synced peers to facilitate requests.
   123  	syncerIdle
   124  )
   125  
   126  // String returns a human readable string describing the target syncerState.
   127  func (s syncerState) String() string {
   128  	switch s {
   129  	case syncingChans:
   130  		return "syncingChans"
   131  
   132  	case waitingQueryRangeReply:
   133  		return "waitingQueryRangeReply"
   134  
   135  	case queryNewChannels:
   136  		return "queryNewChannels"
   137  
   138  	case waitingQueryChanReply:
   139  		return "waitingQueryChanReply"
   140  
   141  	case chansSynced:
   142  		return "chansSynced"
   143  
   144  	case syncerIdle:
   145  		return "syncerIdle"
   146  
   147  	default:
   148  		return "UNKNOWN STATE"
   149  	}
   150  }
   151  
   152  const (
   153  	// DefaultMaxUndelayedQueryReplies specifies how many gossip queries we
   154  	// will respond to immediately before starting to delay responses.
   155  	DefaultMaxUndelayedQueryReplies = 10
   156  
   157  	// DefaultDelayedQueryReplyInterval is the length of time we will wait
   158  	// before responding to gossip queries after replying to
   159  	// maxUndelayedQueryReplies queries.
   160  	DefaultDelayedQueryReplyInterval = 5 * time.Second
   161  
   162  	// maxQueryChanRangeReplies specifies the default limit of replies to
   163  	// process for a single QueryChannelRange request.
   164  	maxQueryChanRangeReplies = 500
   165  
   166  	// maxQueryChanRangeRepliesZlibFactor specifies the factor applied to
   167  	// the maximum number of replies allowed for zlib encoded replies.
   168  	maxQueryChanRangeRepliesZlibFactor = 4
   169  
   170  	// chanRangeQueryBuffer is the number of blocks back that we'll go when
   171  	// asking the remote peer for their any channels they know of beyond
   172  	// our highest known channel ID.
   173  	chanRangeQueryBuffer = 144
   174  
   175  	// syncTransitionTimeout is the default timeout in which we'll wait up
   176  	// to when attempting to perform a sync transition.
   177  	syncTransitionTimeout = 5 * time.Second
   178  
   179  	// requestBatchSize is the maximum number of channels we will query the
   180  	// remote peer for in a QueryShortChanIDs message.
   181  	requestBatchSize = 500
   182  )
   183  
   184  var (
   185  	// encodingTypeToChunkSize maps an encoding type, to the max number of
   186  	// short chan ID's using the encoding type that we can fit into a
   187  	// single message safely.
   188  	encodingTypeToChunkSize = map[lnwire.ShortChanIDEncoding]int32{
   189  		lnwire.EncodingSortedPlain: 8000,
   190  	}
   191  
   192  	// ErrGossipSyncerExiting signals that the syncer has been killed.
   193  	ErrGossipSyncerExiting = errors.New("gossip syncer exiting")
   194  
   195  	// ErrSyncTransitionTimeout is an error returned when we've timed out
   196  	// attempting to perform a sync transition.
   197  	ErrSyncTransitionTimeout = errors.New("timed out attempting to " +
   198  		"transition sync type")
   199  
   200  	// zeroTimestamp is the timestamp we'll use when we want to indicate to
   201  	// peers that we do not want to receive any new graph updates.
   202  	zeroTimestamp time.Time
   203  )
   204  
   205  // syncTransitionReq encapsulates a request for a gossip syncer sync transition.
   206  type syncTransitionReq struct {
   207  	newSyncType SyncerType
   208  	errChan     chan error
   209  }
   210  
   211  // historicalSyncReq encapsulates a request for a gossip syncer to perform a
   212  // historical sync.
   213  type historicalSyncReq struct {
   214  	// doneChan is a channel that serves as a signal and is closed to ensure
   215  	// the historical sync is attempted by the time we return to the caller.
   216  	doneChan chan struct{}
   217  }
   218  
   219  // gossipSyncerCfg is a struct that packages all the information a GossipSyncer
   220  // needs to carry out its duties.
   221  type gossipSyncerCfg struct {
   222  	// chainHash is the chain that this syncer is responsible for.
   223  	chainHash chainhash.Hash
   224  
   225  	// peerPub is the public key of the peer we're syncing with, serialized
   226  	// in compressed format.
   227  	peerPub [33]byte
   228  
   229  	// channelSeries is the primary interface that we'll use to generate
   230  	// our queries and respond to the queries of the remote peer.
   231  	channelSeries ChannelGraphTimeSeries
   232  
   233  	// gossiperState is an interface that provides functions to persist
   234  	// data about the state of this gossiper.
   235  	gossiperState GossiperState
   236  
   237  	// encodingType is the current encoding type we're aware of. Requests
   238  	// with different encoding types will be rejected.
   239  	encodingType lnwire.ShortChanIDEncoding
   240  
   241  	// chunkSize is the max number of short chan IDs using the syncer's
   242  	// encoding type that we can fit into a single message safely.
   243  	chunkSize int32
   244  
   245  	// batchSize is the max number of channels the syncer will query from
   246  	// the remote node in a single QueryShortChanIDs request.
   247  	batchSize int32
   248  
   249  	// sendToPeer sends a variadic number of messages to the remote peer.
   250  	// This method should not block while waiting for sends to be written
   251  	// to the wire.
   252  	sendToPeer func(...lnwire.Message) error
   253  
   254  	// sendToPeerSync sends a variadic number of messages to the remote
   255  	// peer, blocking until all messages have been sent successfully or a
   256  	// write error is encountered.
   257  	sendToPeerSync func(...lnwire.Message) error
   258  
   259  	// maxUndelayedQueryReplies specifies how many gossip queries we will
   260  	// respond to immediately before starting to delay responses.
   261  	maxUndelayedQueryReplies int
   262  
   263  	// delayedQueryReplyInterval is the length of time we will wait before
   264  	// responding to gossip queries after replying to
   265  	// maxUndelayedQueryReplies queries.
   266  	delayedQueryReplyInterval time.Duration
   267  
   268  	// noSyncChannels will prevent the GossipSyncer from spawning a
   269  	// channelGraphSyncer, meaning we will not try to reconcile unknown
   270  	// channels with the remote peer.
   271  	noSyncChannels bool
   272  
   273  	// noReplyQueries will prevent the GossipSyncer from spawning a
   274  	// replyHandler, meaning we will not reply to queries from our remote
   275  	// peer.
   276  	noReplyQueries bool
   277  
   278  	// ignoreHistoricalFilters will prevent syncers from replying with
   279  	// historical data when the remote peer sets a gossip_timestamp_range.
   280  	// This prevents ranges with old start times from causing us to dump the
   281  	// graph on connect.
   282  	ignoreHistoricalFilters bool
   283  
   284  	// bestHeight returns the latest height known of the chain.
   285  	bestHeight func() uint32
   286  
   287  	// markGraphSynced updates the SyncManager's perception of whether we
   288  	// have completed at least one historical sync.
   289  	markGraphSynced func()
   290  
   291  	// maxQueryChanRangeReplies is the maximum number of replies we'll allow
   292  	// for a single QueryChannelRange request.
   293  	maxQueryChanRangeReplies uint32
   294  }
   295  
   296  // GossipSyncer is a struct that handles synchronizing the channel graph state
   297  // with a remote peer. The GossipSyncer implements a state machine that will
   298  // progressively ensure we're synchronized with the channel state of the remote
   299  // node. Once both nodes have been synchronized, we'll use an update filter to
   300  // filter out which messages should be sent to a remote peer based on their
   301  // update horizon. If the update horizon isn't specified, then we won't send
   302  // them any channel updates at all.
   303  type GossipSyncer struct {
   304  	started sync.Once
   305  	stopped sync.Once
   306  
   307  	// state is the current state of the GossipSyncer.
   308  	//
   309  	// NOTE: This variable MUST be used atomically.
   310  	state uint32
   311  
   312  	// syncType denotes the SyncerType the gossip syncer is currently
   313  	// exercising.
   314  	//
   315  	// NOTE: This variable MUST be used atomically.
   316  	syncType uint32
   317  
   318  	// remoteUpdateHorizon is the update horizon of the remote peer. We'll
   319  	// use this to properly filter out any messages.
   320  	remoteUpdateHorizon *lnwire.GossipTimestampRange
   321  
   322  	// localUpdateHorizon is our local update horizon, we'll use this to
   323  	// determine if we've already sent out our update.
   324  	localUpdateHorizon *lnwire.GossipTimestampRange
   325  
   326  	// syncTransitions is a channel through which new sync type transition
   327  	// requests will be sent through. These requests should only be handled
   328  	// when the gossip syncer is in a chansSynced state to ensure its state
   329  	// machine behaves as expected.
   330  	syncTransitionReqs chan *syncTransitionReq
   331  
   332  	// historicalSyncReqs is a channel that serves as a signal for the
   333  	// gossip syncer to perform a historical sync. These can only be done
   334  	// once the gossip syncer is in a chansSynced state to ensure its state
   335  	// machine behaves as expected.
   336  	historicalSyncReqs chan *historicalSyncReq
   337  
   338  	// genHistoricalChanRangeQuery when true signals to the gossip syncer
   339  	// that it should request the remote peer for all of its known channel
   340  	// IDs starting from the genesis block of the chain. This can only
   341  	// happen if the gossip syncer receives a request to attempt a
   342  	// historical sync. It can be unset if the syncer ever transitions from
   343  	// PassiveSync to ActiveSync.
   344  	genHistoricalChanRangeQuery bool
   345  
   346  	// gossipMsgs is a channel that all responses to our queries from the
   347  	// target peer will be sent over, these will be read by the
   348  	// channelGraphSyncer.
   349  	gossipMsgs chan lnwire.Message
   350  
   351  	// queryMsgs is a channel that all queries from the remote peer will be
   352  	// received over, these will be read by the replyHandler.
   353  	queryMsgs chan lnwire.Message
   354  
   355  	// curQueryRangeMsg keeps track of the latest QueryChannelRange message
   356  	// we've sent to a peer to ensure we've consumed all expected replies.
   357  	// This field is primarily used within the waitingQueryChanReply state.
   358  	curQueryRangeMsg *lnwire.QueryChannelRange
   359  
   360  	// prevReplyChannelRange keeps track of the previous ReplyChannelRange
   361  	// message we've received from a peer to ensure they've fully replied to
   362  	// our query by ensuring they covered our requested block range. This
   363  	// field is primarily used within the waitingQueryChanReply state.
   364  	prevReplyChannelRange *lnwire.ReplyChannelRange
   365  
   366  	// bufferedChanRangeReplies is used in the waitingQueryChanReply to
   367  	// buffer all the chunked response to our query.
   368  	bufferedChanRangeReplies []lnwire.ShortChannelID
   369  
   370  	// numChanRangeRepliesRcvd is used to track the number of replies
   371  	// received as part of a QueryChannelRange. This field is primarily used
   372  	// within the waitingQueryChanReply state.
   373  	numChanRangeRepliesRcvd uint32
   374  
   375  	// newChansToQuery is used to pass the set of channels we should query
   376  	// for from the waitingQueryChanReply state to the queryNewChannels
   377  	// state.
   378  	newChansToQuery []lnwire.ShortChannelID
   379  
   380  	cfg gossipSyncerCfg
   381  
   382  	// rateLimiter dictates the frequency with which we will reply to gossip
   383  	// queries from a peer. This is used to delay responses to peers to
   384  	// prevent DOS vulnerabilities if they are spamming with an unreasonable
   385  	// number of queries.
   386  	rateLimiter *rate.Limiter
   387  
   388  	// syncedSignal is a channel that, if set, will be closed when the
   389  	// GossipSyncer reaches its terminal chansSynced state.
   390  	syncedSignal chan struct{}
   391  
   392  	sync.Mutex
   393  
   394  	quit chan struct{}
   395  	wg   sync.WaitGroup
   396  }
   397  
   398  // newGossipSyncer returns a new instance of the GossipSyncer populated using
   399  // the passed config.
   400  func newGossipSyncer(cfg gossipSyncerCfg) *GossipSyncer {
   401  	// If no parameter was specified for max undelayed query replies, set it
   402  	// to the default of 5 queries.
   403  	if cfg.maxUndelayedQueryReplies <= 0 {
   404  		cfg.maxUndelayedQueryReplies = DefaultMaxUndelayedQueryReplies
   405  	}
   406  
   407  	// If no parameter was specified for delayed query reply interval, set
   408  	// to the default of 5 seconds.
   409  	if cfg.delayedQueryReplyInterval <= 0 {
   410  		cfg.delayedQueryReplyInterval = DefaultDelayedQueryReplyInterval
   411  	}
   412  
   413  	// Construct a rate limiter that will govern how frequently we reply to
   414  	// gossip queries from this peer. The limiter will automatically adjust
   415  	// during periods of quiescence, and increase the reply interval under
   416  	// load.
   417  	interval := rate.Every(cfg.delayedQueryReplyInterval)
   418  	rateLimiter := rate.NewLimiter(
   419  		interval, cfg.maxUndelayedQueryReplies,
   420  	)
   421  
   422  	return &GossipSyncer{
   423  		cfg:                cfg,
   424  		rateLimiter:        rateLimiter,
   425  		syncTransitionReqs: make(chan *syncTransitionReq),
   426  		historicalSyncReqs: make(chan *historicalSyncReq),
   427  		gossipMsgs:         make(chan lnwire.Message, 100),
   428  		queryMsgs:          make(chan lnwire.Message, 100),
   429  		quit:               make(chan struct{}),
   430  	}
   431  }
   432  
   433  // Start starts the GossipSyncer and any goroutines that it needs to carry out
   434  // its duties.
   435  func (g *GossipSyncer) Start() {
   436  	g.started.Do(func() {
   437  		log.Debugf("Starting GossipSyncer(%x)", g.cfg.peerPub[:])
   438  
   439  		// TODO(conner): only spawn channelGraphSyncer if remote
   440  		// supports gossip queries, and only spawn replyHandler if we
   441  		// advertise support
   442  		if !g.cfg.noSyncChannels {
   443  			g.wg.Add(1)
   444  			go g.channelGraphSyncer()
   445  		}
   446  		if !g.cfg.noReplyQueries {
   447  			g.wg.Add(1)
   448  			go g.replyHandler()
   449  		}
   450  	})
   451  }
   452  
   453  // Stop signals the GossipSyncer for a graceful exit, then waits until it has
   454  // exited.
   455  func (g *GossipSyncer) Stop() {
   456  	g.stopped.Do(func() {
   457  		close(g.quit)
   458  		g.wg.Wait()
   459  	})
   460  }
   461  
   462  // channelGraphSyncer is the main goroutine responsible for ensuring that we
   463  // properly channel graph state with the remote peer, and also that we only
   464  // send them messages which actually pass their defined update horizon.
   465  func (g *GossipSyncer) channelGraphSyncer() {
   466  	defer g.wg.Done()
   467  
   468  	for {
   469  		state := g.syncState()
   470  		syncType := g.SyncType()
   471  
   472  		log.Debugf("GossipSyncer(%x): state=%v, type=%v",
   473  			g.cfg.peerPub[:], state, syncType)
   474  
   475  		switch state {
   476  		// When we're in this state, we're trying to synchronize our
   477  		// view of the network with the remote peer. We'll kick off
   478  		// this sync by asking them for the set of channels they
   479  		// understand, as we'll as responding to any other queries by
   480  		// them.
   481  		case syncingChans:
   482  			// If we're in this state, then we'll send the remote
   483  			// peer our opening QueryChannelRange message.
   484  			queryRangeMsg, err := g.genChanRangeQuery(
   485  				g.genHistoricalChanRangeQuery,
   486  			)
   487  			if err != nil {
   488  				log.Errorf("Unable to gen chan range "+
   489  					"query: %v", err)
   490  				return
   491  			}
   492  
   493  			err = g.cfg.sendToPeer(queryRangeMsg)
   494  			if err != nil {
   495  				log.Errorf("Unable to send chan range "+
   496  					"query: %v", err)
   497  				return
   498  			}
   499  
   500  			// With the message sent successfully, we'll transition
   501  			// into the next state where we wait for their reply.
   502  			g.setSyncState(waitingQueryRangeReply)
   503  
   504  		// In this state, we've sent out our initial channel range
   505  		// query and are waiting for the final response from the remote
   506  		// peer before we perform a diff to see with channels they know
   507  		// of that we don't.
   508  		case waitingQueryRangeReply:
   509  			// We'll wait to either process a new message from the
   510  			// remote party, or exit due to the gossiper exiting,
   511  			// or us being signalled to do so.
   512  			select {
   513  			case msg := <-g.gossipMsgs:
   514  				// The remote peer is sending a response to our
   515  				// initial query, we'll collate this response,
   516  				// and see if it's the final one in the series.
   517  				// If so, we can then transition to querying
   518  				// for the new channels.
   519  				queryReply, ok := msg.(*lnwire.ReplyChannelRange)
   520  				if ok {
   521  					err := g.processChanRangeReply(queryReply)
   522  					if err != nil {
   523  						log.Errorf("Unable to "+
   524  							"process chan range "+
   525  							"query: %v", err)
   526  						return
   527  					}
   528  					continue
   529  				}
   530  
   531  				log.Warnf("Unexpected message: %T in state=%v",
   532  					msg, state)
   533  
   534  			case <-g.quit:
   535  				return
   536  			}
   537  
   538  		// We'll enter this state once we've discovered which channels
   539  		// the remote party knows of that we don't yet know of
   540  		// ourselves.
   541  		case queryNewChannels:
   542  			// First, we'll attempt to continue our channel
   543  			// synchronization by continuing to send off another
   544  			// query chunk.
   545  			done, err := g.synchronizeChanIDs()
   546  			if err != nil {
   547  				log.Errorf("Unable to sync chan IDs: %v", err)
   548  			}
   549  
   550  			// If this wasn't our last query, then we'll need to
   551  			// transition to our waiting state.
   552  			if !done {
   553  				g.setSyncState(waitingQueryChanReply)
   554  				continue
   555  			}
   556  
   557  			// If we're fully synchronized, then we can transition
   558  			// to our terminal state.
   559  			g.setSyncState(chansSynced)
   560  
   561  			// Ensure that the sync manager becomes aware that the
   562  			// historical sync completed so synced_to_graph is
   563  			// updated over rpc.
   564  			g.cfg.markGraphSynced()
   565  
   566  		// In this state, we've just sent off a new query for channels
   567  		// that we don't yet know of. We'll remain in this state until
   568  		// the remote party signals they've responded to our query in
   569  		// totality.
   570  		case waitingQueryChanReply:
   571  			// Once we've sent off our query, we'll wait for either
   572  			// an ending reply, or just another query from the
   573  			// remote peer.
   574  			select {
   575  			case msg := <-g.gossipMsgs:
   576  				// If this is the final reply to one of our
   577  				// queries, then we'll loop back into our query
   578  				// state to send of the remaining query chunks.
   579  				_, ok := msg.(*lnwire.ReplyShortChanIDsEnd)
   580  				if ok {
   581  					g.setSyncState(queryNewChannels)
   582  					continue
   583  				}
   584  
   585  				log.Warnf("Unexpected message: %T in state=%v",
   586  					msg, state)
   587  
   588  			case <-g.quit:
   589  				return
   590  			}
   591  
   592  		// This is our final terminal state where we'll only reply to
   593  		// any further queries by the remote peer.
   594  		case chansSynced:
   595  			g.Lock()
   596  			if g.syncedSignal != nil {
   597  				close(g.syncedSignal)
   598  				g.syncedSignal = nil
   599  			}
   600  			g.Unlock()
   601  
   602  			// If we haven't yet sent out our update horizon, and
   603  			// we want to receive real-time channel updates, we'll
   604  			// do so now.
   605  			if g.localUpdateHorizon == nil &&
   606  				syncType.IsActiveSync() {
   607  
   608  				err := g.sendGossipTimestampRange(
   609  					g.initialGossipTimestamp(), math.MaxUint32,
   610  				)
   611  				if err != nil {
   612  					log.Errorf("Unable to send update "+
   613  						"horizon to %x: %v",
   614  						g.cfg.peerPub, err)
   615  				}
   616  			}
   617  			// With our horizon set, we'll simply reply to any new
   618  			// messages or process any state transitions and exit if
   619  			// needed.
   620  			fallthrough
   621  
   622  		// Pinned peers will begin in this state, since they will
   623  		// immediately receive a request to perform a historical sync.
   624  		// Otherwise, we fall through after ending in chansSynced to
   625  		// facilitate new requests.
   626  		case syncerIdle:
   627  			select {
   628  			case req := <-g.syncTransitionReqs:
   629  				req.errChan <- g.handleSyncTransition(req)
   630  
   631  			case req := <-g.historicalSyncReqs:
   632  				g.handleHistoricalSync(req)
   633  
   634  			case <-g.quit:
   635  				return
   636  			}
   637  		}
   638  	}
   639  }
   640  
   641  // replyHandler is an event loop whose sole purpose is to reply to the remote
   642  // peers queries. Our replyHandler will respond to messages generated by their
   643  // channelGraphSyncer, and vice versa. Each party's channelGraphSyncer drives
   644  // the other's replyHandler, allowing the replyHandler to operate independently
   645  // from the state machine maintained on the same node.
   646  //
   647  // NOTE: This method MUST be run as a goroutine.
   648  func (g *GossipSyncer) replyHandler() {
   649  	defer g.wg.Done()
   650  
   651  	for {
   652  		select {
   653  		case msg := <-g.queryMsgs:
   654  			err := g.replyPeerQueries(msg)
   655  			switch {
   656  			case err == ErrGossipSyncerExiting:
   657  				return
   658  
   659  			case err == lnpeer.ErrPeerExiting:
   660  				return
   661  
   662  			case err != nil:
   663  				log.Errorf("Unable to reply to peer "+
   664  					"query: %v", err)
   665  			}
   666  
   667  		case <-g.quit:
   668  			return
   669  		}
   670  	}
   671  }
   672  
   673  // sendGossipTimestampRange constructs and sets a GossipTimestampRange for the
   674  // syncer and sends it to the remote peer.
   675  func (g *GossipSyncer) sendGossipTimestampRange(firstTimestamp time.Time,
   676  	timestampRange uint32) error {
   677  
   678  	endTimestamp := firstTimestamp.Add(
   679  		time.Duration(timestampRange) * time.Second,
   680  	)
   681  
   682  	log.Infof("GossipSyncer(%x): applying gossipFilter(start=%v, end=%v)",
   683  		g.cfg.peerPub[:], firstTimestamp, endTimestamp)
   684  
   685  	localUpdateHorizon := &lnwire.GossipTimestampRange{
   686  		ChainHash:      g.cfg.chainHash,
   687  		FirstTimestamp: uint32(firstTimestamp.Unix()),
   688  		TimestampRange: timestampRange,
   689  	}
   690  
   691  	if err := g.cfg.sendToPeer(localUpdateHorizon); err != nil {
   692  		return err
   693  	}
   694  
   695  	if firstTimestamp == zeroTimestamp && timestampRange == 0 {
   696  		g.localUpdateHorizon = nil
   697  	} else {
   698  		g.localUpdateHorizon = localUpdateHorizon
   699  	}
   700  
   701  	return nil
   702  }
   703  
   704  // synchronizeChanIDs is called by the channelGraphSyncer when we need to query
   705  // the remote peer for its known set of channel IDs within a particular block
   706  // range. This method will be called continually until the entire range has
   707  // been queried for with a response received. We'll chunk our requests as
   708  // required to ensure they fit into a single message. We may re-renter this
   709  // state in the case that chunking is required.
   710  func (g *GossipSyncer) synchronizeChanIDs() (bool, error) {
   711  	// If we're in this state yet there are no more new channels to query
   712  	// for, then we'll transition to our final synced state and return true
   713  	// to signal that we're fully synchronized.
   714  	if len(g.newChansToQuery) == 0 {
   715  		log.Infof("GossipSyncer(%x): no more chans to query",
   716  			g.cfg.peerPub[:])
   717  		return true, nil
   718  	}
   719  
   720  	// Otherwise, we'll issue our next chunked query to receive replies
   721  	// for.
   722  	var queryChunk []lnwire.ShortChannelID
   723  
   724  	// If the number of channels to query for is less than the chunk size,
   725  	// then we can issue a single query.
   726  	if int32(len(g.newChansToQuery)) < g.cfg.batchSize {
   727  		queryChunk = g.newChansToQuery
   728  		g.newChansToQuery = nil
   729  
   730  	} else {
   731  		// Otherwise, we'll need to only query for the next chunk.
   732  		// We'll slice into our query chunk, then slide down our main
   733  		// pointer down by the chunk size.
   734  		queryChunk = g.newChansToQuery[:g.cfg.batchSize]
   735  		g.newChansToQuery = g.newChansToQuery[g.cfg.batchSize:]
   736  	}
   737  
   738  	log.Infof("GossipSyncer(%x): querying for %v new channels",
   739  		g.cfg.peerPub[:], len(queryChunk))
   740  
   741  	// With our chunk obtained, we'll send over our next query, then return
   742  	// false indicating that we're net yet fully synced.
   743  	err := g.cfg.sendToPeer(&lnwire.QueryShortChanIDs{
   744  		ChainHash:    g.cfg.chainHash,
   745  		EncodingType: lnwire.EncodingSortedPlain,
   746  		ShortChanIDs: queryChunk,
   747  	})
   748  
   749  	return false, err
   750  }
   751  
   752  // isLegacyReplyChannelRange determines where a ReplyChannelRange message is
   753  // considered legacy. There was a point where lnd used to include the same query
   754  // over multiple replies, rather than including the portion of the query the
   755  // reply is handling. We'll use this as a way of detecting whether we are
   756  // communicating with a legacy node so we can properly sync with them.
   757  func isLegacyReplyChannelRange(query *lnwire.QueryChannelRange,
   758  	reply *lnwire.ReplyChannelRange) bool {
   759  
   760  	return (reply.ChainHash == query.ChainHash &&
   761  		reply.FirstBlockHeight == query.FirstBlockHeight &&
   762  		reply.NumBlocks == query.NumBlocks)
   763  }
   764  
   765  // processChanRangeReply is called each time the GossipSyncer receives a new
   766  // reply to the initial range query to discover new channels that it didn't
   767  // previously know of.
   768  func (g *GossipSyncer) processChanRangeReply(msg *lnwire.ReplyChannelRange) error {
   769  	// If we're not communicating with a legacy node, we'll apply some
   770  	// further constraints on their reply to ensure it satisfies our query.
   771  	if !isLegacyReplyChannelRange(g.curQueryRangeMsg, msg) {
   772  		// The first block should be within our original request.
   773  		if msg.FirstBlockHeight < g.curQueryRangeMsg.FirstBlockHeight {
   774  			return fmt.Errorf("reply includes channels for height "+
   775  				"%v prior to query %v", msg.FirstBlockHeight,
   776  				g.curQueryRangeMsg.FirstBlockHeight)
   777  		}
   778  
   779  		// The last block should also be. We don't need to check the
   780  		// intermediate ones because they should already be in sorted
   781  		// order.
   782  		replyLastHeight := msg.LastBlockHeight()
   783  		queryLastHeight := g.curQueryRangeMsg.LastBlockHeight()
   784  		if replyLastHeight > queryLastHeight {
   785  			return fmt.Errorf("reply includes channels for height "+
   786  				"%v after query %v", replyLastHeight,
   787  				queryLastHeight)
   788  		}
   789  
   790  		// If we've previously received a reply for this query, look at
   791  		// its last block to ensure the current reply properly follows
   792  		// it.
   793  		if g.prevReplyChannelRange != nil {
   794  			prevReply := g.prevReplyChannelRange
   795  			prevReplyLastHeight := prevReply.LastBlockHeight()
   796  
   797  			// The current reply can either start from the previous
   798  			// reply's last block, if there are still more channels
   799  			// for the same block, or the block after.
   800  			if msg.FirstBlockHeight != prevReplyLastHeight &&
   801  				msg.FirstBlockHeight != prevReplyLastHeight+1 {
   802  
   803  				return fmt.Errorf("first block of reply %v "+
   804  					"does not continue from last block of "+
   805  					"previous %v", msg.FirstBlockHeight,
   806  					prevReplyLastHeight)
   807  			}
   808  		}
   809  	}
   810  
   811  	g.prevReplyChannelRange = msg
   812  	g.bufferedChanRangeReplies = append(
   813  		g.bufferedChanRangeReplies, msg.ShortChanIDs...,
   814  	)
   815  	switch g.cfg.encodingType {
   816  	case lnwire.EncodingSortedPlain:
   817  		g.numChanRangeRepliesRcvd++
   818  	case lnwire.EncodingSortedZlib:
   819  		g.numChanRangeRepliesRcvd += maxQueryChanRangeRepliesZlibFactor
   820  	default:
   821  		return fmt.Errorf("unhandled encoding type %v", g.cfg.encodingType)
   822  	}
   823  
   824  	log.Infof("GossipSyncer(%x): buffering chan range reply of size=%v",
   825  		g.cfg.peerPub[:], len(msg.ShortChanIDs))
   826  
   827  	// If this isn't the last response and we can continue to receive more,
   828  	// then we can exit as we've already buffered the latest portion of the
   829  	// streaming reply.
   830  	maxReplies := g.cfg.maxQueryChanRangeReplies
   831  	switch {
   832  	// If we're communicating with a legacy node, we'll need to look at the
   833  	// complete field.
   834  	case isLegacyReplyChannelRange(g.curQueryRangeMsg, msg):
   835  		if msg.Complete == 0 && g.numChanRangeRepliesRcvd < maxReplies {
   836  			return nil
   837  		}
   838  
   839  	// Otherwise, we'll look at the reply's height range.
   840  	default:
   841  		replyLastHeight := msg.LastBlockHeight()
   842  		queryLastHeight := g.curQueryRangeMsg.LastBlockHeight()
   843  
   844  		// TODO(wilmer): This might require some padding if the remote
   845  		// node is not aware of the last height we sent them, i.e., is
   846  		// behind a few blocks from us.
   847  		if replyLastHeight < queryLastHeight &&
   848  			g.numChanRangeRepliesRcvd < maxReplies {
   849  			return nil
   850  		}
   851  	}
   852  
   853  	log.Infof("GossipSyncer(%x): filtering through %v chans",
   854  		g.cfg.peerPub[:], len(g.bufferedChanRangeReplies))
   855  
   856  	// Otherwise, this is the final response, so we'll now check to see
   857  	// which channels they know of that we don't.
   858  	newChans, err := g.cfg.channelSeries.FilterKnownChanIDs(
   859  		g.cfg.chainHash, g.bufferedChanRangeReplies,
   860  	)
   861  	if err != nil {
   862  		return fmt.Errorf("unable to filter chan ids: %v", err)
   863  	}
   864  
   865  	// As we've received the entirety of the reply, we no longer need to
   866  	// hold on to the set of buffered replies or the original query that
   867  	// prompted the replies, so we'll let that be garbage collected now.
   868  	g.curQueryRangeMsg = nil
   869  	g.prevReplyChannelRange = nil
   870  	g.bufferedChanRangeReplies = nil
   871  	g.numChanRangeRepliesRcvd = 0
   872  
   873  	// If there aren't any channels that we don't know of, then we can
   874  	// switch straight to our terminal state.
   875  	if len(newChans) == 0 {
   876  		log.Infof("GossipSyncer(%x): remote peer has no new chans",
   877  			g.cfg.peerPub[:])
   878  
   879  		g.setSyncState(chansSynced)
   880  
   881  		// Ensure that the sync manager becomes aware that the
   882  		// historical sync completed so synced_to_graph is updated over
   883  		// rpc.
   884  		g.cfg.markGraphSynced()
   885  		return nil
   886  	}
   887  
   888  	// Otherwise, we'll set the set of channels that we need to query for
   889  	// the next state, and also transition our state.
   890  	g.newChansToQuery = newChans
   891  	g.setSyncState(queryNewChannels)
   892  
   893  	log.Infof("GossipSyncer(%x): starting query for %v new chans",
   894  		g.cfg.peerPub[:], len(newChans))
   895  
   896  	return nil
   897  }
   898  
   899  // genChanRangeQuery generates the initial message we'll send to the remote
   900  // party when we're kicking off the channel graph synchronization upon
   901  // connection. The historicalQuery boolean can be used to generate a query from
   902  // the genesis block of the chain.
   903  func (g *GossipSyncer) genChanRangeQuery(
   904  	historicalQuery bool) (*lnwire.QueryChannelRange, error) {
   905  
   906  	// First, we'll query our channel graph time series for its highest
   907  	// known channel ID.
   908  	newestChan, err := g.cfg.channelSeries.HighestChanID(g.cfg.chainHash)
   909  	if err != nil {
   910  		return nil, err
   911  	}
   912  
   913  	// Once we have the chan ID of the newest, we'll obtain the block height
   914  	// of the channel, then subtract our default horizon to ensure we don't
   915  	// miss any channels. By default, we go back 1 day from the newest
   916  	// channel, unless we're attempting a historical sync, where we'll
   917  	// actually start from the genesis block instead.
   918  	var startHeight uint32
   919  	switch {
   920  	case historicalQuery:
   921  		fallthrough
   922  	case newestChan.BlockHeight <= chanRangeQueryBuffer:
   923  		startHeight = 0
   924  	default:
   925  		startHeight = newestChan.BlockHeight - chanRangeQueryBuffer
   926  	}
   927  
   928  	// Determine the number of blocks to request based on our best height.
   929  	// We'll take into account any potential underflows and explicitly set
   930  	// numBlocks to its minimum value of 1 if so.
   931  	bestHeight := g.cfg.bestHeight()
   932  	numBlocks := bestHeight - startHeight
   933  	if int64(numBlocks) < 1 {
   934  		numBlocks = 1
   935  	}
   936  
   937  	log.Infof("GossipSyncer(%x): requesting new chans from height=%v "+
   938  		"and %v blocks after", g.cfg.peerPub[:], startHeight, numBlocks)
   939  
   940  	// Finally, we'll craft the channel range query, using our starting
   941  	// height, then asking for all known channels to the foreseeable end of
   942  	// the main chain.
   943  	query := &lnwire.QueryChannelRange{
   944  		ChainHash:        g.cfg.chainHash,
   945  		FirstBlockHeight: startHeight,
   946  		NumBlocks:        numBlocks,
   947  	}
   948  	g.curQueryRangeMsg = query
   949  
   950  	return query, nil
   951  }
   952  
   953  // replyPeerQueries is called in response to any query by the remote peer.
   954  // We'll examine our state and send back our best response.
   955  func (g *GossipSyncer) replyPeerQueries(msg lnwire.Message) error {
   956  	reservation := g.rateLimiter.Reserve()
   957  	delay := reservation.Delay()
   958  
   959  	// If we've already replied a handful of times, we will start to delay
   960  	// responses back to the remote peer. This can help prevent DOS attacks
   961  	// where the remote peer spams us endlessly.
   962  	if delay > 0 {
   963  		log.Infof("GossipSyncer(%x): rate limiting gossip replies, "+
   964  			"responding in %s", g.cfg.peerPub[:], delay)
   965  
   966  		select {
   967  		case <-time.After(delay):
   968  		case <-g.quit:
   969  			return ErrGossipSyncerExiting
   970  		}
   971  	}
   972  
   973  	switch msg := msg.(type) {
   974  
   975  	// In this state, we'll also handle any incoming channel range queries
   976  	// from the remote peer as they're trying to sync their state as well.
   977  	case *lnwire.QueryChannelRange:
   978  		return g.replyChanRangeQuery(msg)
   979  
   980  	// If the remote peer skips straight to requesting new channels that
   981  	// they don't know of, then we'll ensure that we also handle this case.
   982  	case *lnwire.QueryShortChanIDs:
   983  		return g.replyShortChanIDs(msg)
   984  
   985  	default:
   986  		return fmt.Errorf("unknown message: %T", msg)
   987  	}
   988  }
   989  
   990  // replyChanRangeQuery will be dispatched in response to a channel range query
   991  // by the remote node. We'll query the channel time series for channels that
   992  // meet the channel range, then chunk our responses to the remote node. We also
   993  // ensure that our final fragment carries the "complete" bit to indicate the
   994  // end of our streaming response.
   995  func (g *GossipSyncer) replyChanRangeQuery(query *lnwire.QueryChannelRange) error {
   996  	// Before responding, we'll check to ensure that the remote peer is
   997  	// querying for the same chain that we're on. If not, we'll send back a
   998  	// response with a complete value of zero to indicate we're on a
   999  	// different chain.
  1000  	if g.cfg.chainHash != query.ChainHash {
  1001  		log.Warnf("Remote peer requested QueryChannelRange for "+
  1002  			"chain=%v, we're on chain=%v", query.ChainHash,
  1003  			g.cfg.chainHash)
  1004  
  1005  		return g.cfg.sendToPeerSync(&lnwire.ReplyChannelRange{
  1006  			ChainHash:        query.ChainHash,
  1007  			FirstBlockHeight: query.FirstBlockHeight,
  1008  			NumBlocks:        query.NumBlocks,
  1009  			Complete:         0,
  1010  			EncodingType:     g.cfg.encodingType,
  1011  			ShortChanIDs:     nil,
  1012  		})
  1013  	}
  1014  
  1015  	log.Infof("GossipSyncer(%x): filtering chan range: start_height=%v, "+
  1016  		"num_blocks=%v", g.cfg.peerPub[:], query.FirstBlockHeight,
  1017  		query.NumBlocks)
  1018  
  1019  	// Next, we'll consult the time series to obtain the set of known
  1020  	// channel ID's that match their query.
  1021  	startBlock := query.FirstBlockHeight
  1022  	endBlock := query.LastBlockHeight()
  1023  	channelRanges, err := g.cfg.channelSeries.FilterChannelRange(
  1024  		query.ChainHash, startBlock, endBlock,
  1025  	)
  1026  	if err != nil {
  1027  		return err
  1028  	}
  1029  
  1030  	// TODO(roasbeef): means can't send max uint above?
  1031  	//  * or make internal 64
  1032  
  1033  	// We'll send our response in a streaming manner, chunk-by-chunk. We do
  1034  	// this as there's a transport message size limit which we'll need to
  1035  	// adhere to. We also need to make sure all of our replies cover the
  1036  	// expected range of the query.
  1037  	sendReplyForChunk := func(channelChunk []lnwire.ShortChannelID,
  1038  		firstHeight, lastHeight uint32, finalChunk bool) error {
  1039  
  1040  		// The number of blocks contained in the current chunk (the
  1041  		// total span) is the difference between the last channel ID and
  1042  		// the first in the range. We add one as even if all channels
  1043  		// returned are in the same block, we need to count that.
  1044  		numBlocks := lastHeight - firstHeight + 1
  1045  		complete := uint8(0)
  1046  		if finalChunk {
  1047  			complete = 1
  1048  		}
  1049  
  1050  		return g.cfg.sendToPeerSync(&lnwire.ReplyChannelRange{
  1051  			ChainHash:        query.ChainHash,
  1052  			NumBlocks:        numBlocks,
  1053  			FirstBlockHeight: firstHeight,
  1054  			Complete:         complete,
  1055  			EncodingType:     g.cfg.encodingType,
  1056  			ShortChanIDs:     channelChunk,
  1057  		})
  1058  	}
  1059  
  1060  	var (
  1061  		firstHeight  = query.FirstBlockHeight
  1062  		lastHeight   uint32
  1063  		channelChunk []lnwire.ShortChannelID
  1064  	)
  1065  	for _, channelRange := range channelRanges {
  1066  		channels := channelRange.Channels
  1067  		numChannels := int32(len(channels))
  1068  		numLeftToAdd := g.cfg.chunkSize - int32(len(channelChunk))
  1069  
  1070  		// Include the current block in the ongoing chunk if it can fit
  1071  		// and move on to the next block.
  1072  		if numChannels <= numLeftToAdd {
  1073  			channelChunk = append(channelChunk, channels...)
  1074  			continue
  1075  		}
  1076  
  1077  		// Otherwise, we need to send our existing channel chunk as is
  1078  		// as its own reply and start a new one for the current block.
  1079  		// We'll mark the end of our current chunk as the height before
  1080  		// the current block to ensure the whole query range is replied
  1081  		// to.
  1082  		log.Infof("GossipSyncer(%x): sending range chunk of size=%v",
  1083  			g.cfg.peerPub[:], len(channelChunk))
  1084  		lastHeight = channelRange.Height - 1
  1085  		err := sendReplyForChunk(
  1086  			channelChunk, firstHeight, lastHeight, false,
  1087  		)
  1088  		if err != nil {
  1089  			return err
  1090  		}
  1091  
  1092  		// With the reply constructed, we'll start tallying channels for
  1093  		// our next one keeping in mind our chunk size. This may result
  1094  		// in channels for this block being left out from the reply, but
  1095  		// this isn't an issue since we'll randomly shuffle them and we
  1096  		// assume a historical gossip sync is performed at a later time.
  1097  		firstHeight = channelRange.Height
  1098  		chunkSize := numChannels
  1099  		exceedsChunkSize := numChannels > g.cfg.chunkSize
  1100  		if exceedsChunkSize {
  1101  			rand.Shuffle(len(channels), func(i, j int) {
  1102  				channels[i], channels[j] = channels[j], channels[i]
  1103  			})
  1104  			chunkSize = g.cfg.chunkSize
  1105  		}
  1106  		channelChunk = channels[:chunkSize]
  1107  
  1108  		// Sort the chunk once again if we had to shuffle it.
  1109  		if exceedsChunkSize {
  1110  			sort.Slice(channelChunk, func(i, j int) bool {
  1111  				return channelChunk[i].ToUint64() <
  1112  					channelChunk[j].ToUint64()
  1113  			})
  1114  		}
  1115  	}
  1116  
  1117  	// Send the remaining chunk as the final reply.
  1118  	log.Infof("GossipSyncer(%x): sending final chan range chunk, size=%v",
  1119  		g.cfg.peerPub[:], len(channelChunk))
  1120  	return sendReplyForChunk(
  1121  		channelChunk, firstHeight, query.LastBlockHeight(), true,
  1122  	)
  1123  }
  1124  
  1125  // replyShortChanIDs will be dispatched in response to a query by the remote
  1126  // node for information concerning a set of short channel ID's. Our response
  1127  // will be sent in a streaming chunked manner to ensure that we remain below
  1128  // the current transport level message size.
  1129  func (g *GossipSyncer) replyShortChanIDs(query *lnwire.QueryShortChanIDs) error {
  1130  	// Before responding, we'll check to ensure that the remote peer is
  1131  	// querying for the same chain that we're on. If not, we'll send back a
  1132  	// response with a complete value of zero to indicate we're on a
  1133  	// different chain.
  1134  	if g.cfg.chainHash != query.ChainHash {
  1135  		log.Warnf("Remote peer requested QueryShortChanIDs for "+
  1136  			"chain=%v, we're on chain=%v", query.ChainHash,
  1137  			g.cfg.chainHash)
  1138  
  1139  		return g.cfg.sendToPeerSync(&lnwire.ReplyShortChanIDsEnd{
  1140  			ChainHash: query.ChainHash,
  1141  			Complete:  0,
  1142  		})
  1143  	}
  1144  
  1145  	if len(query.ShortChanIDs) == 0 {
  1146  		log.Infof("GossipSyncer(%x): ignoring query for blank short chan ID's",
  1147  			g.cfg.peerPub[:])
  1148  		return nil
  1149  	}
  1150  
  1151  	log.Infof("GossipSyncer(%x): fetching chan anns for %v chans",
  1152  		g.cfg.peerPub[:], len(query.ShortChanIDs))
  1153  
  1154  	// Now that we know we're on the same chain, we'll query the channel
  1155  	// time series for the set of messages that we know of which satisfies
  1156  	// the requirement of being a chan ann, chan update, or a node ann
  1157  	// related to the set of queried channels.
  1158  	replyMsgs, err := g.cfg.channelSeries.FetchChanAnns(
  1159  		query.ChainHash, query.ShortChanIDs,
  1160  	)
  1161  	if err != nil {
  1162  		return fmt.Errorf("unable to fetch chan anns for %v..., %v",
  1163  			query.ShortChanIDs[0].ToUint64(), err)
  1164  	}
  1165  
  1166  	// Reply with any messages related to those channel ID's, we'll write
  1167  	// each one individually and synchronously to throttle the sends and
  1168  	// perform buffering of responses in the syncer as opposed to the peer.
  1169  	for _, msg := range replyMsgs {
  1170  		err := g.cfg.sendToPeerSync(msg)
  1171  		if err != nil {
  1172  			return err
  1173  		}
  1174  	}
  1175  
  1176  	// Regardless of whether we had any messages to reply with, send over
  1177  	// the sentinel message to signal that the stream has terminated.
  1178  	return g.cfg.sendToPeerSync(&lnwire.ReplyShortChanIDsEnd{
  1179  		ChainHash: query.ChainHash,
  1180  		Complete:  1,
  1181  	})
  1182  }
  1183  
  1184  // ApplyGossipFilter applies a gossiper filter sent by the remote node to the
  1185  // state machine. Once applied, we'll ensure that we don't forward any messages
  1186  // to the peer that aren't within the time range of the filter.
  1187  func (g *GossipSyncer) ApplyGossipFilter(filter *lnwire.GossipTimestampRange) error {
  1188  	g.Lock()
  1189  
  1190  	g.remoteUpdateHorizon = filter
  1191  
  1192  	startTime := time.Unix(int64(g.remoteUpdateHorizon.FirstTimestamp), 0)
  1193  	endTime := startTime.Add(
  1194  		time.Duration(g.remoteUpdateHorizon.TimestampRange) * time.Second,
  1195  	)
  1196  
  1197  	g.Unlock()
  1198  
  1199  	// If requested, don't reply with historical gossip data when the remote
  1200  	// peer sets their gossip timestamp range.
  1201  	if g.cfg.ignoreHistoricalFilters {
  1202  		return nil
  1203  	}
  1204  
  1205  	// Now that the remote peer has applied their filter, we'll query the
  1206  	// database for all the messages that are beyond this filter.
  1207  	newUpdatestoSend, err := g.cfg.channelSeries.UpdatesInHorizon(
  1208  		g.cfg.chainHash, startTime, endTime,
  1209  	)
  1210  	if err != nil {
  1211  		return err
  1212  	}
  1213  
  1214  	log.Infof("GossipSyncer(%x): applying new update horizon: start=%v, "+
  1215  		"end=%v, backlog_size=%v", g.cfg.peerPub[:], startTime, endTime,
  1216  		len(newUpdatestoSend))
  1217  
  1218  	// If we don't have any to send, then we can return early.
  1219  	if len(newUpdatestoSend) == 0 {
  1220  		return nil
  1221  	}
  1222  
  1223  	// We'll conclude by launching a goroutine to send out any updates.
  1224  	g.wg.Add(1)
  1225  	go func() {
  1226  		defer g.wg.Done()
  1227  
  1228  		for _, msg := range newUpdatestoSend {
  1229  			err := g.cfg.sendToPeerSync(msg)
  1230  			switch {
  1231  			case err == ErrGossipSyncerExiting:
  1232  				return
  1233  
  1234  			case err == lnpeer.ErrPeerExiting:
  1235  				return
  1236  
  1237  			case err != nil:
  1238  				log.Errorf("Unable to send message for "+
  1239  					"peer catch up: %v", err)
  1240  			}
  1241  		}
  1242  	}()
  1243  
  1244  	return nil
  1245  }
  1246  
  1247  // FilterGossipMsgs takes a set of gossip messages, and only send it to a peer
  1248  // iff the message is within the bounds of their set gossip filter. If the peer
  1249  // doesn't have a gossip filter set, then no messages will be forwarded.
  1250  func (g *GossipSyncer) FilterGossipMsgs(msgs ...msgWithSenders) {
  1251  	// If the peer doesn't have an update horizon set, then we won't send
  1252  	// it any new update messages.
  1253  	if g.remoteUpdateHorizon == nil {
  1254  		log.Tracef("GossipSyncer(%x): filtering due to no remoteUpdateHorizon",
  1255  			g.cfg.peerPub[:])
  1256  		return
  1257  	}
  1258  
  1259  	// If we've been signaled to exit, or are exiting, then we'll stop
  1260  	// short.
  1261  	select {
  1262  	case <-g.quit:
  1263  		return
  1264  	default:
  1265  	}
  1266  
  1267  	// TODO(roasbeef): need to ensure that peer still online...send msg to
  1268  	// gossiper on peer termination to signal peer disconnect?
  1269  
  1270  	var err error
  1271  
  1272  	// Before we filter out the messages, we'll construct an index over the
  1273  	// set of channel announcements and channel updates. This will allow us
  1274  	// to quickly check if we should forward a chan ann, based on the known
  1275  	// channel updates for a channel.
  1276  	chanUpdateIndex := make(map[lnwire.ShortChannelID][]*lnwire.ChannelUpdate)
  1277  	for _, msg := range msgs {
  1278  		chanUpdate, ok := msg.msg.(*lnwire.ChannelUpdate)
  1279  		if !ok {
  1280  			continue
  1281  		}
  1282  
  1283  		chanUpdateIndex[chanUpdate.ShortChannelID] = append(
  1284  			chanUpdateIndex[chanUpdate.ShortChannelID], chanUpdate,
  1285  		)
  1286  	}
  1287  
  1288  	// We'll construct a helper function that we'll us below to determine
  1289  	// if a given messages passes the gossip msg filter.
  1290  	g.Lock()
  1291  	startTime := time.Unix(int64(g.remoteUpdateHorizon.FirstTimestamp), 0)
  1292  	endTime := startTime.Add(
  1293  		time.Duration(g.remoteUpdateHorizon.TimestampRange) * time.Second,
  1294  	)
  1295  	g.Unlock()
  1296  
  1297  	passesFilter := func(timeStamp uint32) bool {
  1298  		t := time.Unix(int64(timeStamp), 0)
  1299  		return t.Equal(startTime) ||
  1300  			(t.After(startTime) && t.Before(endTime))
  1301  	}
  1302  
  1303  	msgsToSend := make([]lnwire.Message, 0, len(msgs))
  1304  	for _, msg := range msgs {
  1305  		// If the target peer is the peer that sent us this message,
  1306  		// then we'll exit early as we don't need to filter this
  1307  		// message.
  1308  		if _, ok := msg.senders[g.cfg.peerPub]; ok {
  1309  			continue
  1310  		}
  1311  
  1312  		switch msg := msg.msg.(type) {
  1313  
  1314  		// For each channel announcement message, we'll only send this
  1315  		// message if the channel updates for the channel are between
  1316  		// our time range.
  1317  		case *lnwire.ChannelAnnouncement:
  1318  			// First, we'll check if the channel updates are in
  1319  			// this message batch.
  1320  			chanUpdates, ok := chanUpdateIndex[msg.ShortChannelID]
  1321  			if !ok {
  1322  				// If not, we'll attempt to query the database
  1323  				// to see if we know of the updates.
  1324  				chanUpdates, err = g.cfg.channelSeries.FetchChanUpdates(
  1325  					g.cfg.chainHash, msg.ShortChannelID,
  1326  				)
  1327  				if err != nil {
  1328  					log.Warnf("no channel updates found for "+
  1329  						"short_chan_id=%s",
  1330  						msg.ShortChannelID)
  1331  					continue
  1332  				}
  1333  			}
  1334  
  1335  			for _, chanUpdate := range chanUpdates {
  1336  				if passesFilter(chanUpdate.Timestamp) {
  1337  					msgsToSend = append(msgsToSend, msg)
  1338  					break
  1339  				}
  1340  			}
  1341  
  1342  			if len(chanUpdates) == 0 {
  1343  				msgsToSend = append(msgsToSend, msg)
  1344  			}
  1345  
  1346  		// For each channel update, we'll only send if it the timestamp
  1347  		// is between our time range.
  1348  		case *lnwire.ChannelUpdate:
  1349  			if passesFilter(msg.Timestamp) {
  1350  				msgsToSend = append(msgsToSend, msg)
  1351  			} else {
  1352  				ts := time.Unix(int64(msg.Timestamp), 0)
  1353  				log.Tracef("GossipSyncer(%x): ChannelUpdate does "+
  1354  					"not pass filter chan=%s ts=%s hz_start=%s "+
  1355  					"hz_end=%s", g.cfg.peerPub[:],
  1356  					msg.ShortChannelID, ts.Format(time.RFC3339),
  1357  					startTime.Format(time.RFC3339),
  1358  					endTime.Format(time.RFC3339))
  1359  			}
  1360  
  1361  		// Similarly, we only send node announcements if the update
  1362  		// timestamp ifs between our set gossip filter time range.
  1363  		case *lnwire.NodeAnnouncement:
  1364  			if passesFilter(msg.Timestamp) {
  1365  				msgsToSend = append(msgsToSend, msg)
  1366  			}
  1367  		}
  1368  	}
  1369  
  1370  	log.Tracef("GossipSyncer(%x): filtered gossip msgs: set=%v, sent=%v",
  1371  		g.cfg.peerPub[:], len(msgs), len(msgsToSend))
  1372  
  1373  	if len(msgsToSend) == 0 {
  1374  		return
  1375  	}
  1376  
  1377  	g.cfg.sendToPeer(msgsToSend...)
  1378  }
  1379  
  1380  // ProcessQueryMsg is used by outside callers to pass new channel time series
  1381  // queries to the internal processing goroutine.
  1382  func (g *GossipSyncer) ProcessQueryMsg(msg lnwire.Message, peerQuit <-chan struct{}) error {
  1383  	var msgChan chan lnwire.Message
  1384  	switch msg.(type) {
  1385  	case *lnwire.QueryChannelRange, *lnwire.QueryShortChanIDs:
  1386  		msgChan = g.queryMsgs
  1387  
  1388  	// Reply messages should only be expected in states where we're waiting
  1389  	// for a reply.
  1390  	case *lnwire.ReplyChannelRange, *lnwire.ReplyShortChanIDsEnd:
  1391  		syncState := g.syncState()
  1392  		if syncState != waitingQueryRangeReply &&
  1393  			syncState != waitingQueryChanReply {
  1394  			return fmt.Errorf("received unexpected query reply "+
  1395  				"message %T", msg)
  1396  		}
  1397  		msgChan = g.gossipMsgs
  1398  
  1399  	default:
  1400  		msgChan = g.gossipMsgs
  1401  	}
  1402  
  1403  	select {
  1404  	case msgChan <- msg:
  1405  	case <-peerQuit:
  1406  	case <-g.quit:
  1407  	}
  1408  
  1409  	return nil
  1410  }
  1411  
  1412  // setSyncState sets the gossip syncer's state to the given state.
  1413  func (g *GossipSyncer) setSyncState(state syncerState) {
  1414  	atomic.StoreUint32(&g.state, uint32(state))
  1415  }
  1416  
  1417  // syncState returns the current syncerState of the target GossipSyncer.
  1418  func (g *GossipSyncer) syncState() syncerState {
  1419  	return syncerState(atomic.LoadUint32(&g.state))
  1420  }
  1421  
  1422  // ResetSyncedSignal returns a channel that will be closed in order to serve as
  1423  // a signal for when the GossipSyncer has reached its chansSynced state.
  1424  func (g *GossipSyncer) ResetSyncedSignal() chan struct{} {
  1425  	g.Lock()
  1426  	defer g.Unlock()
  1427  
  1428  	syncedSignal := make(chan struct{})
  1429  
  1430  	syncState := syncerState(atomic.LoadUint32(&g.state))
  1431  	if syncState == chansSynced {
  1432  		close(syncedSignal)
  1433  		return syncedSignal
  1434  	}
  1435  
  1436  	g.syncedSignal = syncedSignal
  1437  	return g.syncedSignal
  1438  }
  1439  
  1440  // ProcessSyncTransition sends a request to the gossip syncer to transition its
  1441  // sync type to a new one.
  1442  //
  1443  // NOTE: This can only be done once the gossip syncer has reached its final
  1444  // chansSynced state.
  1445  func (g *GossipSyncer) ProcessSyncTransition(newSyncType SyncerType) error {
  1446  	errChan := make(chan error, 1)
  1447  	select {
  1448  	case g.syncTransitionReqs <- &syncTransitionReq{
  1449  		newSyncType: newSyncType,
  1450  		errChan:     errChan,
  1451  	}:
  1452  	case <-time.After(syncTransitionTimeout):
  1453  		return ErrSyncTransitionTimeout
  1454  	case <-g.quit:
  1455  		return ErrGossipSyncerExiting
  1456  	}
  1457  
  1458  	select {
  1459  	case err := <-errChan:
  1460  		return err
  1461  	case <-g.quit:
  1462  		return ErrGossipSyncerExiting
  1463  	}
  1464  }
  1465  
  1466  // handleSyncTransition handles a new sync type transition request.
  1467  //
  1468  // NOTE: The gossip syncer might have another sync state as a result of this
  1469  // transition.
  1470  func (g *GossipSyncer) handleSyncTransition(req *syncTransitionReq) error {
  1471  	// Return early from any NOP sync transitions.
  1472  	syncType := g.SyncType()
  1473  	if syncType == req.newSyncType {
  1474  		return nil
  1475  	}
  1476  
  1477  	log.Debugf("GossipSyncer(%x): transitioning from %v to %v",
  1478  		g.cfg.peerPub, syncType, req.newSyncType)
  1479  
  1480  	var (
  1481  		firstTimestamp time.Time
  1482  		timestampRange uint32
  1483  	)
  1484  
  1485  	switch req.newSyncType {
  1486  	// If an active sync has been requested, then we should resume receiving
  1487  	// new graph updates from the remote peer.
  1488  	case ActiveSync, PinnedSync:
  1489  		firstTimestamp = g.initialGossipTimestamp()
  1490  		timestampRange = math.MaxUint32
  1491  
  1492  	// If a PassiveSync transition has been requested, then we should no
  1493  	// longer receive any new updates from the remote peer. We can do this
  1494  	// by setting our update horizon to a range in the past ensuring no
  1495  	// graph updates match the timestamp range.
  1496  	case PassiveSync:
  1497  		firstTimestamp = zeroTimestamp
  1498  		timestampRange = 0
  1499  
  1500  	default:
  1501  		return fmt.Errorf("unhandled sync transition %v",
  1502  			req.newSyncType)
  1503  	}
  1504  
  1505  	err := g.sendGossipTimestampRange(firstTimestamp, timestampRange)
  1506  	if err != nil {
  1507  		return fmt.Errorf("unable to send local update horizon: %v", err)
  1508  	}
  1509  
  1510  	g.setSyncType(req.newSyncType)
  1511  
  1512  	return nil
  1513  }
  1514  
  1515  // setSyncType sets the gossip syncer's sync type to the given type.
  1516  func (g *GossipSyncer) setSyncType(syncType SyncerType) {
  1517  	atomic.StoreUint32(&g.syncType, uint32(syncType))
  1518  }
  1519  
  1520  // SyncType returns the current SyncerType of the target GossipSyncer.
  1521  func (g *GossipSyncer) SyncType() SyncerType {
  1522  	return SyncerType(atomic.LoadUint32(&g.syncType))
  1523  }
  1524  
  1525  // historicalSync sends a request to the gossip syncer to perofmr a historical
  1526  // sync.
  1527  //
  1528  // NOTE: This can only be done once the gossip syncer has reached its final
  1529  // chansSynced state.
  1530  func (g *GossipSyncer) historicalSync() error {
  1531  	done := make(chan struct{})
  1532  
  1533  	select {
  1534  	case g.historicalSyncReqs <- &historicalSyncReq{
  1535  		doneChan: done,
  1536  	}:
  1537  	case <-time.After(syncTransitionTimeout):
  1538  		return ErrSyncTransitionTimeout
  1539  	case <-g.quit:
  1540  		return ErrGossiperShuttingDown
  1541  	}
  1542  
  1543  	select {
  1544  	case <-done:
  1545  		return nil
  1546  	case <-g.quit:
  1547  		return ErrGossiperShuttingDown
  1548  	}
  1549  }
  1550  
  1551  // handleHistoricalSync handles a request to the gossip syncer to perform a
  1552  // historical sync.
  1553  func (g *GossipSyncer) handleHistoricalSync(req *historicalSyncReq) {
  1554  	// We'll go back to our initial syncingChans state in order to request
  1555  	// the remote peer to give us all of the channel IDs they know of
  1556  	// starting from the genesis block.
  1557  	g.genHistoricalChanRangeQuery = true
  1558  	g.setSyncState(syncingChans)
  1559  	close(req.doneChan)
  1560  }