distributed-topic-tracker
Decentralized auto-bootstrapping for iroh-gossip topics using the mainline BitTorrent DHT.
Quick Start
Add dependencies to Cargo.toml:
[]
= "1"
= "1"
= "0.9"
= "3.0.0-pre.1"
= "^0.97"
= "^0.97"
= "0.3"
Basic iroh-gossip integration:
use Result;
use ;
use Gossip;
use SigningKey;
// Imports from distributed-topic-tracker
use ;
async
Protocol
- Details (spec): PROTOCOL.md
- Architecture: ARCHITECTURE.md
- Feedback: Issue #5
Features
- Decentralized bootstrap for iroh-gossip topics
- Ed25519 signing and HPKE shared-secret encryption
- DHT rate limiting (per-minute record caps)
- Resilient bootstrap with retries and jitter
- Background publisher with bubble detection and peer merging
Testing
Unit Tests
Run core component tests:
End-to-End Tests
Verify peer discovery across Docker containers:
# Requires Docker and Docker Compose
The E2E test confirms multiple nodes discover each other via DHT and join the same gossip topic.
Upgrading from 0.2 to 0.3
0.3 resolves several stability issues present in 0.2. Circular and dangling references between actors caused resource leaks and tasks could outlive topic and channel handles (after Topic, GossipSender and GossipReceiver were dropped). Reduced unnecessary DHT writes and reads, adjusted timeouts, reduced time to bootstrap. All actor lifecycles are now token-gated, references now work as expected (if all dropped, all background tasks shut down gracefully), resolved bugs in merge workers, and many more improvements. If you find any issues, please report them.
tldr: background tasks shutdown as expected, faster bootstrap time, better all around
Breaking changes
RecordTopic removed, use TopicId instead
RecordTopic has been removed. TopicId now serves as the unified topic identifier across the entire API and supports conversion from &str, String, Vec<u8>, and FromStr.
// 0.2
use RecordTopic;
let topic = from_str?;
let publisher = new;
// 0.3
use TopicId;
let topic = new;
// or: let topic: TopicId = "my-topic".into();
// or: let topic: TopicId = "my-topic".parse()?;
let publisher = new;
RecordPublisher::new() now requires a Config parameter
A 5th Config parameter was added. Use Config::default() for most use cases, tune as needed.
// 0.2
let publisher = new;
// 0.3
use Config;
let publisher = new;
// or use the new builder:
let publisher = builder
.config
.build;
MAX_BOOTSTRAP_RECORDS constant removed
The per-minute record cap is now configurable via BootstrapConfig::max_bootstrap_records (default: 5, was hardcoded 100).
// 0.2
use MAX_BOOTSTRAP_RECORDS; // was 100
// 0.3 - configure via Config
let config = builder
.bootstrap_config
.build;
TopicId::raw() removed
TopicId no longer stores the original string. Only the 32-byte hash is retained.
// 0.2
let topic = new;
let original: &str = topic.raw; // no longer available
// 0.3 - store the raw string yourself if needed
let raw = "my-topic".to_string;
let topic = new;
New features
Full configuration system
All timing, retry, and threshold parameters are now configurable:
use Duration;
use ;
builder
.dht_config
.bootstrap_config
.max_join_peer_count
.publisher_config
.merge_config
.timeouts
.build;
Disable merge strategies or publishing
// Run without any merge strategies (bootstrap-only)
let config = builder
.merge_config
.build;
RecordPublisher::builder() for ergonomic construction
let publisher = builder
.secret_rotation
.config
.build;
Todo's
- Network degradation testing
License
Licensed under Apache-2.0 or MIT you choose.
Contributing
- Test and provide feedback: Issue #5
- PRs, issues, and reports welcome.
Contributions are dual-licensed as above unless stated otherwise.