⚡Lightning network: how to explore the topology
Extracting topology data from LND
In previous story, I described how I installed a bitcoin lightning network node at home, running LND on a cheap Raspberry Pi3.
lncli provides a useful command to export the the network topology. We can simply run:
$ lncli describegraph > /tmp/describegraph.json
to obtain a json that contains the topology of the lightning network as seen from the current lnd node.
The format of describegraph.json is pretty simple and self-explanatory:
{
"nodes": [
{
"last_update": 1539310922,
"pub_key": "02004c625d622245606a1ea2c1c69cfb4516b703b47945a3647713c05fe4aaeb1c",
"alias": "LivingRoomOfSatoshi.com (LND) 2",
"addresses": [
{
"network": "tcp",
"addr": "172.81.178.151:9735"
}
],
"color": "#3399ff"
},
...
...
],
"edges": [
{
"channel_id": "595923207643922432",
"chan_point": "dd0d25aadec1ff27a7215834bb3660cb2d0c5c030f3a8a27096e243313648ae2:0",
"last_update": 1540314360,
"node1_pub": "02cdf83ef8e45908b1092125d25c68dcec7751ca8d39f557775cd842e5bc127469",
"node2_pub": "032c4b954f0f171b694b5e8e8323589e54196b48cf2efc27692513a360cb11d76f",
"capacity": "500000",
"node1_policy": {
"time_lock_delta": 144,
"min_htlc": "1000",
"fee_base_msat": "1000",
"fee_rate_milli_msat": "1",
"disabled": false
},
"node2_policy": {
"time_lock_delta": 144,
"min_htlc": "1000",
"fee_base_msat": "1000",
"fee_rate_milli_msat": "1",
"disabled": false
}
},
...
...
]
}
We can then quickly count the number of nodes and channel:
$ cat /tmp/describegraph.json | grep “pub_key” | wc -l
877$ cat /tmp/describegraph.json | grep “channel_id” | wc -l
2796
Import topology data in Neo4j
Installing Neo4jDesktop
What’s better than a Graph Database to explore a network topology? Let’s download Neo4jDesktop from https://neo4j.com/product/ and spin a database to import our describegraph.json
We can now create a new Graph in Neo4jDesktop, just click on Add Graph → Create a Local Graph, set the graph name, the password and click Create.
Then we need to install the APOC library (“ Awesome Procedures On Cypher”), in Neo4j Desktop: go to the Manage screen and the Plugins tab. Now click on the Install button in the APOC box and you’re done.
Because we need to import a local file, we need to change the default configuration: go to the Manage screen and the Settings tab and add this line:
apoc.import.file.enabled=true
Now click on Open Browser and be ready to start or exploration of the lightning network.
Import the network data
It’s now time to import the describegraph file in our Graph database. We can use the procedure load.json
provided by the APOC library to load the json file and then iterate over the edges, creating 2 Node
objects for each edge we found in the list, connected by a relationship LINKED
. Then we can add a field alias
to each Node object to better identify them.
CALL apoc.load.json(“file:///full/path/to/describegraph.json”) YIELD value AS data
UNWIND data.edges as edge
MERGE (n1:Node {id:edge.node1_pub} )
MERGE (n2:Node {id:edge.node2_pub} )
CREATE (n1)-[:LINKED {capacity:edge.capacity}]->(n2)CALL apoc.load.json(“file:///full/path/to/describegraph.json”) YIELD value AS data
UNWIND data.nodes as node
MERGE (n:Node {id:node.pub_key} )
SET n.alias = node.alias
Finally we can add an index on the field alias
to speed up the queries.
CREATE INDEX ON :Node(alias)
Exploring the topology
We are now ready to use the powerful query engine of Neo4j to discover some interesting facts about the network.
Number of Nodes and Channel
First, let’s see how many nodes and channels we know about. This is an easy query, we need to count all the Nodes
objects and then count all the relationships LINKED
present in the graph:
MATCH (n:Node) RETURN COUNT(*)COUNT(*) 877MATCH (n)-[r:LINKED]->() RETURN COUNT(r)COUNT(r)2796
The numbers obtained by those queries match the number obtained from the “grep” that we previously executed directly on the describegraph.json
file, we we can be pretty confident that the import procedure run smooth.
According to https://1ml.com/, at the moment we have more that 3,000 nodes and more than 12,000 channels in the lightning network. So, even after almost 6 weeks of operation, my node knows about less that 1/3 of the nodes and less than 1/4 of the channels that exist in the network.
This is not surprising: mesh routing is unsolved problem in Computer Science yet.
The longest shortest path
The longest shortest path in the network in defined as the max distance between nodes, or network diameter. Neo4j is a Graph oriented DB, so it provides a shortestpath
function out of the box. We can easily find all the shortest paths and get the longest:
MATCH (n1:Node), (n2:Node), route = shortestpath((n1)-[:LINKED*]-(n2))
WHERE id(n1) < id(n2)
RETURN route
ORDER BY LENGTH(route) DESC
LIMIT 1
So, according to my view of the network, the most distant nodes are 8 hops away.
The most distant nodes
We can also find the most distant nodes from a given node, for instance here are the 5 most distant nodes from my at home node, aliased SLL.
MATCH (n1:Node), (n2:Node),
route = shortestpath((n1)-[:LINKED*]-(n2))
WHERE id(n1) < id(n2) AND n1.alias = 'SLL'
RETURN route
ORDER BY LENGTH(route) DESC
LIMIT 5
The top 10 Hubs
Let’s find the nodes with most directly connected nodes (not channels…)
MATCH (n1:Node)-[:LINKED]-(n2:Node)
RETURN n2.alias, SIZE(COLLECT(n1)) as connected
ORDER BY connected DESC
LIMIT 10
The winner is the node tady je slushovo, with 169 nodes directly linked.
Triangle Counting
An interesting query that we can run is the count of Triangles that each node is part of:
CALL algo.triangleCount.stream(‘Node’,’LINKED’,{concurrency:4})
YIELD nodeId, triangles, coefficient
RETURN algo.getNodeById(nodeId).alias AS alias, triangles, coefficient
ORDER BY triangles DESC
clustering coefficient is the likelihood that its neighbors are also connected. You can find more detail in the wikipedia page https://en.wikipedia.org/wiki/Clustering_coefficient , but simply speaking: a node a has clustering coefficient 1 if every neighbor connected to it is also connected to every other node within the neighborhood, and 0 if no node that is connected to it connects to any other node that is connected to it.
The top 10 nodes by number of triangles seam to have a local clustering coefficient lesser than 10%
In a perfect tia
We can also calculate the network average clustering coefficient.
CALL algo.triangleCount(‘Node’, ‘LINKED’,
{concurrency:4, write:true, writeProperty:’triangles’,clusteringCoefficientProperty:’coefficient’})
YIELD nodeCount, triangleCount, averageClusteringCoefficient;
So, my node knows about a total of 877 nodes in the network, meshed in 2045 triangles, and the average of the local clustering coefficient is about 0.123.
Conclusions
I hope you had fun discovering some interesting facts the lightning network topology.
Feel free to suggest more interesting queries to run :)
Feel free to connect my Lightning Network node:
>$ lncli connect 039401f72bc0d40efb58b01de15527a2a5ae1943d7c29067b725a1467a93c7e66f@2.238.144.76:9735
Read Next: Why ⚡Lightning Network⚡ makes no sense 😱