Files
archy/.claude/plans/synchronous-greeting-rose.md
Dorian f273816405 feat: v1.2.0-alpha — E2E encrypted mesh relay, steganography, relay status polling
Phase 5 mesh networking:
- E2E encrypted TX relay (X25519 + ChaCha20-Poly1305) — non-Archy nodes
  relay encrypted blobs transparently via Meshcore native routing
- Steganographic encoding modes (WeatherStation, SensorNetwork) — traffic
  looks like sensor data on the wire, 0xAA marker, configurable per-node
- Pre-flight Bitcoin Core health check on relay node — specific error codes
  (bitcoin_unreachable, bitcoin_syncing, tx_rejected) instead of generic fails
- mesh.relay-status RPC endpoint — frontend polls for relay result every 3s
- On-Chain / Lightning tabs in Off-Grid Bitcoin panel
- Archy Peers vs Mesh Broadcast relay mode selector
- Mesh view fills viewport (no page scroll), internal panel scrolling
- Version bump to 1.2.0-alpha

Also includes: deploy hardening, container fixes, IndeedHub updates,
boot screen, dashboard improvements, MASTER_PLAN task tracking

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-17 23:56:37 +00:00

8.0 KiB

Mesh Phase 4 Completion + Phase 5 Implementation

Context

Mesh Phases 1-3 are complete: serial driver, transport layer (Mesh>LAN>Tor), Double Ratchet encryption, typed messages, store-and-forward, chat UI. Phase 4 is 40% done — data structures, builders, and tests exist (bitcoin_relay.rs, alerts.rs, message_types.rs) but nothing is wired into the listener, MeshService, or RPC layer. Phase 5 (steganographic modes, adaptive routing, multi-hardware) is not started.

Phase 4: Wire Up Off-Grid Bitcoin Operations (Weeks 8-11)

Week 8: Typed Message Dispatch in Listener

The critical foundation — everything else depends on this.

mesh/listener.rs:

  • Add MeshCommand::SendRaw { dest_pubkey_prefix: [u8; 6], payload: Vec<u8> } and BroadcastChannel { channel: u8, payload: Vec<u8> } variants
  • In handle_frame(): after extracting message bytes, check for 0x02 TypedEnvelope prefix
  • New handle_typed_message() dispatches by type:
    • BlockHeader → validate Ed25519 sig, store in BlockHeaderCache, emit event
    • TxRelay → spawn task: Bitcoin RPC sendrawtransaction, send TxRelayResponse back
    • TxRelayResponse → complete pending in RelayTracker, store as MeshMessage
    • LightningRelay → spawn task: LND REST payinvoice, send response back
    • LightningRelayResponse → complete pending, store
    • Alert → verify sig, store, emit MeshEvent::AlertReceived
  • Handle SendRaw and BroadcastChannel in tokio::select! command dispatch

mesh/types.rs: New MeshEvent variants: BlockHeaderReceived, AlertReceived, TxRelayCompleted, LightningRelayCompleted

