From 6c5bac53d7ea511e3942ff006fedab2bb0e0469c Mon Sep 17 00:00:00 2001 From: Alex Haynes Date: Wed, 24 Apr 2019 22:11:54 -0400 Subject: [PATCH] refactored routedhost into router passed to swarm --- libp2p/__init__.py | 15 ++++++------- libp2p/host/basic_host.py | 21 ++++++++++--------- libp2p/kademlia/crawling.py | 2 +- libp2p/kademlia/kad_peerinfo.py | 6 +++--- libp2p/kademlia/network.py | 2 +- libp2p/kademlia/routed_host.py | 21 ------------------- libp2p/kademlia/routing.py | 6 +++--- libp2p/network/swarm.py | 10 +++++++-- libp2p/peer/id.py | 9 ++++++++ libp2p/routing/interfaces.py | 2 +- .../{kadmelia => kademlia}/__init__.py | 0 .../kademlia_content_router.py} | 0 .../kademlia_peer_router.py} | 4 +++- 13 files changed, 48 insertions(+), 50 deletions(-) delete mode 100644 libp2p/kademlia/routed_host.py rename libp2p/routing/{kadmelia => kademlia}/__init__.py (100%) rename libp2p/routing/{kadmelia/kadmelia_content_router.py => kademlia/kademlia_content_router.py} (100%) rename libp2p/routing/{kadmelia/kadmelia_peer_router.py => kademlia/kademlia_peer_router.py} (85%) diff --git a/libp2p/__init__.py b/libp2p/__init__.py index 2e1cf88..faf8f13 100644 --- a/libp2p/__init__.py +++ b/libp2p/__init__.py @@ -10,6 +10,7 @@ from .kademlia.routed_host import RoutedHost from .transport.upgrader import TransportUpgrader from .transport.tcp.tcp import TCP from .kademlia.network import KademliaServer +from .routing.kademlia.kademlia_peer_router import KadmeliaPeerRouter async def cleanup_done_tasks(): @@ -31,7 +32,7 @@ def generate_id(): # private_key = new_key.exportKey("PEM") return new_id -def initialize_default_kademlia( +def initialize_default_kademlia_router( ksize=20, alpha=3, id_opt=None, storage=None): """ initialize swam when no swarm is passed in @@ -46,8 +47,9 @@ def initialize_default_kademlia( id_opt = generate_id() node_id = id_opt.get_raw_id() - return KademliaServer(ksize=ksize, alpha=alpha, - node_id=node_id, storage=storage) + server = KademliaServer(ksize=ksize, alpha=alpha, + node_id=node_id, storage=storage) + return KadmeliaPeerRouter(server) def initialize_default_swarm( @@ -105,12 +107,11 @@ async def new_node( muxer_opt=muxer_opt, sec_opt=sec_opt, peerstore_opt=peerstore_opt) + swarm_opt.add_router(disc_opt) + # TODO enable support for other host type # TODO routing unimplemented - if not disc_opt: - host = BasicHost(swarm_opt) - else: - host = RoutedHost(swarm_opt, disc_opt) + host = BasicHost(swarm_opt) # Kick off cleanup job asyncio.ensure_future(cleanup_done_tasks()) diff --git a/libp2p/host/basic_host.py b/libp2p/host/basic_host.py index 0c3bf0e..b85c413 100644 --- a/libp2p/host/basic_host.py +++ b/libp2p/host/basic_host.py @@ -11,21 +11,22 @@ from .host_interface import IHost class BasicHost(IHost): # default options constructor - def __init__(self, _network): - self.network = _network - self.peerstore = self.network.peerstore + def __init__(self, network, router=None): + self._network = network + self.peerstore = self._network.peerstore + self._router = router def get_id(self): """ :return: peer_id of host """ - return self.network.get_peer_id() + return self._network.get_peer_id() def get_network(self): """ :return: network instance of host """ - return self.network + return self._network def get_peerstore(self): """ @@ -45,7 +46,7 @@ class BasicHost(IHost): p2p_part = multiaddr.Multiaddr('/p2p/{}'.format(self.get_id().pretty())) addrs = [] - for transport in self.network.listeners.values(): + for transport in self._network.listeners.values(): for addr in transport.get_addrs(): addrs.append(addr.encapsulate(p2p_part)) return addrs @@ -57,7 +58,7 @@ class BasicHost(IHost): :param stream_handler: a stream handler function :return: true if successful """ - return self.network.set_stream_handler(protocol_id, stream_handler) + return self._network.set_stream_handler(protocol_id, stream_handler) # protocol_id can be a list of protocol_ids # stream will decide which protocol_id to run on @@ -67,7 +68,7 @@ class BasicHost(IHost): :param protocol_id: protocol id that stream runs on :return: true if successful """ - stream = await self.network.new_stream(peer_id, protocol_ids) + stream = await self._network.new_stream(peer_id, protocol_ids) return stream async def connect(self, peer_info): @@ -84,7 +85,7 @@ class BasicHost(IHost): self.peerstore.add_addrs(peer_info.peer_id, peer_info.addrs, 10) # there is already a connection to this peer - if peer_info.peer_id in self.network.connections: + if peer_info.peer_id in self._network.connections: return - await self.network.dial_peer(peer_info.peer_id) + await self._network.dial_peer(peer_info.peer_id) diff --git a/libp2p/kademlia/crawling.py b/libp2p/kademlia/crawling.py index 6a3b5fe..3fdfbc6 100644 --- a/libp2p/kademlia/crawling.py +++ b/libp2p/kademlia/crawling.py @@ -119,7 +119,7 @@ class ValueSpiderCrawl(SpiderCrawl): value_counts = Counter(values) if len(value_counts) != 1: log.warning("Got multiple values for key %i: %s", - self.node.long_id, str(values)) + self.node.xor_id, str(values)) value = value_counts.most_common(1)[0][0] peer = self.nearest_without_value.popleft() diff --git a/libp2p/kademlia/kad_peerinfo.py b/libp2p/kademlia/kad_peerinfo.py index fb40e3b..0d8c233 100644 --- a/libp2p/kademlia/kad_peerinfo.py +++ b/libp2p/kademlia/kad_peerinfo.py @@ -16,7 +16,7 @@ class KadPeerInfo(PeerInfo): super(KadPeerInfo, self).__init__(peer_id, peer_data) self.peer_id = peer_id.get_raw_id() - self.long_id = int(digest(peer_id.get_raw_id()).hex(), 16) + self.xor_id = peer_id.get_xor_id() self.addrs = peer_data.get_addrs() if peer_data else None @@ -34,7 +34,7 @@ class KadPeerInfo(PeerInfo): """ Get the distance between this node and another. """ - return self.long_id ^ node.long_id + return self.xor_id ^ node.xor_id def __iter__(self): """ @@ -43,7 +43,7 @@ class KadPeerInfo(PeerInfo): return iter([self.peer_id, self.ip, self.port]) def __repr__(self): - return repr([self.long_id, self.ip, self.port]) + return repr([self.xor_id, self.ip, self.port]) def __str__(self): return "%s:%s" % (self.ip, str(self.port)) diff --git a/libp2p/kademlia/network.py b/libp2p/kademlia/network.py index 86522ba..836d34a 100644 --- a/libp2p/kademlia/network.py +++ b/libp2p/kademlia/network.py @@ -67,7 +67,7 @@ class KademliaServer: listen = loop.create_datagram_endpoint(self._create_protocol, local_addr=(interface, port)) log.info("Node %i listening on %s:%i", - self.node.long_id, interface, port) + self.node.xor_id, interface, port) self.transport, self.protocol = await listen # finally, schedule refreshing table self.refresh_table() diff --git a/libp2p/kademlia/routed_host.py b/libp2p/kademlia/routed_host.py deleted file mode 100644 index 45fc0c6..0000000 --- a/libp2p/kademlia/routed_host.py +++ /dev/null @@ -1,21 +0,0 @@ -from libp2p.host.basic_host import BasicHost - -class RoutedHost(BasicHost): - def __init__(self, _network, _kad_network): - super(RoutedHost, self).__init__(_network) - self.kad_network = _kad_network - - def get_kad_network(self): - return self.kad_network - - def routed_listen(self, port, interface='0.0.0.0'): - return self.kad_network.listen(port, interface) - - def routed_get(self, key): - return self.kad_network.get(key) - - def routed_set(self, key, value): - return self.kad_network.set(key, value) - - def routed_set_digest(self, dkey, value): - return self.kad_network.set_digest(dkey, value) diff --git a/libp2p/kademlia/routing.py b/libp2p/kademlia/routing.py index 7d97494..b84717e 100644 --- a/libp2p/kademlia/routing.py +++ b/libp2p/kademlia/routing.py @@ -33,7 +33,7 @@ class KBucket: one = KBucket(self.range[0], midpoint, self.ksize) two = KBucket(midpoint + 1, self.range[1], self.ksize) for node in self.nodes.values(): - bucket = one if node.long_id <= midpoint else two + bucket = one if node.xor_id <= midpoint else two bucket.nodes[node.peer_id] = node return (one, two) @@ -48,7 +48,7 @@ class KBucket: self.nodes[newnode.peer_id] = newnode def has_in_range(self, node): - return self.range[0] <= node.long_id <= self.range[1] + return self.range[0] <= node.xor_id <= self.range[1] def is_new_node(self, node): return node.peer_id not in self.nodes @@ -175,7 +175,7 @@ class RoutingTable: Get the index of the bucket that the given node would fall into. """ for index, bucket in enumerate(self.buckets): - if node.long_id < bucket.range[1]: + if node.xor_id < bucket.range[1]: return index # we should never be here, but make linter happy return None diff --git a/libp2p/network/swarm.py b/libp2p/network/swarm.py index b30567b..4c0c128 100644 --- a/libp2p/network/swarm.py +++ b/libp2p/network/swarm.py @@ -20,6 +20,7 @@ class Swarm(INetwork): self.listeners = dict() self.stream_handlers = dict() self.transport = None + self.router = None # Protocol muxing self.multiselect = Multiselect() @@ -57,8 +58,10 @@ class Swarm(INetwork): if not addrs: raise SwarmException("No known addresses to peer") - # TODO: define logic to choose which address to use, or try them all ? - multiaddr = addrs[0] + if not self.router: + multiaddr = addrs[0] + else: + multiaddr = self.router.find_peer(peer_id) if peer_id in self.connections: # If muxed connection already exists for peer_id, @@ -187,6 +190,9 @@ class Swarm(INetwork): # TODO: Support more than one transport self.transport = transport + def add_router(self, router): + self.router = router + def create_generic_protocol_handler(swarm): """ Create a generic protocol handler from the given swarm. We use swarm diff --git a/libp2p/peer/id.py b/libp2p/peer/id.py index 92b4db3..f3b9647 100644 --- a/libp2p/peer/id.py +++ b/libp2p/peer/id.py @@ -1,5 +1,6 @@ import base58 import multihash +import hashlib # MaxInlineKeyLength is the maximum length a key can be for it to be inlined in # the peer ID. @@ -21,6 +22,9 @@ class ID: def pretty(self): return base58.b58encode(self._id_str).decode() + def get_xor_id(self): + return int(digest(self.get_raw_id()).hex(), 16) + def __str__(self): pid = self.pretty() if len(pid) <= 10: @@ -67,3 +71,8 @@ def id_from_public_key(key): def id_from_private_key(key): return id_from_public_key(key.publickey()) + +def digest(string): + if not isinstance(string, bytes): + string = str(string).encode('utf8') + return hashlib.sha1(string).digest() diff --git a/libp2p/routing/interfaces.py b/libp2p/routing/interfaces.py index 1f29d48..b519a09 100644 --- a/libp2p/routing/interfaces.py +++ b/libp2p/routing/interfaces.py @@ -28,4 +28,4 @@ class IPeerRouting(ABC): Find specific Peer FindPeer searches for a peer with given peer_id, returns a peer.PeerInfo with relevant addresses. - """ + """ \ No newline at end of file diff --git a/libp2p/routing/kadmelia/__init__.py b/libp2p/routing/kademlia/__init__.py similarity index 100% rename from libp2p/routing/kadmelia/__init__.py rename to libp2p/routing/kademlia/__init__.py diff --git a/libp2p/routing/kadmelia/kadmelia_content_router.py b/libp2p/routing/kademlia/kademlia_content_router.py similarity index 100% rename from libp2p/routing/kadmelia/kadmelia_content_router.py rename to libp2p/routing/kademlia/kademlia_content_router.py diff --git a/libp2p/routing/kadmelia/kadmelia_peer_router.py b/libp2p/routing/kademlia/kademlia_peer_router.py similarity index 85% rename from libp2p/routing/kadmelia/kadmelia_peer_router.py rename to libp2p/routing/kademlia/kademlia_peer_router.py index 27be67c..3a13f45 100644 --- a/libp2p/routing/kadmelia/kadmelia_peer_router.py +++ b/libp2p/routing/kademlia/kademlia_peer_router.py @@ -16,7 +16,9 @@ class KadmeliaPeerRouter(IPeerRouting): FindPeer searches for a peer with given peer_id, returns a peer.PeerInfo with relevant addresses. """ - value = self.server.get(peer_id) + # switching peer_id to xor_id used by kademlia as node_id + xor_id = peer_id.get_xor_id() + value = self.server.get(xor_id) return decode_peerinfo(value)