feat(p2p): add MeshNode integrating all production modules

New mesh_node.rs providing a production-ready node:
- MeshNodeBuilder for fluent configuration
- MeshConfig integration for all settings
- MeshMetrics tracking for all operations
- Rate limiting on incoming messages
- Backpressure controller
- Graceful shutdown via ShutdownCoordinator
- Optional FappRouter based on capabilities
- MeshRouter for envelope routing
- TransportManager for multi-transport support

Key APIs:
- MeshNodeBuilder::new().fapp_relay().build()
- node.process_incoming() with rate limiting + metrics
- node.gc() for store/routing table cleanup
- node.shutdown() for graceful termination

222 tests passing (203 lib + 3 fapp_flow + 16 multi_node)
This commit is contained in:
2026-04-01 18:45:41 +02:00
parent a60767a7eb
commit 150f30b0d6
21 changed files with 4413 additions and 0 deletions

View File

@@ -0,0 +1,119 @@
//! Service identity management using Ed25519.
use ed25519_dalek::{Signature, Signer, SigningKey, Verifier, VerifyingKey};
use rand::rngs::OsRng;
use sha2::{Digest, Sha256};
/// A service participant's identity (Ed25519 keypair).
#[derive(Clone)]
pub struct ServiceIdentity {
signing_key: SigningKey,
}
impl ServiceIdentity {
/// Generate a new random identity.
pub fn generate() -> Self {
use rand::RngCore;
let mut secret = [0u8; 32];
OsRng.fill_bytes(&mut secret);
let signing_key = SigningKey::from_bytes(&secret);
Self { signing_key }
}
/// Create from an existing secret key.
pub fn from_secret(secret: &[u8; 32]) -> Self {
let signing_key = SigningKey::from_bytes(secret);
Self { signing_key }
}
/// Get the 32-byte public key.
pub fn public_key(&self) -> [u8; 32] {
self.signing_key.verifying_key().to_bytes()
}
/// Get the 32-byte secret key (for persistence).
pub fn secret_key(&self) -> [u8; 32] {
self.signing_key.to_bytes()
}
/// Compute the 16-byte mesh address from the public key.
pub fn address(&self) -> [u8; 16] {
compute_address(&self.public_key())
}
/// Sign a message.
pub fn sign(&self, message: &[u8]) -> [u8; 64] {
let sig = self.signing_key.sign(message);
sig.to_bytes()
}
/// Verify a signature against a public key.
pub fn verify(public_key: &[u8; 32], message: &[u8], signature: &[u8; 64]) -> bool {
let Ok(verifying_key) = VerifyingKey::from_bytes(public_key) else {
return false;
};
let sig = Signature::from_bytes(signature);
verifying_key.verify(message, &sig).is_ok()
}
}
/// Compute a 16-byte mesh address from a 32-byte public key.
///
/// Address = SHA-256(public_key)[0..16]
pub fn compute_address(public_key: &[u8; 32]) -> [u8; 16] {
let hash = Sha256::digest(public_key);
let mut addr = [0u8; 16];
addr.copy_from_slice(&hash[..16]);
addr
}
impl std::fmt::Debug for ServiceIdentity {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("ServiceIdentity")
.field("address", &hex::encode(self.address()))
.finish()
}
}
// Hex encoding for debug output
mod hex {
pub fn encode(bytes: impl AsRef<[u8]>) -> String {
bytes.as_ref().iter().map(|b| format!("{b:02x}")).collect()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn generate_and_sign() {
let id = ServiceIdentity::generate();
let msg = b"hello world";
let sig = id.sign(msg);
assert!(ServiceIdentity::verify(&id.public_key(), msg, &sig));
}
#[test]
fn address_is_deterministic() {
let id = ServiceIdentity::generate();
let addr1 = id.address();
let addr2 = compute_address(&id.public_key());
assert_eq!(addr1, addr2);
}
#[test]
fn wrong_message_fails() {
let id = ServiceIdentity::generate();
let sig = id.sign(b"correct");
assert!(!ServiceIdentity::verify(&id.public_key(), b"wrong", &sig));
}
#[test]
fn roundtrip_secret() {
let id = ServiceIdentity::generate();
let secret = id.secret_key();
let restored = ServiceIdentity::from_secret(&secret);
assert_eq!(id.public_key(), restored.public_key());
}
}