-
Notifications
You must be signed in to change notification settings - Fork 15
/
nodeview.py
executable file
·155 lines (115 loc) · 5.31 KB
/
nodeview.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
#!/usr/bin/env python3
"""
Plots some node statistics for comparing with neighbours
This script requires describegraph.json
The blue dot represents the node being viewed relative to peers
"""
import sys
import matplotlib.pyplot as plt
import networkx as nx
import numpy as np
from lib.lnGraph import lnGraphV2
median_payment = 200e3 # sat, Payment size for calculating routing costs
# TODO: Should ignore channels smaller than (2x? 4-5x?) the above
feeceiling = 5000 # PPM, ignore fees higher than this
if len(sys.argv) > 1 and len(sys.argv[1]) <= 66:
node2view = sys.argv[1]
else:
print('Please enter the pubkey or alias of the node of interest')
node2view = input('Pubkey: ')
print('Loading graph')
# Using the simplified graph to avoid double counting parallel links
g = lnGraphV2.autoload().simple()
if len(node2view) < 66:
try:
node2view = g.nodes.find(alias=node2view)['pub_key']
except ValueError:
print(f'Could not find node with alias "{node2view}"')
exit()
node = g.nodes.find(node2view)
print('Viewing', node['alias'])
# Collect data for histogram
chanstats = dict(chansizes=[], peersizes=[], peerchancounts=[],
fees=dict(inrate=[], outrate=[], inbase=[], outbase=[]))
channel_data = g.channels.select(_from=node.index)
for chan in channel_data:
assert node2view == chan['local_pubkey']
# ~ assert isinstance(chan['capacity'], int)
chanstats['chansizes'].append(chan['capacity'])
peerkey = chan['remote_pubkey']
peer = g.nodes.find(pub_key=peerkey)
chanstats['peersizes'].append(peer['capacity'])
chanstats['peerchancounts'].append(peer['num_channels'])
def appendfeedata(outrate, outbase, inrate, inbase):
# Rates are in PPM, /1e6 to get a fraction
# Base is in msat, /1e3 to get sat
chanstats['fees']['outrate'].append(int(outrate))
chanstats['fees']['outbase'].append(int(outbase))
chanstats['fees']['inrate'].append(int(inrate))
chanstats['fees']['inbase'].append(int(inbase))
appendfeedata(chan['fee_rate_milli_msat_out'],
chan['fee_base_msat_out'],
chan['fee_rate_milli_msat_in'],
chan['fee_base_msat_in'])
# Convert to array
chanstats['chansizes'] = np.asarray(chanstats['chansizes'])
chanstats['peersizes'] = np.asarray(chanstats['peersizes'])
for k, v in chanstats['fees'].items():
chanstats['fees'][k] = np.array(v)
# ~ exit()
def plothists():
chansizebins = np.array([0, 2e6, 5e6, 10e6, 17e6, 20e6])
if max(node['capacities']) > chansizebins[-1]:
chansizebins[-1] = max(node['capacities'])
fig, ((ax1, ax2), (ax3, ax4)) = plt.subplots(2, 2)
fig.tight_layout()
ax1.hist(chanstats['chansizes'] / 1e6, align='right')
ax1.set_title('Channel Size Distribution')
ax1.set_xlabel('Channel size (Msat)')
ax2.hist(chanstats['peersizes'] / 1e8, align='right')
ax2.set_title('Peer Size Distribution')
ax2.set_xlabel('Peer capacity (BTC)')
median_in_fees = (chanstats['fees']['inbase'] / 1e3 + chanstats['fees']['inrate'] / 1e6 * median_payment)
median_out_fees = (chanstats['fees']['outbase'] / 1e3 + chanstats['fees']['outrate'] / 1e6 * median_payment)
ax3.hist(median_in_fees, align='right')
ax4.hist(median_out_fees, align='right')
ax3.set_title('Receiving Fee Distribution')
ax4.set_title('Sending Fee Distribution')
ax3.set_xlabel(f'Sats to route {median_payment / 1e3:.0f}ksat in')
ax4.set_xlabel(f'Sats to route {median_payment / 1e3:.0f}ksat out')
plt.show()
# ~ plothists()
def pltboxes():
ncols = 5
fig = plt.figure()
# ~ fig.canvas.set_window_title('Viewing '+node['alias'])
peerchanax = plt.subplot(1, ncols, 1)
peersizeax = plt.subplot(1, ncols, 2)
chansizeax = plt.subplot(1, ncols, 3)
feeax = plt.subplot(1, ncols, (4, 5))
feeax.set_title(f'Fee for {median_payment / 1e3:.0f}ksat Forward')
# ~ print(list(zip(chanstats['peerchanco unts'], [g.nodes[k]['alias'] for k in g.adj[node2view]])))
peerchanax.boxplot(chanstats['peerchancounts'], showmeans=True)
peerchanax.scatter([1], [node['num_channels']])
peerchanax.set_title('Peer Channel Counts')
peerchanax.set_ylabel('Peer Channel Count')
peersizeax.boxplot(chanstats['peersizes'] / 1e8, showmeans=True)
peersizeax.scatter([1], [node['capacity'] / 1e8])
peersizeax.set_title('Peer Sizes')
peersizeax.set_ylabel('Peer Capacity (BTC)')
chansizeax.boxplot(chanstats['chansizes'] / 1e6, showmeans=True)
chansizeax.set_title('Channel Sizes')
chansizeax.set_ylabel('Channel Size (Msat)')
median_in_fees = (chanstats['fees']['inbase'] / 1e3 + chanstats['fees']['inrate'] / 1e6 * median_payment)
median_out_fees = (chanstats['fees']['outbase'] / 1e3 + chanstats['fees']['outrate'] / 1e6 * median_payment)
median_in_fees_ppm = median_in_fees * 1e6/median_payment
median_out_fees_ppm = median_out_fees * 1e6/median_payment
# Remove outliers
median_in_fees_ppm = median_in_fees_ppm[np.where(median_in_fees_ppm <= feeceiling)[0]]
median_out_fees_ppm = median_out_fees_ppm[np.where(median_out_fees_ppm <= feeceiling)[0]]
feeax.boxplot([median_in_fees_ppm, median_out_fees_ppm],
labels=['Receiving', 'Sending'], showmeans=True)
feeax.set_ylabel('Fee (PPM)')
fig.tight_layout()
plt.show()
pltboxes()