From f5b2c13d93303803a3fa4ba64524cdfd56c308e0 Mon Sep 17 00:00:00 2001 From: Chris Date: Tue, 14 Jul 2015 21:18:57 -0400 Subject: [PATCH 1/3] Bug fix in protocol.handleCallResponse isNewNode was called after the contact was added to the routing table meaning it would always return false and the key/values would never be transferred. --- kademlia/protocol.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kademlia/protocol.py b/kademlia/protocol.py index 7d963e4..fc11991 100644 --- a/kademlia/protocol.py +++ b/kademlia/protocol.py @@ -108,9 +108,9 @@ class KademliaProtocol(RPCProtocol): """ if result[0]: self.log.info("got response from %s, adding to router" % node) - self.router.addContact(node) if self.router.isNewNode(node): self.transferKeyValues(node) + self.router.addContact(node) else: self.log.debug("no response from %s, removing from router" % node) self.router.removeContact(node) From 2f363cba849c9e9f5bb57ed85df5f3498231124c Mon Sep 17 00:00:00 2001 From: Chris Date: Tue, 14 Jul 2015 21:29:48 -0400 Subject: [PATCH 2/3] Maybe transfer key, values on incoming request. The existing code only checks if we should call transferKeyValues when we receive a response to one of our RPCs. We also need to check when receive a new request from a new node. This commit adds a new method that is called each time we receive a new request. --- kademlia/protocol.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/kademlia/protocol.py b/kademlia/protocol.py index fc11991..882ea58 100644 --- a/kademlia/protocol.py +++ b/kademlia/protocol.py @@ -32,11 +32,13 @@ class KademliaProtocol(RPCProtocol): def rpc_ping(self, sender, nodeid): source = Node(nodeid, sender[0], sender[1]) + self.maybeTransferKeyValues(source) self.router.addContact(source) return self.sourceNode.id def rpc_store(self, sender, nodeid, key, value): source = Node(nodeid, sender[0], sender[1]) + self.maybeTransferKeyValues(source) self.router.addContact(source) self.log.debug("got a store request from %s, storing value" % str(sender)) self.storage[key] = value @@ -45,12 +47,14 @@ class KademliaProtocol(RPCProtocol): def rpc_find_node(self, sender, nodeid, key): self.log.info("finding neighbors of %i in local table" % long(nodeid.encode('hex'), 16)) source = Node(nodeid, sender[0], sender[1]) + self.maybeTransferKeyValues(source) self.router.addContact(source) node = Node(key) return map(tuple, self.router.findNeighbors(node, exclude=source)) def rpc_find_value(self, sender, nodeid, key): source = Node(nodeid, sender[0], sender[1]) + self.maybeTransferKeyValues(source) self.router.addContact(source) value = self.storage.get(key, None) if value is None: @@ -101,6 +105,10 @@ class KademliaProtocol(RPCProtocol): ds.append(self.callStore(node, key, value)) return defer.gatherResults(ds) + def maybeTransferKeyValues(self, node): + if self.router.isNewNode(node): + self.transferKeyValues(node) + def handleCallResponse(self, result, node): """ If we get a response, add the node to the routing table. If From 237d89b6b61d2dabc9518d5c15eceefb3572d697 Mon Sep 17 00:00:00 2001 From: Chris Date: Fri, 17 Jul 2015 21:29:36 -0400 Subject: [PATCH 3/3] Created new method welcomeIfNewNode in protocol. This commit consolidates the maybeTransferKeyValues and addContact calls into the transferKeyValues method and renames it. --- kademlia/protocol.py | 45 +++++++++++++++++++------------------------- 1 file changed, 19 insertions(+), 26 deletions(-) diff --git a/kademlia/protocol.py b/kademlia/protocol.py index 882ea58..884aa85 100644 --- a/kademlia/protocol.py +++ b/kademlia/protocol.py @@ -32,14 +32,12 @@ class KademliaProtocol(RPCProtocol): def rpc_ping(self, sender, nodeid): source = Node(nodeid, sender[0], sender[1]) - self.maybeTransferKeyValues(source) - self.router.addContact(source) + self.welcomeIfNewNode(source) return self.sourceNode.id def rpc_store(self, sender, nodeid, key, value): source = Node(nodeid, sender[0], sender[1]) - self.maybeTransferKeyValues(source) - self.router.addContact(source) + self.welcomeIfNewNode(source) self.log.debug("got a store request from %s, storing value" % str(sender)) self.storage[key] = value return True @@ -47,15 +45,13 @@ class KademliaProtocol(RPCProtocol): def rpc_find_node(self, sender, nodeid, key): self.log.info("finding neighbors of %i in local table" % long(nodeid.encode('hex'), 16)) source = Node(nodeid, sender[0], sender[1]) - self.maybeTransferKeyValues(source) - self.router.addContact(source) + self.welcomeIfNewNode(source) node = Node(key) return map(tuple, self.router.findNeighbors(node, exclude=source)) def rpc_find_value(self, sender, nodeid, key): source = Node(nodeid, sender[0], sender[1]) - self.maybeTransferKeyValues(source) - self.router.addContact(source) + self.welcomeIfNewNode(source) value = self.storage.get(key, None) if value is None: return self.rpc_find_node(sender, nodeid, key) @@ -81,9 +77,10 @@ class KademliaProtocol(RPCProtocol): d = self.store(address, self.sourceNode.id, key, value) return d.addCallback(self.handleCallResponse, nodeToAsk) - def transferKeyValues(self, node): + def welcomeIfNewNode(self, node): """ - Given a new node, send it all the keys/values it should be storing. + Given a new node, send it all the keys/values it should be storing, + then add it to the routing table. @param node: A new node that just joined (or that we just found out about). @@ -94,20 +91,18 @@ class KademliaProtocol(RPCProtocol): is closer than the closest in that list, then store the key/value on the new node (per section 2.5 of the paper) """ - ds = [] - for key, value in self.storage.iteritems(): - keynode = Node(digest(key)) - neighbors = self.router.findNeighbors(keynode) - if len(neighbors) > 0: - newNodeClose = node.distanceTo(keynode) < neighbors[-1].distanceTo(keynode) - thisNodeClosest = self.sourceNode.distanceTo(keynode) < neighbors[0].distanceTo(keynode) - if len(neighbors) == 0 or (newNodeClose and thisNodeClosest): - ds.append(self.callStore(node, key, value)) - return defer.gatherResults(ds) - - def maybeTransferKeyValues(self, node): if self.router.isNewNode(node): - self.transferKeyValues(node) + ds = [] + for key, value in self.storage.iteritems(): + keynode = Node(digest(key)) + neighbors = self.router.findNeighbors(keynode) + if len(neighbors) > 0: + newNodeClose = node.distanceTo(keynode) < neighbors[-1].distanceTo(keynode) + thisNodeClosest = self.sourceNode.distanceTo(keynode) < neighbors[0].distanceTo(keynode) + if len(neighbors) == 0 or (newNodeClose and thisNodeClosest): + ds.append(self.callStore(node, key, value)) + self.router.addContact(node) + return defer.gatherResults(ds) def handleCallResponse(self, result, node): """ @@ -116,9 +111,7 @@ class KademliaProtocol(RPCProtocol): """ if result[0]: self.log.info("got response from %s, adding to router" % node) - if self.router.isNewNode(node): - self.transferKeyValues(node) - self.router.addContact(node) + self.welcomeIfNewNode(node) else: self.log.debug("no response from %s, removing from router" % node) self.router.removeContact(node)