From 2e19012e1a944379b8fc173ecf28ecd1c116c266 Mon Sep 17 00:00:00 2001 From: shum Date: Tue, 27 Oct 2026 13:04:22 +0000 Subject: [PATCH] scripts: write the dev config on first start --- apps/simplex-store-service/README.md | 56 ++++++++++++----- scripts/store-service/compose.dev.yml | 19 +++++- scripts/store-service/dev-chain.sh | 91 +++++++++++++++++++++++---- 3 files changed, 139 insertions(+), 27 deletions(-) diff --git a/apps/simplex-store-service/README.md b/apps/simplex-store-service/README.md index d86b03acaa..f222afaf66 100644 --- a/apps/simplex-store-service/README.md +++ b/apps/simplex-store-service/README.md @@ -441,22 +441,39 @@ each domain to its own port, as the all-in-one example in [Caddy](#caddy) does. on its first start. Its state is kept in `./data/chain`, so restarts keep the contracts, balances and registered names. Its keys are anvil's public test keys, so never use it beside a real chain. - `postgres`: PostgreSQL 17 on `127.0.0.1:5433`, user `simplex`, database `store_service`, without a - password, kept in `./data/postgres`. + password, kept in `./data/postgres`. The service uses it in place of `BADGE_DB_CONN`. -From `scripts/store-service/`: +From a fresh clone: ``` -echo "COMPOSE_FILE=compose.yml:compose.dev.yml" >> .env -echo "BADGE_DB_CONN=postgresql://simplex@127.0.0.1:5433/store_service" >> .env +git clone https://github.com/simplex-chat/simplex-chat && cd simplex-chat +git checkout sh/store-service && git submodule update --init apps/simplex-domains +cd scripts/store-service +echo "COMPOSE_FILE=compose.yml:compose.dev.yml" > .env docker compose up -d --build -docker compose logs chain ``` -The service starts once the chain is up. The chain's log prints its `[chain]` section; put it in -`config/store_service.ini` with a `[names]` section and, under `[listener]`, -`names_export_dir = /srv/names-export` (the names build is the image's `/srv/names`, the default), -then `docker compose restart store-service`. With `serve_webapp = on`, the names site is on -`names_port`, by default 8081. +The names site is then on `http://127.0.0.1:8081` and the badges site on `http://127.0.0.1:8080`. + +On its first start, the chain writes `config/store_service.ini` for its deployment, unless the file +exists; it never rewrites it, so edits there are kept. The file serves both sites all in one, with +`[names]` on the `.simplex` TLD, `[chain]` at the local chain with 1 confirmation, and `[issuer]` +signing with a public test key at index 999, which no client trusts, through `dev_keys`. That key is +in `dev-chain.sh`, as public as anvil's: never use it elsewhere. The service starts once the chain +and the database are healthy. `USER_UID` and `USER_GID` in `.env` (by default 1000) own the file, +mode 600, and its folder, mode 700. + +Names are paid for with prepaid codes, so no payment provider is needed. To issue one, stop the +service and run its console against the dev database: + +``` +docker compose stop store-service +docker compose run --rm store-service -d postgresql://simplex@127.0.0.1:5433/store_service --run-cli --service-config /etc/simplex-store-service/store_service.ini +``` + +There, `//issue name 6` prints a code for one name of 6 letters or more (see +[From the command line](#from-the-command-line)). Leave with `/quit`, then +`docker compose start store-service`. The service key's account starts with 10,000 ETH and a sponsor allowance. To top it up, or set any account's balance: @@ -465,10 +482,21 @@ account's balance: docker compose exec chain dev-chain.sh topup [address] [eth] ``` -Registrations wait 10 seconds after their commit (`MIN_COMMITMENT_AGE` in `compose.dev.yml`), and -prepaid codes need no payment provider. To start over, run `docker compose down` and delete -`./data/chain` and `./data/postgres` together; deleting only the chain leaves orders that point at -names that no longer exist. +Registrations wait 10 seconds after their commit (`MIN_COMMITMENT_AGE` in `compose.dev.yml`). + +Card payments in Stripe's test mode: uncomment `[stripe]` in `config/store_service.ini` (as the +`USER_UID` user, or with `sudo`), put in the test keys and the webhook secret, which +`stripe listen --forward-to 127.0.0.1:8080/webhooks/stripe` prints, and run +`docker compose restart store-service`. With `dev_keys`, the service refuses live keys, and a +BTCPay that is not on loopback. + +To start over, delete the containers and every dev state together, since orders in the database +point at names on the chain. `./data` belongs to root and to Postgres's user, so: + +``` +docker compose down +sudo rm -rf data config +``` ### Caddy diff --git a/scripts/store-service/compose.dev.yml b/scripts/store-service/compose.dev.yml index e64fcc5411..88352e1eb8 100644 --- a/scripts/store-service/compose.dev.yml +++ b/scripts/store-service/compose.dev.yml @@ -1,4 +1,5 @@ -# Development: compose.yml plus a local chain with the names contracts, kept in ./data/chain across restarts. +# Development: compose.yml plus a local chain with the names contracts, kept in ./data/chain across restarts, which +# writes ./config/store_service.ini for them on its first start, and a local database. # Enable it with COMPOSE_FILE=compose.yml:compose.dev.yml in .env; unlike a compose.override.yml, it is never # picked up on its own. services: @@ -14,8 +15,12 @@ services: environment: # seconds a registration waits after its commit; the contracts' production value is 60 MIN_COMMITMENT_AGE: "10" + # the owner of the config it writes, the store service's user + USER_UID: ${USER_UID:-1000} + USER_GID: ${USER_GID:-1000} volumes: - ./data/chain:/chain + - ./config:/config - ./dev-chain.sh:/usr/local/bin/dev-chain.sh:ro command: dev-chain.sh healthcheck: @@ -43,7 +48,19 @@ services: retries: 30 start_period: 10s + # compose replaces a command whole, so this is compose.yml's with the dev database in place of BADGE_DB_CONN store-service: + command: + - "-d" + - "postgresql://simplex@127.0.0.1:5433/store_service" + - "--create-schema" + - "--yes-migrate" + - "--service-config" + - "/etc/simplex-store-service/store_service.ini" + volumes: + # compose creates every container before it starts any, so compose.yml's create_host_path: false would refuse a + # first start before the chain writes ./config; this entry replaces that one by its target + - ./config:/etc/simplex-store-service:ro depends_on: chain: { condition: service_healthy } postgres: { condition: service_healthy } diff --git a/scripts/store-service/dev-chain.sh b/scripts/store-service/dev-chain.sh index d51ae2170d..60ee46755f 100755 --- a/scripts/store-service/dev-chain.sh +++ b/scripts/store-service/dev-chain.sh @@ -1,7 +1,8 @@ #!/bin/sh # The local chain of compose.dev.yml. Runs in the webapp's dev image, which has anvil, node, the deploy script and the # compiled contracts. -# dev-chain.sh anvil with its state kept in $CHAIN_DIR, and the names contracts deployed on the first start +# dev-chain.sh anvil with its state kept in $CHAIN_DIR, the names contracts deployed on the first start, +# and $CONFIG_DIR/store_service.ini written for them unless it exists # dev-chain.sh topup [address] [eth] sets an account's balance, by default the service key's account to 10000 ETH set -eu @@ -11,6 +12,17 @@ ANVIL="${ANVIL:-anvil}" WEBAPP_DIR="${WEBAPP_DIR:-/repo/webapp}" RPC_URL="http://127.0.0.1:$RPC_PORT" DEPLOYMENT="$CHAIN_DIR/deployment.json" +CONFIG_DIR="${CONFIG_DIR:-/config}" +CONFIG="$CONFIG_DIR/store_service.ini" +# the store service's user, which must own its config +USER_UID="${USER_UID:-1000}" +USER_GID="${USER_GID:-1000}" +# A public test key, like anvil's: made once with `simplex-chat badge keygen`. The service trusts it only through +# [issuer] dev_keys, which it accepts only on chain 31337, and refuses it at an index clients trust (1 to 8). +DEV_ISSUER_INDEX=999 +DEV_ISSUER_SECRET=Grc_c1bKCSa3U8mMwRy6XNTJNwSveJi332wAqyyCy2o= +TERMS_VERSION=2026-10-23 +TERMS_URL=https://simplex.chat/ # compose's healthcheck waits for this file, written once the contracts are on the running chain READY="$CHAIN_DIR/ready" # the dumps are taken this often and on exit, so a restart keeps the contracts and every name registered on them @@ -50,17 +62,72 @@ else (cd "$WEBAPP_DIR" && RPC_URL="$RPC_URL" LOCAL_CHAIN_OUT="$DEPLOYMENT" node dev/deploy.ts) fi -node -e ' -const d = require(process.argv[1]) -console.log(`[chain] for config/store_service.ini: -rpc_url = ${d.rpcUrl} -chain_id = ${d.chainId} -controller = ${d.controller} -sponsor = ${d.sponsor} -base_registrar = ${d.baseRegistrar} -resolver = ${d.resolver} -service_key = ${d.registrarKey} -confirmations = 1`)' "$DEPLOYMENT" +field() { + node -p "require('$DEPLOYMENT').$1" +} + +write_config() { + tmp="$CONFIG.tmp" + rm -f "$tmp" + (umask 077 && cat > "$tmp" <