dht 6.4.0

Simple, robust, BitTorrent's Mainline DHT implementation
Documentation
# Changelog

All notable changes to mainline dht will be documented in this file.

## Unpublished 

## Added

- `AsyncDht::as_sync()` to get a reference to the inner synchronous `Dht`.

## [6.3.0]https://github.com/Nuhvi/mainline/compare/v6.0.0...v6.1.0 - 2026-02-26

### Added

- `DhtBuilder::build_async()`, `Dht::new_async()`, and `AsyncDht::new()` to avoid blocking on initial dns queries in async runtimes.

## [6.2.0]https://github.com/Nuhvi/mainline/compare/v6.0.0...v6.1.0 - 2025-01-25

### Fixed

- Unexpected shutdown in actor thread.
- Remove panics and unwraps.
- Fix peers number in signed_peers.

### Refactor

- Large refactor for better maintainability and sans-io Core.

## [6.1.0]https://github.com/Nuhvi/mainline/compare/v6.0.0...v6.1.0 - 2025-10-28

### Fixed

- Respond to `FIND_NODE` with nodes supporting `signing_peers` first.
- In `server_mode`, always add nodes from incoming requests to `signing_peers_routing_table` if they support it.
- When querying `FIND_NODE` find closest nodes from all tables (include `signing_peers_routing_table`).

### Added

- `Info::routing_table_size()` and `Info::signed_peers_routing_table_size()`

## [6.0.0]https://github.com/Nuhvi/mainline/compare/v5.5.1...v6.0.0 - 2025-10-27

### Added

- Internal `request_timeout` estimation based on observed RTTs.
- `announce_signed_peer` and `get_signed_peers` as described at [BEP_????]https://github.com/Nuhvi/mainline/blob/main/beps/bep_signed_peers.rst.

### Removed

- `DhtBuilder::request_timeout()` (Breaking change).
- `node` Feature flag, now the `Dht` is always available
- `RoutingTable::closest_secure()` made private.

### Changed

- Upgrade `getrandom` to `v0.3`
- Upgrade `ed25519-dalek` to `v3.0.0-pre.1` (Breaking change)
- `MutableItem::new()` takes a reference to the signer.
- `DhtBuilder::bootstrap()` and `DhtBuilder::extra_bootstrap()` takes a `ToString`.

### Fixed

- Adaptive request timeout 
- Adaptive interval of polling udp socket for new messages, reducing latency and cpu usage.
- Accept both u16 or u32 transaction ids
- `DhtBuilder::extra_bootstrap()` was removing existing defaults

## [5.4.0]https://github.com/nuhvi/mainline/compare/v5.3.1...v5.4.0  - 2025-04-02

### Added

- Add `Testnet::new_async()`
- Populate the bootstrapping node's routing table with requesting nodes
- Update client version from RS04 to RS05

## [5.3.1]https://github.com/nuhvi/mainline/compare/v5.3.0...v5.3.1  - 2025-02-21

### Fixed

- Delay DNS lookups for default bootstrap to `Rpc::new()`

## [5.3.0] - 2025-02-20

### Changed

- Replace `rand` with `getrandom`

## [5.2.1] - 2025-02-17

### Fixed

