Installation
The easiest (and best) way to install kademlia is through pip:
$ pip install kademlia
Usage
To start a new network, create the first node. Future nodes will connect to this first node (and any other nodes you know about) to create the network.
import argparse
import asyncio
import logging
from kademlia.network import Server
handler = logging.StreamHandler()
formatter = logging.Formatter("%(asctime)s - %(name)s - %(levelname)s - %(message)s")
handler.setFormatter(formatter)
log = logging.getLogger("kademlia")
log.addHandler(handler)
log.setLevel(logging.DEBUG)
server = Server()
def parse_arguments():
parser = argparse.ArgumentParser()
# Optional arguments
parser.add_argument(
"-i", "--ip", help="IP address of existing node", type=str, default=None
)
parser.add_argument(
"-p", "--port", help="port number of existing node", type=int, default=None
)
return parser.parse_args()
def connect_to_bootstrap_node(args):
loop = asyncio.get_event_loop()
loop.set_debug(True)
loop.run_until_complete(server.listen(8469))
bootstrap_node = (args.ip, int(args.port))
loop.run_until_complete(server.bootstrap([bootstrap_node]))
try:
loop.run_forever()
except KeyboardInterrupt:
pass
finally:
server.stop()
loop.close()
def create_bootstrap_node():
loop = asyncio.get_event_loop()
loop.set_debug(True)
loop.run_until_complete(server.listen(8468))
try:
loop.run_forever()
except KeyboardInterrupt:
pass
finally:
server.stop()
loop.close()
def main():
args = parse_arguments()
if args.ip and args.port:
connect_to_bootstrap_node(args)
else:
create_bootstrap_node()
if __name__ == "__main__":
main()
Here’s an example of bootstrapping a new node against a known node and then setting a value:
import asyncio
import logging
import sys
from kademlia.network import Server
if len(sys.argv) != 5:
print("Usage: python set.py <bootstrap node> <bootstrap port> <key> <value>")
sys.exit(1)
handler = logging.StreamHandler()
formatter = logging.Formatter("%(asctime)s - %(name)s - %(levelname)s - %(message)s")
handler.setFormatter(formatter)
log = logging.getLogger("kademlia")
log.addHandler(handler)
log.setLevel(logging.DEBUG)
async def run():
server = Server()
await server.listen(8469)
bootstrap_node = (sys.argv[1], int(sys.argv[2]))
await server.bootstrap([bootstrap_node])
await server.set(sys.argv[3], sys.argv[4])
server.stop()
asyncio.run(run())
Note
You must have at least two nodes running to store values. If a node tries to store a value and there are no other nodes to provide redundancy, then it is an exception state.
Running Tests
To run tests:
$ pip install -r dev-requirements.txt
$ pytest
Fidelity to Original Paper
The current implementation should be an accurate implementation of all aspects of the paper except one - in Section 2.3 there is the requirement that the original publisher of a key/value republish it every 24 hours. This library does not do this (though you can easily do this manually).