Updated graph and minor edits

pull/750/head
Andreas M. Antonopoulos 3 years ago
parent f3409d9b38
commit 70bf8f784c

Binary file not shown.

Before

Width:  |  Height:  |  Size: 273 KiB

After

Width:  |  Height:  |  Size: 4.3 MiB

@ -12,11 +12,7 @@ But, as the Lightning Network has grown explosively, the path finding problem's
[[lngraph]]
image::images/LNGraphJuly2021.png[]
If the sender and recipient are connected to other well-connected nodes and have at least one channel with adequate capacity - there will be thousands of paths. The problem becomes: choosing the _best_ path that will succeed in payment delivery, out of a list of thousands of possible paths.
Delivering a payment can be described as a _transportation problem_. You want to transport some satoshis from your node via your channels and along one or several paths to a recipient.
The problem is difficult because we don't know if remote channels can actually fulfill the routing requests as we do not know their local balance. Which means we have uncertainty. This is why we refer to path finding in this chaptersince we are trying to find paths with _enough liquidity_ through the network that allow the transportation of the satoshis.
If the sender and recipient are connected to other well-connected nodes and have at least one channel with adequate capacity - there will be thousands of paths. The problem becomes: selecting the _best_ path that will succeed in payment delivery, out of a list of thousands of possible paths.
==== Selecting the best path
@ -30,20 +26,38 @@ To select the "best" path, we have to first define what we mean by "best". There
All of these criteria may be desirable to some extent and selecting paths that are favorable across many dimensions is not an easy task. Optimization problems like this may be too complex to solve for the "best" solution, but often can be solved for some approximation of the optimal. Which is good news, because otherwise path finding would be an intractable problem.
=== Fundamentals of path finding
The problem of path finding in the Lightning Network falls under a general category of _graph theory_ in mathematics and the more specific category of _graph traversal_ in computer science.
==== Path finding in math and computer science
Path finding in the Lightning Network falls under a general category of _graph theory_ in mathematics and the more specific category of _graph traversal_ in computer science.
A network such as the Lightning Network can be represented as a mathematical construct called a _graph_, where _nodes_ are connected to each other by _edges_ (equivalent to the payment channels). The Lightning Network forms a _directed graph_ because the nodes are linked _asymmetrically_, since the channel balance is split between the two channel partners and the payment liquidity is different in each direction. A directed graph with numerical capacity constrains on its edges is called a _flow network_, a mathematical construct used to optimize transportation and other similar networks. Flow networks can be used as a framework when solutions need to achieve a specific flow while minimizing cost, known as the Minimum Cost Flow Problem (MCFP)_.
==== Capacity, balance, liquidity
In order to better understand the problem of transporting satoshis from point A to point B, we need to better define three important terms: capacity, balance, and liquidity. We use these terms to describe a payment channel's ability to route a payment.
In a payment channel connecting A<-->B:
A network such as the Lightning Network can be represented as a mathematical construct called a _graph_, where _nodes_ are connected to each other by _edges_ (equivalent to the payment channels). The Lightning Network forms a _directed graph_ because the nodes are linked _asymmetrically_, since the channel balance is split between the two channel partners and the payment liquidity is different in each direction. A directed graph with numerical capacity constrains on its edges is called a _flow network_, a mathematical construct used to optimize transportation and other similar networks. Flow networks can be used as a framework when solutions need to achieve a specific flow while minimizing cost, known as the Minimum Cost Flow Problem (MCFP)_.
Capacity:: This is the aggregate amount of satoshis that were funded into the 2-of-2 multisig with the funding transaction. It represents the maximum amount of value is held in the channel. The channel capacity is announced by the gossip protocol and is known to nodes.
Balance:: This is the amount of satoshis held by each channel partner that can be sent to the other channel partner. A subset of the balance of A, can be sent in the direction (A--->B) towards node B. A subset of the balance of B can be sent in the opposite direction (A<---B).
Liquidity:: The available (subset) balance that can actually be sent across the channel in one direction. Liquidity of A is equal to the balance of A minus the channel reserve and any pending HTLCs committed by A.
The only value known to the network (via gossip announcements) is the aggregate capacity of the channel. Some unknown portion of that capacity is distributed as each partners balance. Some subset of that balance is available to send across the channel in one direction:
----
capacity = balance(A) + balance(B)
liquidity(A) = balance(A) - channel_reserve(A) - pending_HTLCs(A)
----
==== Uncertainty of balances
If we knew the exact channel balances of every channel, we could easily compute one or more payment paths using any of the standard path finding algorithms taught in good computer science programs. But we don't know the channel balances, we only know the aggregate channel capacity, which is advertised by nodes in channel announcements. In order for a payment to succeed, there must be adequate balance on the sending side of the channel. If we don't know how the capacity is distributed between the channel partners, we don't know if there is enough balance in the direction we are trying to send the payment.
If we knew the exact channel balances of every channel, we could compute one or more payment paths using any of the standard path finding algorithms taught in good computer science programs. But we don't know the channel balances, we only know the aggregate channel capacity, which is advertised by nodes in channel announcements. In order for a payment to succeed, there must be adequate balance on the sending side of the channel. If we don't know how the capacity is distributed between the channel partners, we don't know if there is enough balance in the direction we are trying to send the payment.
Balances are not announced in channel updates for two reasons: privacy and scalability. First, announcing balances would reduce the privacy of the Lightning Network as it would allow surveillance of payment by statistical analysis of the changes in balances. Second, if nodes announced balances (globally) with every payment, the Lightning Network's scaling would be as bad as that of on-chain Bitcoin transactions which are broadcast to all participants. Therefore, balances are not announced. To solve the path finding problem in the face of uncertainty of balances, we need innovative path finding strategies. These strategies must relate closely to the routing algorithm that is used, which is source-based onion-routing where it is the responsibility of the sender to find a path through the network.
With only partial information about the network topology available this is a real challenge and active research is still being conducted into optimizing this part of the Lightning Network implementations
==== Path finding complexity
Finding a path through a graph is a problem modern computers can solve rather efficiently.
@ -53,8 +67,7 @@ In our case the weights of the edges can represent the routing fees.
Only edges with a capacity larger than the amount to be sent will be included in the search.
In this basic form, path finding in the Lightning network is very simple and straight forward.
However, as we discussed in the introduction, channel balances cannot be shared with every participant every time a payment takes place as this would prevent scaling the network.
This turns our easy theoretical computer science problem into a rather complex real-world problem.
However, channel liquidity is unknown to the sender. This turns our easy theoretical computer science problem into a rather complex real-world problem.
We now have to solve a path finding problem with only partial knowledge.
For example, we suspect which edges might be able to forward a payment because their capacity seems big enough.
But we can't be certain unless we try it out or ask the channel owners directly.
@ -74,5 +87,3 @@ However, the user might suspect that probing is taking place if the payment is n
While "blind probing" is not optimal and leaves ample room for improvement, it should be noted that even this simplistic strategy works surprisingly well for smaller payments and well-connected nodes.
Most Lightning node and wallet implementation improve on this approach, by ordering/weighting the list of candidate paths. Some implementations order the candidate paths by cost (fees), or some combination of cost/capacity.
====

