config: add island federation and NAT traversal support for federated mesh architecture
Some checks failed
CLI Tests / test-cli (push) Has been cancelled
Documentation Validation / validate-docs (push) Has been cancelled
Integration Tests / test-service-integration (push) Has been cancelled
Python Tests / test-python (push) Has been cancelled
Security Scanning / security-scan (push) Has been cancelled

- Add island configuration fields (island_id, island_name, is_hub, island_chain_id, hub_discovery_url, bridge_islands)
- Add NAT traversal configuration (STUN/TURN servers and credentials)
- Add DEFAULT_ISLAND_ID using UUID for new installations
- Extend PeerNode with public_address, public_port, island_id, island_chain_id, and is_hub fields
- Update DiscoveryMessage to include island metadata and public endpoint
This commit is contained in:
aitbc
2026-04-13 08:57:34 +02:00
parent 57c53c2fc3
commit fefa6c4435
13 changed files with 2308 additions and 34 deletions

View File

@@ -8,16 +8,27 @@ import asyncio
import json
import logging
from .mempool import get_mempool, compute_tx_hash
from typing import Dict, Any, Optional, Set, Tuple
from .network.nat_traversal import NATTraversalService
from .network.island_manager import IslandManager
from .network.hub_manager import HubManager
from typing import Dict, Any, Optional, Set, Tuple, List
logger = logging.getLogger(__name__)
class P2PNetworkService:
def __init__(self, host: str, port: int, node_id: str, peers: str = ""):
def __init__(self, host: str, port: int, node_id: str, peers: str = "", stun_servers: List[str] = None,
island_id: str = "", island_name: str = "default", is_hub: bool = False,
island_chain_id: str = ""):
self.host = host
self.port = port
self.node_id = node_id
# Island configuration
self.island_id = island_id
self.island_name = island_name
self.is_hub = is_hub
self.island_chain_id = island_chain_id or f"ait-{island_id[:8]}" if island_id else ""
# Initial peers to dial (format: "ip:port,ip:port")
self.initial_peers = []
if peers:
@@ -36,6 +47,20 @@ class P2PNetworkService:
self.active_connections: Dict[str, asyncio.StreamWriter] = {}
# Set of active endpoints we've connected to prevent duplicate dialing
self.connected_endpoints: Set[Tuple[str, int]] = set()
# Public endpoint discovered via STUN
self.public_endpoint: Optional[Tuple[str, int]] = None
# NAT traversal service
self.nat_traversal: Optional[NATTraversalService] = None
if stun_servers:
self.nat_traversal = NATTraversalService(stun_servers)
# Island manager
self.island_manager: Optional[IslandManager] = None
# Hub manager
self.hub_manager: Optional[HubManager] = None
self._background_tasks = []
@@ -43,6 +68,44 @@ class P2PNetworkService:
"""Start P2P network service"""
logger.info(f"Starting P2P network mesh service on {self.host}:{self.port}")
logger.info(f"Node ID: {self.node_id}")
logger.info(f"Island ID: {self.island_id}")
logger.info(f"Island Name: {self.island_name}")
logger.info(f"Is Hub: {self.is_hub}")
# Initialize island manager
if self.island_id:
self.island_manager = IslandManager(
self.node_id,
self.island_id,
self.island_chain_id or f"ait-{self.island_id[:8]}"
)
logger.info("Initialized island manager")
# Initialize hub manager if this node is a hub
if self.is_hub:
self.hub_manager = HubManager(
self.node_id,
self.host,
self.port,
self.island_id,
self.island_name
)
self.hub_manager.register_as_hub(self.public_endpoint[0] if self.public_endpoint else None,
self.public_endpoint[1] if self.public_endpoint else None)
logger.info("Initialized hub manager")
# Discover public endpoint via STUN if configured
if self.nat_traversal:
logger.info("Attempting STUN discovery for public endpoint...")
try:
await self.nat_traversal.discover_endpoint()
self.public_endpoint = self.nat_traversal.get_public_endpoint()
if self.public_endpoint:
logger.info(f"Discovered public endpoint: {self.public_endpoint[0]}:{self.public_endpoint[1]}")
else:
logger.warning("STUN discovery failed, will use local address")
except Exception as e:
logger.error(f"STUN discovery error: {e}")
# Create TCP server for inbound P2P connections
self._server = await asyncio.start_server(
@@ -176,11 +239,17 @@ class P2PNetworkService:
# Record that we're connected to this endpoint
self.connected_endpoints.add(endpoint)
# Send handshake immediately
# Send handshake immediately with island information
handshake = {
'type': 'handshake',
'node_id': self.node_id,
'listen_port': self.port
'listen_port': self.port,
'island_id': self.island_id,
'island_name': self.island_name,
'is_hub': self.is_hub,
'island_chain_id': self.island_chain_id,
'public_address': self.public_endpoint[0] if self.public_endpoint else None,
'public_port': self.public_endpoint[1] if self.public_endpoint else None
}
await self._send_message(writer, handshake)
@@ -213,12 +282,25 @@ class P2PNetworkService:
peer_node_id = message.get('node_id')
peer_listen_port = message.get('listen_port', 7070)
peer_island_id = message.get('island_id', '')
peer_island_name = message.get('island_name', '')
peer_is_hub = message.get('is_hub', False)
peer_island_chain_id = message.get('island_chain_id', '')
peer_public_address = message.get('public_address')
peer_public_port = message.get('public_port')
if not peer_node_id or peer_node_id == self.node_id:
logger.warning(f"Peer {addr} provided invalid or self node_id: {peer_node_id}")
writer.close()
return
# Store peer's island information
logger.info(f"Peer {peer_node_id} from island {peer_island_id} (hub: {peer_is_hub})")
# Store peer's public endpoint if provided
if peer_public_address and peer_public_port:
logger.info(f"Peer {peer_node_id} public endpoint: {peer_public_address}:{peer_public_port}")
# Accept handshake and store connection
logger.info(f"Handshake accepted from node {peer_node_id} at {addr}")
@@ -234,11 +316,35 @@ class P2PNetworkService:
remote_ip = addr[0]
self.connected_endpoints.add((remote_ip, peer_listen_port))
# Reply with our handshake
# Add peer to island manager if available
if self.island_manager and peer_island_id:
self.island_manager.add_island_peer(peer_island_id, peer_node_id)
# Add peer to hub manager if available and peer is a hub
if self.hub_manager and peer_is_hub:
from .network.hub_manager import PeerInfo
self.hub_manager.register_peer(PeerInfo(
node_id=peer_node_id,
address=remote_ip,
port=peer_listen_port,
island_id=peer_island_id,
is_hub=peer_is_hub,
public_address=peer_public_address,
public_port=peer_public_port,
last_seen=asyncio.get_event_loop().time()
))
# Reply with our handshake including island information
reply_handshake = {
'type': 'handshake',
'node_id': self.node_id,
'listen_port': self.port
'listen_port': self.port,
'island_id': self.island_id,
'island_name': self.island_name,
'is_hub': self.is_hub,
'island_chain_id': self.island_chain_id,
'public_address': self.public_endpoint[0] if self.public_endpoint else None,
'public_port': self.public_endpoint[1] if self.public_endpoint else None
}
await self._send_message(writer, reply_handshake)
@@ -270,6 +376,9 @@ class P2PNetworkService:
if outbound and peer_id is None:
if msg_type == 'handshake':
peer_id = message.get('node_id')
peer_island_id = message.get('island_id', '')
peer_is_hub = message.get('is_hub', False)
if not peer_id or peer_id == self.node_id:
logger.warning(f"Invalid handshake reply from {addr}. Closing.")
break
@@ -279,7 +388,26 @@ class P2PNetworkService:
break
self.active_connections[peer_id] = writer
logger.info(f"Outbound handshake complete. Connected to node {peer_id}")
# Add peer to island manager if available
if self.island_manager and peer_island_id:
self.island_manager.add_island_peer(peer_island_id, peer_id)
# Add peer to hub manager if available and peer is a hub
if self.hub_manager and peer_is_hub:
from .network.hub_manager import PeerInfo
self.hub_manager.register_peer(PeerInfo(
node_id=peer_id,
address=addr[0],
port=addr[1],
island_id=peer_island_id,
is_hub=peer_is_hub,
public_address=message.get('public_address'),
public_port=message.get('public_port'),
last_seen=asyncio.get_event_loop().time()
))
logger.info(f"Outbound handshake complete. Connected to node {peer_id} (island: {peer_island_id})")
continue
else:
logger.warning(f"Expected handshake reply from {addr}, got {msg_type}")