Skip to content

Instantly share code, notes, and snippets.

@tyzbit
Last active May 4, 2018 16:00
Show Gist options
  • Select an option

  • Save tyzbit/b61d0ee236a9d08060d81345a576b7d2 to your computer and use it in GitHub Desktop.

Select an option

Save tyzbit/b61d0ee236a9d08060d81345a576b7d2 to your computer and use it in GitHub Desktop.
Historical Lightning Data

Forked from vasturiano, with dataset and minor other changes.

Historical data of The Lightning Network as seen from my node from Thu Jan 25 to Feb 21. This data was generated manually, not automatically.

Nodes are colored according to settings set by the node operators. Nodes are sized according to the total amount of BTC in channels they have open. Lines are channels between nodes. Nodes that fly off into the background don't have any channels my node knows about. Line colors are representative of the channel capacity, but is colored dynamically.

Click on a node to see its address info and capacity.

function getGraphDataSets() {
const loadBlocks = function(Graph) {
var snapshot = '.graph' + document.getElementById('snapshot').value + '.json';
qwest.get(snapshot).then((_, data) => {
//data.nodes.forEach(node => { node.name = `${node.alias?node.alias+': ':''}${node.pub_key || node.id}` });
data.nodes.forEach(node => {
node.name = `${node.alias}`
var capacity = 0;
var links = 0;
// check each link, and if it connects to the node, up the node's capacity.
node.size = data.links.forEach(link => {
if ( (node.id == link.source) || (node.id == link.target) ) {
links = links + 1;
capacity = capacity + link.capacity;
}
});
// capacity is in BTC
node.capacity = capacity/100000000;
node.averagechansize = (node.capacity/links);
node.links = links;
// size indicative of average channel size
node.size = node.capacity*100
});
Graph
.cooldownTicks(300)
.cooldownTime(20000)
.nodeColor('color')
.nodeVal('size')
.onNodeClick(function(node) {
document.getElementById('graph-data-description').innerHTML = `Total value of this node's channels: ${node.capacity} BTC. Average channel size: ${node.averagechansize} BTC. Total number of channels: ${node.links}.`
node.addresses.forEach(function(address) {
document.getElementById('graph-data-description').innerHTML += "<font color=\"green\" size=\"4em\"><br><b>" + node.alias + "</b>: " + node.id + "@" + address.addr + "</font>"
})
if ( node.addresses.length < 1 ) {
document.getElementById('graph-data-description').innerHTML = "<font color=\"red\" size=\"4em\"><br><b>" + node.alias + "</b> (" + node.id + ") is not advertising any addresses</font>"
}
})
.linkAutoColorBy('capacity')
.linkLabel('capacity')
.linkOpacity(0.4)
.forceEngine('ngraph')
.graphData(data);
document.getElementById('graph-data-info').innerHTML = "Snapshot from: " + new Date(data.timestamp*1000);
document.getElementById('slider-value').innerHTML = "Snapshot number " + document.getElementById('snapshot').value + " of 3772"
});
};
loadBlocks.description = "<em>Lightning Mainnet</em> data (<a href='https://gist.github.com/tyzbit/93bb73fde487210974977ba29e04b2ed'>https://gist.github.com/tyzbit/93bb73fde487210974977ba29e04b2ed</a>)";
return [loadBlocks];
}
<head>
<script src="//unpkg.com/3d-force-graph@1"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/qwest/4.4.5/qwest.min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/PapaParse/4.1.4/papaparse.min.js"></script>
<script src="data-set-loader.js"></script>
<link rel="stylesheet" href="style.css">
</head>
<body>
<div class="graph-data">
<span id="graph-data-description"></span>
</div>
<div id="graph-data-info"></div>
<div id="graph-data-slider">
<span id="slider-value">LOADING</span><br>
<span><input type="range" min="0" max="3772" value="0" class="slider" id="snapshot" onchange="toggleData();"></span>
</div>
<div id="3d-graph"></div>
<script src="index.js"></script>
</body>
const Graph = ForceGraph3D()
(document.getElementById("3d-graph"));
let curDataSetIdx;
const dataSets = getGraphDataSets();
let toggleData;
(toggleData = function() {
curDataSetIdx = curDataSetIdx === undefined ? 0 : (curDataSetIdx+1)%dataSets.length;
const dataSet = dataSets[curDataSetIdx];
//Graph.resetProps(); // Wipe current state
dataSet(Graph); // Load data set
document.getElementById('graph-data-description').innerHTML = dataSet.description ? `Viewing ${dataSet.description}` : '';
})(); // IIFE init
body {
text-align: center;
font-family: Sans-serif;
margin: 0;
}
.graph-data {
position: absolute;
top: 0px;
right: 0px;
padding: 5px;
z-index: 1;
}
#graph-data-description {
font-size: 12px;
color: slategrey;
z-index: 1;
}
#graph-data-info {
font-size: 2em;
color: slategrey;
position: absolute;
left: 0px;
top: 0px;
z-index: 1;
}
#graph-data-slider {
width: 50%;
height: 4em;
border-radius: 5px;
opacity: 0.7;
position: absolute;
bottom: 1.5em;
margin-left: auto;
margin-right: auto;
z-index: 1;
}
#slider-value {
width: 100%;
height: 2em;
font-size: 1em;
color: slategrey;
position: absolute;
margin-left: auto;
margin-right: auto;
}
.slider {
-webkit-appearance: none;
width: 100%;
height: 1em;
border-radius: 5px;
opacity: 0.7;
position: absolute;
bottom: 1em;
background: #d3d3d3;
outline: none;
opacity: 0.7;
-webkit-transition: .2s;
transition: opacity .2s;
z-index: 1;
}
.slider::-webkit-slider-thumb {
-webkit-appearance: none;
appearance: none;
width: 50px;
height: 50px;
border-radius: 50%;
background: #12cfcf;
cursor: pointer;
}
.slider::-moz-range-thumb {
width: 50px;
height: 50px;
border-radius: 50%;
background: #12cfcf;
cursor: pointer;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment