Intro
Installable via npm install --save libp2p-kad-dht
, it can also be used directly in the browser.
Download
The source is available for download from GitHub. Alternatively, you can install using npm:
$ npm install --save libp2p-kad-dht
You can then require()
libp2p-kad-dht as normal:
const libp2PKadDht = require('libp2p-kad-dht')
In the Browser
Libp2p-kad-dht should work in any ES2015 environment out of the box.
Usage:
<script type="text/javascript" src="index.js"></script>
The portable versions of libp2p-kad-dht, including index.js
and index.min.js
, are included in the /dist
folder. Libp2p-kad-dht can also be found on unpkg.com under
KadDHT
A DHT implementation modeled after Kademlia with S/Kademlia modifications.
Original implementation in go: https://github.com/libp2p/go-libp2p-kad-dht.
Parameters
sw: Switch
:libp2p-switch instanceoptions: object
:DHT options
instance
KadDHT.prototype.concurrency
concurrency: number
ALPHA concurrency at which each query path with run, defaults to 3
KadDHT.prototype.disjointPaths
disjointPaths: number
Number of disjoint query paths to use
This is set to kBucketSize
/2 per the S/Kademlia paper
KadDHT.prototype.datastore
datastore: Datastore
Reference to the datastore, uses an in-memory store if none given.
KadDHT.prototype.start
start(callback: function (Error)): void
Start listening to incoming connections.
Parameters
callback: function (Error)
:
Returns
void
KadDHT.prototype.stop
stop(callback: function (Error)): void
Stop accepting incoming connections and sending outgoing messages.
Parameters
callback: function (Error)
:
Returns
void
KadDHT.prototype.put
put(key: Buffer, value: Buffer, options: Object, callback: function (Error)): void
Store the given key/value pair in the DHT.
Parameters
Returns
void
KadDHT.prototype.get
get(key: Buffer, options: Object, callback: function (Error, Buffer)): void
Get the value to the given key. Times out after 1 minute.
Parameters
key: Buffer
:
Returns
void
KadDHT.prototype.getMany
getMany(key: Buffer, nvals: number, options: Object, callback: function (Error, Array<{from: PeerId, val: Buffer}>)): void
Get the n
values to the given key without sorting.
Parameters
Returns
void
KadDHT.prototype.getClosestPeers
getClosestPeers(key: Buffer, options: Object, callback: function (Error, Array<PeerId>)): void
Kademlia 'node lookup' operation.
Parameters
key: Buffer
:
Returns
void
KadDHT.prototype.getPublicKey
getPublicKey(peer: PeerId, callback: function (Error, PubKey)): void
Get the public key for the given peer id.
Parameters
peer: PeerId
:callback: function (Error, PubKey)
:
Returns
void
KadDHT.prototype.findPeerLocal
findPeerLocal(peer: PeerId, callback: function (Error, PeerInfo)): void
Look if we are connected to a peer with the given id.
Returns the PeerInfo
for it, if found, otherwise undefined
.
Parameters
peer: PeerId
:callback: function (Error, PeerInfo)
:
Returns
void
KadDHT.prototype.provide
provide(key: CID, callback: function (Error)): void
Announce to the network that we can provide given key's value.
Parameters
key: CID
:callback: function (Error)
:
Returns
void
KadDHT.prototype.findProviders
findProviders(key: CID, options: Object, callback: function (Error, Array<PeerInfo>)): void
Search the dht for up to K
providers of the given CID.
Parameters
Returns
void
RoutingTable
A wrapper around k-bucket
, to provide easy store and
retrival for peers.
Parameters
self: PeerId
:kBucketSize: number
:
instance
RoutingTable.prototype.find
find(peer: PeerId, callback: function (Error, PeerId)): void
Find a specific peer by id.
Parameters
peer: PeerId
:callback: function (Error, PeerId)
:
Returns
void
RoutingTable.prototype.closestPeer
closestPeer(key: Buffer, count: number): (PeerId | undefined)
Retrieve the closest peers to the given key.
Returns
(PeerId | undefined)
RoutingTable.prototype.closestPeers
closestPeers(key: Buffer, count: number): Array<PeerId>
Retrieve the count
-closest peers to the given key.
Returns
Array<PeerId>
xorCompare
Compare function to sort an array of elements which have a distance property which is the xor distance to a given element.
Returns
pathSize
Computes how many results to collect on each disjoint path, rounding up. This ensures that we look for at least one result per path.
Returns
Query
Divide peers up into disjoint paths (subqueries). Any peer can only be used once over all paths. Within each path, query peers from closest to farthest away.
Parameters
dht: DHT
:DHT instancekey: Buffer
:makePath: makePath
:Called to set up each disjoint path. Must return the query function.
Run
Manages a single run of the query.
Parameters
query: Query
:
instance
Run.prototype.execute
execute(peers: Array<PeerId>): Promise
Execute the run with the given initial set of peers.
Parameters
peers: Array<PeerId>
:
Returns
Run.prototype.executePaths
executePaths(paths: Array<Path>): Promise<void>
Execute all paths through the DHT.
Returns
Promise<void>
Run.prototype.workerQueue
workerQueue(path: Path): Promise<void>
Initialize the list of queried peers, then start a worker queue for the given path.
Parameters
path: Path
:
Returns
Promise<void>
Run.prototype.startWorker
startWorker(path: Path): Promise<void>
Create and start a worker queue for a particular path.
Parameters
path: Path
:
Returns
Promise<void>
Run.prototype.init
init(): Promise<void>
Initialize the list of closest peers we've queried - this is shared by all paths in the run.
Returns
Promise<void>
Run.prototype.continueQuerying
continueQuerying(worker: WorkerQueue): Promise<Boolean>
If we've queried K peers, and the remaining peers in the given worker
's queue
are all further from the key than the peers we've already queried, then we should
stop querying on that worker
.
Parameters
worker: WorkerQueue
:
PeerDistanceList
Maintains a list of peerIds sorted by distance from a DHT key.
Parameters
instance
PeerDistanceList.prototype.peers
peers
The peerIds in the list, in order of distance from the origin key
PeerDistanceList.prototype.add
add(peerId: PeerId, callback: function (Error)): void
Add a peerId to the list.
Parameters
peerId: PeerId
:callback: function (Error)
:
Returns
void
Path
Manages a single Path through the DHT.
Parameters
run: Run
:queryFunc: queryFunc
:
PeerQueue
PeerQueue is a heap that sorts its entries (PeerIds) by their xor distance to the inital provided key.
Parameters
from: Buffer
:The sha2-256 encoded peer id
stop
Stop the worker, optionally providing an error to pass to the worker's callback.
Parameters
err: Error
:
execute
Use the queue from async to keep concurrency
amount items running
per path.
Returns
Promise<void>
fill
Add peers to the worker queue until there are enough to satisfy the worker queue concurrency. Note that we don't want to take any more than those required to satisfy concurrency from the peers-to-query queue, because we always want to query the closest peers to the key first, and new peers are continously being added to the peers-to-query queue.
Network
Handle network operations for the dht
Parameters
self: KadDHT
:
instance
Network.prototype.start
start(callback: function (Error)): void
Start the network.
Parameters
callback: function (Error)
:
Returns
void
Network.prototype.stop
stop(callback: function (Error)): void
Stop all network activity.
Parameters
callback: function (Error)
:
Returns
void
protocolHandler
Handle incoming streams from the Switch, on the dht protocol.
Parameters
protocol: string
:conn: Connection
:
Returns
LimitedPeerList
Like PeerList but with a length restriction.
Parameters
limit: number
:
PeerList
A list of unique peer infos.
instance
PeerList.prototype.push
push(info: PeerInfo): bool
Add a new info. Returns true
if it was a new one
Parameters
info: PeerInfo
:
Returns
bool
PeerList.prototype.has
has(info: PeerInfo): bool
Check if this PeerInfo is already in here.
Parameters
info: PeerInfo
:
Returns
bool
Providers
This class manages known providers. A provider is a peer that we know to have the content for a given CID.
Every cleanupInterval
providers are checked if they
are still valid, i.e. younger than the provideValidity
.
If they are not, they are deleted.
To ensure the list survives restarts of the daemon, providers are stored in the datastore, but to ensure access is fast there is an LRU cache in front of that.
instance
Providers.prototype.cleanupInterval
cleanupInterval: number
How often invalid records are cleaned. (in seconds)
Providers.prototype.provideValidity
provideValidity: number
How long is a provider valid for. (in seconds)
Providers.prototype.addProvider
addProvider(cid: CID, provider: PeerId): Promise
Add a new provider for the given CID.
Parameters
cid: CID
:provider: PeerId
:
Returns
constructor
Parameters
dht: DHT
:options: object
:options.enabled: randomWalkOptions.enabled
:options.queriesPerPeriod: randomWalkOptions.queriesPerPeriod
:options.interval: randomWalkOptions.interval
:options.timeout: randomWalkOptions.timeout
:options.delay: randomWalkOptions.delay
:options.dht: DHT
:
start
Start the Random Walk process. This means running a number of queries every interval requesting random data. This is done to keep the dht healthy over time.
Returns
void