github.com/decred/dcrlnd@v0.7.6/channeldb/graph_cache.go (about) 1 package channeldb 2 3 import ( 4 "fmt" 5 "sync" 6 7 "github.com/decred/dcrd/dcrutil/v4" 8 9 "github.com/decred/dcrlnd/kvdb" 10 "github.com/decred/dcrlnd/lnwire" 11 "github.com/decred/dcrlnd/routing/route" 12 ) 13 14 // GraphCacheNode is an interface for all the information the cache needs to know 15 // about a lightning node. 16 type GraphCacheNode interface { 17 // PubKey is the node's public identity key. 18 PubKey() route.Vertex 19 20 // Features returns the node's p2p features. 21 Features() *lnwire.FeatureVector 22 23 // ForEachChannel iterates through all channels of a given node, 24 // executing the passed callback with an edge info structure and the 25 // policies of each end of the channel. The first edge policy is the 26 // outgoing edge *to* the connecting node, while the second is the 27 // incoming edge *from* the connecting node. If the callback returns an 28 // error, then the iteration is halted with the error propagated back up 29 // to the caller. 30 ForEachChannel(kvdb.RTx, 31 func(kvdb.RTx, *ChannelEdgeInfo, *ChannelEdgePolicy, 32 *ChannelEdgePolicy) error) error 33 } 34 35 // CachedEdgePolicy is a struct that only caches the information of a 36 // ChannelEdgePolicy that we actually use for pathfinding and therefore need to 37 // store in the cache. 38 type CachedEdgePolicy struct { 39 // ChannelID is the unique channel ID for the channel. The first 3 40 // bytes are the block height, the next 3 the index within the block, 41 // and the last 2 bytes are the output index for the channel. 42 ChannelID uint64 43 44 // MessageFlags is a bitfield which indicates the presence of optional 45 // fields (like max_htlc) in the policy. 46 MessageFlags lnwire.ChanUpdateMsgFlags 47 48 // ChannelFlags is a bitfield which signals the capabilities of the 49 // channel as well as the directed edge this update applies to. 50 ChannelFlags lnwire.ChanUpdateChanFlags 51 52 // TimeLockDelta is the number of blocks this node will subtract from 53 // the expiry of an incoming HTLC. This value expresses the time buffer 54 // the node would like to HTLC exchanges. 55 TimeLockDelta uint16 56 57 // MinHTLC is the smallest value HTLC this node will forward, expressed 58 // in millisatoshi. 59 MinHTLC lnwire.MilliAtom 60 61 // MaxHTLC is the largest value HTLC this node will forward, expressed 62 // in millisatoshi. 63 MaxHTLC lnwire.MilliAtom 64 65 // FeeBaseMAtoms is the base HTLC fee that will be charged for forwarding 66 // ANY HTLC, expressed in mSAT's. 67 FeeBaseMAtoms lnwire.MilliAtom 68 69 // FeeProportionalMillionths is the rate that the node will charge for 70 // HTLCs for each millionth of a satoshi forwarded. 71 FeeProportionalMillionths lnwire.MilliAtom 72 73 // ToNodePubKey is a function that returns the to node of a policy. 74 // Since we only ever store the inbound policy, this is always the node 75 // that we query the channels for in ForEachChannel(). Therefore, we can 76 // save a lot of space by not storing this information in the memory and 77 // instead just set this function when we copy the policy from cache in 78 // ForEachChannel(). 79 ToNodePubKey func() route.Vertex 80 81 // ToNodeFeatures are the to node's features. They are never set while 82 // the edge is in the cache, only on the copy that is returned in 83 // ForEachChannel(). 84 ToNodeFeatures *lnwire.FeatureVector 85 } 86 87 // ComputeFee computes the fee to forward an HTLC of `amt` milli-satoshis over 88 // the passed active payment channel. This value is currently computed as 89 // specified in BOLT07, but will likely change in the near future. 90 func (c *CachedEdgePolicy) ComputeFee( 91 amt lnwire.MilliAtom) lnwire.MilliAtom { 92 93 return c.FeeBaseMAtoms + (amt*c.FeeProportionalMillionths)/feeRateParts 94 } 95 96 // ComputeFeeFromIncoming computes the fee to forward an HTLC given the incoming 97 // amount. 98 func (c *CachedEdgePolicy) ComputeFeeFromIncoming( 99 incomingAmt lnwire.MilliAtom) lnwire.MilliAtom { 100 101 return incomingAmt - divideCeil( 102 feeRateParts*(incomingAmt-c.FeeBaseMAtoms), 103 feeRateParts+c.FeeProportionalMillionths, 104 ) 105 } 106 107 // NewCachedPolicy turns a full policy into a minimal one that can be cached. 108 func NewCachedPolicy(policy *ChannelEdgePolicy) *CachedEdgePolicy { 109 return &CachedEdgePolicy{ 110 ChannelID: policy.ChannelID, 111 MessageFlags: policy.MessageFlags, 112 ChannelFlags: policy.ChannelFlags, 113 TimeLockDelta: policy.TimeLockDelta, 114 MinHTLC: policy.MinHTLC, 115 MaxHTLC: policy.MaxHTLC, 116 FeeBaseMAtoms: policy.FeeBaseMAtoms, 117 FeeProportionalMillionths: policy.FeeProportionalMillionths, 118 } 119 } 120 121 // DirectedChannel is a type that stores the channel information as seen from 122 // one side of the channel. 123 type DirectedChannel struct { 124 // ChannelID is the unique identifier of this channel. 125 ChannelID uint64 126 127 // IsNode1 indicates if this is the node with the smaller public key. 128 IsNode1 bool 129 130 // OtherNode is the public key of the node on the other end of this 131 // channel. 132 OtherNode route.Vertex 133 134 // Capacity is the announced capacity of this channel in satoshis. 135 Capacity dcrutil.Amount 136 137 // OutPolicySet is a boolean that indicates whether the node has an 138 // outgoing policy set. For pathfinding only the existence of the policy 139 // is important to know, not the actual content. 140 OutPolicySet bool 141 142 // InPolicy is the incoming policy *from* the other node to this node. 143 // In path finding, we're walking backward from the destination to the 144 // source, so we're always interested in the edge that arrives to us 145 // from the other node. 146 InPolicy *CachedEdgePolicy 147 } 148 149 // DeepCopy creates a deep copy of the channel, including the incoming policy. 150 func (c *DirectedChannel) DeepCopy() *DirectedChannel { 151 channelCopy := *c 152 153 if channelCopy.InPolicy != nil { 154 inPolicyCopy := *channelCopy.InPolicy 155 channelCopy.InPolicy = &inPolicyCopy 156 157 // The fields for the ToNode can be overwritten by the path 158 // finding algorithm, which is why we need a deep copy in the 159 // first place. So we always start out with nil values, just to 160 // be sure they don't contain any old data. 161 channelCopy.InPolicy.ToNodePubKey = nil 162 channelCopy.InPolicy.ToNodeFeatures = nil 163 } 164 165 return &channelCopy 166 } 167 168 // GraphCache is a type that holds a minimal set of information of the public 169 // channel graph that can be used for pathfinding. 170 type GraphCache struct { 171 nodeChannels map[route.Vertex]map[uint64]*DirectedChannel 172 nodeFeatures map[route.Vertex]*lnwire.FeatureVector 173 174 mtx sync.RWMutex 175 } 176 177 // NewGraphCache creates a new graphCache. 178 func NewGraphCache(preAllocNumNodes int) *GraphCache { 179 return &GraphCache{ 180 nodeChannels: make( 181 map[route.Vertex]map[uint64]*DirectedChannel, 182 // A channel connects two nodes, so we can look it up 183 // from both sides, meaning we get double the number of 184 // entries. 185 preAllocNumNodes*2, 186 ), 187 nodeFeatures: make( 188 map[route.Vertex]*lnwire.FeatureVector, 189 preAllocNumNodes, 190 ), 191 } 192 } 193 194 // Stats returns statistics about the current cache size. 195 func (c *GraphCache) Stats() string { 196 c.mtx.RLock() 197 defer c.mtx.RUnlock() 198 199 numChannels := 0 200 for node := range c.nodeChannels { 201 numChannels += len(c.nodeChannels[node]) 202 } 203 return fmt.Sprintf("num_node_features=%d, num_nodes=%d, "+ 204 "num_channels=%d", len(c.nodeFeatures), len(c.nodeChannels), 205 numChannels) 206 } 207 208 // AddNodeFeatures adds a graph node and its features to the cache. 209 func (c *GraphCache) AddNodeFeatures(node GraphCacheNode) { 210 nodePubKey := node.PubKey() 211 212 // Only hold the lock for a short time. The `ForEachChannel()` below is 213 // possibly slow as it has to go to the backend, so we can unlock 214 // between the calls. And the AddChannel() method will acquire its own 215 // lock anyway. 216 c.mtx.Lock() 217 c.nodeFeatures[nodePubKey] = node.Features() 218 c.mtx.Unlock() 219 } 220 221 // AddNode adds a graph node, including all the (directed) channels of that 222 // node. 223 func (c *GraphCache) AddNode(tx kvdb.RTx, node GraphCacheNode) error { 224 c.AddNodeFeatures(node) 225 226 return node.ForEachChannel( 227 tx, func(tx kvdb.RTx, info *ChannelEdgeInfo, 228 outPolicy *ChannelEdgePolicy, 229 inPolicy *ChannelEdgePolicy) error { 230 231 c.AddChannel(info, outPolicy, inPolicy) 232 233 return nil 234 }, 235 ) 236 } 237 238 // AddChannel adds a non-directed channel, meaning that the order of policy 1 239 // and policy 2 does not matter, the directionality is extracted from the info 240 // and policy flags automatically. The policy will be set as the outgoing policy 241 // on one node and the incoming policy on the peer's side. 242 func (c *GraphCache) AddChannel(info *ChannelEdgeInfo, 243 policy1 *ChannelEdgePolicy, policy2 *ChannelEdgePolicy) { 244 245 if info == nil { 246 return 247 } 248 249 if policy1 != nil && policy1.IsDisabled() && 250 policy2 != nil && policy2.IsDisabled() { 251 252 return 253 } 254 255 // Create the edge entry for both nodes. 256 c.mtx.Lock() 257 c.updateOrAddEdge(info.NodeKey1Bytes, &DirectedChannel{ 258 ChannelID: info.ChannelID, 259 IsNode1: true, 260 OtherNode: info.NodeKey2Bytes, 261 Capacity: info.Capacity, 262 }) 263 c.updateOrAddEdge(info.NodeKey2Bytes, &DirectedChannel{ 264 ChannelID: info.ChannelID, 265 IsNode1: false, 266 OtherNode: info.NodeKey1Bytes, 267 Capacity: info.Capacity, 268 }) 269 c.mtx.Unlock() 270 271 // The policy's node is always the to_node. So if policy 1 has to_node 272 // of node 2 then we have the policy 1 as seen from node 1. 273 if policy1 != nil { 274 fromNode, toNode := info.NodeKey1Bytes, info.NodeKey2Bytes 275 if policy1.Node.PubKeyBytes != info.NodeKey2Bytes { 276 fromNode, toNode = toNode, fromNode 277 } 278 isEdge1 := policy1.ChannelFlags&lnwire.ChanUpdateDirection == 0 279 c.UpdatePolicy(policy1, fromNode, toNode, isEdge1) 280 } 281 if policy2 != nil { 282 fromNode, toNode := info.NodeKey2Bytes, info.NodeKey1Bytes 283 if policy2.Node.PubKeyBytes != info.NodeKey1Bytes { 284 fromNode, toNode = toNode, fromNode 285 } 286 isEdge1 := policy2.ChannelFlags&lnwire.ChanUpdateDirection == 0 287 c.UpdatePolicy(policy2, fromNode, toNode, isEdge1) 288 } 289 } 290 291 // updateOrAddEdge makes sure the edge information for a node is either updated 292 // if it already exists or is added to that node's list of channels. 293 func (c *GraphCache) updateOrAddEdge(node route.Vertex, edge *DirectedChannel) { 294 if len(c.nodeChannels[node]) == 0 { 295 c.nodeChannels[node] = make(map[uint64]*DirectedChannel) 296 } 297 298 c.nodeChannels[node][edge.ChannelID] = edge 299 } 300 301 // UpdatePolicy updates a single policy on both the from and to node. The order 302 // of the from and to node is not strictly important. But we assume that a 303 // channel edge was added beforehand so that the directed channel struct already 304 // exists in the cache. 305 func (c *GraphCache) UpdatePolicy(policy *ChannelEdgePolicy, fromNode, 306 toNode route.Vertex, edge1 bool) { 307 308 c.mtx.Lock() 309 defer c.mtx.Unlock() 310 311 updatePolicy := func(nodeKey route.Vertex) { 312 if len(c.nodeChannels[nodeKey]) == 0 { 313 return 314 } 315 316 channel, ok := c.nodeChannels[nodeKey][policy.ChannelID] 317 if !ok { 318 return 319 } 320 321 // Edge 1 is defined as the policy for the direction of node1 to 322 // node2. 323 switch { 324 // This is node 1, and it is edge 1, so this is the outgoing 325 // policy for node 1. 326 case channel.IsNode1 && edge1: 327 channel.OutPolicySet = true 328 329 // This is node 2, and it is edge 2, so this is the outgoing 330 // policy for node 2. 331 case !channel.IsNode1 && !edge1: 332 channel.OutPolicySet = true 333 334 // The other two cases left mean it's the inbound policy for the 335 // node. 336 default: 337 channel.InPolicy = NewCachedPolicy(policy) 338 } 339 } 340 341 updatePolicy(fromNode) 342 updatePolicy(toNode) 343 } 344 345 // RemoveNode completely removes a node and all its channels (including the 346 // peer's side). 347 func (c *GraphCache) RemoveNode(node route.Vertex) { 348 c.mtx.Lock() 349 defer c.mtx.Unlock() 350 351 delete(c.nodeFeatures, node) 352 353 // First remove all channels from the other nodes' lists. 354 for _, channel := range c.nodeChannels[node] { 355 c.removeChannelIfFound(channel.OtherNode, channel.ChannelID) 356 } 357 358 // Then remove our whole node completely. 359 delete(c.nodeChannels, node) 360 } 361 362 // RemoveChannel removes a single channel between two nodes. 363 func (c *GraphCache) RemoveChannel(node1, node2 route.Vertex, chanID uint64) { 364 c.mtx.Lock() 365 defer c.mtx.Unlock() 366 367 // Remove that one channel from both sides. 368 c.removeChannelIfFound(node1, chanID) 369 c.removeChannelIfFound(node2, chanID) 370 } 371 372 // removeChannelIfFound removes a single channel from one side. 373 func (c *GraphCache) removeChannelIfFound(node route.Vertex, chanID uint64) { 374 if len(c.nodeChannels[node]) == 0 { 375 return 376 } 377 378 delete(c.nodeChannels[node], chanID) 379 } 380 381 // UpdateChannel updates the channel edge information for a specific edge. We 382 // expect the edge to already exist and be known. If it does not yet exist, this 383 // call is a no-op. 384 func (c *GraphCache) UpdateChannel(info *ChannelEdgeInfo) { 385 c.mtx.Lock() 386 defer c.mtx.Unlock() 387 388 if len(c.nodeChannels[info.NodeKey1Bytes]) == 0 || 389 len(c.nodeChannels[info.NodeKey2Bytes]) == 0 { 390 391 return 392 } 393 394 channel, ok := c.nodeChannels[info.NodeKey1Bytes][info.ChannelID] 395 if ok { 396 // We only expect to be called when the channel is already 397 // known. 398 channel.Capacity = info.Capacity 399 channel.OtherNode = info.NodeKey2Bytes 400 } 401 402 channel, ok = c.nodeChannels[info.NodeKey2Bytes][info.ChannelID] 403 if ok { 404 channel.Capacity = info.Capacity 405 channel.OtherNode = info.NodeKey1Bytes 406 } 407 } 408 409 // getChannels returns a copy of the passed node's channels or nil if there 410 // isn't any. 411 func (c *GraphCache) getChannels(node route.Vertex) []*DirectedChannel { 412 c.mtx.RLock() 413 defer c.mtx.RUnlock() 414 415 channels, ok := c.nodeChannels[node] 416 if !ok { 417 return nil 418 } 419 420 features, ok := c.nodeFeatures[node] 421 if !ok { 422 // If the features were set to nil explicitly, that's fine here. 423 // The router will overwrite the features of the destination 424 // node with those found in the invoice if necessary. But if we 425 // didn't yet get a node announcement we want to mimic the 426 // behavior of the old DB based code that would always set an 427 // empty feature vector instead of leaving it nil. 428 features = lnwire.EmptyFeatureVector() 429 } 430 431 toNodeCallback := func() route.Vertex { 432 return node 433 } 434 435 i := 0 436 channelsCopy := make([]*DirectedChannel, len(channels)) 437 for _, channel := range channels { 438 // We need to copy the channel and policy to avoid it being 439 // updated in the cache if the path finding algorithm sets 440 // fields on it (currently only the ToNodeFeatures of the 441 // policy). 442 channelCopy := channel.DeepCopy() 443 if channelCopy.InPolicy != nil { 444 channelCopy.InPolicy.ToNodePubKey = toNodeCallback 445 channelCopy.InPolicy.ToNodeFeatures = features 446 } 447 448 channelsCopy[i] = channelCopy 449 i++ 450 } 451 452 return channelsCopy 453 } 454 455 // ForEachChannel invokes the given callback for each channel of the given node. 456 func (c *GraphCache) ForEachChannel(node route.Vertex, 457 cb func(channel *DirectedChannel) error) error { 458 459 // Obtain a copy of the node's channels. We need do this in order to 460 // avoid deadlocks caused by interaction with the graph cache, channel 461 // state and the graph database from multiple goroutines. This snapshot 462 // is only used for path finding where being stale is acceptable since 463 // the real world graph and our representation may always become 464 // slightly out of sync for a short time and the actual channel state 465 // is stored separately. 466 channels := c.getChannels(node) 467 for _, channel := range channels { 468 if err := cb(channel); err != nil { 469 return err 470 } 471 472 } 473 474 return nil 475 } 476 477 // ForEachNode iterates over the adjacency list of the graph, executing the 478 // call back for each node and the set of channels that emanate from the given 479 // node. 480 // 481 // NOTE: This method should be considered _read only_, the channels or nodes 482 // passed in MUST NOT be modified. 483 func (c *GraphCache) ForEachNode(cb func(node route.Vertex, 484 channels map[uint64]*DirectedChannel) error) error { 485 486 c.mtx.RLock() 487 defer c.mtx.RUnlock() 488 489 for node, channels := range c.nodeChannels { 490 // We don't make a copy here since this is a read-only RPC 491 // call. We also don't need the node features either for this 492 // call. 493 if err := cb(node, channels); err != nil { 494 return err 495 } 496 } 497 498 return nil 499 } 500 501 // GetFeatures returns the features of the node with the given ID. If no 502 // features are known for the node, an empty feature vector is returned. 503 func (c *GraphCache) GetFeatures(node route.Vertex) *lnwire.FeatureVector { 504 c.mtx.RLock() 505 defer c.mtx.RUnlock() 506 507 features, ok := c.nodeFeatures[node] 508 if !ok || features == nil { 509 // The router expects the features to never be nil, so we return 510 // an empty feature set instead. 511 return lnwire.EmptyFeatureVector() 512 } 513 514 return features 515 }