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

     1  package discovery
     2  
     3  import (
     4  	"time"
     5  
     6  	"github.com/decred/dcrd/chaincfg/chainhash"
     7  	"github.com/decred/dcrlnd/channeldb"
     8  	"github.com/decred/dcrlnd/lnwire"
     9  	"github.com/decred/dcrlnd/netann"
    10  	"github.com/decred/dcrlnd/routing/route"
    11  )
    12  
    13  // ChannelGraphTimeSeries is an interface that provides time and block based
    14  // querying into our view of the channel graph. New channels will have
    15  // monotonically increasing block heights, and new channel updates will have
    16  // increasing timestamps. Once we connect to a peer, we'll use the methods in
    17  // this interface to determine if we're already in sync, or need to request
    18  // some new information from them.
    19  type ChannelGraphTimeSeries interface {
    20  	// HighestChanID should return the channel ID of the channel we know of
    21  	// that's furthest in the target chain. This channel will have a block
    22  	// height that's close to the current tip of the main chain as we
    23  	// know it.  We'll use this to start our QueryChannelRange dance with
    24  	// the remote node.
    25  	HighestChanID(chain chainhash.Hash) (*lnwire.ShortChannelID, error)
    26  
    27  	// UpdatesInHorizon returns all known channel and node updates with an
    28  	// update timestamp between the start time and end time. We'll use this
    29  	// to catch up a remote node to the set of channel updates that they
    30  	// may have missed out on within the target chain.
    31  	UpdatesInHorizon(chain chainhash.Hash,
    32  		startTime time.Time, endTime time.Time) ([]lnwire.Message, error)
    33  
    34  	// FilterKnownChanIDs takes a target chain, and a set of channel ID's,
    35  	// and returns a filtered set of chan ID's. This filtered set of chan
    36  	// ID's represents the ID's that we don't know of which were in the
    37  	// passed superSet.
    38  	FilterKnownChanIDs(chain chainhash.Hash,
    39  		superSet []lnwire.ShortChannelID) ([]lnwire.ShortChannelID, error)
    40  
    41  	// FilterChannelRange returns the set of channels that we created
    42  	// between the start height and the end height. The channel IDs are
    43  	// grouped by their common block height. We'll use this to to a remote
    44  	// peer's QueryChannelRange message.
    45  	FilterChannelRange(chain chainhash.Hash,
    46  		startHeight, endHeight uint32) ([]channeldb.BlockChannelRange, error)
    47  
    48  	// FetchChanAnns returns a full set of channel announcements as well as
    49  	// their updates that match the set of specified short channel ID's.
    50  	// We'll use this to reply to a QueryShortChanIDs message sent by a
    51  	// remote peer. The response will contain a unique set of
    52  	// ChannelAnnouncements, the latest ChannelUpdate for each of the
    53  	// announcements, and a unique set of NodeAnnouncements.
    54  	FetchChanAnns(chain chainhash.Hash,
    55  		shortChanIDs []lnwire.ShortChannelID) ([]lnwire.Message, error)
    56  
    57  	// FetchChanUpdates returns the latest channel update messages for the
    58  	// specified short channel ID. If no channel updates are known for the
    59  	// channel, then an empty slice will be returned.
    60  	FetchChanUpdates(chain chainhash.Hash,
    61  		shortChanID lnwire.ShortChannelID) ([]*lnwire.ChannelUpdate, error)
    62  }
    63  
    64  // ChanSeries is an implementation of the ChannelGraphTimeSeries
    65  // interface backed by the channeldb ChannelGraph database. We'll provide this
    66  // implementation to the AuthenticatedGossiper so it can properly use the
    67  // in-protocol channel range queries to quickly and efficiently synchronize our
    68  // channel state with all peers.
    69  type ChanSeries struct {
    70  	graph *channeldb.ChannelGraph
    71  }
    72  
    73  // NewChanSeries constructs a new ChanSeries backed by a channeldb.ChannelGraph.
    74  // The returned ChanSeries implements the ChannelGraphTimeSeries interface.
    75  func NewChanSeries(graph *channeldb.ChannelGraph) *ChanSeries {
    76  	return &ChanSeries{
    77  		graph: graph,
    78  	}
    79  }
    80  
    81  // HighestChanID should return is the channel ID of the channel we know of
    82  // that's furthest in the target chain. This channel will have a block height
    83  // that's close to the current tip of the main chain as we know it.  We'll use
    84  // this to start our QueryChannelRange dance with the remote node.
    85  //
    86  // NOTE: This is part of the ChannelGraphTimeSeries interface.
    87  func (c *ChanSeries) HighestChanID(chain chainhash.Hash) (*lnwire.ShortChannelID, error) {
    88  	chanID, err := c.graph.HighestChanID()
    89  	if err != nil {
    90  		return nil, err
    91  	}
    92  
    93  	shortChanID := lnwire.NewShortChanIDFromInt(chanID)
    94  	return &shortChanID, nil
    95  }
    96  
    97  // UpdatesInHorizon returns all known channel and node updates with an update
    98  // timestamp between the start time and end time. We'll use this to catch up a
    99  // remote node to the set of channel updates that they may have missed out on
   100  // within the target chain.
   101  //
   102  // NOTE: This is part of the ChannelGraphTimeSeries interface.
   103  func (c *ChanSeries) UpdatesInHorizon(chain chainhash.Hash,
   104  	startTime time.Time, endTime time.Time) ([]lnwire.Message, error) {
   105  
   106  	// First, we'll query for all the set of channels that have an update
   107  	// that falls within the specified horizon.
   108  	chansInHorizon, err := c.graph.ChanUpdatesInHorizon(
   109  		startTime, endTime,
   110  	)
   111  	if err != nil {
   112  		return nil, err
   113  	}
   114  
   115  	var updates []lnwire.Message
   116  	for _, channel := range chansInHorizon {
   117  		// If the channel hasn't been fully advertised yet, or is a
   118  		// private channel, then we'll skip it as we can't construct a
   119  		// full authentication proof if one is requested.
   120  		if channel.Info.AuthProof == nil {
   121  			continue
   122  		}
   123  
   124  		chanAnn, edge1, edge2, err := netann.CreateChanAnnouncement(
   125  			channel.Info.AuthProof, channel.Info, channel.Policy1,
   126  			channel.Policy2,
   127  		)
   128  		if err != nil {
   129  			return nil, err
   130  		}
   131  
   132  		updates = append(updates, chanAnn)
   133  		if edge1 != nil {
   134  			updates = append(updates, edge1)
   135  		}
   136  		if edge2 != nil {
   137  			updates = append(updates, edge2)
   138  		}
   139  	}
   140  
   141  	// Next, we'll send out all the node announcements that have an update
   142  	// within the horizon as well. We send these second to ensure that they
   143  	// follow any active channels they have.
   144  	nodeAnnsInHorizon, err := c.graph.NodeUpdatesInHorizon(
   145  		startTime, endTime,
   146  	)
   147  	if err != nil {
   148  		return nil, err
   149  	}
   150  	for _, nodeAnn := range nodeAnnsInHorizon {
   151  		// Ensure we only forward nodes that are publicly advertised to
   152  		// prevent leaking information about nodes.
   153  		isNodePublic, err := c.graph.IsPublicNode(nodeAnn.PubKeyBytes)
   154  		if err != nil {
   155  			log.Errorf("Unable to determine if node %x is "+
   156  				"advertised: %v", nodeAnn.PubKeyBytes, err)
   157  			continue
   158  		}
   159  
   160  		if !isNodePublic {
   161  			log.Tracef("Skipping forwarding announcement for "+
   162  				"node %x due to being unadvertised",
   163  				nodeAnn.PubKeyBytes)
   164  			continue
   165  		}
   166  
   167  		nodeUpdate, err := nodeAnn.NodeAnnouncement(true)
   168  		if err != nil {
   169  			return nil, err
   170  		}
   171  
   172  		updates = append(updates, nodeUpdate)
   173  	}
   174  
   175  	return updates, nil
   176  }
   177  
   178  // FilterKnownChanIDs takes a target chain, and a set of channel ID's, and
   179  // returns a filtered set of chan ID's. This filtered set of chan ID's
   180  // represents the ID's that we don't know of which were in the passed superSet.
   181  //
   182  // NOTE: This is part of the ChannelGraphTimeSeries interface.
   183  func (c *ChanSeries) FilterKnownChanIDs(chain chainhash.Hash,
   184  	superSet []lnwire.ShortChannelID) ([]lnwire.ShortChannelID, error) {
   185  
   186  	chanIDs := make([]uint64, 0, len(superSet))
   187  	for _, chanID := range superSet {
   188  		chanIDs = append(chanIDs, chanID.ToUint64())
   189  	}
   190  
   191  	newChanIDs, err := c.graph.FilterKnownChanIDs(chanIDs)
   192  	if err != nil {
   193  		return nil, err
   194  	}
   195  
   196  	filteredIDs := make([]lnwire.ShortChannelID, 0, len(newChanIDs))
   197  	for _, chanID := range newChanIDs {
   198  		filteredIDs = append(
   199  			filteredIDs, lnwire.NewShortChanIDFromInt(chanID),
   200  		)
   201  	}
   202  
   203  	return filteredIDs, nil
   204  }
   205  
   206  // FilterChannelRange returns the set of channels that we created between the
   207  // start height and the end height. The channel IDs are grouped by their common
   208  // block height. We'll use this respond to a remote peer's QueryChannelRange
   209  // message.
   210  //
   211  // NOTE: This is part of the ChannelGraphTimeSeries interface.
   212  func (c *ChanSeries) FilterChannelRange(chain chainhash.Hash,
   213  	startHeight, endHeight uint32) ([]channeldb.BlockChannelRange, error) {
   214  
   215  	return c.graph.FilterChannelRange(startHeight, endHeight)
   216  }
   217  
   218  // FetchChanAnns returns a full set of channel announcements as well as their
   219  // updates that match the set of specified short channel ID's.  We'll use this
   220  // to reply to a QueryShortChanIDs message sent by a remote peer. The response
   221  // will contain a unique set of ChannelAnnouncements, the latest ChannelUpdate
   222  // for each of the announcements, and a unique set of NodeAnnouncements.
   223  //
   224  // NOTE: This is part of the ChannelGraphTimeSeries interface.
   225  func (c *ChanSeries) FetchChanAnns(chain chainhash.Hash,
   226  	shortChanIDs []lnwire.ShortChannelID) ([]lnwire.Message, error) {
   227  
   228  	chanIDs := make([]uint64, 0, len(shortChanIDs))
   229  	for _, chanID := range shortChanIDs {
   230  		chanIDs = append(chanIDs, chanID.ToUint64())
   231  	}
   232  
   233  	channels, err := c.graph.FetchChanInfos(chanIDs)
   234  	if err != nil {
   235  		return nil, err
   236  	}
   237  
   238  	// We'll use this map to ensure we don't send the same node
   239  	// announcement more than one time as one node may have many channel
   240  	// anns we'll need to send.
   241  	nodePubsSent := make(map[route.Vertex]struct{})
   242  
   243  	chanAnns := make([]lnwire.Message, 0, len(channels)*3)
   244  	for _, channel := range channels {
   245  		// If the channel doesn't have an authentication proof, then we
   246  		// won't send it over as it may not yet be finalized, or be a
   247  		// non-advertised channel.
   248  		if channel.Info.AuthProof == nil {
   249  			continue
   250  		}
   251  
   252  		chanAnn, edge1, edge2, err := netann.CreateChanAnnouncement(
   253  			channel.Info.AuthProof, channel.Info, channel.Policy1,
   254  			channel.Policy2,
   255  		)
   256  		if err != nil {
   257  			return nil, err
   258  		}
   259  
   260  		chanAnns = append(chanAnns, chanAnn)
   261  		if edge1 != nil {
   262  			chanAnns = append(chanAnns, edge1)
   263  
   264  			// If this edge has a validated node announcement, that
   265  			// we haven't yet sent, then we'll send that as well.
   266  			nodePub := channel.Policy1.Node.PubKeyBytes
   267  			hasNodeAnn := channel.Policy1.Node.HaveNodeAnnouncement
   268  			if _, ok := nodePubsSent[nodePub]; !ok && hasNodeAnn {
   269  				nodeAnn, err := channel.Policy1.Node.NodeAnnouncement(true)
   270  				if err != nil {
   271  					return nil, err
   272  				}
   273  
   274  				chanAnns = append(chanAnns, nodeAnn)
   275  				nodePubsSent[nodePub] = struct{}{}
   276  			}
   277  		}
   278  		if edge2 != nil {
   279  			chanAnns = append(chanAnns, edge2)
   280  
   281  			// If this edge has a validated node announcement, that
   282  			// we haven't yet sent, then we'll send that as well.
   283  			nodePub := channel.Policy2.Node.PubKeyBytes
   284  			hasNodeAnn := channel.Policy2.Node.HaveNodeAnnouncement
   285  			if _, ok := nodePubsSent[nodePub]; !ok && hasNodeAnn {
   286  				nodeAnn, err := channel.Policy2.Node.NodeAnnouncement(true)
   287  				if err != nil {
   288  					return nil, err
   289  				}
   290  
   291  				chanAnns = append(chanAnns, nodeAnn)
   292  				nodePubsSent[nodePub] = struct{}{}
   293  			}
   294  		}
   295  	}
   296  
   297  	return chanAnns, nil
   298  }
   299  
   300  // FetchChanUpdates returns the latest channel update messages for the
   301  // specified short channel ID. If no channel updates are known for the channel,
   302  // then an empty slice will be returned.
   303  //
   304  // NOTE: This is part of the ChannelGraphTimeSeries interface.
   305  func (c *ChanSeries) FetchChanUpdates(chain chainhash.Hash,
   306  	shortChanID lnwire.ShortChannelID) ([]*lnwire.ChannelUpdate, error) {
   307  
   308  	chanInfo, e1, e2, err := c.graph.FetchChannelEdgesByID(
   309  		shortChanID.ToUint64(),
   310  	)
   311  	if err != nil {
   312  		return nil, err
   313  	}
   314  
   315  	chanUpdates := make([]*lnwire.ChannelUpdate, 0, 2)
   316  	if e1 != nil {
   317  		chanUpdate, err := netann.ChannelUpdateFromEdge(chanInfo, e1)
   318  		if err != nil {
   319  			return nil, err
   320  		}
   321  
   322  		chanUpdates = append(chanUpdates, chanUpdate)
   323  	}
   324  	if e2 != nil {
   325  		chanUpdate, err := netann.ChannelUpdateFromEdge(chanInfo, e2)
   326  		if err != nil {
   327  			return nil, err
   328  		}
   329  
   330  		chanUpdates = append(chanUpdates, chanUpdate)
   331  	}
   332  
   333  	return chanUpdates, nil
   334  }
   335  
   336  // A compile-time assertion to ensure that ChanSeries meets the
   337  // ChannelGraphTimeSeries interface.
   338  var _ ChannelGraphTimeSeries = (*ChanSeries)(nil)