Skip to content
minip2p
Esc
↑↓navigate↵open⌘Jpreview
On this page

Discover peers

Activate signed presence beacons or local-link mDNS with a bounded peer book and automatic dialing.

Choose the source that matches where peers meet:

  • Use mDNS for peers on the same local network.
  • Use signed discovery when peers already share a pubsub mesh.
  • Enable both when the application needs both sources.

Both sources feed one bounded peer book and one automatic-dial policy.

Enable signed discovery

cargo add minip2p-rs --features discovery

Signed discovery publishes application-scoped presence beacons over pubsub:

let mut node = minip2p::Endpoint::builder()
    .discovery()
    .listen_default()?
    .bind()?;

node.listen_all()?;

.discovery_config(...) selects a custom topic, publication cadence, and announcement limit. Tune the shared address book and dial policy with .peer_discovery_config(...).

Discovery can dial direct addresses announced by other peers without a relay. A configured relay is still required for relay circuits, reservations, and relay-assisted hole punching:

let node = minip2p::Endpoint::builder()
    .relay(relay)
    .discovery()
    .listen_default()?
    .bind()?;

Enable local mDNS

cargo add minip2p-rs --features mdns

Then enable it on the endpoint:

let node = minip2p::Endpoint::builder()
    .mdns()
    .listen_default()?
    .bind()?;

mDNS needs no pubsub or relay. Its observations are unauthenticated until the transport verifies the remote peer, and its automatic dials remain direct-only. KnownPeer::beacon_addrs and KnownPeer::mdns_addrs show where each address came from.

An invalid configuration passed to mdns_config returns MdnsConfigError immediately. If mDNS sockets cannot be opened during bind, it returns BindError::MdnsSocket. Once running, an mDNS socket failure is EndpointEvent::MdnsFailed { error }, not a wait error: mDNS keeps retrying, the rest of the endpoint is unaffected, and EndpointEvent::MdnsRecovered follows once a retry works. Call shutdown() to send goodbyes and stop mDNS; it returns the first goodbye that could not be sent.

Enable both methods on the same builder when the application needs LAN and pubsub-based discovery.

How peers appear

Each endpoint periodically publishes a signed beacon containing its current dialable address snapshot. Discovery:

  1. verifies the beacon identity and signature;
  2. normalizes and bounds the advertised addresses;
  3. updates the TTL-based known-peer book;
  4. starts or cancels NAT-aware dials according to discovery policy.

Address-less beacons can refresh peer presence without starting a dial. Wildcard listen addresses are filtered because another peer cannot dial them.

Observe the address book

for peer in node.known_peers() {
    println!(
        "peer={} connected={} addresses={:?}",
        peer.peer,
        peer.connected,
        peer.addrs,
    );
}

loop {
    match node.wait(std::time::Duration::from_millis(250))? {
        minip2p::EndpointWaitOutcome::Event(minip2p::EndpointEvent::Discovery(event)) => {
            println!("{event:?}");
        }
        minip2p::EndpointWaitOutcome::Event(other) => println!("{other:?}"), // dispatch as usual
        _ => {} // deadline or interruption
    }
}

EndpointEvent::Discovery(DiscoveryEvent) reports peers being discovered, updated, or expired, plus automatic dial failures and rejected beacons. known_peers is a State snapshot and may be ahead of these events.

Customize policy

use minip2p::{BeaconConfig, Endpoint, PeerDiscoveryConfig};

let beacon = BeaconConfig {
    topic: "my-app/discovery/v1".into(),
    ..BeaconConfig::default()
};
let policy = PeerDiscoveryConfig {
    max_known_peers: 256,
    ..PeerDiscoveryConfig::default()
};

let node = Endpoint::builder()
    .discovery_config(beacon)?
    .peer_discovery_config(policy)?
    .listen_default()?
    .bind()?;

BeaconConfig controls the pubsub topic, cadence, and local announcement cap. PeerDiscoveryConfig is shared by signed discovery and mDNS; it controls peer and address bounds, source TTLs, automatic dialing, tie breaking, retry backoff, and mDNS dial-rate limits. Invalid bounds are rejected before a socket is allocated.

For a complete mesh demonstration, use the existing minip2p-chat example. It combines discovery, gossipsub, relay circuits, and direct upgrades.

Last updated on October 22, 2026

Was this page helpful?