From 465a276c02823f8f53b25e6ab93f49cfeca211c7 Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Thu, 11 Jul 2019 10:51:10 +0200 Subject: [PATCH] Dandelion fixes - expiration wasn't handled correctly - objects with no child stems never expired. While this is better for anonymity, it can cause objects getting stuck - upon expiration the nodes weren't marked as not having the object, causing it to not be advertised - I haven't tested it but at least I don't think can make things worse --- src/network/dandelion.py | 6 ++++-- src/network/invthread.py | 28 +++++++++++++++++++++++++--- 2 files changed, 29 insertions(+), 5 deletions(-) diff --git a/src/network/dandelion.py b/src/network/dandelion.py index 06ecca24..e3464dae 100644 --- a/src/network/dandelion.py +++ b/src/network/dandelion.py @@ -122,11 +122,13 @@ class Dandelion(): def expire(self): with self.lock: deadline = time() - # only expire those that have a child node, i.e. those without a child not will stick around - toDelete = [[v.stream, k, v.child] for k, v in self.hashMap.iteritems() if v.timeout < deadline and v.child] + toDelete = [[v.stream, k, v.child] + for k, v in self.hashMap.iteritems() + if v.timeout < deadline] for row in toDelete: self.removeHash(row[1], 'expiration') invQueue.put((row[0], row[1], row[2])) + return toDelete def reRandomiseStems(self): with self.lock: diff --git a/src/network/invthread.py b/src/network/invthread.py index d0d758fb..6f6f1364 100644 --- a/src/network/invthread.py +++ b/src/network/invthread.py @@ -12,6 +12,27 @@ from queues import invQueue import protocol import state + +def handleExpiredDandelion(expired): + """For expired dandelion objects, mark all remotes as not having + the object""" + if not expired: + return + for i in \ + BMConnectionPool().inboundConnections.values() + \ + BMConnectionPool().outboundConnections.values(): + if not i.fullyEstablished: + continue + for x in expired: + streamNumber, hashid, _ = x + try: + del i.objectsNewToMe[hashid] + except KeyError: + if streamNumber in i.streams: + with i.objectsNewToThemLock: + i.objectsNewToThem[hashid] = time() + + class InvThread(threading.Thread, StoppableThread): def __init__(self): threading.Thread.__init__(self, name="InvBroadcaster") @@ -20,8 +41,9 @@ class InvThread(threading.Thread, StoppableThread): def handleLocallyGenerated(self, stream, hashId): Dandelion().addHash(hashId, stream=stream) - for connection in BMConnectionPool().inboundConnections.values() + \ - BMConnectionPool().outboundConnections.values(): + for connection in \ + BMConnectionPool().inboundConnections.values() + \ + BMConnectionPool().outboundConnections.values(): if state.dandelion and connection != Dandelion().objectChildStem(hashId): continue connection.objectsNewToThem[hashId] = time() @@ -31,7 +53,7 @@ class InvThread(threading.Thread, StoppableThread): chunk = [] while True: # Dandelion fluff trigger by expiration - Dandelion().expire() + handleExpiredDandelion(Dandelion().expire()) try: data = invQueue.get(False) chunk.append((data[0], data[1]))