dht

package
v0.1.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Mar 11, 2026 License: MIT Imports: 14 Imported by: 0

Documentation

Index

Constants

View Source
const (
	// Alpha is the Kademlia concurrency parameter.
	Alpha = 3

	// RefreshInterval is how often buckets are refreshed.
	RefreshInterval = 1 * time.Hour

	// RepublishInterval is how often stored data is republished.
	RepublishInterval = 1 * time.Hour
)
View Source
const (
	// IDLength is the length of a NodeID in bytes (160-bit SHA-1).
	IDLength = 20

	// IDBits is the length of a NodeID in bits.
	IDBits = IDLength * 8
)
View Source
const (
	// K is the Kademlia replication parameter (max nodes per bucket).
	K = 20

	// BucketCount is the number of k-buckets (one per bit of NodeID).
	BucketCount = IDBits
)
View Source
const DefaultPoWDifficulty = 16

DefaultPoWDifficulty is the default number of leading zero bits required for PoW.

View Source
const DefaultTTL = 1 * time.Hour

DefaultTTL is the default time-to-live for stored values.

View Source
const NostrDHTEventKind = 20005

NostrDHTEventKind is the Nostr event kind used for DHT RPC messages.

Variables

This section is empty.

Functions

func CommonPrefixLen

func CommonPrefixLen(a, b NodeID) int

CommonPrefixLen returns the number of leading zero bits in the XOR distance, which corresponds to the bucket index in the routing table.

func DefaultBootstrapNodes

func DefaultBootstrapNodes() []string

DefaultBootstrapNodes returns the default list of bootstrap nodes. These are well-known Nostr relay URLs that serve as initial entry points.

func Less

func Less(a, b NodeID) bool

Less returns true if distance a is less than distance b (as big-endian unsigned integers).

func MinePoW

func MinePoW(pubKey string, difficulty int) uint64

MinePoW finds a nonce such that ValidatePoW returns true for the given pubKey and difficulty. This is primarily useful for testing.

func ValidatePoW

func ValidatePoW(pubKey string, nonce uint64, difficulty int) bool

ValidatePoW checks that SHA256(pubKey + nonce) has at least `difficulty` leading zero bits.

Types

type BootstrapConfig

type BootstrapConfig struct {
	// Seeds are the addresses of seed nodes to contact.
	Seeds []string

	// NostrRelays are Nostr relays to use for DHT transport.
	NostrRelays []string
}

BootstrapConfig holds configuration for DHT bootstrapping.

type DHT

type DHT struct {
	// contains filtered or unexported fields
}

DHT implements a minimal Kademlia distributed hash table.

func NewDHT

func NewDHT(self NodeInfo, transport DHTTransport, logger *slog.Logger, keypair ...*coreidentity.Keypair) *DHT

NewDHT creates a new DHT node. An optional keypair can be provided for message signing and verification.

func (*DHT) Bootstrap

func (d *DHT) Bootstrap(ctx context.Context, seeds []NodeInfo) error

Bootstrap contacts seed nodes to populate the routing table.

func (*DHT) FindNode

func (d *DHT) FindNode(ctx context.Context, target NodeID) ([]NodeInfo, error)

FindNode performs an iterative Kademlia node lookup for the given target.

func (*DHT) Get

func (d *DHT) Get(ctx context.Context, key string) ([]byte, error)

Get retrieves a value from the DHT by key.

func (*DHT) LocalStore

func (d *DHT) LocalStore() *Store

Store returns the DHT local store.

func (*DHT) Put

func (d *DHT) Put(ctx context.Context, key string, value []byte) error

Put stores a value in the DHT. The value is stored locally and at the k closest nodes to the key.

func (*DHT) RoutingTable

func (d *DHT) RoutingTable() *RoutingTable

RoutingTable returns the DHT routing table.

func (*DHT) Self

func (d *DHT) Self() NodeInfo

Self returns the local node's info.

func (*DHT) Start

func (d *DHT) Start(ctx context.Context) error

Start begins the DHT background workers (refresh, republish, RPC handler).

func (*DHT) Stop

func (d *DHT) Stop() error

Stop shuts down the DHT.

type DHTTransport

type DHTTransport interface {
	SendRPC(ctx context.Context, target NodeInfo, msg RPCMessage) (*RPCResponse, error)
	Listen(ctx context.Context) (<-chan RPCMessage, error)
	Close() error
}

DHTTransport abstracts the network layer for DHT RPC communication.

type InMemoryTransport

type InMemoryTransport struct {
	// contains filtered or unexported fields
}

InMemoryTransport is a DHTTransport for testing that routes messages in-process.

func NewInMemoryTransport

func NewInMemoryTransport(self NodeInfo, logger *slog.Logger) *InMemoryTransport

NewInMemoryTransport creates a new in-memory transport for testing.

func (*InMemoryTransport) Close

func (t *InMemoryTransport) Close() error

Close closes the transport.

func (*InMemoryTransport) Connect

func (t *InMemoryTransport) Connect(other *InMemoryTransport)

Connect links two in-memory transports for bidirectional communication.

func (*InMemoryTransport) DeliverResponse

func (t *InMemoryTransport) DeliverResponse(target NodeInfo, resp *RPCResponse)

DeliverResponse sends a response back to the requester.

func (*InMemoryTransport) Listen

func (t *InMemoryTransport) Listen(ctx context.Context) (<-chan RPCMessage, error)

Listen returns the channel of incoming RPC messages.

func (*InMemoryTransport) SendRPC

func (t *InMemoryTransport) SendRPC(ctx context.Context, target NodeInfo, msg RPCMessage) (*RPCResponse, error)

SendRPC sends a message and waits for a response.

type NodeID

type NodeID [IDLength]byte

NodeID is a 160-bit identifier for a DHT node, derived from SHA-1 of the public key.

func NodeIDFromHex

func NodeIDFromHex(s string) (NodeID, error)

NodeIDFromHex parses a hex-encoded NodeID.

func NodeIDFromPublicKey

func NodeIDFromPublicKey(pubKey string) NodeID

NodeIDFromPublicKey derives a NodeID from an agent's public key string.

func XORDistance

func XORDistance(a, b NodeID) NodeID

XORDistance computes the XOR distance between two NodeIDs.

func (NodeID) Hex

func (id NodeID) Hex() string

Hex returns the hex-encoded string representation of the NodeID.

func (NodeID) IsZero

func (id NodeID) IsZero() bool

IsZero returns true if the NodeID is all zeros.

type NodeInfo

type NodeInfo struct {
	ID        NodeID    `json:"id"`
	PublicKey string    `json:"public_key"`
	Address   string    `json:"address,omitempty"`
	Relays    []string  `json:"relays,omitempty"`
	Nonce     uint64    `json:"nonce,omitempty"`
	LastSeen  time.Time `json:"last_seen"`
}

NodeInfo contains the identity and network information of a DHT node.

type NostrDHTTransport

type NostrDHTTransport struct {
	// contains filtered or unexported fields
}

NostrDHTTransport implements DHTTransport using Nostr ephemeral events. Uses event kind 20005, NIP-44 encryption, reusing the NostrTransport relay management pattern.

func NewNostrDHTTransport

func NewNostrDHTTransport(self NodeInfo, relayURLs []string, logger *slog.Logger) *NostrDHTTransport

NewNostrDHTTransport creates a new Nostr-based DHT transport.

func (*NostrDHTTransport) Close

func (t *NostrDHTTransport) Close() error

Close closes the transport and disconnects from relays.

func (*NostrDHTTransport) Listen

func (t *NostrDHTTransport) Listen(ctx context.Context) (<-chan RPCMessage, error)

Listen returns a channel of incoming DHT RPC messages.

func (*NostrDHTTransport) SendRPC

func (t *NostrDHTTransport) SendRPC(ctx context.Context, target NodeInfo, msg RPCMessage) (*RPCResponse, error)

SendRPC sends a DHT RPC message via Nostr relay and waits for a response.

type RPCMessage

type RPCMessage struct {
	Type      RPCType         `json:"type"`
	RequestID string          `json:"request_id"`
	Sender    NodeInfo        `json:"sender"`
	Target    NodeID          `json:"target,omitempty"` // For find_node/find_value
	Key       string          `json:"key,omitempty"`    // For store/find_value
	Value     json.RawMessage `json:"value,omitempty"`  // For store
	Signature string          `json:"signature,omitempty"`
}

RPCMessage is a DHT RPC request sent between nodes.

func (RPCMessage) SigningPayload

func (m RPCMessage) SigningPayload() []byte

SigningPayload returns the RPCMessage serialized without the Signature field, suitable for signing and verification.

type RPCResponse

type RPCResponse struct {
	RequestID string          `json:"request_id"`
	Sender    NodeInfo        `json:"sender"`
	Nodes     []NodeInfo      `json:"nodes,omitempty"` // For find_node
	Value     json.RawMessage `json:"value,omitempty"` // For find_value
	Found     bool            `json:"found,omitempty"` // For find_value
	Error     string          `json:"error,omitempty"`
	Signature string          `json:"signature,omitempty"`
}

RPCResponse is a DHT RPC response.

func (RPCResponse) SigningPayload

func (r RPCResponse) SigningPayload() []byte

SigningPayload returns the RPCResponse serialized without the Signature field, suitable for signing and verification.

type RPCType

type RPCType string

RPCType identifies the type of DHT RPC operation.

const (
	RPCPing      RPCType = "ping"
	RPCStore     RPCType = "store"
	RPCFindNode  RPCType = "find_node"
	RPCFindValue RPCType = "find_value"
)

type RoutingTable

type RoutingTable struct {
	// contains filtered or unexported fields
}

RoutingTable is a Kademlia routing table with BucketCount k-buckets.

func NewRoutingTable

func NewRoutingTable(self NodeID) *RoutingTable

NewRoutingTable creates a routing table for the given node.

func (*RoutingTable) AddNode

func (rt *RoutingTable) AddNode(node NodeInfo) bool

AddNode inserts or updates a node in the routing table. If PoW is required, the node must present a valid proof-of-work. If the appropriate bucket is full, the least-recently-seen node is pinged; if it does not respond, it is evicted and the new node is inserted.

func (*RoutingTable) AllNodes

func (rt *RoutingTable) AllNodes() []NodeInfo

AllNodes returns all nodes in the routing table.

func (*RoutingTable) BucketsNeedingRefresh

func (rt *RoutingTable) BucketsNeedingRefresh(maxAge time.Duration) []int

BucketsNeedingRefresh returns bucket indices that haven't been refreshed within the given duration.

func (*RoutingTable) FindClosest

func (rt *RoutingTable) FindClosest(target NodeID, count int) []NodeInfo

FindClosest returns the k closest nodes to the given target ID.

func (*RoutingTable) GetNode

func (rt *RoutingTable) GetNode(id NodeID) (NodeInfo, bool)

GetNode looks up a specific node by ID.

func (*RoutingTable) RemoveNode

func (rt *RoutingTable) RemoveNode(id NodeID) bool

RemoveNode removes a node from the routing table.

func (*RoutingTable) SelfID

func (rt *RoutingTable) SelfID() NodeID

SelfID returns the local node's ID.

func (*RoutingTable) SetPingFunc

func (rt *RoutingTable) SetPingFunc(fn func(ctx context.Context, node NodeInfo) bool)

SetPingFunc sets the function used to ping nodes when a bucket is full.

func (*RoutingTable) SetPoWRequired

func (rt *RoutingTable) SetPoWRequired(required bool, difficulty int)

SetPoWRequired enables or disables proof-of-work validation for new nodes.

func (*RoutingTable) Size

func (rt *RoutingTable) Size() int

Size returns the total number of nodes in the routing table.

type Store

type Store struct {
	// contains filtered or unexported fields
}

Store is a local key-value store for DHT data with TTL-based expiration.

func NewStore

func NewStore(opts ...StoreOption) *Store

NewStore creates a new empty DHT store.

func (*Store) CleanExpired

func (s *Store) CleanExpired() int

CleanExpired removes all expired entries.

func (*Store) Delete

func (s *Store) Delete(key string)

Delete removes a key from the store.

func (*Store) Get

func (s *Store) Get(key string) []byte

Get retrieves a value by key. Returns nil if not found or expired.

func (*Store) Has

func (s *Store) Has(key string) bool

Has checks if a key exists and is not expired.

func (*Store) Keys

func (s *Store) Keys() []string

Keys returns all non-expired keys.

func (*Store) LoadFromFile

func (s *Store) LoadFromFile(path string) error

LoadFromFile loads the store from a JSON file.

func (*Store) Put

func (s *Store) Put(key string, value []byte, ttl time.Duration, sender string) error

Put stores a value with a key and TTL. The sender parameter identifies the peer that is storing the value for per-peer quota enforcement. Returns an error if value exceeds size limits or sender has exceeded quota.

func (*Store) SaveToFile

func (s *Store) SaveToFile(path string) error

SaveToFile persists the store to a JSON file.

func (*Store) Size

func (s *Store) Size() int

Size returns the number of non-expired entries.

type StoreOption

type StoreOption func(*Store)

StoreOption configures a Store.

func WithMaxEntries

func WithMaxEntries(n int) StoreOption

WithMaxEntries sets the maximum number of entries in the store.

func WithMaxPerPeer

func WithMaxPerPeer(n int) StoreOption

WithMaxPerPeer sets the maximum number of entries a single peer can store.

func WithMaxValueSize

func WithMaxValueSize(n int) StoreOption

WithMaxValueSize sets the maximum size of a single stored value in bytes.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL