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>
174 lines
8.0 KiB
Markdown
174 lines
8.0 KiB
Markdown
# 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`**
|
|
|
|
```rust
|
|
#[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
|
|
|
|
```bash
|
|
# 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
|
|
```
|