@ -0,0 +1,78 @@
#!/usr/bin/env python
# coding: utf-8
# In[ ]:
import networkx as nx
import matplotlib.pyplot as plt
import sys
import ujson as json
get_ipython().run_line_magic('matplotlib', 'inline')
filename = 'lngraph0721'
# In[ ]:
# Load channel graph exported from LND
# lndcli describegraph > filename.json
describegraph = open(filename+'.json', 'r')
lngraph = json.load(describegraph)
# In[ ]:
# Construct network graph
graph = nx.Graph()
# Add edges and nodes
for edge in lngraph['edges']:
# Name the nodes by last 4 characters of node ID
node1 = edge['node1_pub'][-4:]
node2 = edge['node2_pub'][-4:]
graph.add_node(node1)
graph.add_node(node2)
graph.add_edge(node1, node2)
# Show graph info before reduction
print(nx.info(graph))
# Remove nodes with fewer than 3 channels to make graph cleaner
remove = [node for node,degree in dict(graph.degree()).items() if degree < 3]
graph.remove_nodes_from(remove)
# Show graph info after reduction
print(nx.info(graph))
# In[ ]:
# Set figure/diagram options (thin grey lines for channels, black dots for nodes)
options = {
"node_color": "black",
"node_size": 2,
"edge_color" : "grey",
"linewidths": 0,
"width": 0.01,
}
# 16:9 image ratio
fig = plt.figure(figsize=(16,9))
# Spring layout arranges nodes automatically.
# Channels cause "attraction" (spring), nodes cause "repulsion" (opposite)
# k controls distance between nodes. Spread them out to make graph less dense
# Seed for reproducible layout
pos = nx.spring_layout(graph,k=0.4, iterations=10, seed=721)
nx.draw(graph, pos, **options)
# Save PNG image
plt.savefig(filename+'.png', format="png", dpi=600)
Loading…
Cancel
Save