From 92dd368259ee13b38b496e4ab66ea1fa9e93dce5 Mon Sep 17 00:00:00 2001 From: Jorge Silva Date: Mon, 13 Apr 2026 18:08:33 +0100 Subject: [PATCH 01/13] start selfhost dir --- selfhost/docker-compose.yml | 131 ++++++++++++++++++++++++++++++++++++ selfhost/readme.md | 0 selfhost/start.sh | 0 3 files changed, 131 insertions(+) create mode 100644 selfhost/docker-compose.yml create mode 100644 selfhost/readme.md create mode 100644 selfhost/start.sh diff --git a/selfhost/docker-compose.yml b/selfhost/docker-compose.yml new file mode 100644 index 00000000..c7df4ed9 --- /dev/null +++ b/selfhost/docker-compose.yml @@ -0,0 +1,131 @@ +services: + + valkey: + image: valkey/valkey:8-alpine + container_name: valkey + command: ["valkey-server", "--save", "60", "1", "--loglevel", "warning"] + volumes: + - /mnt/synd-data/valkey:/data + restart: unless-stopped + + maestro: + image: ghcr.io/syndicateprotocol/syndicate-appchains/synd-maestro:${SYND_APPCHAINS_VERSION:-v1.0.12} + container_name: maestro + env_file: + - .env + environment: + - VALKEY_URL=redis://valkey:6379 + depends_on: + - valkey + restart: unless-stopped + + batch_sequencer: + image: ghcr.io/syndicateprotocol/syndicate-appchains/synd-batch-sequencer:${SYND_APPCHAINS_VERSION:-v1.0.12} + container_name: batch_sequencer + env_file: + - .env + environment: + - VALKEY_URL=redis://valkey:6379 + - CHAIN_ID=${APPCHAIN_CHAIN_ID} + depends_on: + - valkey + - maestro + restart: unless-stopped + + settlement_ingestor: + image: ghcr.io/syndicateprotocol/syndicate-appchains/synd-chain-ingestor:${SYND_APPCHAINS_VERSION:-v1.0.12} + container_name: settlement_ingestor + env_file: + - .env + command: + - "--db-file=/data/settlement.db" + - "--start-block=${SETTLEMENT_INGESTOR_START_BLOCK:-0}" + - "--ws-urls=${SETTLEMENT_INGESTOR_WS_URLS}" + volumes: + - /mnt/synd-data/settlement:/data + restart: unless-stopped + + sequencing_ingestor: + image: ghcr.io/syndicateprotocol/syndicate-appchains/synd-chain-ingestor:${SYND_APPCHAINS_VERSION:-v1.0.12} + container_name: sequencing_ingestor + env_file: + - .env + command: + - "--db-file=/data/sequencing.db" + - "--start-block=${SEQUENCING_INGESTOR_START_BLOCK:-0}" + - "--ws-urls=${SEQUENCING_INGESTOR_WS_URLS}" + volumes: + - /mnt/synd-data/sequencing:/data + restart: unless-stopped + + mchain: + image: ghcr.io/syndicateprotocol/syndicate-appchains/synd-mchain:${SYND_APPCHAINS_VERSION:-v1.0.12} + container_name: mchain + env_file: + - .env + command: + - "--datadir=/data" + volumes: + - /mnt/synd-data/mchain:/data + restart: unless-stopped + + translator: + image: ghcr.io/syndicateprotocol/syndicate-appchains/synd-translator:${SYND_APPCHAINS_VERSION:-v1.0.12} + container_name: translator + env_file: + - .env + environment: + - SETTLEMENT_WS_URL=ws://settlement_ingestor:8545 + - SEQUENCING_WS_URL=ws://sequencing_ingestor:8545 + - MCHAIN_WS_URL=ws://mchain:8545 + depends_on: + - settlement_ingestor + - sequencing_ingestor + - mchain + restart: unless-stopped + + proposer: + image: ghcr.io/syndicateprotocol/syndicate-appchains/synd-proposer:${SYND_APPCHAINS_VERSION:-v1.0.12} + container_name: proposer + env_file: + - .env + environment: + - APPCHAIN_RPC_URL=http://nitro:8547 + restart: unless-stopped + + nitro: + image: ghcr.io/syndicateprotocol/nitro/nitro:${SYND_NITRO_VERSION:-eigenda-v3.6.4} + container_name: nitro + init: true + restart: always + env_file: + - .env + command: + - "--conf.env-prefix=NITRO" + - "--init.validate-checksum=false" + - "--parent-chain.connection.url=ws://mchain:8545" + - "--parent-chain.id=511000" + - "--http.api=arb,eth,net,web3,txpool,arbtrace,debug,synd" + - "--http.addr=0.0.0.0" + - "--http.port=8547" + - "--http.vhosts=*" + - "--http.corsdomain=*" + - "--ws.addr=0.0.0.0" + - "--ws.port=8548" + - "--ws.origins=*" + - "--node.dangerous.disable-blob-reader=true" + - "--node.inbox-reader.check-delay=100ms" + - "--node.staker.enable=false" + - "--node.parent-chain-reader.poll-interval=100ms" + - "--node.parent-chain-reader.old-header-timeout=2540400h" + - "--execution.parent-chain-reader.old-header-timeout=2540400h" + - "--execution.caching.archive=true" + - "--execution.forwarding-target=http://maestro:8080" + - "--ensure-rollup-deployment=false" + ports: + - "8545:8547" + - "8548:8548" + volumes: + - /mnt/nitro-data:/home/user/.arbitrum + depends_on: + - mchain diff --git a/selfhost/readme.md b/selfhost/readme.md new file mode 100644 index 00000000..e69de29b diff --git a/selfhost/start.sh b/selfhost/start.sh new file mode 100644 index 00000000..e69de29b From ea033bbb8e31df6f6950c986e95531913376b354 Mon Sep 17 00:00:00 2001 From: Jorge Silva Date: Mon, 13 Apr 2026 20:23:15 +0100 Subject: [PATCH 02/13] WIP --- selfhost/.env.example | 101 ++++++++++++++++++++++++++++++++++ selfhost/docker-compose.yml | 16 +++--- selfhost/readme.md | 105 ++++++++++++++++++++++++++++++++++++ selfhost/start.sh | 56 +++++++++++++++++++ 4 files changed, 272 insertions(+), 6 deletions(-) create mode 100644 selfhost/.env.example mode change 100644 => 100755 selfhost/start.sh diff --git a/selfhost/.env.example b/selfhost/.env.example new file mode 100644 index 00000000..c9029600 --- /dev/null +++ b/selfhost/.env.example @@ -0,0 +1,101 @@ +# ── Core ────────────────────────────────────────────────────────────────────── +# Directory on the host where all persistent data is stored +DATA_DIR=./data + +# Your appchain's chain ID +APPCHAIN_CHAIN_ID= + +# Image versions (override to pin to a specific release) +SYND_APPCHAINS_VERSION=v1.0.12 +SYND_NITRO_VERSION=eigenda-v3.6.4 + +# ── Ingestors (WebSocket) ────────────────────────────────────────────────────── +# WebSocket RPC URL(s) for the sequencing chain (comma-separated for redundancy) +SEQUENCING_INGESTOR_WS_URLS=wss:// + +# Block number to start ingesting from on the sequencing chain +SEQUENCING_INGESTOR_START_BLOCK=0 + +# WebSocket RPC URL(s) for the settlement chain (comma-separated for redundancy) +SETTLEMENT_INGESTOR_WS_URLS=wss:// + +# Block number to start ingesting from on the settlement chain +SETTLEMENT_INGESTOR_START_BLOCK=0 + +# ── Sequencing Chain Contracts ───────────────────────────────────────────────── +# Address of the sequencing chain inbox contract (used by translator & batch sequencer) +SEQUENCING_CONTRACT_ADDRESS=0x + +# Arbitrum bridge and inbox contract addresses on the sequencing chain +ARBITRUM_BRIDGE_ADDRESS=0x +ARBITRUM_INBOX_ADDRESS=0x + +# ── Batch Sequencer ──────────────────────────────────────────────────────────── +# Private key of the wallet that signs and submits transaction batches +BATCHER_PRIVATE_KEY=0x + +# HTTP RPC URL(s) for the sequencing chain (comma-separated) +SEQUENCING_RPC_URLS=https:// + +# ── Maestro ──────────────────────────────────────────────────────────────────── +# JSON map of chain ID → HTTP RPC URL used by maestro for transaction resubmission +# Example: {"888991": "https://rpc.example.com"} +CHAIN_RPC_URLS= + +# ── Nitro ────────────────────────────────────────────────────────────────────── +# Chain info JSON blob consumed by the Nitro node (NITRO__ double-underscore prefix notation) +NITRO_CHAIN_INFO__JSON= + +# ── MChain Genesis & Snapshots ───────────────────────────────────────────────── +# EVM genesis config JSON for the appchain +GENESIS_CONFIG= + +# Snapshots speed up initial sync by pre-populating data directories. +# You can provide one or both. start.sh downloads and extracts them before +# starting any containers. Each is skipped if its target directory is non-empty. + +# URL to a snapshot archive (.tar or .tar.gz) for the mchain data directory +MCHAIN_SNAPSHOT_URL=https:// + +# URL to a snapshot archive (.tar or .tar.gz) for the Nitro data directory +NITRO_SNAPSHOT_URL=https:// + +# ── Migration (only needed for chains migrated from another sequencer) ────────── +# Block on the settlement chain where the migration happened +SETTLEMENT_START_BLOCK=0 + +MIGRATED_BEFORE_BATCH_ACC=0x +MIGRATED_BATCH_ACC=0x +MIGRATED_BATCH_COUNT=0 +MIGRATED_DELAYED_MSGS_ACC=0x +MIGRATED_DELAYED_MSGS_COUNT=0 +# Appchain block hash at the migration point +MIGRATED_APPCHAIN_BLOCK_HASH=0x + +# ── Proposer ─────────────────────────────────────────────────────────────────── +# Private key used by the proposer to submit state commitments on-chain +PRIVATE_KEY=0x + +# Ethereum L1 RPC URL (used by the proposer to verify attestations) +ETHEREUM_RPC_URL=https:// + +# Settlement chain RPC URL and chain ID +SETTLEMENT_RPC_URL=https:// +SETTLEMENT_CHAIN_ID= + +# HTTP RPC URL for the sequencing chain node (used by the proposer) +SEQUENCING_RPC_URL=https:// + +# Beacon chain RPC URL (used for blob fetching) +BEACON_RPC_URL=https:// + +# URL of the TEE enclave that produces signed state commitments +ENCLAVE_RPC_URL=https:// + +# Contract addresses on the settlement chain +TEE_MODULE_CONTRACT_ADDRESS=0x +APPCHAIN_BRIDGE_ADDRESS=0x +SEQUENCING_BRIDGE_ADDRESS=0x + +# ── Logging ──────────────────────────────────────────────────────────────────── +RUST_LOG=info diff --git a/selfhost/docker-compose.yml b/selfhost/docker-compose.yml index c7df4ed9..0a170987 100644 --- a/selfhost/docker-compose.yml +++ b/selfhost/docker-compose.yml @@ -5,7 +5,7 @@ services: container_name: valkey command: ["valkey-server", "--save", "60", "1", "--loglevel", "warning"] volumes: - - /mnt/synd-data/valkey:/data + - ${DATA_DIR:-./data}/valkey:/data restart: unless-stopped maestro: @@ -27,6 +27,7 @@ services: environment: - VALKEY_URL=redis://valkey:6379 - CHAIN_ID=${APPCHAIN_CHAIN_ID} + - SEQUENCING_ADDRESS=${SEQUENCING_CONTRACT_ADDRESS} depends_on: - valkey - maestro @@ -42,7 +43,7 @@ services: - "--start-block=${SETTLEMENT_INGESTOR_START_BLOCK:-0}" - "--ws-urls=${SETTLEMENT_INGESTOR_WS_URLS}" volumes: - - /mnt/synd-data/settlement:/data + - ${DATA_DIR:-./data}/settlement:/data restart: unless-stopped sequencing_ingestor: @@ -55,7 +56,7 @@ services: - "--start-block=${SEQUENCING_INGESTOR_START_BLOCK:-0}" - "--ws-urls=${SEQUENCING_INGESTOR_WS_URLS}" volumes: - - /mnt/synd-data/sequencing:/data + - ${DATA_DIR:-./data}/sequencing:/data restart: unless-stopped mchain: @@ -66,7 +67,7 @@ services: command: - "--datadir=/data" volumes: - - /mnt/synd-data/mchain:/data + - ${DATA_DIR:-./data}/mchain:/data restart: unless-stopped translator: @@ -91,13 +92,15 @@ services: - .env environment: - APPCHAIN_RPC_URL=http://nitro:8547 + depends_on: + - nitro restart: unless-stopped nitro: image: ghcr.io/syndicateprotocol/nitro/nitro:${SYND_NITRO_VERSION:-eigenda-v3.6.4} container_name: nitro init: true - restart: always + restart: unless-stopped env_file: - .env command: @@ -105,6 +108,7 @@ services: - "--init.validate-checksum=false" - "--parent-chain.connection.url=ws://mchain:8545" - "--parent-chain.id=511000" + - "--chain.id=${APPCHAIN_CHAIN_ID}" - "--http.api=arb,eth,net,web3,txpool,arbtrace,debug,synd" - "--http.addr=0.0.0.0" - "--http.port=8547" @@ -126,6 +130,6 @@ services: - "8545:8547" - "8548:8548" volumes: - - /mnt/nitro-data:/home/user/.arbitrum + - ${DATA_DIR:-./data}/nitro:/home/user/.arbitrum depends_on: - mchain diff --git a/selfhost/readme.md b/selfhost/readme.md index e69de29b..2afbe0e3 100644 --- a/selfhost/readme.md +++ b/selfhost/readme.md @@ -0,0 +1,105 @@ +# Self-Hosting a Syndicate Appchain Node + +Run your own Syndicate appchain RPC node with Docker Compose. + +## Prerequisites + +- [Docker](https://docs.docker.com/get-docker/) with the Compose plugin (v2.20+) +- `curl` and `tar` (for snapshot download) +- Disk space: 1 TB+ recommended +- WebSocket RPC access to your sequencing chain and settlement chain (e.g. via Alchemy, Infura, or a self-hosted node) + +## Setup + +### 1. Copy the env template + +```bash +cp .env.example .env +``` + +### 2. Fill in `.env` + +Open `.env` and supply your chain-specific values. The fields are grouped and commented. Required fields are: + +| Field | Description | +|-------|-------------| +| `APPCHAIN_CHAIN_ID` | Your appchain's chain ID | +| `SEQUENCING_INGESTOR_WS_URLS` | WebSocket RPC URL(s) for the sequencing chain | +| `SEQUENCING_INGESTOR_START_BLOCK` | Block to start ingesting from on the sequencing chain | +| `SETTLEMENT_INGESTOR_WS_URLS` | WebSocket RPC URL(s) for the settlement chain | +| `SETTLEMENT_INGESTOR_START_BLOCK` | Block to start ingesting from on the settlement chain | +| `SEQUENCING_CONTRACT_ADDRESS` | Address of the sequencing chain inbox contract | +| `ARBITRUM_BRIDGE_ADDRESS` | Arbitrum bridge contract address on the sequencing chain | +| `ARBITRUM_INBOX_ADDRESS` | Arbitrum inbox contract address on the sequencing chain | +| `BATCHER_PRIVATE_KEY` | Private key for the wallet that submits transaction batches | +| `SEQUENCING_RPC_URLS` | HTTP RPC URL(s) for the sequencing chain | +| `CHAIN_RPC_URLS` | JSON map of chain ID → HTTP RPC URL used by maestro (e.g. `{"888991":"https://..."}`) | +| `NITRO_CHAIN_INFO__JSON` | Chain info JSON blob for the Nitro node | +| `GENESIS_CONFIG` | EVM genesis config JSON for the appchain | +| `MCHAIN_SNAPSHOT_URL` | URL to a `.tar` or `.tar.gz` snapshot of the mchain data directory _(optional but recommended)_ | +| `NITRO_SNAPSHOT_URL` | URL to a `.tar` or `.tar.gz` snapshot of the Nitro data directory _(optional but recommended)_ | + +At least one snapshot URL (`MCHAIN_SNAPSHOT_URL` or `NITRO_SNAPSHOT_URL`) is strongly recommended — syncing from genesis can take many hours. Both are skipped automatically if the target directory already contains data. + +Fields in the **Migration** and **Proposer** sections are only required if your appchain uses those features. + +> All values for your specific appchain can be provided by the Syndicate team. + +### 3. Start + +```bash +bash start.sh +``` + +The script will: +1. Create local data directories under `DATA_DIR` (default: `./data`) +2. Download and extract the mchain snapshot (if `SNAPSHOT_URL` is set and the data directory is empty) +3. Start all services with `docker compose` + +## Verify + +Check that all containers are running: + +```bash +docker compose ps +``` + +Wait for the mchain and nitro to finish syncing, then test the RPC: + +```bash +curl -s -X POST http://localhost:8545 \ + -H 'Content-Type: application/json' \ + -d '{"jsonrpc":"2.0","method":"eth_blockNumber","params":[],"id":1}' +``` + +## Common commands + +```bash +# Follow logs for all services +docker compose logs -f + +# Follow logs for a specific service +docker compose logs -f nitro + +# Stop all services +docker compose down + +# Stop and remove all data volumes +docker compose down -v + +# Restart a single service +docker compose restart mchain +``` + +## Data directory layout + +``` +./data/ +├── mchain/ # RocksDB state for the intermediate chain node +├── nitro/ # Nitro node state (~/.arbitrum) +├── settlement/ # filesystem cache for the settlement ingestor +├── sequencing/ # filesystem cache for the sequencing ingestor +└── valkey/ # Valkey (Redis-compatible) persistence +``` + +To change the location, set `DATA_DIR` in your `.env` before running `start.sh`. diff --git a/selfhost/start.sh b/selfhost/start.sh old mode 100644 new mode 100755 index e69de29b..bad5b37c --- a/selfhost/start.sh +++ b/selfhost/start.sh @@ -0,0 +1,56 @@ +#!/usr/bin/env bash +set -euo pipefail + +# Resolve the directory this script lives in so it works from any call site +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +cd "$SCRIPT_DIR" + +# ── Preflight ────────────────────────────────────────────────────────────────── +if [ ! -f .env ]; then + echo "Error: .env file not found." + echo " cp .env.example .env" + echo " # fill in your values, then re-run this script" + exit 1 +fi + +source .env + +DATA_DIR="${DATA_DIR:-./data}" + +# ── Data directories ─────────────────────────────────────────────────────────── +echo "Creating data directories under $DATA_DIR ..." +mkdir -p \ + "$DATA_DIR/valkey" \ + "$DATA_DIR/settlement" \ + "$DATA_DIR/sequencing" \ + "$DATA_DIR/mchain" \ + "$DATA_DIR/nitro" + +# ── Snapshots ───────────────────────────────────────────────────────────────── +download_snapshot() { + local url="$1" + local dest="$2" + local label="$3" + + if [ -n "$url" ]; then + if [ -z "$(ls -A "$dest" 2>/dev/null)" ]; then + echo "Downloading $label snapshot from $url ..." + curl -L --progress-bar "$url" | tar -xf - -C "$dest" + echo "$label snapshot extracted to $dest" + else + echo "Skipping $label snapshot: $dest is not empty" + fi + fi +} + +download_snapshot "${MCHAIN_SNAPSHOT_URL:-}" "$DATA_DIR/mchain" "mchain" +download_snapshot "${NITRO_SNAPSHOT_URL:-}" "$DATA_DIR/nitro" "nitro" + +# ── Start services ───────────────────────────────────────────────────────────── +echo "Starting services ..." +docker compose --env-file .env up -d + +echo "" +echo "All services started." +echo "Appchain JSON-RPC will be available at http://localhost:8545 once nitro is ready." +echo "Run 'docker compose logs -f' to follow logs." From 70e357b4eba833ea518ec44ea955883444c1bf9a Mon Sep 17 00:00:00 2001 From: Jorge Silva Date: Tue, 14 Apr 2026 11:33:42 +0100 Subject: [PATCH 03/13] improve docker setup --- selfhost/.env.example | 34 +++++++++++----------- selfhost/docker-compose.yml | 56 ++++++++++++++++++++++++++----------- selfhost/start.sh | 19 +++++++------ 3 files changed, 67 insertions(+), 42 deletions(-) diff --git a/selfhost/.env.example b/selfhost/.env.example index c9029600..5b9a84fd 100644 --- a/selfhost/.env.example +++ b/selfhost/.env.example @@ -2,6 +2,16 @@ # Directory on the host where all persistent data is stored DATA_DIR=./data +# Snapshots speed up initial sync by pre-populating data directories. +# You can provide one or both. start.sh downloads and extracts them before +# starting any containers. Each is skipped if its target directory is non-empty. + +# URL to a snapshot archive (.tar or .tar.gz) for the mchain data directory +MCHAIN_SNAPSHOT_URL=https:// + +# URL to a snapshot archive (.tar or .tar.gz) for the Nitro data directory +NITRO_SNAPSHOT_URL=https:// + # Your appchain's chain ID APPCHAIN_CHAIN_ID= @@ -22,11 +32,11 @@ SETTLEMENT_INGESTOR_WS_URLS=wss:// # Block number to start ingesting from on the settlement chain SETTLEMENT_INGESTOR_START_BLOCK=0 -# ── Sequencing Chain Contracts ───────────────────────────────────────────────── -# Address of the sequencing chain inbox contract (used by translator & batch sequencer) +# ── Parent Chains Contracts ───────────────────────────────────────────────── +# Address of the sequencing contract on the sequencing chain (used by translator & batch sequencer) SEQUENCING_CONTRACT_ADDRESS=0x -# Arbitrum bridge and inbox contract addresses on the sequencing chain +# Arbitrum bridge and inbox contract addresses on the settlement chain ARBITRUM_BRIDGE_ADDRESS=0x ARBITRUM_INBOX_ADDRESS=0x @@ -46,31 +56,19 @@ CHAIN_RPC_URLS= # Chain info JSON blob consumed by the Nitro node (NITRO__ double-underscore prefix notation) NITRO_CHAIN_INFO__JSON= -# ── MChain Genesis & Snapshots ───────────────────────────────────────────────── +# ── MChain ───────────────────────────────────────────────────────────────────── # EVM genesis config JSON for the appchain -GENESIS_CONFIG= - -# Snapshots speed up initial sync by pre-populating data directories. -# You can provide one or both. start.sh downloads and extracts them before -# starting any containers. Each is skipped if its target directory is non-empty. - -# URL to a snapshot archive (.tar or .tar.gz) for the mchain data directory -MCHAIN_SNAPSHOT_URL=https:// - -# URL to a snapshot archive (.tar or .tar.gz) for the Nitro data directory -NITRO_SNAPSHOT_URL=https:// +MCHAIN_GENESIS_CONFIG= -# ── Migration (only needed for chains migrated from another sequencer) ────────── # Block on the settlement chain where the migration happened SETTLEMENT_START_BLOCK=0 +# ── Migration (only needed for chains migrated from vanilla orbit) ────────── MIGRATED_BEFORE_BATCH_ACC=0x MIGRATED_BATCH_ACC=0x MIGRATED_BATCH_COUNT=0 MIGRATED_DELAYED_MSGS_ACC=0x MIGRATED_DELAYED_MSGS_COUNT=0 -# Appchain block hash at the migration point -MIGRATED_APPCHAIN_BLOCK_HASH=0x # ── Proposer ─────────────────────────────────────────────────────────────────── # Private key used by the proposer to submit state commitments on-chain diff --git a/selfhost/docker-compose.yml b/selfhost/docker-compose.yml index 0a170987..54b6b609 100644 --- a/selfhost/docker-compose.yml +++ b/selfhost/docker-compose.yml @@ -11,10 +11,11 @@ services: maestro: image: ghcr.io/syndicateprotocol/syndicate-appchains/synd-maestro:${SYND_APPCHAINS_VERSION:-v1.0.12} container_name: maestro - env_file: - - .env environment: - VALKEY_URL=redis://valkey:6379 + - CHAIN_RPC_URLS=${CHAIN_RPC_URLS:-} + - SKIP_BALANCE_CHECK=true + - RUST_LOG=${RUST_LOG:-info} depends_on: - valkey restart: unless-stopped @@ -22,12 +23,13 @@ services: batch_sequencer: image: ghcr.io/syndicateprotocol/syndicate-appchains/synd-batch-sequencer:${SYND_APPCHAINS_VERSION:-v1.0.12} container_name: batch_sequencer - env_file: - - .env environment: - VALKEY_URL=redis://valkey:6379 - CHAIN_ID=${APPCHAIN_CHAIN_ID} - SEQUENCING_ADDRESS=${SEQUENCING_CONTRACT_ADDRESS} + - BATCHER_PRIVATE_KEY=${BATCHER_PRIVATE_KEY} + - SEQUENCING_RPC_URLS=${SEQUENCING_RPC_URLS} + - RUST_LOG=${RUST_LOG:-info} depends_on: - valkey - maestro @@ -36,12 +38,12 @@ services: settlement_ingestor: image: ghcr.io/syndicateprotocol/syndicate-appchains/synd-chain-ingestor:${SYND_APPCHAINS_VERSION:-v1.0.12} container_name: settlement_ingestor - env_file: - - .env command: - "--db-file=/data/settlement.db" - "--start-block=${SETTLEMENT_INGESTOR_START_BLOCK:-0}" - "--ws-urls=${SETTLEMENT_INGESTOR_WS_URLS}" + environment: + - RUST_LOG=${RUST_LOG:-info} volumes: - ${DATA_DIR:-./data}/settlement:/data restart: unless-stopped @@ -49,12 +51,12 @@ services: sequencing_ingestor: image: ghcr.io/syndicateprotocol/syndicate-appchains/synd-chain-ingestor:${SYND_APPCHAINS_VERSION:-v1.0.12} container_name: sequencing_ingestor - env_file: - - .env command: - "--db-file=/data/sequencing.db" - "--start-block=${SEQUENCING_INGESTOR_START_BLOCK:-0}" - "--ws-urls=${SEQUENCING_INGESTOR_WS_URLS}" + environment: + - RUST_LOG=${RUST_LOG:-info} volumes: - ${DATA_DIR:-./data}/sequencing:/data restart: unless-stopped @@ -62,10 +64,19 @@ services: mchain: image: ghcr.io/syndicateprotocol/syndicate-appchains/synd-mchain:${SYND_APPCHAINS_VERSION:-v1.0.12} container_name: mchain - env_file: - - .env command: - "--datadir=/data" + environment: + - APPCHAIN_CHAIN_ID=${APPCHAIN_CHAIN_ID} + - GENESIS_CONFIG=${MCHAIN_GENESIS_CONFIG:-} + - SNAPSHOT_URL=${MCHAIN_SNAPSHOT_URL:-} + - SETTLEMENT_START_BLOCK=${SETTLEMENT_START_BLOCK:-0} + - MIGRATED_BEFORE_BATCH_ACC=${MIGRATED_BEFORE_BATCH_ACC:-} + - MIGRATED_BATCH_ACC=${MIGRATED_BATCH_ACC:-} + - MIGRATED_BATCH_COUNT=${MIGRATED_BATCH_COUNT:-0} + - MIGRATED_DELAYED_MSGS_ACC=${MIGRATED_DELAYED_MSGS_ACC:-} + - MIGRATED_DELAYED_MSGS_COUNT=${MIGRATED_DELAYED_MSGS_COUNT:-0} + - RUST_LOG=${RUST_LOG:-info} volumes: - ${DATA_DIR:-./data}/mchain:/data restart: unless-stopped @@ -73,12 +84,16 @@ services: translator: image: ghcr.io/syndicateprotocol/syndicate-appchains/synd-translator:${SYND_APPCHAINS_VERSION:-v1.0.12} container_name: translator - env_file: - - .env environment: - SETTLEMENT_WS_URL=ws://settlement_ingestor:8545 - SEQUENCING_WS_URL=ws://sequencing_ingestor:8545 - MCHAIN_WS_URL=ws://mchain:8545 + - APPCHAIN_CHAIN_ID=${APPCHAIN_CHAIN_ID} + - SEQUENCING_CONTRACT_ADDRESS=${SEQUENCING_CONTRACT_ADDRESS} + - ARBITRUM_BRIDGE_ADDRESS=${ARBITRUM_BRIDGE_ADDRESS} + - ARBITRUM_INBOX_ADDRESS=${ARBITRUM_INBOX_ADDRESS} + - SETTLEMENT_START_BLOCK=${SETTLEMENT_START_BLOCK:-0} + - RUST_LOG=${RUST_LOG:-info} depends_on: - settlement_ingestor - sequencing_ingestor @@ -88,10 +103,19 @@ services: proposer: image: ghcr.io/syndicateprotocol/syndicate-appchains/synd-proposer:${SYND_APPCHAINS_VERSION:-v1.0.12} container_name: proposer - env_file: - - .env environment: - APPCHAIN_RPC_URL=http://nitro:8547 + - PRIVATE_KEY=${PRIVATE_KEY} + - ETHEREUM_RPC_URL=${ETHEREUM_RPC_URL} + - SETTLEMENT_RPC_URL=${SETTLEMENT_RPC_URL} + - SETTLEMENT_CHAIN_ID=${SETTLEMENT_CHAIN_ID} + - SEQUENCING_RPC_URL=${SEQUENCING_RPC_URL} + - BEACON_RPC_URL=${BEACON_RPC_URL:-} + - ENCLAVE_RPC_URL=${ENCLAVE_RPC_URL} + - TEE_MODULE_CONTRACT_ADDRESS=${TEE_MODULE_CONTRACT_ADDRESS} + - APPCHAIN_BRIDGE_ADDRESS=${APPCHAIN_BRIDGE_ADDRESS} + - SEQUENCING_BRIDGE_ADDRESS=${SEQUENCING_BRIDGE_ADDRESS} + - SEQUENCING_CONTRACT_ADDRESS=${SEQUENCING_CONTRACT_ADDRESS} depends_on: - nitro restart: unless-stopped @@ -101,8 +125,8 @@ services: container_name: nitro init: true restart: unless-stopped - env_file: - - .env + environment: + - NITRO_CHAIN_INFO__JSON=${NITRO_CHAIN_INFO__JSON} command: - "--conf.env-prefix=NITRO" - "--init.validate-checksum=false" diff --git a/selfhost/start.sh b/selfhost/start.sh index bad5b37c..02eb51e4 100755 --- a/selfhost/start.sh +++ b/selfhost/start.sh @@ -31,16 +31,19 @@ download_snapshot() { local url="$1" local dest="$2" local label="$3" + local marker="$dest/.snapshot_downloaded" - if [ -n "$url" ]; then - if [ -z "$(ls -A "$dest" 2>/dev/null)" ]; then - echo "Downloading $label snapshot from $url ..." - curl -L --progress-bar "$url" | tar -xf - -C "$dest" - echo "$label snapshot extracted to $dest" - else - echo "Skipping $label snapshot: $dest is not empty" - fi + [ -z "$url" ] && return 0 + + if [ -f "$marker" ]; then + echo "Skipping $label snapshot: already downloaded" + return 0 fi + + echo "Downloading $label snapshot from $url ..." + curl -L --progress-bar "$url" | tar -xf - -C "$dest" + touch "$marker" + echo "$label snapshot extracted to $dest" } download_snapshot "${MCHAIN_SNAPSHOT_URL:-}" "$DATA_DIR/mchain" "mchain" From 358f2e0d333c0ea83a0de0f1c7b12d8c3ee880dd Mon Sep 17 00:00:00 2001 From: Jorge Silva Date: Tue, 14 Apr 2026 13:21:55 +0100 Subject: [PATCH 04/13] multiple fixes and improvements --- selfhost/.env.example | 35 +++++++++++++++-------------------- selfhost/.gitignore | 1 + selfhost/docker-compose.yml | 27 +++++++++++++++------------ selfhost/start.sh | 3 +-- 4 files changed, 32 insertions(+), 34 deletions(-) create mode 100644 selfhost/.gitignore diff --git a/selfhost/.env.example b/selfhost/.env.example index 5b9a84fd..b6357852 100644 --- a/selfhost/.env.example +++ b/selfhost/.env.example @@ -7,10 +7,10 @@ DATA_DIR=./data # starting any containers. Each is skipped if its target directory is non-empty. # URL to a snapshot archive (.tar or .tar.gz) for the mchain data directory -MCHAIN_SNAPSHOT_URL=https:// +# SNAPSHOT_URL=https:// # URL to a snapshot archive (.tar or .tar.gz) for the Nitro data directory -NITRO_SNAPSHOT_URL=https:// +# NITRO_SNAPSHOT_URL=https:// # Your appchain's chain ID APPCHAIN_CHAIN_ID= @@ -47,32 +47,27 @@ BATCHER_PRIVATE_KEY=0x # HTTP RPC URL(s) for the sequencing chain (comma-separated) SEQUENCING_RPC_URLS=https:// -# ── Maestro ──────────────────────────────────────────────────────────────────── -# JSON map of chain ID → HTTP RPC URL used by maestro for transaction resubmission -# Example: {"888991": "https://rpc.example.com"} -CHAIN_RPC_URLS= - # ── Nitro ────────────────────────────────────────────────────────────────────── # Chain info JSON blob consumed by the Nitro node (NITRO__ double-underscore prefix notation) NITRO_CHAIN_INFO__JSON= -# ── MChain ───────────────────────────────────────────────────────────────────── -# EVM genesis config JSON for the appchain -MCHAIN_GENESIS_CONFIG= - -# Block on the settlement chain where the migration happened -SETTLEMENT_START_BLOCK=0 +# ── trans ───────────────────────────────────────────────────────────────────── +TRANSLATOR_SETTLEMENT_START_BLOCK=0 +TRANSLATOR_SEQUENCING_START_BLOCK=0 +# ── MChain ───────────────────────────────────────────────────────────────────── # ── Migration (only needed for chains migrated from vanilla orbit) ────────── -MIGRATED_BEFORE_BATCH_ACC=0x -MIGRATED_BATCH_ACC=0x -MIGRATED_BATCH_COUNT=0 -MIGRATED_DELAYED_MSGS_ACC=0x -MIGRATED_DELAYED_MSGS_COUNT=0 +# MCHAIN_GENESIS_CONFIG= +# MIGRATED_SETTLEMENT_START_BLOCK=0 +# MIGRATED_BEFORE_BATCH_ACC=0x +# MIGRATED_BATCH_ACC=0x +# MIGRATED_BATCH_COUNT=0 +# MIGRATED_DELAYED_MSGS_ACC=0x +# MIGRATED_DELAYED_MSGS_COUNT=0 # ── Proposer ─────────────────────────────────────────────────────────────────── -# Private key used by the proposer to submit state commitments on-chain -PRIVATE_KEY=0x +# Private key used by the proposer to submit state commitments on-chain (WITHOUT 0x prefix) +PROPOSER_PRIVATE_KEY= # Ethereum L1 RPC URL (used by the proposer to verify attestations) ETHEREUM_RPC_URL=https:// diff --git a/selfhost/.gitignore b/selfhost/.gitignore new file mode 100644 index 00000000..8fce6030 --- /dev/null +++ b/selfhost/.gitignore @@ -0,0 +1 @@ +data/ diff --git a/selfhost/docker-compose.yml b/selfhost/docker-compose.yml index 54b6b609..306cc1c7 100644 --- a/selfhost/docker-compose.yml +++ b/selfhost/docker-compose.yml @@ -1,7 +1,7 @@ services: valkey: - image: valkey/valkey:8-alpine + image: valkey/valkey:9.0.3-alpine container_name: valkey command: ["valkey-server", "--save", "60", "1", "--loglevel", "warning"] volumes: @@ -13,7 +13,7 @@ services: container_name: maestro environment: - VALKEY_URL=redis://valkey:6379 - - CHAIN_RPC_URLS=${CHAIN_RPC_URLS:-} + - CHAIN_RPC_URLS={"${APPCHAIN_CHAIN_ID}":["http://nitro:8547"]} - SKIP_BALANCE_CHECK=true - RUST_LOG=${RUST_LOG:-info} depends_on: @@ -69,13 +69,13 @@ services: environment: - APPCHAIN_CHAIN_ID=${APPCHAIN_CHAIN_ID} - GENESIS_CONFIG=${MCHAIN_GENESIS_CONFIG:-} - - SNAPSHOT_URL=${MCHAIN_SNAPSHOT_URL:-} - - SETTLEMENT_START_BLOCK=${SETTLEMENT_START_BLOCK:-0} - - MIGRATED_BEFORE_BATCH_ACC=${MIGRATED_BEFORE_BATCH_ACC:-} - - MIGRATED_BATCH_ACC=${MIGRATED_BATCH_ACC:-} - - MIGRATED_BATCH_COUNT=${MIGRATED_BATCH_COUNT:-0} - - MIGRATED_DELAYED_MSGS_ACC=${MIGRATED_DELAYED_MSGS_ACC:-} - - MIGRATED_DELAYED_MSGS_COUNT=${MIGRATED_DELAYED_MSGS_COUNT:-0} + - SNAPSHOT_URL + - SETTLEMENT_START_BLOCK + - MIGRATED_BEFORE_BATCH_ACC + - MIGRATED_BATCH_ACC + - MIGRATED_BATCH_COUNT + - MIGRATED_DELAYED_MSGS_ACC + - MIGRATED_DELAYED_MSGS_COUNT - RUST_LOG=${RUST_LOG:-info} volumes: - ${DATA_DIR:-./data}/mchain:/data @@ -87,12 +87,13 @@ services: environment: - SETTLEMENT_WS_URL=ws://settlement_ingestor:8545 - SEQUENCING_WS_URL=ws://sequencing_ingestor:8545 - - MCHAIN_WS_URL=ws://mchain:8545 - APPCHAIN_CHAIN_ID=${APPCHAIN_CHAIN_ID} - SEQUENCING_CONTRACT_ADDRESS=${SEQUENCING_CONTRACT_ADDRESS} - ARBITRUM_BRIDGE_ADDRESS=${ARBITRUM_BRIDGE_ADDRESS} - ARBITRUM_INBOX_ADDRESS=${ARBITRUM_INBOX_ADDRESS} - - SETTLEMENT_START_BLOCK=${SETTLEMENT_START_BLOCK:-0} + - SETTLEMENT_START_BLOCK=${TRANSLATOR_SETTLEMENT_START_BLOCK:-} + - SEQUENCING_START_BLOCK=${TRANSLATOR_SEQUENCING_START_BLOCK:-} + - MCHAIN_WS_URL=ws://mchain:8545 - RUST_LOG=${RUST_LOG:-info} depends_on: - settlement_ingestor @@ -105,7 +106,7 @@ services: container_name: proposer environment: - APPCHAIN_RPC_URL=http://nitro:8547 - - PRIVATE_KEY=${PRIVATE_KEY} + - PRIVATE_KEY=${PROPOSER_PRIVATE_KEY} - ETHEREUM_RPC_URL=${ETHEREUM_RPC_URL} - SETTLEMENT_RPC_URL=${SETTLEMENT_RPC_URL} - SETTLEMENT_CHAIN_ID=${SETTLEMENT_CHAIN_ID} @@ -116,6 +117,8 @@ services: - APPCHAIN_BRIDGE_ADDRESS=${APPCHAIN_BRIDGE_ADDRESS} - SEQUENCING_BRIDGE_ADDRESS=${SEQUENCING_BRIDGE_ADDRESS} - SEQUENCING_CONTRACT_ADDRESS=${SEQUENCING_CONTRACT_ADDRESS} + - MTLS_ENABLED_ENCLAVE=false + - EIGEN_RPC_URL="noop.com" depends_on: - nitro restart: unless-stopped diff --git a/selfhost/start.sh b/selfhost/start.sh index 02eb51e4..a569f156 100755 --- a/selfhost/start.sh +++ b/selfhost/start.sh @@ -46,12 +46,11 @@ download_snapshot() { echo "$label snapshot extracted to $dest" } -download_snapshot "${MCHAIN_SNAPSHOT_URL:-}" "$DATA_DIR/mchain" "mchain" download_snapshot "${NITRO_SNAPSHOT_URL:-}" "$DATA_DIR/nitro" "nitro" # ── Start services ───────────────────────────────────────────────────────────── echo "Starting services ..." -docker compose --env-file .env up -d +DOCKER_DEFAULT_PLATFORM=linux/amd64 docker compose --env-file .env up -d echo "" echo "All services started." From b3fa3cefd1a2b0e65fe25af79f009aa9b00c66e2 Mon Sep 17 00:00:00 2001 From: Jorge Silva Date: Tue, 14 Apr 2026 18:21:24 +0100 Subject: [PATCH 05/13] minor fix --- selfhost/docker-compose.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/selfhost/docker-compose.yml b/selfhost/docker-compose.yml index 306cc1c7..920e5e6c 100644 --- a/selfhost/docker-compose.yml +++ b/selfhost/docker-compose.yml @@ -93,6 +93,7 @@ services: - ARBITRUM_INBOX_ADDRESS=${ARBITRUM_INBOX_ADDRESS} - SETTLEMENT_START_BLOCK=${TRANSLATOR_SETTLEMENT_START_BLOCK:-} - SEQUENCING_START_BLOCK=${TRANSLATOR_SEQUENCING_START_BLOCK:-} + - SETTLEMENT_DELAY=60 - MCHAIN_WS_URL=ws://mchain:8545 - RUST_LOG=${RUST_LOG:-info} depends_on: From c402b923959262d8244b587a63a06f41bce5b154 Mon Sep 17 00:00:00 2001 From: Jorge Silva Date: Tue, 14 Apr 2026 18:23:57 +0100 Subject: [PATCH 06/13] minor fix --- selfhost/docker-compose.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/selfhost/docker-compose.yml b/selfhost/docker-compose.yml index 920e5e6c..f6394b8b 100644 --- a/selfhost/docker-compose.yml +++ b/selfhost/docker-compose.yml @@ -154,6 +154,7 @@ services: - "--execution.caching.archive=true" - "--execution.forwarding-target=http://maestro:8080" - "--ensure-rollup-deployment=false" + - "--parent-chain-is-arbitrum=false" ports: - "8545:8547" - "8548:8548" From 562d8158f19154643640568bdb1691e2b3b9884b Mon Sep 17 00:00:00 2001 From: Jorge Silva Date: Tue, 14 Apr 2026 18:30:34 +0100 Subject: [PATCH 07/13] minor fix --- selfhost/docker-compose.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/selfhost/docker-compose.yml b/selfhost/docker-compose.yml index f6394b8b..4499c167 100644 --- a/selfhost/docker-compose.yml +++ b/selfhost/docker-compose.yml @@ -154,7 +154,7 @@ services: - "--execution.caching.archive=true" - "--execution.forwarding-target=http://maestro:8080" - "--ensure-rollup-deployment=false" - - "--parent-chain-is-arbitrum=false" + - "--persistent.chain=/home/user/data/" ports: - "8545:8547" - "8548:8548" From 2d4a9f6fe0cc98309be044dd45b0cbb8d52ff963 Mon Sep 17 00:00:00 2001 From: Jorge Silva Date: Wed, 15 Apr 2026 11:21:39 +0100 Subject: [PATCH 08/13] fix mchain init --- selfhost/.env.example | 2 +- selfhost/docker-compose.yml | 4 ++-- selfhost/start.sh | 4 ++++ 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/selfhost/.env.example b/selfhost/.env.example index b6357852..c751e0a3 100644 --- a/selfhost/.env.example +++ b/selfhost/.env.example @@ -7,7 +7,7 @@ DATA_DIR=./data # starting any containers. Each is skipped if its target directory is non-empty. # URL to a snapshot archive (.tar or .tar.gz) for the mchain data directory -# SNAPSHOT_URL=https:// +# MCHAIN_SNAPSHOT_URL=https:// # URL to a snapshot archive (.tar or .tar.gz) for the Nitro data directory # NITRO_SNAPSHOT_URL=https:// diff --git a/selfhost/docker-compose.yml b/selfhost/docker-compose.yml index 4499c167..78b7a837 100644 --- a/selfhost/docker-compose.yml +++ b/selfhost/docker-compose.yml @@ -68,7 +68,7 @@ services: - "--datadir=/data" environment: - APPCHAIN_CHAIN_ID=${APPCHAIN_CHAIN_ID} - - GENESIS_CONFIG=${MCHAIN_GENESIS_CONFIG:-} + - GENESIS_CONFIG - SNAPSHOT_URL - SETTLEMENT_START_BLOCK - MIGRATED_BEFORE_BATCH_ACC @@ -159,6 +159,6 @@ services: - "8545:8547" - "8548:8548" volumes: - - ${DATA_DIR:-./data}/nitro:/home/user/.arbitrum + - ${DATA_DIR:-./data}/nitro:/home/user/data depends_on: - mchain diff --git a/selfhost/start.sh b/selfhost/start.sh index a569f156..8f31a3c4 100755 --- a/selfhost/start.sh +++ b/selfhost/start.sh @@ -48,6 +48,10 @@ download_snapshot() { download_snapshot "${NITRO_SNAPSHOT_URL:-}" "$DATA_DIR/nitro" "nitro" +# ── Forward optional env vars ────────────────────────────────────────────────── +[ -n "${MCHAIN_GENESIS_CONFIG:-}" ] && export GENESIS_CONFIG="$MCHAIN_GENESIS_CONFIG" +[ -n "${MCHAIN_SNAPSHOT_URL:-}" ] && export SNAPSHOT_URL="$MCHAIN_SNAPSHOT_URL" + # ── Start services ───────────────────────────────────────────────────────────── echo "Starting services ..." DOCKER_DEFAULT_PLATFORM=linux/amd64 docker compose --env-file .env up -d From 1523f9db11790347e807f9a1d5b53722773ec9e2 Mon Sep 17 00:00:00 2001 From: Jorge Silva Date: Wed, 15 Apr 2026 11:33:01 +0100 Subject: [PATCH 09/13] local setup works --- selfhost/docker-compose.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/selfhost/docker-compose.yml b/selfhost/docker-compose.yml index 78b7a837..aa6ed924 100644 --- a/selfhost/docker-compose.yml +++ b/selfhost/docker-compose.yml @@ -125,7 +125,7 @@ services: restart: unless-stopped nitro: - image: ghcr.io/syndicateprotocol/nitro/nitro:${SYND_NITRO_VERSION:-eigenda-v3.6.4} + image: ghcr.io/syndicateprotocol/nitro/nitro:${SYND_NITRO_VERSION:-eigenda-v3.7.6} container_name: nitro init: true restart: unless-stopped @@ -155,6 +155,8 @@ services: - "--execution.forwarding-target=http://maestro:8080" - "--ensure-rollup-deployment=false" - "--persistent.chain=/home/user/data/" + # uncomment to test the setup on arm64 MacOs machine + # - "--execution.stylus-target.amd64=x86_64-linux-unknown+sse4.2+lzcnt" ports: - "8545:8547" - "8548:8548" From 95f44da8efbda077b6dee00b9adc529ea1c3c028 Mon Sep 17 00:00:00 2001 From: Jorge Silva Date: Wed, 15 Apr 2026 11:52:24 +0100 Subject: [PATCH 10/13] improve instructions --- selfhost/docker-compose.yml | 1 + selfhost/readme.md | 47 ++++++++++++++----------------------- 2 files changed, 19 insertions(+), 29 deletions(-) diff --git a/selfhost/docker-compose.yml b/selfhost/docker-compose.yml index aa6ed924..81d28b8d 100644 --- a/selfhost/docker-compose.yml +++ b/selfhost/docker-compose.yml @@ -138,6 +138,7 @@ services: - "--parent-chain.id=511000" - "--chain.id=${APPCHAIN_CHAIN_ID}" - "--http.api=arb,eth,net,web3,txpool,arbtrace,debug,synd" + - "--ws.api=arb,eth,net,web3,txpool,arbtrace,debug,synd" - "--http.addr=0.0.0.0" - "--http.port=8547" - "--http.vhosts=*" diff --git a/selfhost/readme.md b/selfhost/readme.md index 2afbe0e3..f13f72b3 100644 --- a/selfhost/readme.md +++ b/selfhost/readme.md @@ -19,31 +19,12 @@ cp .env.example .env ### 2. Fill in `.env` -Open `.env` and supply your chain-specific values. The fields are grouped and commented. Required fields are: - -| Field | Description | -|-------|-------------| -| `APPCHAIN_CHAIN_ID` | Your appchain's chain ID | -| `SEQUENCING_INGESTOR_WS_URLS` | WebSocket RPC URL(s) for the sequencing chain | -| `SEQUENCING_INGESTOR_START_BLOCK` | Block to start ingesting from on the sequencing chain | -| `SETTLEMENT_INGESTOR_WS_URLS` | WebSocket RPC URL(s) for the settlement chain | -| `SETTLEMENT_INGESTOR_START_BLOCK` | Block to start ingesting from on the settlement chain | -| `SEQUENCING_CONTRACT_ADDRESS` | Address of the sequencing chain inbox contract | -| `ARBITRUM_BRIDGE_ADDRESS` | Arbitrum bridge contract address on the sequencing chain | -| `ARBITRUM_INBOX_ADDRESS` | Arbitrum inbox contract address on the sequencing chain | -| `BATCHER_PRIVATE_KEY` | Private key for the wallet that submits transaction batches | -| `SEQUENCING_RPC_URLS` | HTTP RPC URL(s) for the sequencing chain | -| `CHAIN_RPC_URLS` | JSON map of chain ID → HTTP RPC URL used by maestro (e.g. `{"888991":"https://..."}`) | -| `NITRO_CHAIN_INFO__JSON` | Chain info JSON blob for the Nitro node | -| `GENESIS_CONFIG` | EVM genesis config JSON for the appchain | -| `MCHAIN_SNAPSHOT_URL` | URL to a `.tar` or `.tar.gz` snapshot of the mchain data directory _(optional but recommended)_ | -| `NITRO_SNAPSHOT_URL` | URL to a `.tar` or `.tar.gz` snapshot of the Nitro data directory _(optional but recommended)_ | - -At least one snapshot URL (`MCHAIN_SNAPSHOT_URL` or `NITRO_SNAPSHOT_URL`) is strongly recommended — syncing from genesis can take many hours. Both are skipped automatically if the target directory already contains data. - -Fields in the **Migration** and **Proposer** sections are only required if your appchain uses those features. - -> All values for your specific appchain can be provided by the Syndicate team. +Open `.env` and supply your chain-specific values. +All initial values for your specific appchain can be provided by the Syndicate team. + +NOTE: `BATCHER_PRIVATE_KEY` and `PROPOSER_PRIVATE_KEY` need to have funds on the sequencing / settlement chains respectively. Aditionally, the BATCHER must be authorized to sequence on the sequencing contract. + +To change the location where data is persisted, set `DATA_DIR` in your `.env` before running `start.sh`. ### 3. Start @@ -53,7 +34,7 @@ bash start.sh The script will: 1. Create local data directories under `DATA_DIR` (default: `./data`) -2. Download and extract the mchain snapshot (if `SNAPSHOT_URL` is set and the data directory is empty) +2. Download and extract the nitro and/or mchain snapshot if specified 3. Start all services with `docker compose` ## Verify @@ -96,10 +77,18 @@ docker compose restart mchain ``` ./data/ ├── mchain/ # RocksDB state for the intermediate chain node -├── nitro/ # Nitro node state (~/.arbitrum) -├── settlement/ # filesystem cache for the settlement ingestor +├── nitro/ # Nitro node state ├── sequencing/ # filesystem cache for the sequencing ingestor +├── settlement/ # filesystem cache for the settlement ingestor └── valkey/ # Valkey (Redis-compatible) persistence ``` -To change the location, set `DATA_DIR` in your `.env` before running `start.sh`. +## Summary + +At this point you should have a function synd-stack rollup deriving state from the parent chains. +You can assert that the rollup node is synced by checking the `eth_blockNumber` rpc call result. +You should also be able to send new transactions by calling `eth_sendRawTransaction` on the rollup node. + +# TEE Withdrawals + + From 453ef0645bc368324f2008b9e796c58346ec7e73 Mon Sep 17 00:00:00 2001 From: Jorge Silva Date: Wed, 15 Apr 2026 17:05:53 +0100 Subject: [PATCH 11/13] readme improvements --- selfhost/.gitignore | 1 + selfhost/readme.md | 10 ++++++---- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/selfhost/.gitignore b/selfhost/.gitignore index 8fce6030..0c54f604 100644 --- a/selfhost/.gitignore +++ b/selfhost/.gitignore @@ -1 +1,2 @@ data/ +.env diff --git a/selfhost/readme.md b/selfhost/readme.md index f13f72b3..a018f325 100644 --- a/selfhost/readme.md +++ b/selfhost/readme.md @@ -8,9 +8,11 @@ Run your own Syndicate appchain RPC node with Docker Compose. - `curl` and `tar` (for snapshot download) - Disk space: 1 TB+ recommended - WebSocket RPC access to your sequencing chain and settlement chain (e.g. via Alchemy, Infura, or a self-hosted node) +- For synd-TEE withdrawals to be functional you'll need to set up a synd-enclave on a AWS nitro TEE instance and provide that URL as the `ENCLAVE_RPC_URL`. (a guide on how to set up the TEE enclave can be found [here](https://docs.syndicate.io/en/docs/syndicate-stack/guides/run-withdrawals-infra#run-synd-enclave-in-aws-tee) ## Setup + ### 1. Copy the env template ```bash @@ -22,7 +24,9 @@ cp .env.example .env Open `.env` and supply your chain-specific values. All initial values for your specific appchain can be provided by the Syndicate team. -NOTE: `BATCHER_PRIVATE_KEY` and `PROPOSER_PRIVATE_KEY` need to have funds on the sequencing / settlement chains respectively. Aditionally, the BATCHER must be authorized to sequence on the sequencing contract. + +> [!WARNING] +>`BATCHER_PRIVATE_KEY` and `PROPOSER_PRIVATE_KEY` must to have funds on the sequencing / settlement chains respectively. Aditionally, the BATCHER must be authorized to sequence on the sequencing contract. To change the location where data is persisted, set `DATA_DIR` in your `.env` before running `start.sh`. @@ -88,7 +92,5 @@ docker compose restart mchain At this point you should have a function synd-stack rollup deriving state from the parent chains. You can assert that the rollup node is synced by checking the `eth_blockNumber` rpc call result. You should also be able to send new transactions by calling `eth_sendRawTransaction` on the rollup node. - -# TEE Withdrawals - +Withdrawals should also be functional, you can assert this by monitoring the `TEEModule` contract for `assertionPosted` and `closeChallengeWindow` events ([example](https://basescan.org/address/0xA61C573986bf21D1B93010c8D50909a6c313Dd61#events)) From 9b2ebb63e179f480a1f355089ec3b5354a41281d Mon Sep 17 00:00:00 2001 From: Jorge Silva Date: Wed, 15 Apr 2026 17:23:09 +0100 Subject: [PATCH 12/13] readme improvements --- selfhost/.env.example | 27 ++++++++++++++------------- selfhost/readme.md | 21 ++++++++++++++------- 2 files changed, 28 insertions(+), 20 deletions(-) diff --git a/selfhost/.env.example b/selfhost/.env.example index c751e0a3..4674e4f6 100644 --- a/selfhost/.env.example +++ b/selfhost/.env.example @@ -16,8 +16,8 @@ DATA_DIR=./data APPCHAIN_CHAIN_ID= # Image versions (override to pin to a specific release) -SYND_APPCHAINS_VERSION=v1.0.12 -SYND_NITRO_VERSION=eigenda-v3.6.4 +# SYND_APPCHAINS_VERSION=v1.0.12 +# SYND_NITRO_VERSION=eigenda-v3.7.6 # ── Ingestors (WebSocket) ────────────────────────────────────────────────────── # WebSocket RPC URL(s) for the sequencing chain (comma-separated for redundancy) @@ -51,20 +51,10 @@ SEQUENCING_RPC_URLS=https:// # Chain info JSON blob consumed by the Nitro node (NITRO__ double-underscore prefix notation) NITRO_CHAIN_INFO__JSON= -# ── trans ───────────────────────────────────────────────────────────────────── +# ── Translator ───────────────────────────────────────────────────────────────────── TRANSLATOR_SETTLEMENT_START_BLOCK=0 TRANSLATOR_SEQUENCING_START_BLOCK=0 -# ── MChain ───────────────────────────────────────────────────────────────────── -# ── Migration (only needed for chains migrated from vanilla orbit) ────────── -# MCHAIN_GENESIS_CONFIG= -# MIGRATED_SETTLEMENT_START_BLOCK=0 -# MIGRATED_BEFORE_BATCH_ACC=0x -# MIGRATED_BATCH_ACC=0x -# MIGRATED_BATCH_COUNT=0 -# MIGRATED_DELAYED_MSGS_ACC=0x -# MIGRATED_DELAYED_MSGS_COUNT=0 - # ── Proposer ─────────────────────────────────────────────────────────────────── # Private key used by the proposer to submit state commitments on-chain (WITHOUT 0x prefix) PROPOSER_PRIVATE_KEY= @@ -90,5 +80,16 @@ TEE_MODULE_CONTRACT_ADDRESS=0x APPCHAIN_BRIDGE_ADDRESS=0x SEQUENCING_BRIDGE_ADDRESS=0x + +# ── MChain ───────────────────────────────────────────────────────────────────── +# ── Migration (only needed for chains migrated from vanilla orbit) ────────── +# MCHAIN_GENESIS_CONFIG= +# MIGRATED_SETTLEMENT_START_BLOCK=0 +# MIGRATED_BEFORE_BATCH_ACC=0x +# MIGRATED_BATCH_ACC=0x +# MIGRATED_BATCH_COUNT=0 +# MIGRATED_DELAYED_MSGS_ACC=0x +# MIGRATED_DELAYED_MSGS_COUNT=0 + # ── Logging ──────────────────────────────────────────────────────────────────── RUST_LOG=info diff --git a/selfhost/readme.md b/selfhost/readme.md index a018f325..185a3a1b 100644 --- a/selfhost/readme.md +++ b/selfhost/readme.md @@ -7,8 +7,13 @@ Run your own Syndicate appchain RPC node with Docker Compose. - [Docker](https://docs.docker.com/get-docker/) with the Compose plugin (v2.20+) - `curl` and `tar` (for snapshot download) - Disk space: 1 TB+ recommended +- RAM: 16 GB+ recommended +- CPU: 4+ cores recommended +- Ports `8545` (HTTP RPC) and `8548` (WebSocket RPC) available on the host - WebSocket RPC access to your sequencing chain and settlement chain (e.g. via Alchemy, Infura, or a self-hosted node) -- For synd-TEE withdrawals to be functional you'll need to set up a synd-enclave on a AWS nitro TEE instance and provide that URL as the `ENCLAVE_RPC_URL`. (a guide on how to set up the TEE enclave can be found [here](https://docs.syndicate.io/en/docs/syndicate-stack/guides/run-withdrawals-infra#run-synd-enclave-in-aws-tee) + +> [!NOTE] +> For synd-TEE withdrawals to be functional, you'll need to set up a synd-enclave on an AWS Nitro TEE instance and provide that URL as `ENCLAVE_RPC_URL`. See the [TEE enclave setup guide](https://docs.syndicate.io/en/docs/syndicate-stack/guides/run-withdrawals-infra#run-synd-enclave-in-aws-tee) for instructions. ## Setup @@ -26,7 +31,7 @@ All initial values for your specific appchain can be provided by the Syndicate t > [!WARNING] ->`BATCHER_PRIVATE_KEY` and `PROPOSER_PRIVATE_KEY` must to have funds on the sequencing / settlement chains respectively. Aditionally, the BATCHER must be authorized to sequence on the sequencing contract. +> `BATCHER_PRIVATE_KEY` and `PROPOSER_PRIVATE_KEY` must have funds on the sequencing / settlement chains respectively. Additionally, the BATCHER must be authorized to sequence on the sequencing contract. To change the location where data is persisted, set `DATA_DIR` in your `.env` before running `start.sh`. @@ -38,8 +43,8 @@ bash start.sh The script will: 1. Create local data directories under `DATA_DIR` (default: `./data`) -2. Download and extract the nitro and/or mchain snapshot if specified -3. Start all services with `docker compose` +2. Download and extract the nitro snapshot if `NITRO_SNAPSHOT_URL` is set +3. Start all services with `docker compose` (the mchain container handles its own snapshot download via `MCHAIN_SNAPSHOT_URL` if set) ## Verify @@ -57,6 +62,8 @@ curl -s -X POST http://localhost:8545 \ -d '{"jsonrpc":"2.0","method":"eth_blockNumber","params":[],"id":1}' ``` +WebSocket RPC is also available at `ws://localhost:8548`. + ## Common commands ```bash @@ -69,8 +76,8 @@ docker compose logs -f nitro # Stop all services docker compose down -# Stop and remove all data volumes -docker compose down -v +# Stop and remove all persisted data (bind-mounted) +docker compose down && rm -rf ${DATA_DIR:-./data} # Restart a single service docker compose restart mchain @@ -89,7 +96,7 @@ docker compose restart mchain ## Summary -At this point you should have a function synd-stack rollup deriving state from the parent chains. +At this point you should have a functional synd-stack rollup deriving state from the parent chains. You can assert that the rollup node is synced by checking the `eth_blockNumber` rpc call result. You should also be able to send new transactions by calling `eth_sendRawTransaction` on the rollup node. Withdrawals should also be functional, you can assert this by monitoring the `TEEModule` contract for `assertionPosted` and `closeChallengeWindow` events ([example](https://basescan.org/address/0xA61C573986bf21D1B93010c8D50909a6c313Dd61#events)) From 3d50b06803ed3bc88207569438d2e7efce3cfacc Mon Sep 17 00:00:00 2001 From: Jorge Silva Date: Wed, 15 Apr 2026 17:32:34 +0100 Subject: [PATCH 13/13] fix nitro snapshot download dir --- selfhost/start.sh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/selfhost/start.sh b/selfhost/start.sh index 8f31a3c4..c1e462ab 100755 --- a/selfhost/start.sh +++ b/selfhost/start.sh @@ -24,7 +24,7 @@ mkdir -p \ "$DATA_DIR/settlement" \ "$DATA_DIR/sequencing" \ "$DATA_DIR/mchain" \ - "$DATA_DIR/nitro" + "$DATA_DIR/nitro/nitro" # ── Snapshots ───────────────────────────────────────────────────────────────── download_snapshot() { @@ -46,7 +46,7 @@ download_snapshot() { echo "$label snapshot extracted to $dest" } -download_snapshot "${NITRO_SNAPSHOT_URL:-}" "$DATA_DIR/nitro" "nitro" +download_snapshot "${NITRO_SNAPSHOT_URL:-}" "$DATA_DIR/nitro/nitro" "nitro" # ── Forward optional env vars ────────────────────────────────────────────────── [ -n "${MCHAIN_GENESIS_CONFIG:-}" ] && export GENESIS_CONFIG="$MCHAIN_GENESIS_CONFIG" @@ -54,7 +54,7 @@ download_snapshot "${NITRO_SNAPSHOT_URL:-}" "$DATA_DIR/nitro" "nitro" # ── Start services ───────────────────────────────────────────────────────────── echo "Starting services ..." -DOCKER_DEFAULT_PLATFORM=linux/amd64 docker compose --env-file .env up -d +docker compose --env-file .env up -d echo "" echo "All services started."