Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added RoutedHost #153

Merged
merged 5 commits into from
Apr 25, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 38 additions & 5 deletions libp2p/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,10 @@
from .peer.id import id_from_public_key
from .network.swarm import Swarm
from .host.basic_host import BasicHost
from .kademlia.routed_host import RoutedHost
from .transport.upgrader import TransportUpgrader
from .transport.tcp.tcp import TCP
from .kademlia.network import KademliaServer


async def cleanup_done_tasks():
Expand All @@ -23,6 +25,30 @@ async def cleanup_done_tasks():
# Some sleep necessary to context switch
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(
id_opt=None, transport_opt=None,
Expand All @@ -37,10 +63,9 @@ def initialize_default_swarm(
:return: return a default swarm instance
"""
# pylint: disable=too-many-arguments, unused-argument

if not id_opt:
new_key = RSA.generate(2048, e=65537)
id_opt = id_from_public_key(new_key.publickey())
# private_key = new_key.exportKey("PEM")
id_opt = generate_id()

transport_opt = transport_opt or ["/ip4/127.0.0.1/tcp/8001"]
transport = [multiaddr.Multiaddr(t) for t in transport_opt]
Expand All @@ -58,7 +83,8 @@ def initialize_default_swarm(

async def new_node(
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
:param id_opt: optional id for host
Expand All @@ -69,6 +95,10 @@ async def new_node(
:return: return a default swarm instance
"""
# pylint: disable=too-many-arguments

if not id_opt:
id_opt = generate_id()

if not swarm_opt:
swarm_opt = initialize_default_swarm(
id_opt=id_opt, transport_opt=transport_opt,
Expand All @@ -77,7 +107,10 @@ async def new_node(

# TODO enable support for other host type
# 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
asyncio.ensure_future(cleanup_done_tasks())
Expand Down
5 changes: 2 additions & 3 deletions libp2p/kademlia/kad_peerinfo.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,8 @@ class KadPeerInfo(PeerInfo):
def __init__(self, peer_id, peer_data=None):
super(KadPeerInfo, self).__init__(peer_id, peer_data)

# pylint: disable=protected-access
self.peer_id = peer_id._id_str
self.long_id = int(digest(peer_id._id_str).hex(), 16)
self.peer_id = peer_id.get_raw_id()
self.long_id = int(digest(peer_id.get_raw_id()).hex(), 16)

self.addrs = peer_data.get_addrs() if peer_data else None

Expand Down
4 changes: 2 additions & 2 deletions libp2p/kademlia/network.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@


# pylint: disable=too-many-instance-attributes
class Server:
class KademliaServer:
"""
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.
Expand Down Expand Up @@ -219,7 +219,7 @@ def load_state(cls, fname):
log.info("Loading state from %s", fname)
with open(fname, 'rb') as file:
data = pickle.load(file)
svr = Server(data['ksize'], data['alpha'], data['id'])
svr = KademliaServer(data['ksize'], data['alpha'], data['id'])
if data['neighbors']:
svr.bootstrap(data['neighbors'])
return svr
Expand Down
21 changes: 21 additions & 0 deletions libp2p/kademlia/routed_host.py
Original file line number Diff line number Diff line change
@@ -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)
3 changes: 3 additions & 0 deletions libp2p/peer/id.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@ class ID:
def __init__(self, id_str):
self._id_str = id_str

def get_raw_id(self):
return self._id_str

def pretty(self):
return base58.b58encode(self._id_str).decode()

Expand Down
14 changes: 7 additions & 7 deletions tests/kademlia/test_basic.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
import pytest
from libp2p.kademlia.network import Server
from libp2p.kademlia.network import KademliaServer


@pytest.mark.asyncio
async def test_example():
node_a = Server()
node_a = KademliaServer()
await node_a.listen(5678)

node_b = Server()
node_b = KademliaServer()
await node_b.listen(5679)

# Bootstrap the node by connecting to other known nodes, in this case
Expand All @@ -29,12 +29,12 @@ async def test_example():
@pytest.mark.asyncio
async def test_multiple_nodes_bootstrap_set_get(nodes_nr):

node_bootstrap = Server()
node_bootstrap = KademliaServer()
await node_bootstrap.listen(3000 + nodes_nr * 2)

nodes = []
for i in range(nodes_nr):
node = Server()
node = KademliaServer()
addrs = [("127.0.0.1", 3000 + nodes_nr * 2)]
await node.listen(3001 + i + nodes_nr * 2)
await node.bootstrap(addrs)
Expand All @@ -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.asyncio
async def test_multiple_nodes_set_bootstrap_get(nodes_nr):
node_bootstrap = Server()
node_bootstrap = KademliaServer()
await node_bootstrap.listen(2000 + nodes_nr * 2)

nodes = []
for i in range(nodes_nr):
node = Server()
node = KademliaServer()
addrs = [("127.0.0.1", 2000 + nodes_nr * 2)]
await node.listen(2001 + i + nodes_nr * 2)
await node.bootstrap(addrs)
Expand Down