Merge pull request #153 from libp2p/routed-host

Added RoutedHost
This commit is contained in:
Alex Haynes 2019-04-24 21:12:15 -04:00 committed by GitHub
commit fc4fc74b87
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 73 additions and 17 deletions

View File

@ -6,8 +6,10 @@ from .peer.peerstore import PeerStore
from .peer.id import id_from_public_key from .peer.id import id_from_public_key
from .network.swarm import Swarm from .network.swarm import Swarm
from .host.basic_host import BasicHost from .host.basic_host import BasicHost
from .kademlia.routed_host import RoutedHost
from .transport.upgrader import TransportUpgrader from .transport.upgrader import TransportUpgrader
from .transport.tcp.tcp import TCP from .transport.tcp.tcp import TCP
from .kademlia.network import KademliaServer
async def cleanup_done_tasks(): async def cleanup_done_tasks():
@ -23,6 +25,30 @@ async def cleanup_done_tasks():
# Some sleep necessary to context switch # Some sleep necessary to context switch
await asyncio.sleep(3) await asyncio.sleep(3)
def generate_id():
new_key = RSA.generate(2048, e=65537)
new_id = id_from_public_key(new_key.publickey())
# private_key = new_key.exportKey("PEM")
return new_id
def initialize_default_kademlia(
ksize=20, alpha=3, id_opt=None, storage=None):
"""
initialize swam when no swarm is passed in
:param ksize: The k parameter from the paper
:param alpha: The alpha parameter from the paper
:param id_opt: optional id for host
:param storage: An instance that implements
:interface:`~kademlia.storage.IStorage`
:return: return a default kademlia instance
"""
if not id_opt:
id_opt = generate_id()
node_id = id_opt.get_raw_id()
return KademliaServer(ksize=ksize, alpha=alpha,
node_id=node_id, storage=storage)
def initialize_default_swarm( def initialize_default_swarm(
id_opt=None, transport_opt=None, id_opt=None, transport_opt=None,
@ -37,10 +63,9 @@ def initialize_default_swarm(
:return: return a default swarm instance :return: return a default swarm instance
""" """
# pylint: disable=too-many-arguments, unused-argument # pylint: disable=too-many-arguments, unused-argument
if not id_opt: if not id_opt:
new_key = RSA.generate(2048, e=65537) id_opt = generate_id()
id_opt = id_from_public_key(new_key.publickey())
# private_key = new_key.exportKey("PEM")
transport_opt = transport_opt or ["/ip4/127.0.0.1/tcp/8001"] transport_opt = transport_opt or ["/ip4/127.0.0.1/tcp/8001"]
transport = [multiaddr.Multiaddr(t) for t in transport_opt] transport = [multiaddr.Multiaddr(t) for t in transport_opt]
@ -58,7 +83,8 @@ def initialize_default_swarm(
async def new_node( async def new_node(
swarm_opt=None, id_opt=None, transport_opt=None, swarm_opt=None, id_opt=None, transport_opt=None,
muxer_opt=None, sec_opt=None, peerstore_opt=None): muxer_opt=None, sec_opt=None, peerstore_opt=None,
disc_opt=None):
""" """
create new libp2p node create new libp2p node
:param id_opt: optional id for host :param id_opt: optional id for host
@ -69,6 +95,10 @@ async def new_node(
:return: return a default swarm instance :return: return a default swarm instance
""" """
# pylint: disable=too-many-arguments # pylint: disable=too-many-arguments
if not id_opt:
id_opt = generate_id()
if not swarm_opt: if not swarm_opt:
swarm_opt = initialize_default_swarm( swarm_opt = initialize_default_swarm(
id_opt=id_opt, transport_opt=transport_opt, id_opt=id_opt, transport_opt=transport_opt,
@ -77,7 +107,10 @@ async def new_node(
# TODO enable support for other host type # TODO enable support for other host type
# TODO routing unimplemented # TODO routing unimplemented
host = BasicHost(swarm_opt) if not disc_opt:
host = BasicHost(swarm_opt)
else:
host = RoutedHost(swarm_opt, disc_opt)
# Kick off cleanup job # Kick off cleanup job
asyncio.ensure_future(cleanup_done_tasks()) asyncio.ensure_future(cleanup_done_tasks())

View File

@ -15,9 +15,8 @@ class KadPeerInfo(PeerInfo):
def __init__(self, peer_id, peer_data=None): def __init__(self, peer_id, peer_data=None):
super(KadPeerInfo, self).__init__(peer_id, peer_data) super(KadPeerInfo, self).__init__(peer_id, peer_data)
# pylint: disable=protected-access self.peer_id = peer_id.get_raw_id()
self.peer_id = peer_id._id_str self.long_id = int(digest(peer_id.get_raw_id()).hex(), 16)
self.long_id = int(digest(peer_id._id_str).hex(), 16)
self.addrs = peer_data.get_addrs() if peer_data else None self.addrs = peer_data.get_addrs() if peer_data else None

View File

@ -16,7 +16,7 @@ log = logging.getLogger(__name__) # pylint: disable=invalid-name
# pylint: disable=too-many-instance-attributes # pylint: disable=too-many-instance-attributes
class Server: class KademliaServer:
""" """
High level view of a node instance. This is the object that should be High level view of a node instance. This is the object that should be
created to start listening as an active node on the network. created to start listening as an active node on the network.
@ -219,7 +219,7 @@ class Server:
log.info("Loading state from %s", fname) log.info("Loading state from %s", fname)
with open(fname, 'rb') as file: with open(fname, 'rb') as file:
data = pickle.load(file) data = pickle.load(file)
svr = Server(data['ksize'], data['alpha'], data['id']) svr = KademliaServer(data['ksize'], data['alpha'], data['id'])
if data['neighbors']: if data['neighbors']:
svr.bootstrap(data['neighbors']) svr.bootstrap(data['neighbors'])
return svr return svr

View File

@ -0,0 +1,21 @@
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)

View File

@ -15,6 +15,9 @@ class ID:
def __init__(self, id_str): def __init__(self, id_str):
self._id_str = id_str self._id_str = id_str
def get_raw_id(self):
return self._id_str
def pretty(self): def pretty(self):
return base58.b58encode(self._id_str).decode() return base58.b58encode(self._id_str).decode()

View File

@ -1,13 +1,13 @@
import pytest import pytest
from libp2p.kademlia.network import Server from libp2p.kademlia.network import KademliaServer
@pytest.mark.asyncio @pytest.mark.asyncio
async def test_example(): async def test_example():
node_a = Server() node_a = KademliaServer()
await node_a.listen(5678) await node_a.listen(5678)
node_b = Server() node_b = KademliaServer()
await node_b.listen(5679) await node_b.listen(5679)
# Bootstrap the node by connecting to other known nodes, in this case # Bootstrap the node by connecting to other known nodes, in this case
@ -29,12 +29,12 @@ async def test_example():
@pytest.mark.asyncio @pytest.mark.asyncio
async def test_multiple_nodes_bootstrap_set_get(nodes_nr): async def test_multiple_nodes_bootstrap_set_get(nodes_nr):
node_bootstrap = Server() node_bootstrap = KademliaServer()
await node_bootstrap.listen(3000 + nodes_nr * 2) await node_bootstrap.listen(3000 + nodes_nr * 2)
nodes = [] nodes = []
for i in range(nodes_nr): for i in range(nodes_nr):
node = Server() node = KademliaServer()
addrs = [("127.0.0.1", 3000 + nodes_nr * 2)] addrs = [("127.0.0.1", 3000 + nodes_nr * 2)]
await node.listen(3001 + i + nodes_nr * 2) await node.listen(3001 + i + nodes_nr * 2)
await node.bootstrap(addrs) await node.bootstrap(addrs)
@ -56,12 +56,12 @@ async def test_multiple_nodes_bootstrap_set_get(nodes_nr):
@pytest.mark.parametrize("nodes_nr", [(2**i) for i in range(2, 5)]) @pytest.mark.parametrize("nodes_nr", [(2**i) for i in range(2, 5)])
@pytest.mark.asyncio @pytest.mark.asyncio
async def test_multiple_nodes_set_bootstrap_get(nodes_nr): async def test_multiple_nodes_set_bootstrap_get(nodes_nr):
node_bootstrap = Server() node_bootstrap = KademliaServer()
await node_bootstrap.listen(2000 + nodes_nr * 2) await node_bootstrap.listen(2000 + nodes_nr * 2)
nodes = [] nodes = []
for i in range(nodes_nr): for i in range(nodes_nr):
node = Server() node = KademliaServer()
addrs = [("127.0.0.1", 2000 + nodes_nr * 2)] addrs = [("127.0.0.1", 2000 + nodes_nr * 2)]
await node.listen(2001 + i + nodes_nr * 2) await node.listen(2001 + i + nodes_nr * 2)
await node.bootstrap(addrs) await node.bootstrap(addrs)