diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..fc11a47 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,3 @@ +# Everything — the Dockerfile doesn't COPY from the build context. +# Guest binaries are staged via docker cp separately. +* diff --git a/.github/Dockerfile.sim b/.github/Dockerfile.sim new file mode 100644 index 0000000..6e0d548 --- /dev/null +++ b/.github/Dockerfile.sim @@ -0,0 +1,170 @@ +# =========================================================================== +# Stage 1: Builder — build everything, package runtime closure +# =========================================================================== +FROM catthehacker/ubuntu:act-latest AS builder + +RUN apt-get update -qq && apt-get install -y -qq \ + build-essential pkg-config libssl-dev git curl docker.io xxd \ + && rm -rf /var/lib/apt/lists/* + +# Nix +RUN curl -L https://nixos.org/nix/install | bash -s -- --daemon --yes +RUN mkdir -p /root/.config/nix && \ + printf 'experimental-features = nix-command flakes\nsandbox = false\n' > /root/.config/nix/nix.conf +RUN rmdir /homeless-shelter 2>/dev/null || true + +# Rust + cargo-risczero +RUN curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y +ENV PATH="/root/.cargo/bin:${PATH}" +RUN cargo install cargo-risczero + +RUN git config --global url."https://github.com/".insteadOf "git@github.com:" + +SHELL ["/bin/bash", "-lc"] + +# logos-blockchain-circuits (architecture-aware) +RUN ARCH=$(uname -m | sed 's/arm64/aarch64/') && \ + CIRCUITS_URL="https://github.com/logos-blockchain/logos-blockchain-circuits/releases/download/v0.4.2/logos-blockchain-circuits-v0.4.2-linux-${ARCH}.tar.gz" && \ + echo "Downloading circuits: $CIRCUITS_URL" && \ + mkdir -p /root/.logos-blockchain-circuits && \ + curl -sL "$CIRCUITS_URL" | tar xz -C /root/.logos-blockchain-circuits && \ + mv /root/.logos-blockchain-circuits/logos-blockchain-circuits-*/* /root/.logos-blockchain-circuits/ 2>/dev/null || true && \ + rmdir /root/.logos-blockchain-circuits/logos-blockchain-circuits-* 2>/dev/null || true + +# --- LEZ modules --- + +RUN source /nix/var/nix/profiles/default/etc/profile.d/nix-daemon.sh && \ + cd /root && \ + git clone -b feat/mix-rln-gifter-sim https://github.com/logos-co/logos-lez-rln.git && \ + cd logos-lez-rln && \ + git submodule update --init && \ + (cd logos-delivery-module && git submodule update --init --recursive) + +RUN source /nix/var/nix/profiles/default/etc/profile.d/nix-daemon.sh && \ + cd /root/logos-lez-rln && \ + nix build .#logos-rln-module -o logos-rln-module/result-rln + +RUN source /nix/var/nix/profiles/default/etc/profile.d/nix-daemon.sh && \ + cd /root/logos-lez-rln && \ + (cd logos-execution-zone-module && \ + RISC0_SKIP_BUILD_KERNELS=1 nix build --impure \ + --override-input logos-execution-zone "git+file://$(pwd)/../lssa" \ + -o ../logos-rln-module/result-wallet) + +RUN source /nix/var/nix/profiles/default/etc/profile.d/nix-daemon.sh && \ + nix build github:logos-co/logos-liblogos/7df6195 \ + --override-input logos-cpp-sdk github:logos-co/logos-cpp-sdk/a4bd66c \ + -o /root/logoscore-result + +RUN source /nix/var/nix/profiles/default/etc/profile.d/nix-daemon.sh && \ + cd /root/logos-lez-rln/logos-delivery-module/vendor/logos-delivery && \ + make -j1 liblogosdelivery 2>&1 | tail -5 + +RUN source /nix/var/nix/profiles/default/etc/profile.d/nix-daemon.sh && \ + cd /root/logos-lez-rln && \ + SDK_PATH=$(nix build github:logos-co/logos-cpp-sdk/a4bd66c --no-link --print-out-paths 2>/dev/null) && \ + LIBLOGOS_PATH=$(nix build github:logos-co/logos-liblogos/7df6195 \ + --override-input logos-cpp-sdk github:logos-co/logos-cpp-sdk/a4bd66c \ + --no-link --print-out-paths 2>/dev/null) && \ + QT_BASE=$(find /nix/store -maxdepth 1 -name "*qtbase-6*" -type d 2>/dev/null | head -1) && \ + QT_RO=$(find /nix/store -maxdepth 1 -name "*qtremoteobjects-6*" -type d 2>/dev/null | head -1) && \ + DELIVERY_MOD="$PWD/logos-delivery-module" && \ + cd logos-delivery-module && rm -rf build_plugin && mkdir build_plugin && cd build_plugin && \ + mkdir -p delivery_root/bin delivery_root/liblogosdelivery && \ + cp "$DELIVERY_MOD/vendor/logos-delivery/build/liblogosdelivery."* delivery_root/bin/ 2>/dev/null || true && \ + cp "$DELIVERY_MOD/vendor/logos-delivery/liblogosdelivery/liblogosdelivery.h" delivery_root/liblogosdelivery/ && \ + nix-shell -p cmake ninja pkg-config postgresql --run " \ + cmake .. -GNinja \ + -DLOGOS_CPP_SDK_ROOT=$SDK_PATH \ + -DLOGOS_LIBLOGOS_ROOT=$LIBLOGOS_PATH \ + -DLOGOS_DELIVERY_ROOT=\$PWD/delivery_root \ + -DLOGOS_MESSAGING_MODULE_USE_VENDOR=OFF \ + -DCMAKE_PREFIX_PATH=\"$QT_BASE;$QT_RO\" \ + -DQT_ADDITIONAL_PACKAGES_PREFIX_PATH=$QT_RO && \ + ninja" 2>&1 | tail -5 + +RUN source /nix/var/nix/profiles/default/etc/profile.d/nix-daemon.sh && \ + CLANG_SO=$(find /nix/store -maxdepth 3 -name 'libclang.so' 2>/dev/null | head -1) && \ + export LIBCLANG_PATH=$(dirname "$CLANG_SO") && \ + STDBOOL=$(find "$LIBCLANG_PATH" -maxdepth 5 -name 'stdbool.h' 2>/dev/null | head -1) && \ + [ -n "$STDBOOL" ] && export BINDGEN_EXTRA_CLANG_ARGS="-I$(dirname $STDBOOL)" ; \ + cd /root/logos-lez-rln/lssa && \ + cargo build --features standalone -p sequencer_service 2>&1 | tail -5 + +# Build run_setup binary (deploys LEZ programs to sequencer at sim runtime) +RUN cd /root/logos-lez-rln/lez-rln && \ + cargo build --bin run_setup 2>&1 | tail -5 + +# --- logos-chat (liblogoschat) --- + +RUN source /nix/var/nix/profiles/default/etc/profile.d/nix-daemon.sh && \ + cd /root && \ + git clone -b feat/logos-delivery https://github.com/adklempner/logos-chat.git && \ + cd logos-chat && \ + git submodule update --init --depth 1 && \ + (cd vendor/nwaku && git submodule update --init --recursive --depth 1) && \ + (cd vendor/nimbus-build-system && git submodule update --init --recursive --depth 1) && \ + make update && make liblogoschat 2>&1 | tail -5 + +# --- logos-chat-module (chat_module_plugin) --- + +RUN source /nix/var/nix/profiles/default/etc/profile.d/nix-daemon.sh && \ + cd /root && \ + git clone -b feat/logos-delivery https://github.com/adklempner/logos-chat-module.git && \ + cd logos-chat-module && nix build 2>&1 | tail -5 + +# --- Package runtime closure --- + +RUN source /nix/var/nix/profiles/default/etc/profile.d/nix-daemon.sh && \ + { \ + nix-store -qR /root/logos-lez-rln/logos-rln-module/result-rln; \ + nix-store -qR /root/logos-lez-rln/logos-rln-module/result-wallet; \ + nix-store -qR /root/logoscore-result; \ + nix-store -qR /root/logos-chat-module/result; \ + } | sort -u > /tmp/nix-closure-paths.txt && \ + tar cf /tmp/nix-closure.tar -T /tmp/nix-closure-paths.txt && \ + echo "Closure: $(wc -l < /tmp/nix-closure-paths.txt) paths, $(du -sh /tmp/nix-closure.tar | cut -f1)" + + + + +# =========================================================================== +# Stage 2: Runtime — minimal image, no nix/Rust/cargo needed +# =========================================================================== +FROM catthehacker/ubuntu:act-latest + +RUN apt-get update -qq && apt-get install -y -qq \ + build-essential pkg-config libssl-dev git curl xxd netcat-openbsd lsof \ + clang libclang-dev \ + && rm -rf /var/lib/apt/lists/* + +# Rust + r0vm (needed for: sequencer build + risc0 dev prover) +RUN curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y +ENV PATH="/root/.cargo/bin:${PATH}" +RUN cargo install cargo-risczero + +RUN git config --global url."https://github.com/".insteadOf "git@github.com:" + +# Import runtime nix closure from builder +COPY --from=builder /tmp/nix-closure.tar /tmp/ +# Import nix store runtime closure from builder. These are loaded by +# direct path (not via nix), so no nix DB registration needed. +# The runtime nix has its own clean DB for nix-shell package downloads. +RUN mkdir -p /nix/store && tar xf /tmp/nix-closure.tar -C / && rm /tmp/nix-closure.tar + +# Pre-built LEZ module outputs +COPY --from=builder /root/logos-lez-rln/logos-rln-module/result-rln /root/lez-modules/result-rln +COPY --from=builder /root/logos-lez-rln/logos-rln-module/result-wallet /root/lez-modules/result-wallet +COPY --from=builder /root/logos-lez-rln/logos-delivery-module/build_plugin/modules/ /root/lez-modules/delivery-plugin/ +COPY --from=builder /root/logos-lez-rln/logos-delivery-module/vendor/logos-delivery/build/ /root/lez-modules/delivery-build/ +# NOTE: sequencer + run_setup are NOT pre-built. Binaries compiled in the +# builder stage crash at runtime due to library mismatch between Docker stages. +# They're built from source at runtime with system clang (~1.5 min). +# The lssa source is cloned at runtime via setup_and_run.sh submodule init. +COPY --from=builder /root/logoscore-result /root/lez-modules/logoscore-result +COPY --from=builder /root/.logos-blockchain-circuits /root/.logos-blockchain-circuits +COPY --from=builder /root/logos-lez-rln/dev /root/lez-modules/dev + +# Pre-built logos-chat outputs +COPY --from=builder /root/logos-chat/build/liblogoschat.so /root/lez-modules/liblogoschat.so +COPY --from=builder /root/logos-chat-module/result /root/lez-modules/chat-module-result diff --git a/scripts/run_in_docker.sh b/scripts/run_in_docker.sh index 504b557..d8bf856 100755 --- a/scripts/run_in_docker.sh +++ b/scripts/run_in_docker.sh @@ -1,39 +1,38 @@ #!/usr/bin/env bash -# Run the mix+LEZ chat simulation inside a Docker container (Linux aarch64). +# Run the mix+LEZ chat simulation inside a Docker container (Linux). # -# The Docker image pre-builds EVERYTHING: LEZ modules, sequencer, logoscore, -# liblogoschat, chat_module_plugin. Each sim run only clones the repo (for -# scripts + configs), symlinks pre-built artifacts, and runs the simulation. +# The Docker image pre-builds all heavy nix modules. Each sim run clones +# the repo, builds sequencer + run_setup from source (nix-shell), symlinks +# pre-built artifacts, and runs the simulation. # # First run: ~60 min (one-time docker build) -# Subsequent runs: ~5 min (clone + submodule init + sim) +# Subsequent runs: ~10 min (clone + sequencer build + sim) # # Prerequisites: Docker Desktop running. # # Usage: # bash scripts/run_in_docker.sh -# BRANCH=my-branch bash scripts/run_in_docker.sh # test a different branch -# -# Environment variables: -# BRANCH — git branch to clone (default: feat/logos-delivery) -# REPO_URL — git repo URL -# GUEST_BINARIES_DIR — path to pre-built guest .bin files (auto-detected) -# REBUILD_IMAGE — set to 1 to force image rebuild -# SIM_* — simulation parameters, passed through to run_simulation.sh +# BRANCH=my-branch bash scripts/run_in_docker.sh set -euo pipefail SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" ROOT="$(cd "$SCRIPT_DIR/.." && pwd)" DOCKERFILE="$ROOT/.github/Dockerfile.sim" -IMAGE_NAME="logos-chat-sim" +IMAGE_NAME="${DOCKER_IMAGE:-ghcr.io/adklempner/logos-chat-sim:latest}" CONTAINER_NAME="logos-chat-sim-run" BRANCH="${BRANCH:-feat/logos-delivery}" REPO_URL="${REPO_URL:-https://github.com/adklempner/logos-chat.git}" # Build image if it doesn't exist or REBUILD_IMAGE=1 -if [ "${REBUILD_IMAGE:-0}" = "1" ] || ! docker image inspect "$IMAGE_NAME" >/dev/null 2>&1; then - echo "=== Building Docker image (one-time — ~60 min) ===" +if [ "${REBUILD_IMAGE:-0}" = "1" ]; then + echo "=== Building Docker image locally (~60 min) ===" docker build -t "$IMAGE_NAME" -f "$DOCKERFILE" "$ROOT" +elif ! docker image inspect "$IMAGE_NAME" >/dev/null 2>&1; then + echo "=== Pulling Docker image from GHCR ===" + docker pull "$IMAGE_NAME" || { + echo "Pull failed, building locally..." + docker build -t "$IMAGE_NAME" -f "$DOCKERFILE" "$ROOT" + } else echo "=== Docker image cached ===" fi @@ -42,7 +41,7 @@ docker rm -f "$CONTAINER_NAME" 2>/dev/null || true trap 'echo "=== Rescuing logs ==="; docker cp "$CONTAINER_NAME:/root/logos-chat/simulations/mix_lez_chat/.sim_state" ./docker-sim-logs 2>/dev/null || true; docker rm -f "$CONTAINER_NAME" 2>/dev/null || true' EXIT echo "=== Starting container ===" -docker run --rm -d --name "$CONTAINER_NAME" "$IMAGE_NAME" tail -f /dev/null +docker run -d --name "$CONTAINER_NAME" "$IMAGE_NAME" tail -f /dev/null # Stage guest binaries GUEST_REL="vendor/logos-lez-rln/lez-rln/methods/guest/target/riscv32im-risc0-zkvm-elf/docker" @@ -64,58 +63,61 @@ fi # Collect SIM_* env vars SIM_ENVS="" for var in $(env | grep '^SIM_' | cut -d= -f1); do - SIM_ENVS="$SIM_ENVS export $var='${!var}';" + SIM_ENVS="${SIM_ENVS}export $var='${!var}'; " done -echo "=== Running simulation ===" -docker exec "$CONTAINER_NAME" bash -c " -$SIM_ENVS +# Write the run script to the container (avoids heredoc escaping issues) +docker exec -i "$CONTAINER_NAME" bash -c "cat > /root/run-sim.sh && chmod +x /root/run-sim.sh" << 'SIMSCRIPT' +#!/bin/bash +set -euo pipefail + export RISC0_DEV_MODE=1 -# Clone repo (just for scripts + configs, not for building) +# Clone repo cd /root rm -rf logos-chat -git clone --depth 1 -b $BRANCH $REPO_URL +git clone --depth 1 -b "$BRANCH" "$REPO_URL" cd logos-chat -# Only init top-level submodules + logos-lez-rln selectively (for sim script paths) + +# Init submodules (lssa needs full history for auto-sync) git submodule update --init --depth 1 -(cd vendor/logos-lez-rln && git submodule update --init --depth 1 lssa logos-delivery logos-delivery-module logos-execution-zone-module) +(cd vendor/logos-lez-rln && git submodule update --init lssa && \ + git submodule update --init --depth 1 logos-delivery logos-delivery-module logos-execution-zone-module) (cd vendor/logos-lez-rln/logos-delivery-module && git submodule update --init --depth 1 vendor/logos-delivery) -# Symlink ALL pre-built artifacts from the Docker image +# Symlink pre-built nix modules from image LEZ_DIR=vendor/logos-lez-rln -ln -sf /root/lez-modules/result-rln \$LEZ_DIR/logos-rln-module/result-rln -ln -sf /root/lez-modules/result-wallet \$LEZ_DIR/logos-rln-module/result-wallet -mkdir -p \$LEZ_DIR/logos-delivery-module/build_plugin -cp -r /root/lez-modules/delivery-plugin \$LEZ_DIR/logos-delivery-module/build_plugin/modules -mkdir -p \$LEZ_DIR/logos-delivery-module/vendor/logos-delivery/build -cp /root/lez-modules/delivery-build/* \$LEZ_DIR/logos-delivery-module/vendor/logos-delivery/build/ 2>/dev/null || true -# Sequencer is built from source at runtime (pre-built crashes in risc0 dev prover). -# Reuse cargo target cache from image to speed up (~30s vs ~2min). -ln -sf /root/lez-modules/lssa-target-cache \$LEZ_DIR/lssa/target -mkdir -p \$LEZ_DIR/lez-rln/target/debug -cp /root/lez-modules/run_setup \$LEZ_DIR/lez-rln/target/debug/ +ln -sf /root/lez-modules/result-rln $LEZ_DIR/logos-rln-module/result-rln +ln -sf /root/lez-modules/result-wallet $LEZ_DIR/logos-rln-module/result-wallet +mkdir -p $LEZ_DIR/logos-delivery-module/build_plugin +cp -r /root/lez-modules/delivery-plugin $LEZ_DIR/logos-delivery-module/build_plugin/modules +mkdir -p $LEZ_DIR/logos-delivery-module/vendor/logos-delivery/build +cp /root/lez-modules/delivery-build/* $LEZ_DIR/logos-delivery-module/vendor/logos-delivery/build/ 2>/dev/null || true mkdir -p build cp /root/lez-modules/liblogoschat.so build/ # Restore guest binaries -GUEST_DIR=\"\$LEZ_DIR/lez-rln/methods/guest/target/riscv32im-risc0-zkvm-elf/docker\" +GUEST_DIR="$LEZ_DIR/lez-rln/methods/guest/target/riscv32im-risc0-zkvm-elf/docker" if [ -f /tmp/guest-bins/rln_registration.bin ]; then - mkdir -p \"\$GUEST_DIR\" - cp /tmp/guest-bins/*.bin \"\$GUEST_DIR/\" + mkdir -p "$GUEST_DIR" + cp /tmp/guest-bins/*.bin "$GUEST_DIR/" fi -# Chat module — symlink from pre-built in image -ln -sf /root/lez-modules/chat-module-result /root/logos-chat-module/result 2>/dev/null || \ - (mkdir -p /root/logos-chat-module && ln -sf /root/lez-modules/chat-module-result /root/logos-chat-module/result) +# Chat module +mkdir -p /root/logos-chat-module +ln -sf /root/lez-modules/chat-module-result /root/logos-chat-module/result -# Set env vars for sim -export LOGOSCORE=\"/root/lez-modules/logoscore-result/bin/logoscore\" -CLANG_SO=\$(find /nix/store -maxdepth 3 -name 'libclang.so' 2>/dev/null | head -1 || true) -[ -n \"\$CLANG_SO\" ] && export LIBCLANG_PATH=\$(dirname \"\$CLANG_SO\") +# Build sequencer + run_setup from source (system clang, r0vm in PATH) +echo "Building sequencer + run_setup..." +export LIBCLANG_PATH=/usr/lib/llvm-18/lib +(cd $LEZ_DIR/lssa && cargo build --features standalone -p sequencer_service 2>&1 | tail -3) +(cd $LEZ_DIR/lez-rln && cargo build --bin run_setup 2>&1 | tail -3) +export LOGOSCORE="/root/lez-modules/logoscore-result/bin/logoscore" bash simulations/mix_lez_chat/run_simulation.sh --fresh -" +SIMSCRIPT + +echo "=== Running simulation ===" +docker exec -e BRANCH="$BRANCH" -e REPO_URL="$REPO_URL" $SIM_ENVS "$CONTAINER_NAME" bash /root/run-sim.sh echo "=== Done ===" -# Container cleanup handled by EXIT trap (which also rescues logs on failure) diff --git a/simulations/mix_lez_chat/INSTRUCTIONS.md b/simulations/mix_lez_chat/INSTRUCTIONS.md new file mode 100644 index 0000000..682aef3 --- /dev/null +++ b/simulations/mix_lez_chat/INSTRUCTIONS.md @@ -0,0 +1,72 @@ +# Running the 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. + +Two logoscore instances (sender + receiver) 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 sender publishes via `lightpushPublish(mixify=true)`, the mix exit node verifies the RLN proof before fanning out via gossipsub relay, and the receiver consumes the message via a Waku filter subscription. + +## macOS + +**Prereqs:** nix (with flakes), Docker, cargo-risczero, SSH access to GitHub. + +```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 +``` + +First run: ~15-25 min. Re-runs: `bash simulations/mix_lez_chat/run_simulation.sh --fresh` (~5 min). + +## Linux (native) + +**Prereqs:** nix (with flakes), Docker, cargo-risczero, SSH access to GitHub. + +```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 +``` + +Same as macOS. On x86_64 Linux this should work out of the box. On aarch64 Linux, guest zkVM binaries must be pre-built on another platform (rzup doesn't support aarch64-linux) and the wallet module nix build needs `RISC0_SKIP_BUILD_KERNELS=1`. + +## Linux (via Docker) + +**Prereqs:** Docker. + +```bash +git clone -b feat/logos-delivery git@github.com:adklempner/logos-chat.git +cd logos-chat && bash scripts/run_in_docker.sh +``` + +The pre-built image (`ghcr.io/adklempner/logos-chat-sim`) is pulled automatically (~8.5GB download). Guest zkVM binaries must exist on the host from a previous macOS/x86_64 build, or set `GUEST_BINARIES_DIR`. + +Each sim run: ~10 min (clone + sequencer build + sim). To force a local image rebuild: `REBUILD_IMAGE=1 bash scripts/run_in_docker.sh`. + +## Pass criteria + +**ALL 15 CHECKS PASSED** — 4 mix nodes mounted, gifter service, LEZ RLN active, sender+receiver initialized/started/mix-mounted, intro bundle created, messages sent and received. + +## Configuration + +```bash +SIM_LOG_LEVEL=TRACE SIM_KADEMLIA_MIN_WAIT=10 bash simulations/mix_lez_chat/run_simulation.sh --fresh +``` + +Full list of `SIM_*` variables in `simulations/mix_lez_chat/README.md`. + +## If it fails + +Re-run with fresh state: +```bash +bash simulations/mix_lez_chat/run_simulation.sh --fresh +``` + +Wallet/sequencer errors: +```bash +rm -f vendor/logos-lez-rln/dev/wallet_config.json vendor/logos-lez-rln/dev/storage.json +``` + +Guest binary errors after updating submodules: +```bash +rm -rf vendor/logos-lez-rln/lez-rln/methods/guest/target +bash simulations/mix_lez_chat/setup_and_run.sh +``` + +Docker logs are rescued to `./docker-sim-logs/` on failure. diff --git a/simulations/mix_lez_chat/README.md b/simulations/mix_lez_chat/README.md index 7a08380..b82ecba 100644 --- a/simulations/mix_lez_chat/README.md +++ b/simulations/mix_lez_chat/README.md @@ -1,8 +1,47 @@ # 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. +End-to-end private chat between two logos-chat-module clients over a 4-node mix network with LEZ-backed RLN spam protection. -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. +Two logoscore instances (sender + receiver) 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 sender publishes via `lightpushPublish(mixify=true)`, the mix exit node verifies the RLN proof before fanning out via gossipsub relay, and the receiver consumes the message via a Waku filter subscription. + +## macOS + +**Prereqs:** nix (with flakes), Docker, cargo-risczero, SSH access to GitHub. + +```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 +``` + +First run: ~15-25 min. Re-runs: `bash simulations/mix_lez_chat/run_simulation.sh --fresh` (~5 min). + +## Linux (native) + +**Prereqs:** nix (with flakes), Docker, cargo-risczero, SSH access to GitHub. + +```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 +``` + +Same as macOS. On x86_64 Linux this should work out of the box. On aarch64 Linux, guest zkVM binaries must be pre-built on another platform (rzup doesn't support aarch64-linux) and the wallet module nix build needs `RISC0_SKIP_BUILD_KERNELS=1`. + +## Linux (via Docker) + +**Prereqs:** Docker with 24GB RAM allocated. + +```bash +git clone -b feat/logos-delivery git@github.com:adklempner/logos-chat.git +cd logos-chat && bash scripts/run_in_docker.sh +``` + +The pre-built image (`ghcr.io/adklempner/logos-chat-sim`) is pulled automatically (~8.5GB download). Guest zkVM binaries must exist on the host from a previous macOS/x86_64 build, or set `GUEST_BINARIES_DIR`. + +Each sim run: ~10 min (clone + sequencer build + sim). To force a local image rebuild: `REBUILD_IMAGE=1 bash scripts/run_in_docker.sh`. + +## Pass criteria + +**ALL 15 CHECKS PASSED** — 4 mix nodes mounted, gifter service, LEZ RLN active, sender+receiver initialized/started/mix-mounted, intro bundle created, messages sent and received. ## Architecture @@ -18,28 +57,9 @@ logoscore (per mix node) logoscore (per chat 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: +Override defaults via environment: | Variable | Default | Description | |---|---|---| @@ -73,22 +93,13 @@ When `--fresh` is passed: 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 +**Re-run with fresh state:** +```bash +bash simulations/mix_lez_chat/run_simulation.sh --fresh +``` + **"Sequencer failed to start"** — port 3040 already in use: ```bash kill $(lsof -ti tcp:3040) && bash simulations/mix_lez_chat/run_simulation.sh --fresh @@ -107,10 +118,7 @@ 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 -``` +Docker logs are rescued to `./docker-sim-logs/` on failure. ## Adapting for other LEZ programs @@ -131,7 +139,7 @@ The chat_module sender/receiver instances (phase 5 of run_simulation.sh). Your m - 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. +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 (gated by `LOGOS_EVENT_STDERR` env var) for cross-platform reliability. ### How to stage your module @@ -160,3 +168,4 @@ 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 +- `sequencer.log` — LEZ sequencer diff --git a/simulations/mix_lez_chat/run_simulation.sh b/simulations/mix_lez_chat/run_simulation.sh index 4bf0570..41ac988 100755 --- a/simulations/mix_lez_chat/run_simulation.sh +++ b/simulations/mix_lez_chat/run_simulation.sh @@ -137,7 +137,7 @@ else else # Sequencer guest binaries must match the lssa rev that lez-rln's host-side # client pins. Mismatch → DeserializeUnexpectedEnd (wire format divergence). - LSSA_REV=$(grep -oE 'rev\s*=\s*"[0-9a-f]+"' "$LEZ_RLN_DIR/lez-rln/Cargo.toml" | head -1 | sed 's/.*"\([0-9a-f]*\)"/\1/') + LSSA_REV=$(grep -oE '(rev|tag)\s*=\s*"[^"]+"' "$LEZ_RLN_DIR/lez-rln/Cargo.toml" | head -1 | sed 's/.*"\([^"]*\)"/\1/') [ -z "$LSSA_REV" ] && die "Could not extract lssa rev from lez-rln/Cargo.toml" if ! git -C "$LEZ_RLN_DIR/lssa" merge-base --is-ancestor "$LSSA_REV" HEAD 2>/dev/null; then log " Pinning lssa to $LSSA_REV..." diff --git a/vendor/logos-lez-rln b/vendor/logos-lez-rln index ad17d90..f3f1aa6 160000 --- a/vendor/logos-lez-rln +++ b/vendor/logos-lez-rln @@ -1 +1 @@ -Subproject commit ad17d9026b5bc69c6c42d7617fb08b18ae135f42 +Subproject commit f3f1aa6c609fae776712e04ccf0aa5a64f004391