104 lines
3.5 KiB
Rust
104 lines
3.5 KiB
Rust
|
|
// Transport build helper для libp2p Swarm с TLS 1.3 + Noise + Yamux.
|
|||
|
|
//
|
|||
|
|
// Spec section "Connection lifecycle" Step 1-3:
|
|||
|
|
// TCP SYN → TLS 1.3 handshake → Noise key agreement
|
|||
|
|
//
|
|||
|
|
// Step 4-5 (IBT proof + access level) — см. ibt_upgrade::classify_proof.
|
|||
|
|
// Step 6 (ProtocolMessage exchange) — caller responsibility поверх данного swarm.
|
|||
|
|
|
|||
|
|
use libp2p::{noise, tcp, tls, yamux, Multiaddr, Swarm, SwarmBuilder};
|
|||
|
|
|
|||
|
|
use crate::error::TransportError;
|
|||
|
|
|
|||
|
|
pub struct NetworkConfig {
|
|||
|
|
pub listen_addrs: Vec<Multiaddr>,
|
|||
|
|
pub max_inbound: u32,
|
|||
|
|
pub max_outbound: u32,
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
impl NetworkConfig {
|
|||
|
|
pub fn defaults() -> Self {
|
|||
|
|
// Defaults per spec Network section + critic-fix P-S3
|
|||
|
|
// (operator-configurable, не Genesis Decree binding).
|
|||
|
|
NetworkConfig {
|
|||
|
|
listen_addrs: Vec::new(),
|
|||
|
|
max_inbound: 13,
|
|||
|
|
max_outbound: 24,
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
pub fn build_swarm<B>(behaviour: B, config: &NetworkConfig) -> Result<Swarm<B>, TransportError>
|
|||
|
|
where
|
|||
|
|
B: libp2p::swarm::NetworkBehaviour + Send,
|
|||
|
|
{
|
|||
|
|
let mut swarm = SwarmBuilder::with_new_identity()
|
|||
|
|
.with_tokio()
|
|||
|
|
.with_tcp(
|
|||
|
|
tcp::Config::default(),
|
|||
|
|
// TLS 1.3 (rustls) + Noise — двойное шифрование per spec
|
|||
|
|
// Transport Obfuscation; TLS hides traffic от passive observer
|
|||
|
|
// (DPI), Noise authenticates peer identity.
|
|||
|
|
(tls::Config::new, noise::Config::new),
|
|||
|
|
yamux::Config::default,
|
|||
|
|
)
|
|||
|
|
.map_err(|e| TransportError::Setup(format!("transport upgrade: {e}")))?
|
|||
|
|
.with_behaviour(|_| behaviour)
|
|||
|
|
.map_err(|e| TransportError::Setup(format!("behaviour: {e}")))?
|
|||
|
|
.build();
|
|||
|
|
|
|||
|
|
for addr in &config.listen_addrs {
|
|||
|
|
swarm
|
|||
|
|
.listen_on(addr.clone())
|
|||
|
|
.map_err(|e| TransportError::Setup(format!("listen_on {addr}: {e}")))?;
|
|||
|
|
}
|
|||
|
|
Ok(swarm)
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/// Сборка swarm-а с фиксированным libp2p Keypair (production-режим).
|
|||
|
|
///
|
|||
|
|
/// В отличие от `build_swarm` (генерит fresh keypair каждый запуск, для тестов),
|
|||
|
|
/// эта функция принимает готовый Ed25519 keypair, derived from operator's
|
|||
|
|
/// identity. PeerId узла стабилен между перезапусками — обязательно для
|
|||
|
|
/// genesis-cohort peer pinning через `GenesisManifest`.
|
|||
|
|
pub fn build_swarm_with_keypair<B>(
|
|||
|
|
keypair: libp2p::identity::Keypair,
|
|||
|
|
behaviour: B,
|
|||
|
|
config: &NetworkConfig,
|
|||
|
|
) -> Result<Swarm<B>, TransportError>
|
|||
|
|
where
|
|||
|
|
B: libp2p::swarm::NetworkBehaviour + Send,
|
|||
|
|
{
|
|||
|
|
let mut swarm = SwarmBuilder::with_existing_identity(keypair)
|
|||
|
|
.with_tokio()
|
|||
|
|
.with_tcp(
|
|||
|
|
tcp::Config::default(),
|
|||
|
|
(tls::Config::new, noise::Config::new),
|
|||
|
|
yamux::Config::default,
|
|||
|
|
)
|
|||
|
|
.map_err(|e| TransportError::Setup(format!("transport upgrade: {e}")))?
|
|||
|
|
.with_behaviour(|_| behaviour)
|
|||
|
|
.map_err(|e| TransportError::Setup(format!("behaviour: {e}")))?
|
|||
|
|
.with_swarm_config(|c| c.with_idle_connection_timeout(std::time::Duration::from_secs(60)))
|
|||
|
|
.build();
|
|||
|
|
|
|||
|
|
for addr in &config.listen_addrs {
|
|||
|
|
swarm
|
|||
|
|
.listen_on(addr.clone())
|
|||
|
|
.map_err(|e| TransportError::Setup(format!("listen_on {addr}: {e}")))?;
|
|||
|
|
}
|
|||
|
|
Ok(swarm)
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
#[cfg(test)]
|
|||
|
|
mod tests {
|
|||
|
|
use super::*;
|
|||
|
|
|
|||
|
|
#[test]
|
|||
|
|
fn defaults_match_spec() {
|
|||
|
|
let c = NetworkConfig::defaults();
|
|||
|
|
assert_eq!(c.max_outbound, 24);
|
|||
|
|
assert_eq!(c.max_inbound, 13);
|
|||
|
|
}
|
|||
|
|
}
|