added changes from future commits to last passing bmuller commit

This commit is contained in:
Alex Haynes
2019-04-17 20:21:59 -04:00
parent c5289952ee
commit d5c7cc7cb7
9 changed files with 115 additions and 12 deletions

View File

@ -13,7 +13,7 @@ install:
script: script:
- pytest --cov=./libp2p tests/ - pytest --cov=./libp2p tests/
- pylint --rcfile=.pylintrc libp2p/!(kademlia) tests - pylint --rcfile=.pylintrc libp2p tests
after_success: after_success:
- codecov - codecov

View File

@ -15,6 +15,7 @@ class SpiderCrawl:
""" """
def __init__(self, protocol, node, peers, ksize, alpha): def __init__(self, protocol, node, peers, ksize, alpha):
# pylint: disable=too-many-arguments
""" """
Create a new C{SpiderCrawl}er. Create a new C{SpiderCrawl}er.
@ -71,6 +72,7 @@ class SpiderCrawl:
class ValueSpiderCrawl(SpiderCrawl): class ValueSpiderCrawl(SpiderCrawl):
def __init__(self, protocol, node, peers, ksize, alpha): def __init__(self, protocol, node, peers, ksize, alpha):
# pylint: disable=too-many-arguments
SpiderCrawl.__init__(self, protocol, node, peers, ksize, alpha) SpiderCrawl.__init__(self, protocol, node, peers, ksize, alpha)
# keep track of the single nearest node without value - per # keep track of the single nearest node without value - per
# section 2.3 so we can set the key there if found # section 2.3 so we can set the key there if found

View File

@ -12,6 +12,15 @@ log = logging.getLogger(__name__) # pylint: disable=invalid-name
class KademliaProtocol(RPCProtocol): class KademliaProtocol(RPCProtocol):
"""
There are four main RPCs in the Kademlia protocol
PING, STORE, FIND_NODE, FIND_VALUE
PING probes if a node is still online
STORE instructs a node to store (key, value)
FIND_NODE takes a 160-bit ID and gets back
(ip, udp_port, node_id) for k closest nodes to target
FIND_VALUE behaves like FIND_NODE unless a value is stored
"""
def __init__(self, source_node, storage, ksize): def __init__(self, source_node, storage, ksize):
RPCProtocol.__init__(self) RPCProtocol.__init__(self)
self.router = RoutingTable(self, ksize, source_node) self.router = RoutingTable(self, ksize, source_node)
@ -28,6 +37,12 @@ class KademliaProtocol(RPCProtocol):
ids.append(rid) ids.append(rid)
return ids return ids
def rpc_add_provider(self, sender, nodeid, key):
pass
def rpc_get_providers(self, sender, nodeid, key):
pass
def rpc_stun(self, sender): # pylint: disable=no-self-use def rpc_stun(self, sender): # pylint: disable=no-self-use
return sender return sender

View File

@ -8,6 +8,13 @@ from .utils import OrderedSet, shared_prefix, bytes_to_bit_string
class KBucket: class KBucket:
"""
each node keeps a list of (ip, udp_port, node_id)
for nodes of distance between 2^i and 2^(i+1)
this list that every node keeps is a k-bucket
each k-bucket implements a last seen eviction
policy except that live nodes are never removed
"""
def __init__(self, rangeLower, rangeUpper, ksize): def __init__(self, rangeLower, rangeUpper, ksize):
self.range = (rangeLower, rangeUpper) self.range = (rangeLower, rangeUpper)
self.nodes = OrderedDict() self.nodes = OrderedDict()

78
libp2p/kademlia/rpc.proto Normal file
View File

