feat(ente-zero): wire de Arje con brahman-net (red P2P opcional + keypair persistente)
Cierra el ultimo pendiente del plan de red: Arje ahora puede arrancar
opcionalmente con BrahmanNet configurado, persistir su identidad
libp2p entre reboots, y participar en la malla brahman como nodo
publico. Sin breaking changes: usuarios actuales (sin env vars) siguen
viendo el comportamiento Unix-only de antes.
Activacion por env vars:
- BRAHMAN_LISTEN_MULTIADDR — si set, activa la red P2P. Ej:
/ip4/0.0.0.0/tcp/4101 (publico), /ip4/127.0.0.1/tcp/0 (loopback).
- BRAHMAN_KEYPAIR_PATH — override del path donde se persiste la
keypair Ed25519. Defaults: PID 1 -> /var/lib/brahman/init-keypair.bin;
dev mode -> $XDG_DATA_HOME/brahman/init-keypair.bin con fallbacks.
- BRAHMAN_BOOTSTRAP_PEERS — multiaddrs coma-separados a dial-ear al
arranque para entrar al DHT.
Comportamiento al activarse:
1. keypair_store::load_or_generate carga keypair de disco o genera y
persiste una nueva (32 bytes raw, 0o600, atomic rename). peer_id
estable across reboots.
2. BrahmanNet::with_keypair arma el swarm con esa identidad.
3. net.listen() resuelve la addr y se loggea.
4. BRAHMAN_BOOTSTRAP_PEERS si set -> dial cada multiaddr.
5. ServerConfig.net = Some(net), activando announce_outputs automatico
en el DHT por cada Card con outputs.
6. Ademas del Unix accept loop, se monta libp2p accept loop sobre el
mismo Server compartido (Arc<Server>). Sesiones locales y remotas
conviven en las mismas tablas.
Refactor del Unix accept loop: antes consumia server via run().await;
ahora usa Arc<Server>::accept_one().await en loop para coexistir con
el libp2p accept loop sin moverse el server.
Degradacion gracil: si la keypair no carga, multiaddr invalido,
listen falla, bootstrap dial revienta -> log + continuamos en
Unix-only. Doctrina PID 1 ("ningun subsistema opcional rompe el
bucle primordial") preservada.
Tests: 4 unit en keypair_store: generate_persist_and_reload_yields_
same_peer_id (la property fundamental), rejects_corrupted_file,
persisted_file_is_owner_only (0o600 verificados), default_path_
honors_env.
Activacion en una linea:
BRAHMAN_LISTEN_MULTIADDR=/ip4/0.0.0.0/tcp/4101 ente-zero
Pendientes: stop_providing en cleanup, allowlist/denylist (PKI),
rotacion de keypair sin perder peer_id.
This commit is contained in:
@@ -6,6 +6,80 @@ ratio/diff ver `git show <sha>`.
|
||||
|
||||
## 2026-05-09
|
||||
|
||||
### feat(ente-zero): wire de Arje con brahman-net (red P2P opcional + identidad persistente)
|
||||
Cierra el último pendiente del plan de red: Arje ahora puede arrancar
|
||||
opcionalmente con `BrahmanNet` configurado, persistir su identidad
|
||||
libp2p entre reboots, y participar en la malla brahman como nodo
|
||||
público. Sin breaking changes: usuarios actuales (sin env vars) siguen
|
||||
viendo el comportamiento Unix-only de antes.
|
||||
|
||||
Activación por env vars:
|
||||
- **`BRAHMAN_LISTEN_MULTIADDR`** — si set, activa la red P2P. Ej:
|
||||
`/ip4/0.0.0.0/tcp/4101` (público), `/ip4/127.0.0.1/tcp/0` (loopback,
|
||||
port aleatorio). Sin la var, `brahman_net = None` y todo sigue
|
||||
como antes.
|
||||
- **`BRAHMAN_KEYPAIR_PATH`** — override del path donde se persiste
|
||||
la keypair Ed25519 de identidad libp2p del nodo. Defaults sensatos:
|
||||
- PID 1 (root): `/var/lib/brahman/init-keypair.bin`.
|
||||
- Dev mode: `$XDG_DATA_HOME/brahman/init-keypair.bin` →
|
||||
`$HOME/.local/share/brahman/init-keypair.bin` →
|
||||
`/tmp/brahman-init-keypair.bin` (último recurso).
|
||||
- **`BRAHMAN_BOOTSTRAP_PEERS`** — lista coma-separada de multiaddrs
|
||||
para dial-ear al arranque y entrar al DHT. Sin esto, el nodo
|
||||
arranca aislado hasta que alguien se conecte a él.
|
||||
|
||||
Comportamiento al activarse:
|
||||
1. `keypair_store::load_or_generate(path)` carga la keypair de disco
|
||||
o genera+persiste una nueva (32 bytes raw, permisos 0o600,
|
||||
atomic rename). Reboots conservan el `peer_id`.
|
||||
2. `BrahmanNet::with_keypair(kp)` arma el swarm con esa identidad.
|
||||
3. `net.listen(multiaddr)` espera dirección resuelta y la loggea.
|
||||
4. `BRAHMAN_BOOTSTRAP_PEERS` (si set) → dial a cada multiaddr.
|
||||
5. El handshake server se levanta con `ServerConfig.net = Some(net)`,
|
||||
que activa `announce_outputs` automático en el DHT por cada Card
|
||||
con outputs.
|
||||
6. Además del Unix accept loop (existing), se monta un libp2p accept
|
||||
loop sobre el mismo `Server` compartido. Sesiones locales y
|
||||
remotas conviven en las mismas tablas (sessions, push_table,
|
||||
broker, last_matches).
|
||||
|
||||
Refactor del Unix accept loop: antes consumía el server vía
|
||||
`server.run().await`; ahora usa `Arc<Server>::accept_one().await` en
|
||||
loop para coexistir con el libp2p accept loop sin moverse el server.
|
||||
|
||||
Degradación grácil en cada paso: si la keypair no carga, si el
|
||||
multiaddr es inválido, si el listen falla, si el bootstrap dial
|
||||
revienta — loggeamos y seguimos en modo Unix-only. La doctrina de
|
||||
PID 1 ("ningún subsistema opcional rompe el bucle primordial") se
|
||||
mantiene.
|
||||
|
||||
Tests: 4 unit en `keypair_store`:
|
||||
- `generate_persist_and_reload_yields_same_peer_id` — peer_id estable
|
||||
across reloads (la propiedad fundamental).
|
||||
- `rejects_corrupted_file` — archivo de tamaño incorrecto rechazado.
|
||||
- `persisted_file_is_owner_only` — permisos 0o600 verificados.
|
||||
- `default_path_honors_env` — `BRAHMAN_KEYPAIR_PATH` override
|
||||
respeta tanto dev como root mode.
|
||||
|
||||
Ente-zero compila clean. Ningún test del workspace regresa.
|
||||
|
||||
Lo que esto desbloquea hoy:
|
||||
- Para activar Arje como nodo público, basta:
|
||||
```sh
|
||||
BRAHMAN_LISTEN_MULTIADDR=/ip4/0.0.0.0/tcp/4101 ente-zero
|
||||
```
|
||||
- Cualquier consumer (en otra máquina) puede luego dial-ar a ese
|
||||
multiaddr + descubrir Cards anunciadas via DHT + abrir handshake
|
||||
remoto firmado.
|
||||
- La identidad del nodo (su `peer_id`) sobrevive reboots, así que
|
||||
los nodos remotos pueden cachear "este peer_id es Arje en
|
||||
máquina X" sin invalidarse cada vez.
|
||||
|
||||
Pendientes futuros:
|
||||
- `stop_providing` al cleanup de sesión (records DHT con TTL ~24h).
|
||||
- Allowlist/Denylist de peers (PKI explícito).
|
||||
- Rotación de keypair sin perder peer_id (multi-key identity).
|
||||
|
||||
### feat(brahman-handshake): Fase 3 — trust remoto vía firma Ed25519 anclada al peer libp2p
|
||||
Cuarto y último paso del plan "el encuentro entre Entes no se
|
||||
restringe a local". Cierra la falla de seguridad que dejaba la red
|
||||
|
||||
Reference in New Issue
Block a user