Arseniy Klempner 695ecb42bc
feat: add mix+LEZ chat simulation with Docker support
End-to-end simulation: 4 mix nodes with RLN spam protection, LEZ
sequencer, gifter service, and two logos-chat-module clients exchanging
double-ratchet-encrypted messages through 3-hop Sphinx onion routes.

Simulation scripts:
- run_simulation.sh: orchestrates sequencer, mix nodes, chat clients,
  with poll-based readiness checks and 15 verification checks
- setup_and_run.sh: one-shot build + run for fresh clones
- run_in_docker.sh: Docker-based Linux testing with pre-built modules
- README.md: configuration, troubleshooting, architecture guide

Configurable via SIM_* env vars (ports, timeouts, log level).
Cross-platform: macOS native + Linux via Docker.

Docker image (Dockerfile.sim) uses multi-stage build:
- Stage 1: builds all LEZ modules, sequencer, liblogoschat, chat-module
- Stage 2: copies only runtime nix closure (~1.9GB) + output artifacts
- Pre-built modules are symlinked at runtime, skipping build_all.sh
2026-05-06 10:50:14 -06:00

163 lines
7.2 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Mix + LEZ RLN Chat Simulation
End-to-end private chat between two `logos-chat-module` clients over a 4-node mix network with LEZ-backed RLN spam protection against a local LEZ sequencer.
Two logoscore instances (sender + receiver) load `chat_module` and establish an X3DH key agreement via an out-of-band intro bundle, then exchange double-ratchet-encrypted messages routed through 3-hop Sphinx onion routes with per-hop RLN proof generation and verification. Node 0 mounts the `rln_gifter` service; nodes 1-3 and both chat clients register RLN memberships on-chain via the gifter protocol. The chat clients run `mix: true, relay: false, filter: true` — the sender publishes via `lightpushPublish(mixify=true)`, the mix exit node verifies the RLN proof before fanning out via gossipsub relay to the shard, and the receiver consumes the message via a Waku filter subscription on one of the mix nodes.
## Architecture
```
logoscore (per mix node) logoscore (per chat client)
├── wallet_module (LEZ wallet) ├── wallet_module (LEZ wallet)
├── liblogos_rln_module (RLN proofs) ├── liblogos_rln_module (RLN proofs)
└── delivery_module (Waku mix relay) └── chat_module (logos-chat-module)
├── liblogosdelivery.so ├── chat_module_plugin.so
└── mix + relay + filter + gifter └── liblogoschat.so
└── mix client + filter + gifter client
```
Node 0 runs the RLN gifter service. Nodes 1-3 register via gifter on startup. Chat clients also register via gifter when `startChat()` runs.
## Quick start
**Prereqs:** nix (with flakes), Docker (for guest zkVM binaries), cargo-risczero, SSH access to GitHub.
**Run from scratch:**
```bash
git clone -b feat/logos-delivery git@github.com:adklempner/logos-chat.git
cd logos-chat && bash simulations/mix_lez_chat/setup_and_run.sh
```
**Re-run (after initial build):**
```bash
bash simulations/mix_lez_chat/run_simulation.sh --fresh
```
Pass = **ALL 15 CHECKS PASSED**.
## Configuration
Override via environment variables:
| Variable | Default | Description |
|---|---|---|
| `SIM_NUM_NODES` | `4` | Number of mix relay nodes |
| `SIM_BASE_TCP_PORT` | `60001` | First node's TCP port (increments per node) |
| `SIM_BASE_DISC_PORT` | `9001` | First node's discv5 UDP port (increments per node) |
| `SIM_CLUSTER_ID` | `99` | Waku cluster ID |
| `SIM_LOG_LEVEL` | `INFO` | Node log level (TRACE, DEBUG, INFO, WARN, ERROR) |
| `SIM_CHAT_RECV_PORT` | `60010` | Chat receiver TCP port |
| `SIM_CHAT_SEND_PORT` | `60011` | Chat sender TCP port |
| `SIM_KADEMLIA_MIN_WAIT` | `30` | Minimum seconds to wait for kademlia propagation |
| `SIM_RECEIVER_MIN_WAIT` | `15` | Minimum seconds to wait for receiver to join mix |
| `SIM_DELIVERY_TIMEOUT` | `120` | Max seconds to wait for message delivery |
Example — fast iteration with verbose logging:
```bash
SIM_LOG_LEVEL=TRACE SIM_KADEMLIA_MIN_WAIT=10 SIM_RECEIVER_MIN_WAIT=5 \
bash simulations/mix_lez_chat/run_simulation.sh --fresh
```
## `--fresh` behavior
When `--fresh` is passed:
- Kills all existing `logos_host` processes
- Cleans `/tmp/logos_*` Qt RemoteObjects sockets
- Removes `.sim_state/` directory
- Removes sequencer state (`rocksdb/`, `bedrock_signing_key`)
- Rebuilds and restarts the sequencer
- Redeploys RLN programs via `run_setup`
Without `--fresh`, reuses existing sequencer if port 3040 is already bound.
## Checks (15 total)
| Category | Check | What it verifies |
|---|---|---|
| Mix nodes (4) | Node N mounted mix | Mix protocol handler registered |
| RLN gifter | Node 0 gifter service mounted | `/logos/rln-gifter/1.0.0` protocol handler |
| LEZ RLN | LEZ root polling active | Nodes polling valid Merkle roots from LEZ |
| Chat module (4) | Receiver/Sender initialized | `chatInitResult` event fired |
| | Receiver/Sender started | `Waku client started` + `chatStartResult` |
| | Receiver/Sender mounted mix+LEZ | Mix protocol + LEZ callbacks wired |
| | Receiver created intro bundle | X3DH pre-key bundle generated |
| Message exchange (2) | Sender sent message | `chatNewPrivateConversationResult` |
| | Receiver received message | `chatNewMessage` via filter subscription |
## Troubleshooting
**"Sequencer failed to start"** — port 3040 already in use:
```bash
kill $(lsof -ti tcp:3040) && bash simulations/mix_lez_chat/run_simulation.sh --fresh
```
**"run_setup failed" / "Timeout waiting for account"** — stale guest binaries or wallet state:
```bash
rm -rf vendor/logos-lez-rln/lez-rln/methods/guest/target
rm -f vendor/logos-lez-rln/dev/wallet_config.json vendor/logos-lez-rln/dev/storage.json
bash simulations/mix_lez_chat/setup_and_run.sh
```
**"Sender started FAIL"** — stale Qt RemoteObjects sockets:
```bash
rm -f /tmp/logos_*
bash simulations/mix_lez_chat/run_simulation.sh --fresh
```
**"FAIL: Receiver received message (0)"** — timing issue, try re-running:
```bash
bash simulations/mix_lez_chat/run_simulation.sh --fresh
```
## Adapting for other LEZ programs
This simulation provides a complete mix network infrastructure that other logos modules can reuse for testing. To test your own module:
### What the sim provides
- 4 logoscore mix nodes with `delivery_module` (Waku relay + mix + RLN)
- LEZ sequencer with deployed RLN programs
- RLN gifter service on node 0
- Wallet modules for on-chain transactions
### What you replace
The chat_module sender/receiver instances (phase 5 of run_simulation.sh). Your module needs:
1. **A C++ Qt plugin** implementing `PluginInterface` (see `chat_module_plugin.cpp`)
- `initLogos(LogosAPI*)` — receive the LogosAPI instance
- `eventResponse(QString, QVariantList)` signal — mandatory per logos-liblogos contract
- Methods exposed via `LOGOS_METHOD` for logoscore `-c` invocation
2. **A shared library** with your program logic (like `liblogoschat.so`)
3. **RLN integration** — wire `setRlnConfig` to pass RLN credentials from the C++ plugin to your library
4. **EVENT: stderr fallback** — on Linux, Qt signal forwarding from plugin to logoscore doesn't work across the FFI thread boundary. Write event data to stderr in `EVENT:name:data` format for cross-platform reliability.
### How to stage your module
```bash
MDIR=$(mktemp -d)
mkdir -p "$MDIR/your_module"
cp your_module_plugin.so "$MDIR/your_module/"
cp libyour_library.so "$MDIR/your_module/"
echo '{"name":"your_module","version":"1.0.0","type":"core",...}' > "$MDIR/your_module/manifest.json"
logoscore -m "$MDIR" \
-l "liblogos_execution_zone_wallet_module,liblogos_rln_module,your_module" \
-c "liblogos_execution_zone_wallet_module.open($WALLET_CONFIG,$WALLET_STORAGE)" \
-c "your_module.init(@config.json)" \
-c "your_module.start()"
```
### Reference
- `chat_module_plugin.cpp` — complete working example with RLN, gifter, mix, and event emission
- `delivery_module_plugin.cpp` — more complex example with full RLN fetcher integration
- `run_simulation.sh` — orchestration, module staging, and verification patterns
## Logs
All logs in `simulations/mix_lez_chat/.sim_state/`:
- `node0.log` `node3.log` — mix relay nodes
- `chat_receiver.log` — receiver chat module
- `chat_sender.log` — sender chat module