@ -0,0 +1,78 @@
// Record represents a dht record that contains a value
// for a key value pair
message Record {
// The key that references this record
bytes key = 1;
// The actual value this record is storing
bytes value = 2;
// Note: These fields were removed from the Record message
// hash of the authors public key
//optional string author = 3;
// A PKI signature for the key+value+author
//optional bytes signature = 4;
// Time the record was received, set by receiver
string timeReceived = 5;
};
message Message {
enum MessageType {
PUT_VALUE = 0;
GET_VALUE = 1;
ADD_PROVIDER = 2;
GET_PROVIDERS = 3;
FIND_NODE = 4;
PING = 5;
}
enum ConnectionType {
// sender does not have a connection to peer, and no extra information (default)
NOT_CONNECTED = 0;
// sender has a live connection to peer
CONNECTED = 1;
// sender recently connected to peer
CAN_CONNECT = 2;
// sender recently tried to connect to peer repeatedly but failed to connect
// ("try" here is loose, but this should signal "made strong effort, failed")
CANNOT_CONNECT = 3;
}
message Peer {
// ID of a given peer.
bytes id = 1;
// multiaddrs for a given peer
repeated bytes addrs = 2;
// used to signal the sender's connection capabilities to the peer
ConnectionType connection = 3;
}
// defines what type of message it is.
MessageType type = 1;
// defines what coral cluster level this query/response belongs to.
// in case we want to implement coral's cluster rings in the future.
int32 clusterLevelRaw = 10; // NOT USED
// Used to specify the key associated with this message.
// PUT_VALUE, GET_VALUE, ADD_PROVIDER, GET_PROVIDERS
bytes key = 2;
// Used to return a value
// PUT_VALUE, GET_VALUE
Record record = 3;
// Used to return peers closer to a key in a query
// GET_VALUE, GET_PROVIDERS, FIND_NODE
repeated Peer closerPeers = 8;
// Used to return Providers
// GET_VALUE, ADD_PROVIDER, GET_PROVIDERS
repeated Peer providerPeers = 9;
}

View File

@ -33,7 +33,7 @@ class IStorage(ABC):
def iter_older_than(self, seconds_old): def iter_older_than(self, seconds_old):
""" """
Return the an iterator over (key, value) tuples for items older Return the an iterator over (key, value) tuples for items older
than the given secondsOld. than the given seconds_old.
""" """
@abstractmethod @abstractmethod

View File

@ -9,6 +9,8 @@ class KadmeliaContentRouter(IContentRouting):
it also announces it, otherwise it is just kept in the local it also announces it, otherwise it is just kept in the local
accounting of which objects are being provided. accounting of which objects are being provided.
""" """
# the DHT finds the closest peers to `key` using the `FIND_NODE` RPC
# then sends a `ADD_PROVIDER` RPC with its own `PeerInfo` to each of these peers.
pass pass
def find_provider_iter(self, cid, count): def find_provider_iter(self, cid, count):

View File

@ -5,6 +5,7 @@ from libp2p.peer.peerdata import PeerData
class KadmeliaPeerRouter(IPeerRouting): class KadmeliaPeerRouter(IPeerRouting):
# pylint: disable=too-few-public-methods
def __init__(self, dht_server): def __init__(self, dht_server):
self.server = dht_server self.server = dht_server

View File

@ -1,5 +1,6 @@
import pytest import pytest
from libp2p.kademlia.network import Server from libp2p.kademlia.network import Server
import math
@pytest.mark.asyncio @pytest.mark.asyncio
@ -28,16 +29,15 @@ async def test_example():
@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_bootstrap_set_get(nodes_nr): async def test_multiple_nodes_bootstrap_set_get(nodes_nr):
nodes_nr = 25
node_bootstrap = Server() node_bootstrap = Server()
await node_bootstrap.listen(5678) await node_bootstrap.listen(1000 + nodes_nr * 2)
nodes = [] nodes = []
for i in range(nodes_nr): for i in range(nodes_nr):
node = Server() node = Server()
addrs = [("127.0.0.1", 5678)] addrs = [("127.0.0.1", 1000 + nodes_nr * 2)]
await node.listen(5679 + i) await node.listen(1001 + i + nodes_nr * 2)
await node.bootstrap(addrs) await node.bootstrap(addrs)
nodes.append(node) nodes.append(node)
@ -57,16 +57,14 @@ 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):
nodes_nr = 25
node_bootstrap = Server() node_bootstrap = Server()
await node_bootstrap.listen(5678) 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 = Server()
addrs = [("127.0.0.1", 5678)] addrs = [("127.0.0.1", 2000 + nodes_nr * 2)]
await node.listen(5679 + i) await node.listen(2001 + i + nodes_nr * 2)
await node.bootstrap(addrs) await node.bootstrap(addrs)
value = "my awesome value %d" % i value = "my awesome value %d" % i