Skip to content

Instantly share code, notes, and snippets.

@chris-belcher
Last active April 13, 2019 21:19
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save chris-belcher/ed23486f4d5cd7bd5190db074bf7cbaa to your computer and use it in GitHub Desktop.
Save chris-belcher/ed23486f4d5cd7bd5190db074bf7cbaa to your computer and use it in GitHub Desktop.
getpeerinfo-parse.py
#run with
#/path/to/bitcoin/bin/bitcoin-cli getpeerinfo | python getpeerinfo-parse.py
#output looks like
#zlato@zlato:~/bitcoin-0.17.1/bin$ ./bitcoin-cli getpeerinfo | python getpeerinfo-parse.py
#services L=NODE_NETWORK_LIMITED N=NODE_NETWORK G=NODE_GETUTXO B=NODE_BLOOM R=NODE_REPLACE_BY_FEE W=NODE_WITNESS X=NODE_XTHIN U=UNKNOWN
# id addr user-agent iB se re conn'd ping serv lastr
# # host oO nt cv MMDD-HHMM msec ices HHMMSS
# 414 27.102.130.92 /Satoshi:0.17.1/ oF 20M 28M 0411-2005 358 LNBW 121021
# 417 139.59.34.217 /Satoshi:0.15.1/ oF 17M 46M 0411-2006 163 NBW 121019
# 421 24.241.102.26 /Satoshi:0.17.1/ oF 17M 46M 0411-2007 131 LNBW 121010
# 425 127.0.0.1 /bitnodes.bitcoin-russia.ru:0.0.1f/ iF 21M 306k 0411-2012 557 121003
# 429 127.0.0.1 /Satoshi:0.13.2/ iF 11M 66M 0411-2019 242 NBW 121019
# 446 62.77.158.217 /Satoshi:0.16.0/ oF 17M 54M 0411-2048 65 LNBW 121021
# 451 127.0.0.1 /Satoshi:0.16.3/ iF 21M 19M 0411-2054 516 LNBW 121016
# 527 127.0.0.1 /Satoshi:0.17.0.1/ iF 46M 15M 0411-2305 335 LNBW 121020
# 580 127.0.0.1 /Satoshi:0.17.1/ iT 187k 105k 0412-0035 292 LNBW 120905
# 646 127.0.0.1 /Satoshi:0.17.0.1/ iF 26M 14M 0412-0238 517 LNBW 121019
# 774 127.0.0.1 /Satoshi:0.17.0.1/ iF 11M 33M 0412-0642 212 LNBW 121020
# 1160 127.0.0.1 /Satoshi:0.17.1/ iF 16M 7M 0412-1817 309 LNBW 121021
# 1204 192.223.31.132 /Satoshi:0.17.1/ oF 7M 14M 0412-1950 81 LNBW 121017
# 1311 93.104.213.244 /Satoshi:0.17.1/ oF 5M 11M 0412-2304 35 LNBW 121020
# 1323 113.52.135.125 /Satoshi:0.17.0.1/ oF 5M 6M 0412-2331 267 LNBW 121020
# 1377 127.0.0.1 /Satoshi:0.17.0/ iF 15M 4M 0413-0057 1066 LNBW 121021
# 1470 127.0.0.1 /Satoshi:0.17.99/ iF 13M 3M 0413-0339 710 LNBW 121017
# 1473 127.0.0.1 /Satoshi:0.17.1/ iF 7M 4M 0413-0344 232 LBW 121020
# 1513 127.0.0.1 /Satoshi:0.17.0.1/ iF 5M 3M 0413-0502 603 LNBW 121020
# 1550 127.0.0.1 /Satoshi:0.17.1/ iF 2M 5M 0413-0611 455 LNBW 121019
# 1575 127.0.0.1 /Satoshi:0.17.1/Knots:20181229/ iF 10M 2M 0413-0655 760 LBW 121021
# 1583 127.0.0.1 /Satoshi:0.17.1/ iF 2M 1M 0413-0710 705 LNBW 121021
# 1757 52.39.235.86 /Satoshi:0.16.3/ oF 135k 105k 0413-1155 -1 LNBW 121020
#23 connections
#explainations of some columns
#id = connection id
#io = incoming (i) or outgoing (o) connection
#BO = blocksonly, T=enabled, F=not enabled
import sys, json, pprint, datetime
from math import log
data = "".join(sys.stdin)
dataj = json.loads(data)
def tsstr_date(s):
return datetime.datetime.fromtimestamp(s).strftime("%m%d-%H%M")
def tsstr_time(s):
return datetime.datetime.fromtimestamp(s).strftime("%H%M%S")
unit_list = zip(['b', 'k', 'M', 'G', 'T', 'P'], [0, 0, 0, 0, 0, 0])
#unit_list = zip(['b', 'k', 'M', 'G', 'T', 'P'], [0, 0, 1, 2, 2, 2])
def bytes_fmt(num):
"""Human friendly file size"""
if num > 1:
exponent = min(int(log(num, 1024)), len(unit_list) - 1)
quotient = float(num) / 1024**exponent
unit, num_decimals = unit_list[exponent]
format_string = '{:.%sf}{}' % (num_decimals)
return format_string.format(quotient, unit)
if num == 0:
return '0 bytes'
if num == 1:
return '1 byte'
#https://github.com/bitcoin/bitcoin/blob/master/src/protocol.h
service_flags = {1: ("NODE_NETWORK", "N"), 1<<1: ("NODE_GETUTXO", "G"), 1<<2: ("NODE_BLOOM", "B"),
1<<3:("NODE_WITNESS", "W"), 1<<4: ("NODE_XTHIN", "X"), 1<<10: ("NODE_NETWORK_LIMITED", "L"),
1<<26: ("NODE_REPLACE_BY_FEE", "R")}
print("services " + " ".join([abr + "=" + name for name, abr in service_flags.values()]) + " U=UNKNOWN")
def make_service_bits_str(s):
#TODO split this up on many lines so its more readable
return "".join(filter(lambda l: len(l) > 0, [abr if s & bits != 0 else "" for bits, (name, abr) in service_flags.iteritems()] + ["U" if s & ~reduce(lambda a, b: a|b, service_flags.keys()) else ""]))
formatstr = "% 6s % 22s %-56s % 1s% 1s % 4s % 4s % 9s %4s % 5s % 6s"
print formatstr % ("id", "addr", "user-agent", "i", "B", "se", "re", "conn'd", "ping", "serv", "lastr")
print formatstr % ( "#", "host", "", "o", "O", "nt", "cv", "MMDD-HHMM", "msec", "ices", "HHMMSS")
for p in dataj:
print(formatstr % ((p['id']), p['addr'][:p['addr'].index(':')], p['subver'],
("i" if p["inbound"] else "o"),
("F" if p["relaytxes"] else "T"),
bytes_fmt(p["bytessent"]), bytes_fmt(p["bytesrecv"]),
tsstr_date(p['conntime']), str(int(p.get('pingtime', -0.001)*1000)),
make_service_bits_str(int(p["services"], 16)), tsstr_time(p['lastrecv'])))
print str(len(dataj)) + ' connections'
@Empty2k12
Copy link

One could also host this on a local apache server to get a nice interface with connected peers, graphs, ...

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment