Harden mesh bootstrap defaults

This commit is contained in:
BigBodyCobain
2026-07-10 20:27:56 -06:00
parent 09c8a2e6d4
commit d38c886af9
15 changed files with 183 additions and 24 deletions
+12
View File
@@ -1489,9 +1489,21 @@ def _refresh_node_peer_store(*, now: float | None = None) -> dict[str, Any]:
push_records = [record for record in push_records if _is_private_infonet_transport(record.transport)]
swarm_sync_peer_count = len([record for record in sync_records if str(record.source or "") == "swarm"])
swarm_push_peer_count = len([record for record in push_records if str(record.source or "") == "swarm"])
swarm_pull_ok = bool(swarm_pull.get("ok")) and not bool(swarm_pull.get("skipped"))
if swarm_pull_ok or manifest is not None or swarm_sync_peer_count > 0:
bootstrap_state = "ready"
bootstrap_detail = "Bootstrap peer discovery is ready."
elif bootstrap_seed_peers:
bootstrap_state = "connecting"
bootstrap_detail = "Bootstrap seeds are configured; local node stays active and retries in the background."
else:
bootstrap_state = "solo"
bootstrap_detail = "No bootstrap seeds configured; local node is running in solo mode."
snapshot = {
"node_mode": mode,
"private_transport_required": private_transport_required,
"bootstrap_state": bootstrap_state,
"bootstrap_detail": bootstrap_detail,
"skipped_clearnet_peer_count": skipped_clearnet_peers,
"pruned_clearnet_peer_count": pruned_clearnet_peers,
"manifest_loaded": manifest is not None,
+4 -1
View File
@@ -148,12 +148,15 @@ def _is_private_infonet_transport(transport: str) -> bool:
def _configured_bootstrap_seed_peer_urls() -> list[str]:
from services.config import get_settings
from services.mesh.mesh_fleet_defaults import configured_bootstrap_seed_peers_with_fleet_default
from services.mesh.mesh_router import parse_configured_relay_peers
settings = get_settings()
primary = str(getattr(settings, "MESH_BOOTSTRAP_SEED_PEERS", "") or "").strip()
legacy = str(getattr(settings, "MESH_DEFAULT_SYNC_PEERS", "") or "").strip()
return parse_configured_relay_peers(primary or legacy)
return configured_bootstrap_seed_peers_with_fleet_default(
parse_configured_relay_peers(primary or legacy)
)
def _refresh_node_peer_store(*, now: float | None = None) -> dict[str, Any]:
+4 -1
View File
@@ -39,7 +39,10 @@ class Settings(BaseSettings):
MESH_PUBLIC_PEER_URL: str = ""
# Bootstrap seeds are discovery hints, not authoritative network roots.
# Nodes promote healthy discovered peers from the store/manifest over time.
MESH_BOOTSTRAP_SEED_PEERS: str = "http://gqpbunqbgtkcqilvclm3xrkt3zowjyl3s62kkktvojgvxzizamvbrqid.onion:8000"
MESH_BOOTSTRAP_SEED_PEERS: str = ""
# Optional comma-separated override for the public fleet's bundled onion seeds.
# This lets seed rotation/addition ship as env/config without weakening private sync.
MESH_FLEET_SEED_PEERS: str = ""
# Legacy name kept for older compose/.env files.
MESH_DEFAULT_SYNC_PEERS: str = ""
# Infonet/Wormhole must fail closed to private transports by default.
+32 -3
View File
@@ -10,6 +10,9 @@ FLEET_NETWORK_ID = "sb-testnet-0"
FLEET_SEED_ONION_URL = (
"http://gqpbunqbgtkcqilvclm3xrkt3zowjyl3s62kkktvojgvxzizamvbrqid.onion:8000"
)
FLEET_SEED_ONION_URLS = (
FLEET_SEED_ONION_URL,
)
FLEET_BOOTSTRAP_SIGNER_PUBLIC_KEY_B64 = (
"ul1d0kj/ODPIp0OhHzX8eLAVXzJ3CVvzW1vn2IC6q3I="
)
@@ -56,9 +59,35 @@ def effective_peer_push_secret() -> str:
return ""
def _dedupe_peer_urls(peers: list[str]) -> list[str]:
from services.mesh.mesh_router import parse_configured_relay_peers
seen: set[str] = set()
normalized: list[str] = []
for peer in parse_configured_relay_peers(",".join(str(item or "") for item in peers)):
if peer in seen:
continue
seen.add(peer)
normalized.append(peer)
return normalized
def effective_fleet_seed_peers() -> list[str]:
try:
from services.config import get_settings
configured = str(getattr(get_settings(), "MESH_FLEET_SEED_PEERS", "") or "").strip()
if configured:
return _dedupe_peer_urls([configured])
except Exception:
pass
return _dedupe_peer_urls(list(FLEET_SEED_ONION_URLS))
def configured_bootstrap_seed_peers_with_fleet_default(peers: list[str]) -> list[str]:
if peers:
return peers
normalized_peers = _dedupe_peer_urls(peers)
if normalized_peers:
return normalized_peers
if infonet_fleet_join_enabled():
return [FLEET_SEED_ONION_URL]
return effective_fleet_seed_peers()
return []
+10 -3
View File
@@ -301,8 +301,9 @@ def refresh_swarm_manifest_from_seeds(*, now: float | None = None, force: bool =
if not _signer_public_key_b64():
return {"ok": False, "detail": "MESH_BOOTSTRAP_SIGNER_PUBLIC_KEY is not configured"}
last_error = "manifest fetch failed"
for seed_url in _configured_seed_peer_urls():
seed_urls = _configured_seed_peer_urls()
last_error = "bootstrap seeds unreachable; local node will retry"
for seed_url in seed_urls:
manifest = fetch_remote_bootstrap_manifest(seed_url, now=timestamp)
if manifest is None:
continue
@@ -311,12 +312,18 @@ def refresh_swarm_manifest_from_seeds(*, now: float | None = None, force: bool =
return {
"ok": True,
"seed_peer_url": seed_url,
"tried_seed_count": len(seed_urls),
"peer_count": len(manifest.peers),
"merged_peer_count": merged,
}
except Exception as exc:
last_error = str(exc or type(exc).__name__)
return {"ok": False, "detail": last_error}
return {
"ok": False,
"detail": last_error,
"tried_seed_count": len(seed_urls),
"retrying": bool(seed_urls),
}
def announce_local_peer_to_seeds(*, now: float | None = None, force: bool = False) -> dict[str, Any]:
@@ -103,11 +103,12 @@ def _invite_lookup_request_timeout(peer_url: str) -> tuple[int, int]:
def _bootstrap_seed_peer_urls() -> set[str]:
try:
from services.config import get_settings
from services.mesh.mesh_fleet_defaults import configured_bootstrap_seed_peers_with_fleet_default
from services.mesh.mesh_router import parse_configured_relay_peers
seeds: set[str] = set()
raw = str(getattr(get_settings(), "MESH_BOOTSTRAP_SEED_PEERS", "") or "")
for peer in parse_configured_relay_peers(raw):
for peer in configured_bootstrap_seed_peers_with_fleet_default(parse_configured_relay_peers(raw)):
normalized = str(peer or "").strip().rstrip("/")
if normalized:
seeds.add(normalized)
@@ -318,6 +319,8 @@ def _configured_public_lookup_peer_urls() -> list[str]:
from services.mesh.mesh_router import active_sync_peer_urls, parse_configured_relay_peers
settings = get_settings()
from services.mesh.mesh_fleet_defaults import configured_bootstrap_seed_peers_with_fleet_default
candidates: list[str] = []
# Operator-configured peers first, then recently active fleet nodes.
# Invite handles are minted on a specific node; cold bootstrap seeds
@@ -330,7 +333,11 @@ def _configured_public_lookup_peer_urls() -> list[str]:
for raw in (
getattr(settings, "MESH_BOOTSTRAP_SEED_PEERS", ""),
):
candidates.extend(parse_configured_relay_peers(str(raw or "")))
candidates.extend(
configured_bootstrap_seed_peers_with_fleet_default(
parse_configured_relay_peers(str(raw or ""))
)
)
except Exception:
return []
+51 -2
View File
@@ -1,6 +1,9 @@
from services.mesh.mesh_fleet_defaults import (
FLEET_SEED_ONION_URL,
FLEET_PEER_PUSH_SECRET,
configured_bootstrap_seed_peers_with_fleet_default,
effective_bootstrap_signer_public_key_b64,
effective_fleet_seed_peers,
effective_peer_push_secret,
infonet_fleet_join_enabled,
)
@@ -9,8 +12,8 @@ from services.mesh.mesh_fleet_defaults import (
def test_fleet_defaults_apply_when_join_enabled(monkeypatch):
from services.config import get_settings
monkeypatch.delenv("MESH_BOOTSTRAP_SIGNER_PUBLIC_KEY", raising=False)
monkeypatch.delenv("MESH_PEER_PUSH_SECRET", raising=False)
monkeypatch.setenv("MESH_BOOTSTRAP_SIGNER_PUBLIC_KEY", "")
monkeypatch.setenv("MESH_PEER_PUSH_SECRET", "")
monkeypatch.setenv("MESH_INFONET_FLEET_JOIN", "true")
get_settings.cache_clear()
try:
@@ -21,6 +24,52 @@ def test_fleet_defaults_apply_when_join_enabled(monkeypatch):
get_settings.cache_clear()
def test_empty_bootstrap_peers_use_fleet_seed_defaults(monkeypatch):
from services.config import get_settings
monkeypatch.delenv("MESH_FLEET_SEED_PEERS", raising=False)
monkeypatch.setenv("MESH_INFONET_FLEET_JOIN", "true")
get_settings.cache_clear()
try:
assert configured_bootstrap_seed_peers_with_fleet_default([]) == [FLEET_SEED_ONION_URL]
finally:
get_settings.cache_clear()
def test_configured_bootstrap_peers_override_fleet_defaults(monkeypatch):
from services.config import get_settings
monkeypatch.setenv("MESH_INFONET_FLEET_JOIN", "true")
get_settings.cache_clear()
try:
assert configured_bootstrap_seed_peers_with_fleet_default(
["http://alphaexample.onion:8000", "http://alphaexample.onion:8000"]
) == ["http://alphaexample.onion:8000"]
finally:
get_settings.cache_clear()
def test_fleet_seed_override_can_ship_multiple_seeds(monkeypatch):
from services.config import get_settings
monkeypatch.setenv(
"MESH_FLEET_SEED_PEERS",
"http://alphaexample.onion:8000,http://betaexample.onion:8000,http://alphaexample.onion:8000",
)
get_settings.cache_clear()
try:
assert effective_fleet_seed_peers() == [
"http://alphaexample.onion:8000",
"http://betaexample.onion:8000",
]
assert configured_bootstrap_seed_peers_with_fleet_default([]) == [
"http://alphaexample.onion:8000",
"http://betaexample.onion:8000",
]
finally:
get_settings.cache_clear()
def test_fleet_defaults_disabled(monkeypatch):
from services.config import get_settings
@@ -479,4 +479,4 @@ def test_meshnode_scripts_enable_private_hashchain_runtime():
assert "MESH_INFONET_ALLOW_CLEARNET_SYNC=false" in script
assert "MESH_ARTI_ENABLED=true" in script
assert "MESH_DM_HASHCHAIN_SPOOL_LIMIT=2" in script
assert "gqpbunqbgtkcqilvclm3xrkt3zowjyl3s62kkktvojgvxzizamvbrqid.onion:8000" in script
assert "sb-testnet fleet defaults" in script
@@ -16,6 +16,7 @@ from services.mesh.mesh_swarm_runtime import (
merge_manifest_into_peer_store,
peer_registry_enabled,
publish_registry_manifest,
refresh_swarm_manifest_from_seeds,
record_peer_announcement,
)
@@ -180,6 +181,30 @@ def test_parse_bootstrap_manifest_dict_rejects_expired():
)
def test_refresh_swarm_manifest_reports_retrying_when_all_seeds_unreachable(monkeypatch):
from services.config import get_settings
monkeypatch.setenv("MESH_BOOTSTRAP_SIGNER_PUBLIC_KEY", "ul1d0kj/ODPIp0OhHzX8eLAVXzJ3CVvzW1vn2IC6q3I=")
monkeypatch.setenv(
"MESH_BOOTSTRAP_SEED_PEERS",
"http://seed-a.onion:8000,http://seed-b.onion:8000",
)
monkeypatch.setattr(
"services.mesh.mesh_swarm_runtime.fetch_remote_bootstrap_manifest",
lambda *_args, **_kwargs: None,
)
get_settings.cache_clear()
try:
result = refresh_swarm_manifest_from_seeds(force=True, now=1_750_000_000)
finally:
get_settings.cache_clear()
assert result["ok"] is False
assert result["retrying"] is True
assert result["tried_seed_count"] == 2
assert result["detail"] == "bootstrap seeds unreachable; local node will retry"
@pytest.mark.asyncio
async def test_bootstrap_manifest_endpoint_serves_live_registry(tmp_path, monkeypatch):
import main
+4 -1
View File
@@ -14,7 +14,10 @@ services:
MESH_SYNC_MAX_PEERS_PER_CYCLE: "5"
MESH_INFONET_ALLOW_CLEARNET_SYNC: "false"
MESH_PUBLIC_PEER_URL: ""
MESH_BOOTSTRAP_SEED_PEERS: "http://gqpbunqbgtkcqilvclm3xrkt3zowjyl3s62kkktvojgvxzizamvbrqid.onion:8000"
# Empty means: use the sb-testnet fleet seed list from code/config.
# Operators can rotate/add public fleet seeds with MESH_FLEET_SEED_PEERS.
MESH_BOOTSTRAP_SEED_PEERS: ""
MESH_FLEET_SEED_PEERS: "${MESH_FLEET_SEED_PEERS:-}"
MESH_RELAY_PEERS: ""
MESH_DEFAULT_SYNC_PEERS: ""
MESH_BOOTSTRAP_SIGNER_PUBLIC_KEY: "ul1d0kj/ODPIp0OhHzX8eLAVXzJ3CVvzW1vn2IC6q3I="
@@ -66,6 +66,8 @@ export default function BootstrapView({ marketId, onBack }: BootstrapViewProps)
const swarmPullOk = Boolean(swarmPull?.ok) && !swarmPull?.skipped;
const lastPeerUrl = String(nodeStatus?.sync_runtime?.last_peer_url || '').trim();
const privateTransportRequired = Boolean(nodeStatus?.private_transport_required);
const bootstrapState = String(nodeStatus?.bootstrap?.bootstrap_state || '').toLowerCase();
const bootstrapDetail = String(nodeStatus?.bootstrap?.bootstrap_detail || '').trim();
const toggleNode = useCallback(async (enabled: boolean) => {
setNodeToggleBusy(true);
@@ -179,14 +181,16 @@ export default function BootstrapView({ marketId, onBack }: BootstrapViewProps)
? 'LOCAL FILE'
: swarmPull?.skipped
? 'WAITING'
: 'NOT LOADED'}
: bootstrapState === 'connecting'
? 'CONNECTING'
: 'LOCAL ONLY'}
</div>
</div>
</div>
<div className="mt-3 flex flex-col md:flex-row md:items-center gap-3">
<div className="flex-1 text-[11px] text-gray-500 leading-relaxed">
{nodeEnabled
? `Infonet sync is ${syncOutcome || 'active'}${lastPeerUrl ? ` via ${lastPeerUrl}` : ''}.`
? (bootstrapDetail || `Infonet sync is ${syncOutcome || 'active'}${lastPeerUrl ? ` via ${lastPeerUrl}` : ''}.`)
: 'Start a local participant node to sync through available Wormhole onion/RNS peers while this backend is running.'}
</div>
<button
@@ -14,12 +14,15 @@ interface Stats {
nodeEnabled: boolean;
syncOutcome: string;
syncError: string;
bootstrapState: string;
bootstrapDetail: string;
artiReady: boolean | null;
}
const EMPTY: Stats = {
meshtastic: 0, aprs: 0, ledgerNodes: 0, infonetEvents: 0,
syncPeers: 0, seedPeers: 0, nodeEnabled: false, syncOutcome: 'offline', syncError: '',
bootstrapState: 'offline', bootstrapDetail: '',
artiReady: null,
};
@@ -57,6 +60,7 @@ export default function NetworkStats() {
?? 0,
);
const syncOutcome = String(infonet?.sync_runtime?.last_outcome || 'offline').toLowerCase();
const bootstrapState = String(infonet?.bootstrap?.bootstrap_state || '').toLowerCase();
const artiReady = typeof wormholeRes?.arti_ready === 'boolean' ? wormholeRes.arti_ready : null;
setStats({
meshtastic: Number(channelsRes?.total_live || channelsRes?.total_nodes || meshRes?.signal_counts?.meshtastic || 0),
@@ -68,6 +72,8 @@ export default function NetworkStats() {
nodeEnabled: Boolean(infonet?.node_enabled),
syncOutcome,
syncError: String(infonet?.sync_runtime?.last_error || '').trim(),
bootstrapState,
bootstrapDetail: String(infonet?.bootstrap?.bootstrap_detail || '').trim(),
artiReady,
});
} catch { /* ignore */ }
@@ -78,17 +84,21 @@ export default function NetworkStats() {
}, []);
const artiBlocked = isArtiTransportBlocked(stats.syncError, stats.artiReady);
const connecting = stats.bootstrapState === 'connecting';
const localActive = stats.syncOutcome === 'solo' || (stats.nodeEnabled && connecting);
const nodeColor = stats.syncOutcome === 'ok' || stats.syncOutcome === 'solo' ? 'text-green-400'
: stats.syncOutcome === 'running' ? 'text-amber-400'
: stats.nodeEnabled ? 'text-amber-400' : 'text-gray-600';
const nodeLabel = stats.syncOutcome === 'ok' ? 'SEED SYNCED'
: stats.syncOutcome === 'solo' ? 'SOLO'
: localActive ? 'LOCAL ACTIVE'
: stats.syncOutcome === 'running' ? 'SYNCING'
: stats.syncOutcome === 'error' || stats.syncOutcome === 'fork'
? (artiBlocked ? 'ARTI WARMING' : 'SYNC BACKOFF')
? (artiBlocked ? 'ARTI WARMING' : 'CONNECTING')
: stats.nodeEnabled ? 'WAITING' : 'OFFLINE';
const nodeTitle = stats.syncError
? `Infonet seed sync: ${stats.syncError}`
const nodeTitle = stats.bootstrapDetail
? stats.bootstrapDetail
: stats.syncError
? `Infonet seed sync is retrying in the background: ${stats.syncError}`
: stats.nodeEnabled
? 'Participant node enabled; waiting for seed ledger sync.'
: 'Participant node offline.';
@@ -15,6 +15,8 @@ export interface RnsStatusSnapshot {
export interface InfonetBootstrapSnapshot {
node_mode?: string;
bootstrap_state?: string;
bootstrap_detail?: string;
manifest_loaded?: boolean;
manifest_signer_id?: string;
manifest_valid_until?: number;
@@ -32,6 +34,8 @@ export interface InfonetBootstrapSnapshot {
skipped?: boolean;
reason?: string;
detail?: string;
retrying?: boolean;
tried_seed_count?: number;
peer_count?: number;
merged_peer_count?: number;
seed_peer_url?: string;
+5 -2
View File
@@ -104,7 +104,6 @@ set MESH_INFONET_ALLOW_CLEARNET_SYNC=false
set MESH_ARTI_ENABLED=true
set MESH_DM_HASHCHAIN_SPOOL_LIMIT=2
set MESH_DM_HASHCHAIN_SPOOL_TTL_S=3600
if "%MESH_BOOTSTRAP_SEED_PEERS%"=="" set MESH_BOOTSTRAP_SEED_PEERS=http://gqpbunqbgtkcqilvclm3xrkt3zowjyl3s62kkktvojgvxzizamvbrqid.onion:8000
if "%MESH_INFONET_FLEET_JOIN%"=="" set MESH_INFONET_FLEET_JOIN=true
if "%MESH_BOOTSTRAP_SIGNER_PUBLIC_KEY%"=="" set MESH_BOOTSTRAP_SIGNER_PUBLIC_KEY=ul1d0kj/ODPIp0OhHzX8eLAVXzJ3CVvzW1vn2IC6q3I=
if "%MESH_SYNC_TIMEOUT_S%"=="" set MESH_SYNC_TIMEOUT_S=45
@@ -116,7 +115,11 @@ echo.
echo ===================================================
echo Mesh node starting on port 8000
echo Mode: MESH_ONLY (no data feeds)
echo Bootstrap: %MESH_BOOTSTRAP_SEED_PEERS%
if "%MESH_BOOTSTRAP_SEED_PEERS%"=="" (
echo Bootstrap: sb-testnet fleet defaults
) else (
echo Bootstrap: %MESH_BOOTSTRAP_SEED_PEERS%
)
echo Swarm: announce + signed manifest pull (fleet join)
echo Press Ctrl+C to stop
echo ===================================================
+2 -2
View File
@@ -59,7 +59,7 @@ export MESH_INFONET_ALLOW_CLEARNET_SYNC=false
export MESH_ARTI_ENABLED=true
export MESH_DM_HASHCHAIN_SPOOL_LIMIT=2
export MESH_DM_HASHCHAIN_SPOOL_TTL_S=3600
export MESH_BOOTSTRAP_SEED_PEERS="${MESH_BOOTSTRAP_SEED_PEERS:-http://gqpbunqbgtkcqilvclm3xrkt3zowjyl3s62kkktvojgvxzizamvbrqid.onion:8000}"
export MESH_BOOTSTRAP_SEED_PEERS="${MESH_BOOTSTRAP_SEED_PEERS:-}"
export MESH_INFONET_FLEET_JOIN="${MESH_INFONET_FLEET_JOIN:-true}"
export MESH_BOOTSTRAP_SIGNER_PUBLIC_KEY="${MESH_BOOTSTRAP_SIGNER_PUBLIC_KEY:-ul1d0kj/ODPIp0OhHzX8eLAVXzJ3CVvzW1vn2IC6q3I=}"
export MESH_SYNC_TIMEOUT_S="${MESH_SYNC_TIMEOUT_S:-45}"
@@ -71,7 +71,7 @@ echo ""
echo "==================================================="
echo " Mesh node starting on port 8000"
echo " Mode: MESH_ONLY (no data feeds)"
echo " Bootstrap: ${MESH_BOOTSTRAP_SEED_PEERS}"
echo " Bootstrap: ${MESH_BOOTSTRAP_SEED_PEERS:-sb-testnet fleet defaults}"
echo " Swarm: announce + signed manifest pull (fleet join)"
echo " Press Ctrl+C to stop"
echo "==================================================="