test(mix-sim): chat-ui-over-mixnet test setup

- config*.toml: disable cover traffic (mix-disable-cover-traffic=true) and bump
  RLN userMessageLimit 4 -> 100 to match the chat client's RLN default.
- setup_credentials.nim: DefaultUserMessageLimit -> 100.
- chat-ui/: env.sh + run_chat_ui.sh launch two logos-chat-ui clients that adopt
  the two provisioned chat memberships (via CHAT_NODEKEY) against the 5-node sim,
  plus a README runbook.

Creds (rln_tree.db, rln_keystore_*.json) are generated by build_setup.sh, not
checked in.
This commit is contained in:
Prem Chaitanya Prathi 2026-06-25 18:57:35 +05:30
parent efafdfdc24
commit 658a9ea108
No known key found for this signature in database
10 changed files with 155 additions and 6 deletions

1
simulations/mixnet/chat-ui/.gitignore vendored Normal file
View File

@ -0,0 +1 @@
run-*/

View File

@ -0,0 +1,81 @@
# Testing logos-chat-ui against 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).
The two clients adopt the **two provisioned chat memberships** the sim already
generates (peer-IDs `…1Qx…` and `…RABscN`, the same identities `run_chat_mix*.sh`
use), via `CHAT_NODEKEY`. RLN keystores are peer-ID-derived, so fixing the nodekey
makes the right `rln_keystore_<peerId>.json` resolve.
## Prerequisites
- Nix (the chat-ui builds via `nix run`).
- This sim built + provisioned (run from `simulations/mixnet/`):
```bash
make -C ../../ wakunode2 # build the mix node binary
./build_setup.sh # generate rln_tree.db + 7 keystores
```
> `build_setup.sh` regenerates `rln_tree.db` + all keystores from
> `setup_credentials.nim`. This sim is configured with **cover traffic disabled**
> and **userMessageLimit = 100** (matches the chat's RLN default).
## 1. Start the 5 mix nodes
Each in its own terminal, bootstrap first:
```bash
./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.
## 2. Start the two chat-ui clients
```bash
cd chat-ui
./run_chat_ui.sh A # ClientA on tcp/60010
./run_chat_ui.sh B # ClientB on tcp/60011
```
Each opens a GUI window. 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:
```bash
CHAT_UI="$HOME/Code/logos-chat-ui" ./run_chat_ui.sh A
```
## 3. 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.
## How the config flows
`run_chat_ui.sh` sets env that `logos-chat-ui` reads into the chat config:
| env | meaning |
|-----|---------|
| `CHAT_MIX_NODES` | the 5 mix nodes (`multiaddr:curve25519pubkey`) — **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 |
## 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. For real testing prefer fleet
nodes; locally, lower `log-level` if the UI feels sluggish.
- **Static membership only:** the two chat slots are fixed. Adding more clients
means adding their peer-IDs to `setup_credentials.nim` + re-running `build_setup.sh`.
- **No mix discovery on the client:** all mix nodes must be in `CHAT_MIX_NODES`.

View File

@ -0,0 +1,26 @@
# Shared env for running logos-chat-ui clients against this mixnet sim.
# Values mirror ../config*.toml (5 mix nodes on tcp/60001-60005, clusterId 2,
# shard 0). Sourced by run_chat_ui.sh.
# The 5 sim mix nodes as <multiaddr>:<curve25519 mix pubkey>, comma-separated.
# NOTE: the chat client seeds its mix pool from this STATIC list — it does NOT do
# mix-peer discovery — so every node must be listed explicitly.
export CHAT_MIX_NODES="\
/ip4/127.0.0.1/tcp/60001/p2p/16Uiu2HAmPiEs2ozjjJF2iN2Pe2FYeMC9w4caRHKYdLdAfjgbWM6o:9d09ce624f76e8f606265edb9cca2b7de9b41772a6d784bddaf92ffa8fba7d2c,\
/ip4/127.0.0.1/tcp/60002/p2p/16Uiu2HAmLtKaFaSWDohToWhWUZFLtqzYZGPFuXwKrojFVF6az5UF:9231e86da6432502900a84f867004ce78632ab52cd8e30b1ec322cd795710c2a,\
/ip4/127.0.0.1/tcp/60003/p2p/16Uiu2HAmTEDHwAziWUSz6ZE23h5vxG2o4Nn7GazhMor4bVuMXTrA:275cd6889e1f29ca48e5b9edb800d1a94f49f13d393a0ecf1a07af753506de6c,\
/ip4/127.0.0.1/tcp/60004/p2p/16Uiu2HAmPwRKZajXtfb1Qsv45VVfRZgK3ENdfmnqzSrVm3BczF6f:e0ed594a8d506681be075e8e23723478388fb182477f7a469309a25e7076fc18,\
/ip4/127.0.0.1/tcp/60005/p2p/16Uiu2HAmRhxmCHBYdXt1RibXrjAUNJbduAhzaTHwFCZT4qWnqZAu:8fd7a1a7c19b403d231452a9b1ea40eb1cc76f455d918ef8980e7685f9eeeb1f"
# Bootstrap mix node, which doubles as the relay the chat connects to (for
# receiving + RLN membership broadcast).
export CHAT_STATIC_PEER="/ip4/127.0.0.1/tcp/60001/p2p/16Uiu2HAmPiEs2ozjjJF2iN2Pe2FYeMC9w4caRHKYdLdAfjgbWM6o"
export CHAT_CLUSTER_ID=2
export CHAT_SHARD_ID=0
export CHAT_MIN_MIX_POOL=4
export CHAT_MIX_REQUIRED=1 # force Required (mix) mode without the UI toggle
# logos-chat-ui flake to run. Override with a local checkout to iterate, e.g.
# CHAT_UI="$HOME/Code/logos-chat-ui" ./run_chat_ui.sh A
export CHAT_UI="${CHAT_UI:-github:logos-co/logos-chat-ui?ref=feat/logos-testnetv02-mix}"

View File

@ -0,0 +1,36 @@
#!/usr/bin/env bash
# Run a logos-chat-ui client against this mixnet sim.
#
# ./run_chat_ui.sh A # first client (adopts provisioned chat membership 1)
# ./run_chat_ui.sh B # second client (adopts provisioned chat membership 2)
#
# Each client adopts one of the two provisioned chat memberships via CHAT_NODEKEY
# (the same nodekeys run_chat_mix*.sh use), and runs from a per-client dir holding
# the RLN tree + keystores — mountMix loads rln_keystore_<peerId>.json + rln_tree.db
# from cwd, and CHAT_NODEKEY fixes the peerId so the right keystore resolves.
#
# Prereqs (from ../):
# 1. make wakunode2 # build the mix node binary
# 2. ./build_setup.sh # generate rln_tree.db + keystores
# 3. ./run_mix_node.sh and run_mix_node1..4.sh # all 5 mix nodes running
set -euo pipefail
HERE="$(cd "$(dirname "$0")" && pwd)"
SIM="$(cd "$HERE/.." && pwd)"
source "$HERE/env.sh"
case "${1:-}" in
A) export CHAT_NAME=ClientA CHAT_PORT=60010 \
CHAT_NODEKEY=35eace7ccb246f20c487e05015ca77273d8ecaed0ed683de3d39bf4f69336feb ;;
B) export CHAT_NAME=ClientB CHAT_PORT=60011 \
CHAT_NODEKEY=cb6fe589db0e5d5b48f7e82d33093e4d9d35456f4aaffc2322c473a173b2ac49 ;;
*) echo "usage: $0 <A|B>"; exit 1 ;;
esac
DIR="$HERE/run-${1}"
mkdir -p "$DIR"
cp -f "$SIM/rln_tree.db" "$DIR/" 2>/dev/null \
|| { echo "missing rln_tree.db — run ../build_setup.sh first"; exit 1; }
cp -f "$SIM"/rln_keystore_*.json "$DIR/"
cd "$DIR"
exec nix run "$CHAT_UI" --accept-flake-config

View File

@ -27,5 +27,6 @@ nat = "extip:127.0.0.1"
ext-multiaddr = ["/ip4/127.0.0.1/tcp/60001"]
ext-multiaddr-only = true
ip-colocation-limit=0
mix-user-message-limit=4
mix-user-message-limit=100
mix-disable-spam-protection=false
mix-disable-cover-traffic=true

View File

@ -28,6 +28,7 @@ nat = "extip:127.0.0.1"
ext-multiaddr = ["/ip4/127.0.0.1/tcp/60002"]
ext-multiaddr-only = true
ip-colocation-limit=0
mix-user-message-limit=4
mix-user-message-limit=100
mix-disable-spam-protection=false
mix-disable-cover-traffic=true
#staticnode = ["/ip4/127.0.0.1/tcp/60001/p2p/16Uiu2HAmPiEs2ozjjJF2iN2Pe2FYeMC9w4caRHKYdLdAfjgbWM6o", "/ip4/127.0.0.1/tcp/60003/p2p/16Uiu2HAmTEDHwAziWUSz6ZE23h5vxG2o4Nn7GazhMor4bVuMXTrA","/ip4/127.0.0.1/tcp/60004/p2p/16Uiu2HAmPwRKZajXtfb1Qsv45VVfRZgK3ENdfmnqzSrVm3BczF6f","/ip4/127.0.0.1/tcp/60005/p2p/16Uiu2HAmRhxmCHBYdXt1RibXrjAUNJbduAhzaTHwFCZT4qWnqZAu"]

View File

@ -28,6 +28,7 @@ nat = "extip:127.0.0.1"
ext-multiaddr = ["/ip4/127.0.0.1/tcp/60003"]
ext-multiaddr-only = true
ip-colocation-limit=0
mix-user-message-limit=4
mix-user-message-limit=100
mix-disable-spam-protection=false
mix-disable-cover-traffic=true
#staticnode = ["/ip4/127.0.0.1/tcp/60001/p2p/16Uiu2HAmPiEs2ozjjJF2iN2Pe2FYeMC9w4caRHKYdLdAfjgbWM6o", "/ip4/127.0.0.1/tcp/60002/p2p/16Uiu2HAmLtKaFaSWDohToWhWUZFLtqzYZGPFuXwKrojFVF6az5UF","/ip4/127.0.0.1/tcp/60004/p2p/16Uiu2HAmPwRKZajXtfb1Qsv45VVfRZgK3ENdfmnqzSrVm3BczF6f","/ip4/127.0.0.1/tcp/60005/p2p/16Uiu2HAmRhxmCHBYdXt1RibXrjAUNJbduAhzaTHwFCZT4qWnqZAu"]

View File

@ -28,6 +28,7 @@ nat = "extip:127.0.0.1"
ext-multiaddr = ["/ip4/127.0.0.1/tcp/60004"]
ext-multiaddr-only = true
ip-colocation-limit=0
mix-user-message-limit=4
mix-user-message-limit=100
mix-disable-spam-protection=false
mix-disable-cover-traffic=true
#staticnode = ["/ip4/127.0.0.1/tcp/60002/p2p/16Uiu2HAmLtKaFaSWDohToWhWUZFLtqzYZGPFuXwKrojFVF6az5UF", "/ip4/127.0.0.1/tcp/60003/p2p/16Uiu2HAmTEDHwAziWUSz6ZE23h5vxG2o4Nn7GazhMor4bVuMXTrA","/ip4/127.0.0.1/tcp/60001/p2p/16Uiu2HAmPiEs2ozjjJF2iN2Pe2FYeMC9w4caRHKYdLdAfjgbWM6o","/ip4/127.0.0.1/tcp/60005/p2p/16Uiu2HAmRhxmCHBYdXt1RibXrjAUNJbduAhzaTHwFCZT4qWnqZAu"]

View File

@ -28,6 +28,7 @@ nat = "extip:127.0.0.1"
ext-multiaddr = ["/ip4/127.0.0.1/tcp/60005"]
ext-multiaddr-only = true
ip-colocation-limit=0
mix-user-message-limit=4
mix-user-message-limit=100
mix-disable-spam-protection=false
mix-disable-cover-traffic=true
#staticnode = ["/ip4/127.0.0.1/tcp/60001/p2p/16Uiu2HAmPiEs2ozjjJF2iN2Pe2FYeMC9w4caRHKYdLdAfjgbWM6o", "/ip4/127.0.0.1/tcp/60003/p2p/16Uiu2HAmTEDHwAziWUSz6ZE23h5vxG2o4Nn7GazhMor4bVuMXTrA","/ip4/127.0.0.1/tcp/60004/p2p/16Uiu2HAmPwRKZajXtfb1Qsv45VVfRZgK3ENdfmnqzSrVm3BczF6f","/ip4/127.0.0.1/tcp/60002/p2p/16Uiu2HAmLtKaFaSWDohToWhWUZFLtqzYZGPFuXwKrojFVF6az5UF"]

View File

@ -20,7 +20,7 @@ import
const
KeystorePassword = "mix-rln-password" # Must match protocol.nim
DefaultUserMessageLimit = 4'u64 # R=4 slots per 10s epoch
DefaultUserMessageLimit = 100'u64 # R=100 slots per 10s epoch (chat default)
# Peer IDs derived from nodekeys in config files
# config.toml: nodekey = "f98e3fba96c32e8d1967d460f1b79457380e1a895f7971cecc8528abe733781a"