feat: Phase 4 — off-grid Bitcoin relay, block headers, dead man's switch

- Typed message dispatch in listener (BlockHeader, TxRelay, LightningRelay, Alert, TxConfirmation)
- Base64 encoding for binary payloads over LoRa (fixes NUL byte truncation)
- Compact block header announcements (88 bytes, fits 160-byte LoRa limit)
- Block header announcer: internet nodes auto-announce new blocks to Archy peers
- TX relay: mesh-only nodes can broadcast transactions via internet-connected peers
- Confirmation tracking: relay node monitors 1/3, 2/3, 3/3 confirmations, sends updates back
- Dead man's switch background task with configurable interval and signed alert broadcast
- 6 new RPC endpoints: relay-tx, block-headers, relay-lightning, deadman-status/configure/checkin
- lnd.create-raw-tx: create signed TX without broadcasting (for mesh relay)
- Web5 wallet: offline detection + "Send via mesh?" prompt with auto relay + confirmation polling
- Mesh.vue: Off-Grid Bitcoin tab, Dead Man tab, Send Bitcoin/Lightning buttons
- TX/Lightning relay sends only to Archy peers (not broadcast to all devices)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Dorian
2026-03-17 15:51:56 +00:00
co-authored by Claude Opus 4.6
parent 4b7c765cd1
commit d1ac098edb
13 changed files with 2091 additions and 126 deletions
+10
View File
@@ -175,6 +175,16 @@ impl DeadManSwitch {
envelope.to_wire()
}
/// Check if the alert has already been sent (prevents re-broadcasting every 60s).
pub async fn triggered_flag(&self) -> tokio::sync::RwLockReadGuard<'_, bool> {
self.triggered.read().await
}
/// Mark the switch as having fired (alert already sent).
pub async fn mark_triggered(&self) {
*self.triggered.write().await = true;
}
/// Get the list of emergency contact DIDs.
pub async fn emergency_contacts(&self) -> Vec<String> {
self.config.read().await.emergency_contacts.clone()