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)