Skip to content

v2.3.0

Choose a tag to compare

@richard-ramos richard-ramos released this 26 Aug 02:42
· 1 commit to release/v2.3 since this release
Immutable release. Only release title and notes can be modified.

Highlights

  • The C bindings were rebuilt around generated nim-ffi bindings, replacing the legacy hand-written implementation while restoring API coverage for connectivity, streams, custom protocols, GossipSub, Kademlia, service discovery, relay, peerstore, crypto, and metrics.
  • QUIC performance was significantly improved by upgrading to nim-lsquic v0.8.0, with more efficient socket draining and engine scheduling, lower-copy receive/write paths, faster packet routing, and more reliable settlement of pending stream operations during connection close.
  • Android and iOS build targets were added for the C bindings, including device and simulator architectures and tests on Android and iOS simulators.
  • Kademlia received substantial interoperability and performance improvements: larger protocol-compatible message limits, 48-hour provider records, liveness-gated routing-table admission and eviction, continuous alpha-concurrency lookups, beta convergence, optimistic provider announcements, and dynamic client/server mode driven by network reachability.
  • Service Discovery gained automatic bootstrapping for per-service routing tables, safer shutdown and concurrency handling, IPv6-aware peer scoring, routing-table admission checks, registrar-cache improvements, and support for advertising a caller-provided signed Extended Peer Record.
  • Protocol interoperability was tightened across the stack: routing records now use the specified proto3 encoding, yamux uses the standard 256 KiB window and rejects invalid versions, QUIC validates the expected peer ID during the TLS handshake, and DCUtR preserves the QUIC server role during hole punching.
  • NAT port mapping now uses nim-libplum, providing automatic PCP, NAT-PMP, and UPnP-IGD selection with simpler lifecycle and build integration.
  • PubSub protobuf messages now use protobuf Editions. Common Message and control-message fields are plain Nim values again, while fields whose wire presence is meaningful remain Opt[T].
  • GossipSub ingress controls are exposed through the C bindings, including maximum message size, per-peer protocol-overhead rate limits, and optional disconnection of peers that exceed those limits.
  • Runtime log filtering can now be configured before C-binding node construction, avoiding unwanted startup logs.
  • Dependency setup was simplified around Nimble’s resolver: contributors can now use make followed by make test, while lockfiles remain for application-like artifacts such as C bindings and Nix builds.

Breaking changes

  • The legacy hand-written C bindings were replaced by nim-ffi generated bindings. C consumers must regenerate c_bindings/libp2p.h, rebuild against the new ABI, and adapt their context calls and result callbacks. The old cbind/libp2p.h and legacy threaded implementation were removed.
  • Additional C ABI changes include:
    • transport, muxer, and peer direction now use generated enums instead of integer literals.
    • libp2p_ctx_create_cid and libp2p_ctx_decode_xpr became libp2p_static_create_cid and libp2p_static_decode_xpr and no longer require a context.
    • libp2p_ctx_destroy now returns an integer status.
    • Raw callbacks may receive the non-terminal RET_STALE_WARN status while a long-running request remains in flight.
    • Libp2pConfig now contains a nested gossipsub configuration. mountGossipsub and gossipsubTriggerSelf moved to gossipsub.mount and gossipsub.triggerSelf.
  • Relay v1 HOP is no longer advertised by the default Relay.new(). Applications that still need the legacy protocol must explicitly use Relay.new(circuitRelayV1 = true). Relay v2 remains enabled by default.
  • IdentifyPusher is disabled by default. Applications that rely on Identify Push announcements must opt in with SwitchBuilder.new().withIdentifyPusher().
  • KadDHT.new(..., client: bool) became KadDHT.new(..., isServer: bool = true). Note the inverted meaning: the old client = true is equivalent to isServer = false. Switch-builder users can instead select KadMode.Client, KadMode.Server, or KadMode.Auto.
  • AutoNAT v1’s AutonatMsg.msgType and AutonatDialResponse.status are now Opt[T]. Code that directly constructs or reads those protobuf structures must wrap or unwrap the values.
  • NAT port-mapping configuration changed with the move to nim-libplum:
    • upnpConfig() and natPmpConfig() no longer accept refreshInterval or leaseDuration; they accept discoveryTimeout and mappingTimeout.
    • natConfig() is the recommended default and automatically tries PCP, NAT-PMP, and UPnP-IGD.
    • DefaultRefreshInterval and DefaultLeaseDuration were removed.
    • Custom PortMapper implementations must remove discover; map no longer accepts a lease and now returns a MappedPort.
  • Outbound dialing and identification now have bounded deadlines, dial locks are cleaned up safely, and inbound connection rejection no longer stalls the accept loop or causes unbounded cleanup work.
  • Kademlia now reuses per-peer RPC streams, enforces per-bucket IP diversity, backs off failed admission probes, automatically re-seeds undersized routing tables, and preserves peer addresses when admission-probe capacity is exhausted.

