Tenzro Testnet is live. Get testnet TNZO

Networking

Tenzro uses libp2p for peer-to-peer networking, providing decentralized communication via gossipsub pub/sub and Kademlia DHT for peer discovery.

libp2p Stack

  • Transport: TCP with noise encryption
  • Pub/Sub: Gossipsub for message propagation
  • Discovery: Kademlia DHT + mDNS (local)
  • Identify: Peer identification and capability exchange
  • Ping: Keep-alive and latency measurement

Gossipsub Topics

Nodes subscribe to gossipsub topics for different message types:

TopicPurpose
tenzro/blocks/1.0.0Block propagation
tenzro/transactions/1.0.0Transaction propagation
tenzro/consensus/1.0.0Consensus messages (HotStuff-2)
tenzro/attestations/1.0.0TEE attestations
tenzro/models/1.0.0Model registrations
tenzro/inference/1.0.0Inference requests/responses
tenzro/status/1.0.0Status and discovery

Peer Discovery

Bootstrap Nodes

Nodes connect to bootstrap nodes on startup for initial peer discovery:

# Start node with bootstrap nodes tenzro-node \ --boot-nodes \ /ip4/bootstrap-node-1-ip/tcp/9000/p2p/12D3KooWABC... \ /ip4/bootstrap-node-2-ip/tcp/9000/p2p/12D3KooWDEF...

Kademlia DHT

Kademlia DHT enables decentralized peer discovery without central servers:

  • Peers organized in XOR distance metric
  • K-bucket routing table (k=20)
  • Periodic table refreshes every 10 minutes
  • Peer records published to DHT with TTL

mDNS (Local Discovery)

mDNS discovers local peers on the same network without bootstrap nodes:

# Enable mDNS for local development tenzro-node --enable-mdns

Peer Management

use tenzro_network::PeerManager; let peer_manager = PeerManager::new()?; // Connect to peer peer_manager.connect_peer( "/ip4/bootstrap-node-ip/tcp/9000/p2p/12D3KooWABC..." ).await?; // Get connected peers let peers = peer_manager.get_connected_peers().await?; for peer in peers { println!("Peer: {}", peer.peer_id); println!("Latency: {}ms", peer.latency_ms); println!("Role: {:?}", peer.role); } // Disconnect peer peer_manager.disconnect_peer(&peer_id).await?;

Message Deduplication

MessageDeduplicator prevents amplification attacks by tracking seen messages:

// Message deduplication with 60-second window let dedup = MessageDeduplicator::new(Duration::from_secs(60)); if dedup.is_duplicate(&message_id) { // Ignore duplicate message return Ok(()); } dedup.mark_seen(message_id); // Process message...

Rate Limiting

Rate limiting prevents peers from flooding the network:

// Rate limit: 100 messages per second per peer let rate_limiter = RateLimiter::new(100, Duration::from_secs(1)); if !rate_limiter.check_and_update(&peer_id) { // Peer exceeded rate limit peer_manager.disconnect_peer(&peer_id).await?; return Err("Rate limit exceeded"); } // Process message...

Peer Authentication

Peers authenticate using Ed25519 signatures on their peer ID:

// Verify peer identity let verified = peer_manager.verify_peer_identity( &peer_id, &signature, ).await?; if !verified { peer_manager.ban_peer(&peer_id).await?; return Err("Invalid peer signature"); }

Validator Authentication

The ValidatorRegistry trait provides validator-specific authentication for consensus and block messages, ensuring only registered validators can participate in consensus topics:

// ValidatorRegistry trait in peer_manager.rs pub trait ValidatorRegistry: Send + Sync { fn is_validator(&self, peer_id: &PeerId) -> bool; fn validator_peer_ids(&self) -> Vec<PeerId>; } // NodeValidatorRegistry wraps consensus engine // Validates peers by checking against active validator set impl ValidatorRegistry for NodeValidatorRegistry { fn is_validator(&self, peer_id: &PeerId) -> bool { // Checks peer against consensus engine's active validator set self.consensus.is_registered_validator(peer_id) } fn validator_peer_ids(&self) -> Vec<PeerId> { // Returns all active validator peer IDs self.consensus.get_validator_peer_ids() } } // Wired at node startup in tenzro-node let validator_registry = NodeValidatorRegistry::new(consensus_engine); peer_manager.set_validator_registry(validator_registry); // Topic-based authorization ENFORCED // Consensus and block messages require validator authentication peer_manager.authorize_peer_for_topic(&peer_id, "tenzro/consensus/1.0.0")?; peer_manager.authorize_peer_for_topic(&peer_id, "tenzro/blocks/1.0.0")?; // Non-validator peers can still participate as light clients // - Subscribe to transactions (tenzro/transactions/1.0.0) // - Subscribe to blocks (read-only) // - Cannot publish to consensus topic (enforced by ValidatorRegistry)

This ensures that only registered validators can participate in consensus, while allowing light clients and non-validator nodes to observe the network and submit transactions. The ValidatorRegistry integration is production-ready and prevents Sybil attacks on consensus topics.

Network Metrics

// Get network metrics let metrics = peer_manager.get_metrics().await?; println!("Connected Peers: {}", metrics.connected_peers); println!("Inbound Connections: {}", metrics.inbound_connections); println!("Outbound Connections: {}", metrics.outbound_connections); println!("Messages Sent: {}", metrics.messages_sent); println!("Messages Received: {}", metrics.messages_received); println!("Bytes Sent: {}", metrics.bytes_sent); println!("Bytes Received: {}", metrics.bytes_received);

Gossipsub Configuration

// Gossipsub parameters { "mesh_size": 8, // Target mesh size (D in spec) "mesh_low": 6, // Min mesh size before grafting "mesh_high": 12, // Max mesh size before pruning "fanout_ttl_seconds": 60, // Fanout cache TTL "heartbeat_interval": 1, // Heartbeat interval (seconds) "history_length": 5, // Message cache size "history_gossip": 3 // Messages to gossip in IHAVE }

NAT Traversal

Tenzro supports NAT traversal for nodes behind firewalls:

  • UPnP: Automatic port mapping for home routers
  • Relay: Circuit relay for unreachable peers
  • Hole Punching: DCUtR protocol for direct connections
# Enable NAT traversal tenzro-node --enable-upnp --enable-relay

Performance

MetricValue
Max Connections1000
Messages per Second1000+ per topic
Message Propagation100-500ms (mesh size 8)
DHT Lookup~500ms (network size 1000)