- DHT size estimate from repetitive GET queries (PR #50)

## [5.2.0] - 2025-02-11

### Changed

- Update dev-dependencies

## [5.1.0] - 2025-02-11

### Changed

- Use Rust 2021 edition

## [5.0.0] - 2025-02-11

### Added

- Add `Id::from_ipv4()`.
- Add `Id::is_valid_for_ipv4`.
- Add `RoutingTable::nodes()` iterator.
- Add `DhtBuilder::server_mode` to force server mode.
- Add `DhtBuilder::public_ip` for manually setting the node's public ip to generate secure node `Id` from.
- Add [adaptive mode]https://github.com/nuhvi/mainline?tab=readme-ov-file#adaptive-mode.
- Add `DhtBuilder::extra_bootstrap()` to add more bootstrapping nodes from previous sessions.
- Add `Dht::bootstrapped()` and `AsyncDht::bootstrapped()` to wait for the routing table to be bootstrapped.
- Add `RoutingTable::to_bootstrap()`, `Dht::to_bootstrap()`, and `AsyncDht::to_bootstrap()` to export the addresses nodes in the routing table.
- Add `Info::public_address()` which returns the best estimate for this node's public address.
- Add `Info::firewalled()` which returns whether or not this node is firewalled, or publicly accessible.
- Add `Info::server_mode()` which returns whether or not this node is running in server mode.
- Add `DhtBuilder::info()` to export a thread safe and lightweight summary of the node's information and statistics.
- Add `cache_bootstrap.rs` example to show how you can store your routing table to disk and use it for subsequent bootstrapping.
- Add `Dht::get_mutable_most_recent()` and `AsyncDht::get_mutable_most_recent()` to get the most recent mutable item from the network.
- Add `PutQueryError::Timeout` in case put query is terminated unsuccessfully, but no error responses.
- Add `PutMutableError::Concurrrency(ConcurrrencyError)` for all cases where a `Lost Update Problem` may occur (read `Dht::put_mutable` documentation for more details).
- Add `Dht::get_closest_nodes()` and `AsyncDht::get_closest_nodes()` to return the closest nodes (that support BEP_0044) with valid tokens.
- Add `Dht::put()` and `AsyncDht::put()` to put a request to the closest nodes, and optionally to extra arbitrary nodes with valid tokens.
- Add `Testnet::leak()` to keep the dht network running as a `'static`
- Add `MutableError `.
- Add `DecodeIdError`
- Export `Dhtbuilder`.
- Export `RoutingTable`.
- Support `BEP_0042 DHT Security extension` when running in server mode. 

### Removed

- Remove `bytes` dependency.
- Remove `ipv6` optionality and commit to `ipv4`.
- Remove `Id::to_vec()`.
- Exported `ClosestNodes`, you have to use it from `mainline::rpc`.
- Removed `Node::unique()`, `Node::with_id()`, `Node::with_address()`, and `Node::with_token()`.
- Removed `RoutingTable::default()`.
- Removed exporting `rpc` module, and `Rpc` struct.
- Removed `Dht::shutdown()` and `AsyncDht::shutdown()`.
- Removed `DhtWasShutdown`
- Removed `DefaultServer` export.

### Changed

- Rename `Settings` to `ClientBuilder`.
- `Dht`, and `AsyncDht` is now behind a feature flag `node`, so you can include the `Rpc` only and build your own node.
- All methods that were returning `Result<T, DhtWasShutdown>` now return `T`.
- Enable calling `Dht::announce_peer()` and `Dht::put_immutable()` multiple times concurrently. 
- Return `PutMutableError::Concurrrency(ConcurrrencyError)` from `Dht::put_mutable()`.
- `Info::local_addr()` is infallible.
- `MutableItem::seq()` returns `i64` instead of a reference.
- `Dht::put_immutable()` and `AsyncDh::put_immutable()` take `&[u8]` instead of `bytes::Bytes`.
- `Dht::get_immutable()` and `AsyncDh::get_immutable()` return boxed slice `Box<[u8]>` instead of `bytes::Bytes`.
- `Dht::put_immutable()` and `AsyncDh::put_immutable()` return `PutImmutableError`.
- `Dht::announce_peer()` and `AsyncDh::announce_peer()` return `AnnouncePeerError`.
- `Dht::put_mutable()` and `AsyncDh::put_mutable()` return `PutMutableError`.
- All tracing logs are either `TRACE` (for krpcsocket), `DEBUG`, or `INFO` only for rare and singular events, 
  like starting the node, updating the node Id, or switching to server mode (from adaptive mode).
- Change `PutError` to contain transparent elements for generic `PutQueryError`, and more specialized `ConcurrrencyError`.
- Remove `MutableItem::cas` field, and add optional `CAS` parameter to `Dht::put_mutable` and `AsyncDht::put_mutable`.
- `Dht::find_node()` and `AsyncDht::find_node()` return `Box<[Node]>` instead of `Vec<Node>`.
- `Node` is `Send` and `Sync`, and cheap to clone using an internal `Arc`.
- `Node::new()` take `Id` and `SocketAddrV4`.
- `RoutingTable::new()` takes an `Id`.
- Return `GetIterator<T>` and `GetStream<T>` from `get_` methods from `Dht` and `AsyncDht` instead of exposing `flume`.
- Remove `Server` trait and replace it with `RequestFilter` trait.
- `DhtBuilder` is not consuming, thanks to `Config` being `Clone`.

## [4.2.0]https://github.com/nuhvi/mainline/compare/v4.1.0...v4.2.0 - 2024-12-13

### Added

- Make MutableItem de/serializable (mikedilger)

## [4.1.0]https://github.com/nuhvi/mainline/compare/v3.0.0...v4.1.0 - 2024-11-29

### Added

- Export `errors` module containing `PutError` as a part of the response of `Rpc::put`.
- `Dht::find_node()` and `AsyncDht::find_node()` to find the closest nodes to a certain target.
- `Dht::info()` and `AsyncDht::info()` some internal information about the node from one method.
- `Info::dht_size_estimate` to get the ongoing dht size estimate resulting from watching results of all queries.
- `Info::id` to get the Id of the node.
- `measure_dht` example to estimate the DHT size.

### Changed

- Removed all internal panic `#![deny(clippy::unwrap_used)]`.
- `Testnet::new(size)` returns a `Result<Testnet>`.
- `Dht::local_addr()` and `AsyncDht::local_addr()` replaced with `::info()`.
- `Dht::shutdown()` and `AsyncDht::shutdown()` are now idempotent, and returns `()`.
- `Rpc::drop` uses `tracing::debug!()` to log dropping the Rpc.
- `Id::as_bytes()` instead of exposing internal `bytes` property.
- Replace crate `Error` with more granular errors.
- Replace Flume's `RecvError` with `expect()` message, since the sender should never be dropped to soon.
- `DhtWasShutdown` error is a standalone error.
- `InvalidIdSize` error is a standalone error.
- Rename `DhtSettings` to `Settings`
- Rename `DhtServer` to `DefaultServer`
- `Dht::get_immutable()` and `AsyncDht::get_immutable()` return `Result<Option<bytes::Bytes>, DhtWasShutdown>`
- `Node` fields are now all private, with `id()` and `address()` getters.
- Changed `Settings` to be a the Builder, and make fields private.
- Replaced `Rpc::new()` with `Settings::build_rpc()`.
- Update the client version from `RS01` to `RS04`

### Removed

- Removed `mainline::error::Error` and `mainline::error::Result`.