| Safe Haskell | None |
|---|---|
| Language | GHC2021 |
LibP2P.DHT
Description
DHT node state, RPC handler, and record/provider stores.
The DHTNode is the top-level coordinator for Kademlia DHT operations. It owns the routing table, record store, provider store, and handles both inbound (as handler) and outbound (dhtSendRequest) RPC.
The outbound sender is wired to the Switch by newDHTNode; it remains
a record field so tests can inject mocks without a real network.
Synopsis
- data DHTNode = DHTNode {
- dhtSwitch :: !Switch
- dhtRoutingTable :: !(TVar RoutingTable)
- dhtRecordStore :: !(TVar (Map ByteString DHTRecord))
- dhtProviderStore :: !(TVar (Map ByteString [ProviderEntry]))
- dhtLocalKey :: !DHTKey
- dhtLocalPeerId :: !PeerId
- dhtMode :: !DHTMode
- dhtValidator :: !Validator
- dhtStreams :: !(TVar (Map PeerId StreamIO))
- dhtSendRequest :: !(PeerId -> DHTMessage -> IO (Either String DHTMessage))
- data DHTMode
- data ProviderEntry = ProviderEntry {
- peProvider :: !PeerId
- peAddrs :: ![Multiaddr]
- peTimestamp :: !UTCTime
- data Validator = Validator {
- valValidate :: ByteString -> ByteString -> Either String ()
- valSelect :: ByteString -> [ByteString] -> Either String Int
- defaultValidator :: Validator
- namespacedValidator :: Map ByteString Validator -> Validator
- pkValidator :: Validator
- newDHTNode :: Switch -> DHTMode -> IO DHTNode
- registerDHTHandler :: DHTNode -> IO ()
- handleDHTRequest :: DHTNode -> StreamIO -> PeerId -> IO ()
- addPeerToTable :: DHTNode -> BucketEntry -> IO InsertResult
- storeRecord :: DHTNode -> DHTRecord -> IO ()
- lookupRecord :: DHTNode -> ByteString -> IO (Maybe DHTRecord)
- addProvider :: DHTNode -> ByteString -> ProviderEntry -> IO ()
- getProviders :: DHTNode -> ByteString -> IO [ProviderEntry]
- decodePeerAddrs :: [ByteString] -> [Multiaddr]
- dhtProtocolId :: Text
- providerRecordTTL :: NominalDiffTime
Types
Top-level DHT node state.
Constructors
| DHTNode | |
Fields
| |
Server or client mode.
data ProviderEntry Source #
A provider record for content routing.
Constructors
| ProviderEntry | |
Fields
| |
Instances
| Show ProviderEntry Source # | |
Defined in LibP2P.DHT Methods showsPrec :: Int -> ProviderEntry -> ShowS # show :: ProviderEntry -> String # showList :: [ProviderEntry] -> ShowS # | |
| Eq ProviderEntry Source # | |
Defined in LibP2P.DHT Methods (==) :: ProviderEntry -> ProviderEntry -> Bool # (/=) :: ProviderEntry -> ProviderEntry -> Bool # | |
Validator interface for record validation.
valValidate checks that a value is well-formed for its key and
returns an error for records that must not be stored or served.
valSelect picks the index of the best value among conflicting
candidates for the same key (used for GET_VALUE conflict resolution).
Constructors
| Validator | |
Fields
| |
Validators
defaultValidator :: Validator Source #
The default validator set: pk records only. Additional
namespaces can be registered by building a custom
namespacedValidator and storing it in the DHT node.
namespacedValidator :: Map ByteString Validator -> Validator Source #
Dispatch validation by key namespace. Keys without a registered namespace are rejected, matching go-libp2p's namespaced validator ("invalid record keytype").
pkValidator :: Validator Source #
Validator for the pk namespace: the value must be a serialized
PublicKey protobuf whose derived Peer ID equals the multihash in the
key path. Public keys never conflict, so valSelect keeps the first
candidate (go-libp2p's record.PublicKeyValidator does the same).
Construction
newDHTNode :: Switch -> DHTMode -> IO DHTNode Source #
Create a new DHT node with the outbound sender wired to the Switch.
Handler registration
registerDHTHandler :: DHTNode -> IO () Source #
Register the DHT handler on the Switch.
Per specs/kad-dht (client and server mode), nodes operating in client
mode do not offer the Kademlia protocol identifier for incoming
streams, so this is a no-op for DHTClient nodes: they keep issuing
outbound queries via dhtSendRequest but never serve inbound RPC.
Inbound RPC handler
handleDHTRequest :: DHTNode -> StreamIO -> PeerId -> IO () Source #
Handle an inbound DHT stream.
Per specs/kad-dht, implementations must handle additional RPC request messages on the same incoming stream: go-libp2p keeps one long-lived stream per peer and pipelines requests over it. Loop until the stream errors, is reset, or reaches EOF.
Routing table maintenance
addPeerToTable :: DHTNode -> BucketEntry -> IO InsertResult Source #
Insert a peer into the routing table, applying the Kademlia full-bucket eviction policy.
When the target bucket is full, the least-recently-seen peer is
probed with a FIND_NODE request (the DHT liveness check; our
MessageType has no PING, and go-libp2p likewise treats any
successful RPC as proof of liveness):
- if the LRS peer answers, it is kept (refreshed to
most-recently-seen) and the new peer is dropped (
BucketFull); - if it does not answer, it is evicted and the new peer takes its
place (
Inserted).
Store operations
lookupRecord :: DHTNode -> ByteString -> IO (Maybe DHTRecord) Source #
Look up a record by key.
addProvider :: DHTNode -> ByteString -> ProviderEntry -> IO () Source #
Add a provider entry for a content key.
A provider republishing on schedule replaces its previous entry (deduplicated by peer ID) instead of appending a duplicate, so the entry's timestamp is refreshed and GET_PROVIDERS responses stay bounded.
getProviders :: DHTNode -> ByteString -> IO [ProviderEntry] Source #
Get providers for a content key, pruning entries older than
providerRecordTTL (48h expiration interval per specs/kad-dht).
Wire helpers
decodePeerAddrs :: [ByteString] -> [Multiaddr] Source #
Decode raw wire multiaddrs from a Peer record, dropping any that fail to parse: a malformed address from a remote peer must not poison the rest of the record.
Constants
dhtProtocolId :: Text Source #
DHT protocol identifier for multistream-select.
providerRecordTTL :: NominalDiffTime Source #
Provider record expiration interval, per specs/kad-dht (48 hours).
Expired entries are pruned on read in getProviders.