From 7eb9f344f41d3b0045a7cec04d2cb368edcf12a2 Mon Sep 17 00:00:00 2001 From: Victor Shyba Date: Fri, 28 Sep 2018 13:47:37 -0300 Subject: [PATCH 1/2] test recover from invalid tokens --- tests/functional/dht/test_store.py | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/tests/functional/dht/test_store.py b/tests/functional/dht/test_store.py index f5dc8a648..2fabd05ab 100644 --- a/tests/functional/dht/test_store.py +++ b/tests/functional/dht/test_store.py @@ -13,6 +13,31 @@ log = logging.getLogger() class TestStoreExpiration(TestKademliaBase): network_size = 40 + @defer.inlineCallbacks + def test_nullify_token(self): + blob_hash = generate_id(1) + announcing_node = self.nodes[20] + # announce the blob + announce_d = announcing_node.announceHaveBlob(blob_hash) + self.pump_clock(5+1) + storing_node_ids = yield announce_d + self.assertEqual(len(storing_node_ids), 8) + + for node in set(self.nodes).union(set(self._seeds)): + # now, everyone has the wrong token + node.change_token() + node.change_token() + + announce_d = announcing_node.announceHaveBlob(blob_hash) + self.pump_clock(5+1) + storing_node_ids = yield announce_d + self.assertEqual(len(storing_node_ids), 0) # cant store, wrong tokens, but they get nullified + + announce_d = announcing_node.announceHaveBlob(blob_hash) + self.pump_clock(5+1) + storing_node_ids = yield announce_d + self.assertEqual(len(storing_node_ids), 8) # next attempt succeeds as it refreshes tokens + @defer.inlineCallbacks def test_store_and_expire(self): blob_hash = generate_id(1) From 9178ca701c87772100634567a03dd822af77ee0d Mon Sep 17 00:00:00 2001 From: Victor Shyba Date: Fri, 28 Sep 2018 14:19:51 -0300 Subject: [PATCH 2/2] nullify and refresh tokens --- lbrynet/dht/contact.py | 2 +- lbrynet/dht/node.py | 15 +++++++-------- lbrynet/dht/protocol.py | 2 ++ 3 files changed, 10 insertions(+), 9 deletions(-) diff --git a/lbrynet/dht/contact.py b/lbrynet/dht/contact.py index 101492ef3..bc25fc5d5 100644 --- a/lbrynet/dht/contact.py +++ b/lbrynet/dht/contact.py @@ -40,7 +40,7 @@ class _Contact: self._token = (None, 0) # token, timestamp def update_token(self, token): - self._token = token, self.getTime() + self._token = token, self.getTime() if token else 0 @property def token(self): diff --git a/lbrynet/dht/node.py b/lbrynet/dht/node.py index ce9d2da81..960136b41 100644 --- a/lbrynet/dht/node.py +++ b/lbrynet/dht/node.py @@ -299,25 +299,24 @@ class Node(MockKademliaHelper): @defer.inlineCallbacks def storeToContact(self, blob_hash, contact): try: - token = contact.token - if not token: - find_value_response = yield contact.findValue(blob_hash) - token = find_value_response[b'token'] - contact.update_token(token) - res = yield contact.store(blob_hash, token, self.peerPort, self.node_id, 0) + if not contact.token: + yield contact.findValue(blob_hash) + res = yield contact.store(blob_hash, contact.token, self.peerPort, self.node_id, 0) if res != b"OK": raise ValueError(res) - defer.returnValue(True) log.debug("Stored %s to %s (%s)", binascii.hexlify(blob_hash), contact.log_id(), contact.address) + return True except protocol.TimeoutError: log.debug("Timeout while storing blob_hash %s at %s", binascii.hexlify(blob_hash), contact.log_id()) except ValueError as err: log.error("Unexpected response: %s" % err) except Exception as err: + if 'Invalid token' in str(err): + contact.update_token(None) log.error("Unexpected error while storing blob_hash %s at %s: %s", binascii.hexlify(blob_hash), contact, err) - defer.returnValue(False) + return False @defer.inlineCallbacks def announceHaveBlob(self, blob_hash): diff --git a/lbrynet/dht/protocol.py b/lbrynet/dht/protocol.py index e3130468c..b26364410 100644 --- a/lbrynet/dht/protocol.py +++ b/lbrynet/dht/protocol.py @@ -184,6 +184,8 @@ class KademliaProtocol(protocol.DatagramProtocol): def _update_contact(result): # refresh the contact in the routing table contact.update_last_replied() if method == b'findValue': + if b'token' in result: + contact.update_token(result[b'token']) if b'protocolVersion' not in result: contact.update_protocol_version(0) else: