Documentation
¶
Index ¶
- Constants
- Variables
- func ObservedAddr(from net.Addr) []byte
- type BootstrapSeed
- type Config
- type Node
- func (n *Node) AddContact(addr net.Addr, ni protocol.NodeInfo)
- func (n *Node) Address() a2al.Address
- func (n *Node) BindPeerAddr(id a2al.NodeID, addr net.Addr)
- func (n *Node) Bootstrap(ctx context.Context, seeds []BootstrapSeed) error
- func (n *Node) BootstrapAddrs(ctx context.Context, addrs []net.Addr) error
- func (n *Node) BootstrapCandidateAddrs(max int) []net.Addr
- func (n *Node) Close() error
- func (n *Node) DebugHTTPHandler() http.Handler
- func (n *Node) FindNode(ctx context.Context, peer net.Addr, target a2al.NodeID) ([]protocol.NodeInfo, error)
- func (n *Node) FindValue(ctx context.Context, peer net.Addr, key a2al.NodeID) (*protocol.SignedRecord, error)
- func (n *Node) FindValueWithNodes(ctx context.Context, peer net.Addr, key a2al.NodeID, recType uint8) ([]protocol.SignedRecord, []protocol.NodeInfo, error)
- func (n *Node) LocalAddr() net.Addr
- func (n *Node) NodeID() a2al.NodeID
- func (n *Node) Ping(ctx context.Context, peer net.Addr) error
- func (n *Node) PingIdentity(ctx context.Context, peer net.Addr) (*PeerIdentity, error)
- func (n *Node) PublishEndpointRecord(ctx context.Context, rec protocol.SignedRecord) error
- func (n *Node) PublishMailboxRecord(ctx context.Context, storeKey a2al.NodeID, rec protocol.SignedRecord) error
- func (n *Node) PublishTopicRecord(ctx context.Context, storeKey a2al.NodeID, rec protocol.SignedRecord) error
- func (n *Node) SetSelfExtIP(ip net.IP)
- func (n *Node) Start()
- func (n *Node) StartDebugHTTP(addr string) (stop func(), err error)
- func (n *Node) StartWithBootstrap(ctx context.Context, addrs []net.Addr) error
- func (n *Node) StoreAt(ctx context.Context, peer net.Addr, storeKey a2al.NodeID, ...) (bool, error)
- type PeerIdentity
- type Query
- func (q *Query) AggregateRecords(ctx context.Context, target a2al.NodeID, recType uint8) ([]protocol.SignedRecord, error)
- func (q *Query) FindNode(ctx context.Context, target a2al.NodeID) ([]protocol.NodeInfo, error)
- func (q *Query) FindRecords(ctx context.Context, target a2al.NodeID, recType uint8) ([]protocol.SignedRecord, error)
- func (q *Query) Resolve(ctx context.Context, target a2al.NodeID) (*protocol.EndpointRecord, error)
- type RecordAuthFunc
- type Store
- func (s *Store) DebugRecords(now time.Time) []StoreRecordDebug
- func (s *Store) Get(key a2al.NodeID, now time.Time) *protocol.SignedRecord
- func (s *Store) GetAll(key a2al.NodeID, recType uint8, now time.Time) []protocol.SignedRecord
- func (s *Store) Len() int
- func (s *Store) Put(key a2al.NodeID, rec protocol.SignedRecord, now time.Time) error
- type StoreRecordDebug
Constants ¶
const ( DefaultAlpha = 3 DefaultStagger = 5 * time.Millisecond )
const DebugHTTPAddr = "127.0.0.1:2634"
DebugHTTPAddr is a suggested address for StartDebugHTTP when embedding the dht package directly (without a2ald). The daemon serves /debug/* on its own API port.
const (
DefaultMaxTotalKeys = 100_000
)
Variables ¶
var ErrNoEndpoint = errors.New("dht: no endpoint record")
ErrNoEndpoint is returned when iterative FIND_VALUE does not yield a valid endpoint record.
var ErrNoMatchingRecords = errors.New("dht: no matching records")
ErrNoMatchingRecords is returned when FindRecords finds nothing for the filter.
var ErrStaleRecord = errors.New("dht: stale record")
ErrStaleRecord means an equal or older record already exists for the same slot.
Functions ¶
func ObservedAddr ¶
ObservedAddr encodes remote IP:port for PONG / FIND_*_RESP (spec §7.6).
Types ¶
type BootstrapSeed ¶
BootstrapSeed is a known dial address plus wire NodeInfo (legacy; prefer BootstrapAddrs).
type Config ¶
type Config struct {
Transport transport.Transport
Keystore crypto.KeyStore
// OnObservedAddr is called whenever a DHT response carries an observed_addr
// (PONG, FIND_NODE_RESP, FIND_VALUE_RESP). reporter is the responding node's
// NodeID; wire is the raw observed_addr bytes (6 or 18 bytes).
// May be nil.
OnObservedAddr func(reporter a2al.NodeID, wire []byte)
// RecordAuth is an optional authority policy called by Store.Put after
// signature/expiry verification passes (Phase 4: includes DHT key).
// If nil, no authority check is performed (useful in tests).
RecordAuth RecordAuthFunc
// MaxStoreKeys limits the number of distinct DHT keys in the local store.
// 0 uses DefaultMaxTotalKeys. Configurable per-node soft limit.
MaxStoreKeys int
// Logger is used for DHT-level diagnostics (send failures, RPC retries).
// If nil, slog.Default() is used.
Logger *slog.Logger
}
Config holds runtime dependencies for a DHT node (spec Step 7).
type Node ¶
type Node struct {
// contains filtered or unexported fields
}
Node is a single DHT participant (routing + local store + wire handler).
func (*Node) AddContact ¶
AddContact pins a peer's dial address and seeds the routing table.
func (*Node) BindPeerAddr ¶
BindPeerAddr registers the transport dial address for a remote NodeID (e.g. MemTransport name lookup in tests).
func (*Node) Bootstrap ¶
func (n *Node) Bootstrap(ctx context.Context, seeds []BootstrapSeed) error
Bootstrap registers seeds with pre-known identity and runs FIND_NODE(self). For seeds where only ip:port is known, use BootstrapAddrs instead.
func (*Node) BootstrapAddrs ¶
BootstrapAddrs connects to seed nodes by raw network addresses (ip:port only). For each address it sends PING, extracts the peer's identity from the PONG, registers the peer, then runs FIND_NODE(self) to widen the routing table. This is the recommended bootstrap entry point — callers do not need to know the seed's Address or NodeID in advance.
func (*Node) BootstrapCandidateAddrs ¶
BootstrapCandidateAddrs returns up to max UDP addresses for cold-start bootstrap (routing table + remembered peer addrs). Best-effort for persisting peers.cache.
func (*Node) Close ¶
Close stops the node, closes the transport, and waits for the receive loop to exit.
func (*Node) DebugHTTPHandler ¶
DebugHTTPHandler returns read-only /debug/* handlers for mounting on an existing server (spec §3.6).
func (*Node) FindNode ¶
func (n *Node) FindNode(ctx context.Context, peer net.Addr, target a2al.NodeID) ([]protocol.NodeInfo, error)
FindNode asks peer for closest nodes to target NodeID.
func (*Node) FindValue ¶
func (n *Node) FindValue(ctx context.Context, peer net.Addr, key a2al.NodeID) (*protocol.SignedRecord, error)
FindValue queries peer for the best endpoint record at key NodeID (legacy helper).
func (*Node) FindValueWithNodes ¶
func (n *Node) FindValueWithNodes(ctx context.Context, peer net.Addr, key a2al.NodeID, recType uint8) ([]protocol.SignedRecord, []protocol.NodeInfo, error)
FindValueWithNodes queries peer. recType 0 requests all record types in the response.
func (*Node) PingIdentity ¶
PingIdentity sends PING, waits for PONG, and returns the remote peer's identity extracted from the response. The peer is automatically registered into the routing table and dial address map.
func (*Node) PublishEndpointRecord ¶
PublishEndpointRecord stores the record locally and pushes it to up to three closest reachable peers via FIND_NODE + STORE. Storing locally ensures the node is always discoverable (even as the first node in the network).
func (*Node) PublishMailboxRecord ¶
func (n *Node) PublishMailboxRecord(ctx context.Context, storeKey a2al.NodeID, rec protocol.SignedRecord) error
PublishMailboxRecord stores the mailbox record at storeKey (recipient NodeID) locally and replicates to every k-closest reachable peer via FIND_NODE + STORE (spec §4.4).
func (*Node) PublishTopicRecord ¶
func (n *Node) PublishTopicRecord(ctx context.Context, storeKey a2al.NodeID, rec protocol.SignedRecord) error
PublishTopicRecord stores the topic record at storeKey (SHA-256("topic:"+topic)) locally and replicates to every k-closest reachable peer (spec §5.4).
func (*Node) SetSelfExtIP ¶
SetSelfExtIP records our own public IP (from STUN/HTTP probe). Used to detect NAT hairpin peers: nodes behind the same NAT share the same public IP and typically cannot reach each other via that IP (router hairpinning not supported).
func (*Node) StartDebugHTTP ¶
StartDebugHTTP listens on addr and serves read-only /debug/* JSON (spec §3.6). When using the a2ald daemon the /debug/* routes are served on the API port (default 127.0.0.1:2121) and this method is not needed. Use it only when embedding the dht package directly without the daemon. stop shuts the server down (idempotent).
func (*Node) StartWithBootstrap ¶
StartWithBootstrap starts the receive loop then bootstraps with raw addresses.
type PeerIdentity ¶
type PeerIdentity struct {
Address a2al.Address
NodeID a2al.NodeID
ObservedWire []byte // BodyPong.observed_addr (how reporter sees us); may be nil
}
PeerIdentity holds the identity extracted from a PONG response.
type Query ¶
Query runs iterative FIND_NODE / FIND_VALUE (spec Step 8).
func (*Query) AggregateRecords ¶
func (q *Query) AggregateRecords(ctx context.Context, target a2al.NodeID, recType uint8) ([]protocol.SignedRecord, error)
AggregateRecords queries until the k-closest set is exhausted, merges and deduplicates (Phase 4 Topic/Mailbox).
func (*Query) FindNode ¶
FindNode runs iterative FIND_NODE until k-closest known nodes are exhausted or all have been queried.
type RecordAuthFunc ¶
RecordAuthFunc decides whether a record may be stored at the given DHT key after signature and expiry checks (Phase 4: includes key binding for sovereign).
type Store ¶
type Store struct {
// contains filtered or unexported fields
}
Store is an in-memory record map keyed by DHT NodeID (Phase 4 multi-category).
func NewStore ¶
func NewStore(auth RecordAuthFunc, maxKeys int) *Store
NewStore creates an empty Store. auth is optional (see Config.RecordAuth). maxKeys limits distinct key count; 0 uses DefaultMaxTotalKeys.
func (*Store) DebugRecords ¶
func (s *Store) DebugRecords(now time.Time) []StoreRecordDebug
DebugRecords lists non-expired verified records (spec §3.6).
func (*Store) GetAll ¶
GetAll returns verified non-expired records at key, optionally filtered by RecType (0 = all).
type StoreRecordDebug ¶
type StoreRecordDebug struct {
KeyNodeIDHex string `json:"key_node_id_hex"`
AddressHex string `json:"address_hex"`
RecType uint8 `json:"rec_type"`
Seq uint64 `json:"seq"`
Timestamp uint64 `json:"timestamp"`
TTL uint32 `json:"ttl_seconds"`
PayloadLen int `json:"payload_cbor_len"`
}
StoreRecordDebug is a JSON-friendly store row (spec §3.6).