//! Network configuration. use crate::{ChainId, DEFAULT_PORT, MAX_PEERS}; use libp2p::Multiaddr; use std::time::Duration; /// Network configuration. #[derive(Clone, Debug)] pub struct NetworkConfig { /// Chain identifier. pub chain_id: ChainId, /// Listen addresses. pub listen_addresses: Vec, /// Bootstrap peers. pub bootstrap_peers: Vec, /// Maximum number of inbound connections. pub max_inbound: usize, /// Maximum number of outbound connections. pub max_outbound: usize, /// Enable mDNS for local peer discovery. pub enable_mdns: bool, /// Enable Kademlia DHT. pub enable_kad: bool, /// Connection idle timeout. pub idle_timeout: Duration, /// Ping interval. pub ping_interval: Duration, /// Gossipsub configuration. pub gossipsub: GossipsubConfig, /// Sync configuration. pub sync: SyncConfig, /// External address (for NAT traversal). pub external_address: Option, /// Node name for identification. pub node_name: Option, } impl Default for NetworkConfig { fn default() -> Self { NetworkConfig { chain_id: ChainId::Mainnet, listen_addresses: vec![ format!("/ip4/0.0.0.0/tcp/{}", DEFAULT_PORT) .parse() .unwrap(), format!("/ip6/::/tcp/{}", DEFAULT_PORT).parse().unwrap(), ], bootstrap_peers: Vec::new(), max_inbound: MAX_PEERS / 2, max_outbound: MAX_PEERS / 2, enable_mdns: true, enable_kad: true, idle_timeout: Duration::from_secs(30), ping_interval: Duration::from_secs(15), gossipsub: GossipsubConfig::default(), sync: SyncConfig::default(), external_address: None, node_name: None, } } } impl NetworkConfig { /// Creates a configuration for mainnet. pub fn mainnet() -> Self { NetworkConfig { chain_id: ChainId::Mainnet, bootstrap_peers: mainnet_bootstrap_peers(), enable_mdns: false, ..Default::default() } } /// Creates a configuration for testnet. pub fn testnet() -> Self { NetworkConfig { chain_id: ChainId::Testnet, bootstrap_peers: testnet_bootstrap_peers(), listen_addresses: vec![format!("/ip4/0.0.0.0/tcp/{}", DEFAULT_PORT + 1000) .parse() .unwrap()], ..Default::default() } } /// Creates a configuration for local development. pub fn devnet() -> Self { NetworkConfig { chain_id: ChainId::Devnet, enable_mdns: true, enable_kad: false, max_inbound: 10, max_outbound: 10, ..Default::default() } } /// Total maximum peers. pub fn max_peers(&self) -> usize { self.max_inbound + self.max_outbound } /// Adds a bootstrap peer. pub fn with_bootstrap_peer(mut self, addr: Multiaddr) -> Self { self.bootstrap_peers.push(addr); self } /// Sets the listen address. pub fn with_listen_address(mut self, addr: Multiaddr) -> Self { self.listen_addresses = vec![addr]; self } /// Sets the node name. pub fn with_node_name(mut self, name: impl Into) -> Self { self.node_name = Some(name.into()); self } } /// GossipSub configuration. #[derive(Clone, Debug)] pub struct GossipsubConfig { /// Heartbeat interval. pub heartbeat_interval: Duration, /// Target mesh size. pub mesh_n: usize, /// Minimum mesh size. pub mesh_n_low: usize, /// Maximum mesh size. pub mesh_n_high: usize, /// Number of lazy peers to send gossip. pub gossip_lazy: usize, /// Fanout time-to-live. pub fanout_ttl: Duration, /// History length for gossip. pub history_length: usize, /// History gossip length. pub history_gossip: usize, /// Duplicate cache time. pub duplicate_cache_time: Duration, /// Message validation mode. pub validate_messages: bool, } impl Default for GossipsubConfig { fn default() -> Self { GossipsubConfig { heartbeat_interval: Duration::from_secs(1), mesh_n: 6, mesh_n_low: 4, mesh_n_high: 12, gossip_lazy: 6, fanout_ttl: Duration::from_secs(60), history_length: 5, history_gossip: 3, duplicate_cache_time: Duration::from_secs(60), validate_messages: true, } } } /// Synchronization configuration. #[derive(Clone, Debug)] pub struct SyncConfig { /// Maximum concurrent block downloads. pub max_concurrent_downloads: usize, /// Block request timeout. pub request_timeout: Duration, /// Maximum blocks per request. pub max_blocks_per_request: usize, /// Sync batch size. pub batch_size: usize, /// Time to wait before retrying failed requests. pub retry_delay: Duration, /// Maximum retries for failed requests. pub max_retries: u32, /// Header-first sync depth. pub headers_first_depth: u64, } impl Default for SyncConfig { fn default() -> Self { SyncConfig { max_concurrent_downloads: 16, request_timeout: Duration::from_secs(30), max_blocks_per_request: 100, batch_size: 500, retry_delay: Duration::from_secs(5), max_retries: 3, headers_first_depth: 10000, } } } /// Returns mainnet bootstrap peers. fn mainnet_bootstrap_peers() -> Vec { // Mainnet bootstrap nodes - will be populated after mainnet launch // Format: /dns4//tcp//p2p/ vec![ // Example (uncomment when deployed): // "/dns4/seed1.synor.cc/tcp/16511/p2p/12D3KooW...".parse().unwrap(), // "/dns4/seed2.synor.cc/tcp/16511/p2p/12D3KooW...".parse().unwrap(), // "/dns4/seed3.synor.cc/tcp/16511/p2p/12D3KooW...".parse().unwrap(), ] } /// Returns testnet bootstrap peers. /// /// # Seed Node Deployment Process /// /// To add a new seed node: /// /// 1. **Deploy synord on a server** with a static IP/hostname: /// ```bash /// synord --network testnet --rpc-host 0.0.0.0 /// ``` /// /// 2. **Get the peer ID** from startup logs: /// ``` /// INFO synor_network::service: Local peer ID: 12D3KooWAbCdEfGhIjKlMnOpQrStUvWxYz123456789 /// ``` /// /// 3. **Add the full multiaddr** (hostname + port + peer_id): /// ```text /// /dns4/testnet-seed1.synor.cc/tcp/17511/p2p/12D3KooWAbCdEfGhIjKlMnOpQrStUvWxYz123456789 /// ``` /// /// # Runtime Configuration /// /// Instead of hardcoding, operators can use the `SYNOR_BOOTSTRAP_PEERS` environment /// variable at the synord application level (comma-separated multiaddrs). fn testnet_bootstrap_peers() -> Vec { // Testnet bootstrap nodes - add peer IDs when seed nodes are deployed // Format: /dns4//tcp//p2p/ // // NOTE: Seeds are configured empty here because peer IDs are only known // after deployment. Use SYNOR_BOOTSTRAP_PEERS env var or config file // to specify bootstrap peers at runtime. let seeds: &[&str] = &[ // North America (seed1.synor.cc) - uncomment after deployment: // "/dns4/testnet-seed1.synor.cc/tcp/17511/p2p/12D3KooW...", // Europe (seed2.synor.cc) - uncomment after deployment: // "/dns4/testnet-seed2.synor.cc/tcp/17511/p2p/12D3KooW...", // Asia (seed3.synor.cc) - uncomment after deployment: // "/dns4/testnet-seed3.synor.cc/tcp/17511/p2p/12D3KooW...", ]; seeds.iter().filter_map(|s| s.parse().ok()).collect() } /// Returns devnet bootstrap peers for local development. /// /// For local multi-node testing, start the first node and note its peer ID, /// then configure other nodes to bootstrap from it. fn devnet_bootstrap_peers() -> Vec { // Local devnet typically uses mDNS for discovery // Add local bootstrap peers here if needed for testing without mDNS vec![] } /// Testnet network parameters. pub mod testnet_params { /// Testnet chain ID. pub const CHAIN_ID: u64 = 1; /// Target block time in milliseconds. pub const BLOCK_TIME_MS: u64 = 100; /// GHOSTDAG K parameter. pub const GHOSTDAG_K: u32 = 18; /// Default P2P port for testnet. pub const DEFAULT_PORT: u16 = 17511; /// Default RPC port for testnet. pub const RPC_PORT: u16 = 17110; /// Default WebSocket port for testnet. pub const WS_PORT: u16 = 17111; } /// Mainnet network parameters. pub mod mainnet_params { /// Mainnet chain ID. pub const CHAIN_ID: u64 = 0; /// Target block time in milliseconds. pub const BLOCK_TIME_MS: u64 = 1000; /// GHOSTDAG K parameter. pub const GHOSTDAG_K: u32 = 18; /// Default P2P port for mainnet. pub const DEFAULT_PORT: u16 = 16511; /// Default RPC port for mainnet. pub const RPC_PORT: u16 = 16110; /// Default WebSocket port for mainnet. pub const WS_PORT: u16 = 16111; } /// Devnet network parameters for local development and testing. pub mod devnet_params { /// Devnet chain ID. pub const CHAIN_ID: u64 = 2; /// Target block time in milliseconds (faster for testing). pub const BLOCK_TIME_MS: u64 = 50; /// GHOSTDAG K parameter (smaller for faster consensus). pub const GHOSTDAG_K: u32 = 8; /// Default P2P port for devnet. pub const DEFAULT_PORT: u16 = 18511; /// Default RPC port for devnet. pub const RPC_PORT: u16 = 18110; /// Default WebSocket port for devnet. pub const WS_PORT: u16 = 18111; } #[cfg(test)] mod tests { use super::*; #[test] fn test_default_config() { let config = NetworkConfig::default(); assert_eq!(config.chain_id, ChainId::Mainnet); assert!(config.max_peers() > 0); } #[test] fn test_testnet_config() { let config = NetworkConfig::testnet(); assert_eq!(config.chain_id, ChainId::Testnet); } #[test] fn test_devnet_config() { let config = NetworkConfig::devnet(); assert!(config.enable_mdns); assert!(!config.enable_kad); } }