Skip to content

Commit

Permalink
summary: fix persistent peerstate zero leading window
Browse files Browse the repository at this point in the history
  • Loading branch information
m-schmoock authored and cdecker committed Aug 3, 2020
1 parent f4e3383 commit 158a151
Show file tree
Hide file tree
Showing 3 changed files with 49 additions and 25 deletions.
10 changes: 6 additions & 4 deletions summary/summary.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ def run(self):
try:
rpcpeers = plugin.rpc.listpeers()
trace_availability(plugin, rpcpeers)
plugin.avail_peerstate.sync()
plugin.persist.sync()
time.sleep(plugin.avail_interval)
except Exception as ex:
plugin.log("[PeerThread] " + str(ex), 'warn')
Expand Down Expand Up @@ -143,7 +143,7 @@ def summary(plugin, exclude=''):
c['private'],
p['connected'],
c['short_channel_id'],
plugin.avail_peerstate[pid]['avail']
plugin.persist['peerstate'][pid]['avail']
))

if not active_channel and p['connected']:
Expand Down Expand Up @@ -224,10 +224,12 @@ def init(options, configuration, plugin):
plugin.currency_prefix = options['summary-currency-prefix']
plugin.fiat_per_btc = 0

plugin.avail_peerstate = shelve.open('summary.dat', writeback=True)
plugin.avail_count = 0
plugin.avail_interval = float(options['summary-availability-interval'])
plugin.avail_window = 60 * 60 * int(options['summary-availability-window'])
plugin.persist = shelve.open('summary.dat', writeback=True)
if not 'peerstate' in plugin.persist:
plugin.persist['peerstate'] = {}
plugin.persist['availcount'] = 0

info = plugin.rpc.getinfo()

Expand Down
18 changes: 9 additions & 9 deletions summary/summary_avail.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@
# ensure an rpc peer is added
def addpeer(p, rpcpeer):
pid = rpcpeer['id']
if not pid in p.avail_peerstate:
p.avail_peerstate[pid] = {
if not pid in p.persist['peerstate']:
p.persist['peerstate'][pid] = {
'connected' : rpcpeer['connected'],
'last_seen' : datetime.now() if rpcpeer['connected'] else None,
'avail' : 1.0 if rpcpeer['connected'] else 0.0
Expand All @@ -13,8 +13,8 @@ def addpeer(p, rpcpeer):

# exponetially smooth online/offline states of peers
def trace_availability(p, rpcpeers):
p.avail_count += 1
leadwin = max(min(p.avail_window, p.avail_count * p.avail_interval), p.avail_interval)
p.persist['availcount'] += 1
leadwin = max(min(p.avail_window, p.persist['availcount'] * p.avail_interval), p.avail_interval)
samples = leadwin / p.avail_interval
alpha = 1.0 / samples
beta = 1.0 - alpha
Expand All @@ -24,9 +24,9 @@ def trace_availability(p, rpcpeers):
addpeer(p, rpcpeer)

if rpcpeer['connected']:
p.avail_peerstate[pid]['last_seen'] = datetime.now()
p.avail_peerstate[pid]['connected'] = True
p.avail_peerstate[pid]['avail'] = 1.0 * alpha + p.avail_peerstate[pid]['avail'] * beta
p.persist['peerstate'][pid]['last_seen'] = datetime.now()
p.persist['peerstate'][pid]['connected'] = True
p.persist['peerstate'][pid]['avail'] = 1.0 * alpha + p.persist['peerstate'][pid]['avail'] * beta
else:
p.avail_peerstate[pid]['connected'] = False
p.avail_peerstate[pid]['avail'] = 0.0 * alpha + p.avail_peerstate[pid]['avail'] * beta
p.persist['peerstate'][pid]['connected'] = False
p.persist['peerstate'][pid]['avail'] = 0.0 * alpha + p.persist['peerstate'][pid]['avail'] * beta
46 changes: 34 additions & 12 deletions summary/test_summary.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,11 @@
# returns a test plugin stub
def get_stub():
plugin = Plugin()
plugin.avail_peerstate = {}
plugin.avail_count = 0
plugin.avail_interval = 60
plugin.avail_window = 3600
plugin.persist = {}
plugin.persist['peerstate'] = {}
plugin.persist['availcount'] = 0
return plugin


Expand Down Expand Up @@ -60,12 +61,12 @@ def test_summary_avail_101():
trace_availability(plugin, rpcpeers)

# then
assert(plugin.avail_peerstate['1']['avail'] == 1.0)
assert(plugin.avail_peerstate['2']['avail'] == 0.0)
assert(plugin.avail_peerstate['3']['avail'] == 1.0)
assert(plugin.avail_peerstate['1']['connected'] == True)
assert(plugin.avail_peerstate['2']['connected'] == False)
assert(plugin.avail_peerstate['3']['connected'] == True)
assert(plugin.persist['peerstate']['1']['avail'] == 1.0)
assert(plugin.persist['peerstate']['2']['avail'] == 0.0)
assert(plugin.persist['peerstate']['3']['avail'] == 1.0)
assert(plugin.persist['peerstate']['1']['connected'] == True)
assert(plugin.persist['peerstate']['2']['connected'] == False)
assert(plugin.persist['peerstate']['3']['connected'] == True)


# tests for 50% downtime
Expand All @@ -90,7 +91,7 @@ def test_summary_avail_50():
trace_availability(plugin, rpcpeers_off)

# then
assert(round(plugin.avail_peerstate['1']['avail'], 3) == 0.5)
assert(round(plugin.persist['peerstate']['1']['avail'], 3) == 0.5)


# tests for 2/3 downtime
Expand All @@ -115,7 +116,7 @@ def test_summary_avail_33():
trace_availability(plugin, rpcpeers_off)

# then
assert(round(plugin.avail_peerstate['1']['avail'], 3) == 0.333)
assert(round(plugin.persist['peerstate']['1']['avail'], 3) == 0.333)


# tests for 1/3 downtime
Expand All @@ -140,7 +141,7 @@ def test_summary_avail_66():
trace_availability(plugin, rpcpeers_off)

# then
assert(round(plugin.avail_peerstate['1']['avail'], 3) == 0.667)
assert(round(plugin.persist['peerstate']['1']['avail'], 3) == 0.667)


# checks the leading window is smaller if interval count is low
Expand All @@ -165,7 +166,28 @@ def test_summary_avail_leadwin():
trace_availability(plugin, rpcpeers_off)

# then
assert(round(plugin.avail_peerstate['1']['avail'], 3) == 0.667)
assert(round(plugin.persist['peerstate']['1']['avail'], 3) == 0.667)


# checks whether the peerstate is persistent
def test_summary_persist(node_factory):
# in order to give the PeerThread a chance in a unit test
# we need to give it a low interval
opts = {'summary-availability-interval' : 0.1}
opts.update(pluginopt)
l1, l2 = node_factory.line_graph(2, opts=opts)

# when
time.sleep(0.5) # wait a bit for the PeerThread to capture data
s1 = l1.rpc.summary()
l1.restart()
s2 = l1.rpc.summary()

# then
avail1 = int(re.search(' ([0-9]*)% ', s1['channels'][2]).group(1))
avail2 = int(re.search(' ([0-9]*)% ', s2['channels'][2]).group(1))
assert(avail1 == 100)
assert(avail2 > 0)


def test_summary_start(node_factory):
Expand Down

0 comments on commit 158a151

Please sign in to comment.