E2E: logos-chat-ui over the local mixnet sim
Run two logos-chat-ui clients that exchange end-to-end messages through the
5-node mix sim (Sphinx routing + RLN spam protection + exit-node delivery).
This is a full from-scratch runbook: clone → build → provision → run → message.
The two clients adopt the two provisioned chat memberships the sim generates
(peer-IDs …1Qx… and …RABscN), via CHAT_NODEKEY. RLN keystores are
peer-ID-derived, so fixing the nodekey makes the right rln_keystore_<peerId>.json
resolve.
0. Prerequisites
- Nix with flakes enabled (the chat client is built/run via
nix run). - Rust toolchain (
rustc+cargo, via rustup) and the standard dev tools (C compiler, GNU Make, Bash, Git) — needed to build the mix node (wakunode2). - macOS or Linux.
1. Repos & branches
Only logos-delivery needs to be cloned. The chat client (and its whole
dependency chain) is pulled automatically by nix run.
| repo | branch | role | how it's consumed |
|---|---|---|---|
logos-messaging/logos-delivery |
feat/logos-testnetv02-mix |
mix sim (5 nodes) + this harness | clone + make wakunode2 |
logos-co/logos-chat-ui |
feat/logos-testnetv02-mix |
the GUI client | nix run github:… (pulls the rest) |
logos-co/logos-chat-module |
feat/logos-testnetv02-mix |
liblogoschat module |
transitive flake input |
logos-messaging/logos-chat |
feat/logos-testnetv02-mix |
Nim SDK (in-process nwaku) | transitive flake input (submodules=1) |
2. Build & provision the sim
git clone --recurse-submodules -b feat/logos-testnetv02-mix \
https://github.com/logos-messaging/logos-delivery
cd logos-delivery
make wakunode2 # builds Nim + deps + librln + the mix node (first run is long)
cd simulations/mixnet
./build_setup.sh # generates rln_tree.db + 7 keystores (mix nodes + 2 chat slots)
build_setup.shsources the nwakuenv.sh, sonimandlibrln_v2.0.2.a(built bymake wakunode2) are already in place. The sim is configured with cover traffic disabled and userMessageLimit = 100 (matches the chat's RLN default) inconfig*.toml.
3. Start the 5 mix nodes
Each in its own terminal, bootstrap (run_mix_node.sh) first:
cd simulations/mixnet
./run_mix_node.sh # bootstrap tcp/60001
./run_mix_node1.sh # tcp/60002
./run_mix_node2.sh # tcp/60003
./run_mix_node3.sh # tcp/60004
./run_mix_node4.sh # tcp/60005
Wait for MixRlnSpamProtection started + Node setup complete on each.
4. Start the two chat-ui clients
Two more terminals. The first run builds the whole chat chain via nix (slow once, cached after):
cd simulations/mixnet/chat-ui
./run_chat_ui.sh A # ClientA, tcp/60010
./run_chat_ui.sh B # ClientB, tcp/60011
Each opens a GUI. The bottom status bar should show MIX 5/4 (mix pool full)
with the send button enabled.
To iterate on a local chat-ui checkout instead of the pushed branch:
CHAT_UI="$HOME/Code/logos-chat-ui" ./run_chat_ui.sh A
5. Exchange messages
- In ClientA: click My Bundle and copy the intro bundle.
- In ClientB: + new → paste A's bundle + a first message → create.
- Send messages each way — they route A↔B through the mixnet.
⚠️ Expect up to ~1 minute for a message to appear on the other side locally. This is not mix delay — the actual forward path through the mixnet is ~0.4–1.2 s end-to-end. It's the local-sim load: 5 mix nodes at
log-level=TRACEburn CPU and starve the desktop GUI's render loop, so the view repaints late. On fleet nodes (no local logging load) messages render promptly. See the Load note below.
To confirm a message actually traversed the mix, watch a mix node log for
onMessage - exit is destination (the exit hop delivering to the recipient) — the
timestamp there is within a second or two of when the message was sent, even when
the GUI takes longer to repaint.
How the config flows
run_chat_ui.sh sources env.sh and sets the env logos-chat-ui reads into the
chat config:
| env | meaning |
|---|---|
CHAT_MIX_NODES |
the 5 mix nodes as multiaddr:curve25519pubkey — both the node ID and the mix pubkey are hardcoded; the chat does no mix-peer discovery |
CHAT_STATIC_PEER |
bootstrap node (relay the chat connects to) |
CHAT_CLUSTER_ID / CHAT_SHARD_ID |
2 / 0 (must match the mix nodes) |
CHAT_NODEKEY |
adopt a provisioned chat identity so its RLN keystore resolves |
CHAT_MIX_REQUIRED |
force Required (mix) mode |
CHAT_UI |
flake to run (default: the pushed feat/logos-testnetv02-mix branch) |
Notes / limitations
- Load: 5 mix nodes at
log-level=TRACE(the default inconfig*.toml) write multi-GB logs and can starve a desktop machine — that, not the mix or the code, is what made messages take ~a minute to render in earlier testing. For real testing prefer fleet nodes; locally, lowerlog-levelif the UI feels sluggish. - Static membership only: the two chat slots are fixed. More clients means
adding their peer-IDs to
setup_credentials.nim+ re-runningbuild_setup.sh. - No mix discovery on the client: every mix node must be listed in
CHAT_MIX_NODES(multiaddr and curve25519 mix pubkey). The mix nodes discover each other via kad; the chat client does not. - Creds are not checked in —
rln_tree.db/rln_keystore_*.jsonare binary and regenerated bybuild_setup.sh.