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.sh sources the nwaku env.sh, so nim and librln_v2.0.2.a (built by make wakunode2) are already in place. The sim is configured with cover traffic disabled and userMessageLimit = 100 (matches the chat's RLN default) in config*.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

  1. In ClientA: click My Bundle and copy the intro bundle.
  2. In ClientB: + new → paste A's bundle + a first message → create.
  3. 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.41.2 s end-to-end. It's the local-sim load: 5 mix nodes at log-level=TRACE burn 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:curve25519pubkeyboth 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 in config*.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, lower log-level if 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-running build_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 inrln_tree.db / rln_keystore_*.json are binary and regenerated by build_setup.sh.