Key design: Spawn separate tokio tasks for Bitcoin/LND HTTP calls (don't block serial read loop). Response sent back via cmd_tx channel.

Week 9: MeshService Integration + Dead Man's Switch Task

mesh/mod.rs:

  • Add fields: block_header_cache: Arc<BlockHeaderCache>, relay_tracker: Arc<RelayTracker>, dead_man_switch: Arc<DeadManSwitch>, signing_key: ed25519_dalek::SigningKey
  • Init in new(), pass cache + tracker into listener via MeshState
  • Accessor methods for RPC layer

Dead Man background task (spawned in start()):

  • Check every 60s: if triggered → build signed alert → broadcast on channel 0 + direct to emergency contacts
  • Persist last_check_in_time as unix timestamp on disk (survives restarts)

Week 10: RPC Endpoints

api/rpc/mesh.rs — New handlers:

Endpoint Params Description
mesh.relay-tx { tx_hex } Queue TX for relay via internet peer
mesh.block-headers { count? } Return cached block headers
mesh.relay-lightning { bolt11, amount_sats } Queue LN invoice for payment
mesh.deadman-status Query switch state
mesh.deadman-configure { enabled, interval_secs, lat, lng, contacts, custom_message } Configure
mesh.deadman-checkin Heartbeat reset

Fix mesh.send-invoice: Replace placeholder bolt11 with real LND POST /v1/invoices call.

api/rpc/mod.rs: Register all new routes (~line 643).

Week 11: Block Header Announcer + Frontend

Backend: Optional background task: poll Bitcoin Core getblockchaininfo every 30s → on new block → signed announcement → broadcast channel 0. Config: announce_block_headers: bool.

Frontend stores/mesh.ts: New methods for all Phase 4 RPC calls.

Frontend views/Mesh.vue:

  • "Off-Grid Bitcoin" panel: block height, headers, TX relay form, LN relay form
  • "Dead Man's Switch" panel: enable/disable, interval, GPS, contacts, countdown, check-in
  • Uses .path-option-card, .glass-button, .info-card

Phase 5: Mesh Network Intelligence (Weeks 12-15)

Week 12: Steganographic Modes

New: mesh/steganography.rs

  • SteganographyMode enum: Normal, WeatherStation, SensorNetwork
  • Weather Station: Map payload bytes → plausible weather readings (temp, humidity, pressure, wind). Marker 0xAA replaces 0x02.
  • Sensor Network: Industrial sensor format (voltage, current, vibration)
  • to_wire_steganographic(mode) / from_wire_steganographic(data) on TypedEnvelope
  • Listener detects 0xAA → decode stego → normal dispatch
  • Config: steganography_mode in MeshConfig
  • Budget: ~80 bytes real data per 160-byte LoRa frame with stego overhead

Week 13: Adaptive Routing & Signal Intelligence

New: mesh/routing.rs

  • LinkQuality per peer: RSSI/SNR rolling 1h history, packet loss, hop count
  • RoutingTable: link quality per peer + best route per destination DID
  • Score: (rssi+120)*0.4 + (snr+20)*0.3 + (1-loss)*100*0.3
  • Best relay selection for TX/LN relay (highest quality peer with internet)
  • Multi-hop forwarding: if dest DID != ours and hops < 3, forward to best next-hop
  • Extract RSSI from v3 frames (bytes 1-2, currently unused)
  • RPC: mesh.routing-table

Week 14: LoRa Radio Parameter Control

mesh/protocol.rs: Builders for SET_RADIO_PARAMS (0x0B), SET_TX_POWER (0x0C), SET_TUNING_PARAMS (0x15). Parse RESP_STATS (0x18).

RPC: mesh.set-radio-params, mesh.set-tx-power, mesh.get-radio-stats

Auto-adaptive SF: If link quality drops → increase spreading factor (longer range, slower). Config toggle.

Frontend: Radio tuning panel with SF/TX power sliders, stats, auto-adaptive toggle.

Week 15: Multi-Hardware + Topology UI

New: mesh/device_trait.rs

#[async_trait]
pub trait MeshDevice: Send + Sync {
    async fn open(path: &str) -> Result<Self> where Self: Sized;
    async fn initialize(&mut self) -> Result<DeviceInfo>;
    async fn send_text(&mut self, dest: &[u8; 6], msg: &[u8]) -> Result<()>;
    async fn try_recv_frame(&mut self) -> Result<Option<InboundFrame>>;
    // ...
}
  • Implement for MeshcoreDevice, stub Meshtastic/WiFi/BLE
  • listener.rs uses Box<dyn MeshDevice>
  • Topology UI: SVG graph (this node center, peers as satellites), edge thickness = quality, color = green/yellow/red, tooltips with RSSI/SNR/hops
  • Stego mode selector, block relay status panel

Key Challenges

  1. TX hex > 160 bytes: Use Reed-Solomon chunking (already in transport/chunking.rs)
  2. Async in listener: Spawn tasks for Bitcoin/LND calls, don't block serial loop
  3. Dead man false triggers: Persist check-in time as unix timestamp on disk
  4. Stego overhead: ~80 bytes real data per 160-byte frame

Files Modified

Phase 4:

  • core/archipelago/src/mesh/listener.rs — typed dispatch, new MeshCommand variants
  • core/archipelago/src/mesh/mod.rs — new fields, init, background tasks
  • core/archipelago/src/mesh/types.rs — new MeshEvent variants
  • core/archipelago/src/api/rpc/mesh.rs — 6+ new endpoints, fix send-invoice
  • core/archipelago/src/api/rpc/mod.rs — register routes
  • neode-ui/src/stores/mesh.ts — new store methods
  • neode-ui/src/views/Mesh.vue — off-grid + dead man panels

Phase 5 new files:

  • core/archipelago/src/mesh/steganography.rs
  • core/archipelago/src/mesh/routing.rs
  • core/archipelago/src/mesh/device_trait.rs

Existing Code to Reuse

  • bitcoin_relay.rs: BlockHeaderCache, RelayTracker, all build_* functions
  • alerts.rs: DeadManSwitch, AlertConfig, load_config/save_config
  • message_types.rs: All payload types, TypedEnvelope, encode_payload/decode_payload
  • api/rpc/lnd.rs:128-141: lnd_client() pattern for LND REST calls
  • api/rpc/bitcoin.rs:74-107: bitcoin_rpc_call() for Bitcoin Core RPC
  • transport/chunking.rs: Reed-Solomon FEC for payloads > 160 bytes

Verification

# Unit tests on server
ssh archipelago@192.168.1.228 'cd ~/archy/core && source ~/.cargo/env && cargo test --all-features -- mesh'

# Type check frontend
cd neode-ui && npm run type-check

# Deploy to both
./scripts/deploy-to-target.sh --both

# E2E tests:
# 1. .228 (internet) relays TX from .198 (mesh-only)
# 2. .228 announces block headers, .198 receives them
# 3. Dead man's switch triggers after interval, broadcasts alert
# 4. Steganographic packet looks like weather data on wire