What's Changed

  • test: remove unnecessary test that takes too much time by @vladopajic in #2754
  • test(misc): dual stack 5 by @rlve in #2746
  • fix: eliminate race condition in "e2e drop peer from inside its own stream handler" test by @vladopajic with @Copilot in #2760
  • test(dcutr): better synchronisation and assertion for "DCUtR establishes a new QUIC connection" by @vladopajic in #2762
  • test(autonat): fix flaky test "Peer must be not reachable and then reachable" by @vladopajic in #2764
  • test(mplex): make tests teardown more robust by @vladopajic in #2761
  • test(transports): accept fails by @rlve in #2759
  • fix(memory-transport): serialize concurrent writes by @vladopajic in #2765
  • feat(service-disco): service table bootstrapping by @SionoiS in #2718
  • fix(multiaddress): decode empty optional observedAddr by @rlve in #2783
  • chore(cbind): nim-ffi migration [1/9] — deps + pinning scaffold by @gmelodie in #2772
  • fix(yamux): align default window with spec and reject invalid versions by @richard-ramos in #2787
  • fix(kademlia): align DHT message and provider limits for interop by @richard-ramos in #2788
  • fix(identify): handle missing optional pub key by @rlve in #2793
  • chore(cbind): nim-ffi migration [2/9] — new-library scaffold + CI by @gmelodie in #2773
  • chore(makefile): simplify code by @vladopajic in #2792
  • chore(cbind): change dep commit by @vladopajic in #2804
  • feat(tests): tests as subproject of repo by @vladopajic in #2794
  • test(identify): repro test for #2800 by @rlve in #2802
  • test: fix flakines with "client-mode node successfully completes lookup against server-mode registrars" by @vladopajic in #2801
  • chore(relay)!: make v1 hop opt-in by @richard-ramos in #2785
  • fix(autonat): optional msgType and status fields by @richard-ramos in #2790
  • fix(protobuf): tolerate empty custom fields by @richard-ramos in #2789
  • fix(routing-record): use proto3 peer record encoding by @richard-ramos in #2807
  • chore: add issue and feature templates by @richard-ramos in #2770
  • chore(cbind): nim-ffi migration [3/9] — connectivity & identity by @gmelodie in #2774
  • chore(builders): disable IdentifyPusher by default by @vladopajic in #2819
  • chore(cbind): nim-ffi migration [4/9] — streams & custom protocols (+ echo example) by @gmelodie in #2775
  • chore(cbind): nim-ffi migration [5/9] — pubsub / gossipsub (+ gossipsub example) by @gmelodie in #2776
  • fix(service-discovery): drain bootstrap futures on shutdown by @vladopajic with @Copilot in #2823
  • chore(kad-dht): loosen validation on AddProvider for interop tests by @rlve in #2824
  • chore(nat): replace nim-nat-traversal with nim-libplum by @gmelodie in #2821
  • chore(cbind): nim-ffi migration [6/9] — kademlia + CID + crypto by @gmelodie in #2777
  • build(android): add libp2p_ffi mobile targets by @richard-ramos in #2813
  • chore(cbind): nim-ffi migration [7/9] — service discovery + extended peer records by @gmelodie in #2778
  • fix(dialer): reset streams after failed protocol negotiation by @richard-ramos in #2828
  • build(ios): add libp2p_ffi mobile targets by @richard-ramos in #2814
  • feat(android): simulator by @richard-ramos in #2827
  • chore(cbind): nim-ffi migration [8/9] — relay, peerstore, metrics (API parity) by @gmelodie in #2779
  • feat(ios): simulator by @richard-ramos in #2833
  • fix: avoid unused allFinished copies by @richard-ramos in #2830
  • test(interop): kad-dht for unified-testing by @rlve in #2832
  • fix(quic): propagate accept errors instead of nil by @richard-ramos in #2837
  • test(interop): build unified-testing dockerfiles workflow by @rlve in #2840
  • chore(cbind): nim-ffi migration [9/9] — flip to libp2p.nim, delete legacy cbind by @gmelodie in #2780
  • fix(dcutr): preserve QUIC server role during hole punching by @richard-ramos in #2838
  • fix(service-disco): wait time cap by @SionoiS in #2834
  • chore: print selected platform in test_multiformat_exts by @richard-ramos in #2843
  • fix(service-disco): don't rescale bucket index by maxBuckets by @gmelodie in #2841
  • fix(kad): avoid advertising ephemeral peer addresses by @richard-ramos in #2844
  • fix(service-disco): extend IP-similarity scoring to IPv6 by @tinniaru3005 in #2805
  • fix(kad): exclude the requester from closerPeers by @gmelodie in #2850
  • fix(kad): target the requested bucket when refreshing by @gmelodie in #2842
  • fix: ensure memory transport tags directions by @etan-status in #2809
  • chore(tests): use await insted of waitFor by @vladopajic in #2867
  • fix(kad): retry peers that respond with an error, not just silent ones by @tinniaru3005 in #2865
  • fix(service-disco): apply routing-table admission checks to per-service inserts by @tinniaru3005 in #2870
  • chore(deps): bump nimble to v0.24.1 by @vladopajic in #2873
  • chore(kad): liveness-gated bucket eviction by @gmelodie in #2862
  • feat(cbind): list connected peers regardless of direction by @gmelodie in #2878
  • build(deps): replace custom pins with Nimble resolver setup by @richard-ramos in #2871
  • fix(kad): flaky Get providers returns at most k closest peers by @gmelodie in #2879
  • feat(quic): validate expected peer id during dial by @richard-ramos in #2880
  • fix(build): remove --noLockFile and dir rm by @richard-ramos in #2882
  • chore(service-disco): add timeouts and refactor for concurency by @SionoiS in #2872
  • fix(pubsub): resolve flaky FloodSub multiple-peer tests by @paschal533 in #2810
  • chore(cbind): adopt nim-ffi 0.3.0 by @gmelodie in #2885
  • chore: bump lsquic by @richard-ramos in #2889
  • test: improve checkTrackers by @rlve in #2886
  • feat(cbind): nat config by @richard-ramos in #2884
  • feat(cbind): dial with addrs by @gmelodie in #2883
  • chore(kad): probe peers before inserting them into the routing table by @gmelodie in #2863
  • chore(kad): replace round-synchronized lookup with a continuous alpha-concurrency pipeline by @gmelodie in #2864
  • fix(cbind): bump nim-ffi for CBOR byte-string replies by @gmelodie in #2891
  • chore(make): format .nimble files by @vladopajic in #2894
  • chore(.gitignore): cleanup by @vladopajic in #2895
  • chore(service-disco): refactor registrar cache by @SionoiS in #2849
  • feat(log): add runtime logs filtering support by @vladopajic in #2896
  • test(kad): import tables in the find test by @gmelodie in #2897
  • chore(log): libp2pSetLogLevel changed to static by @vladopajic in #2899
  • fix(logs): adding logLevel to Libp2pConfig to avoid logs created in createLibp2pNode by @vladopajic in #2904
  • refactor(pubsub): use protobuf proto editions by @richard-ramos in #2900
  • fix(test): guard the logging test on a dynamic chronicles sink by @gmelodie in #2905
  • chore(kad): batch reprovide by keyspace region by @gmelodie in #2902
  • chore(kad): evict stale peer on refresh by @SionoiS in #2898
  • chore(cbind): change procs to static by @vladopajic in #2913
  • chore(kad): converge lookups on beta and confirm the k closest in a follow-up phase by @gmelodie in #2903
  • refactor(nat): a ReachabilityObservers store for reachability subscribers by @gmelodie in #2915
  • fix(service-disco): self registration ticket carry over by @SionoiS in #2914
  • feat(kad): send optimistic ADD_PROVIDER during lookup by @gmelodie in #2911
  • feat(kad): dynamic client/server mode via reachability by @gmelodie in #2910
  • fix(service-disco): let a caller advertise a full XPR by @gmelodie in #2917
  • fix(service-disco): initialise the network size estimator by @gmelodie in #2920
  • feat(cbind): expose the GossipSub ingress limits in Libp2pConfig by @gmelodie in #2919
  • test(quic): pin nim-lsquic close fix by @richard-ramos in #2925
  • chore(kad): refactor probe & evict scheduling by @SionoiS in #2907
  • ci: change log lvl by @vladopajic in #2926
  • chore(kad): reuse per-peer streams instead of dialing a fresh stream per RPC by @gmelodie in #2901
  • chore: adding more metrics by @vladopajic in #2927
  • fix(service-disco): validate advert length and re-check client mode by @gmelodie in #2922
  • chore(cbind): use nim-ffi 0.3.0 by @gmelodie in #2909
  • fix(dialer): bound outbound dials so one stuck peer cannot stall the node by @gmelodie in #2929
  • refactor(kad): tables into virtual system by @SionoiS in #2918
  • fix(autotls): checkDNSRecords retry loop by @rlve in #2930
  • fix(pubsub): initialize RPC handlers before connecting by @richard-ramos in #2941
  • fix(kad): an admission probe no longer waits out the dialer timeout by @gmelodie in #2936
  • fix(switch): prevent accept-loop resource exhaustion by @richard-ramos in #2951
  • feat(quic): add stream idle timeouts by @richard-ramos in #2947
  • chore(kad): per-bucket IP diversity caps by @gmelodie in #2938
  • fix(ipaddr): a public IPv6 address counts as a public address by @gmelodie in #2944
  • feat(kad): re-seed a routing table that fell below a minimum size by @gmelodie in #2937
  • fix(ipaddr): compare IPv6 clients too by @gmelodie in #2956
  • chore(kad): stop re-probing a peer whose admission probe just failed by @gmelodie in #2939
  • fix(kad): findNode no longer double-hashes a service table's target by @gmelodie in #2943
  • fix(kad): keep peer addresses when the admission probe cap is full by @gmelodie in #2967
  • fix(pubsub): bound seen cache and add overhead observability by @richard-ramos in fc41697

New Contributors

Full Changelog: v2.2.0...v2.3.0