[794-5][@ant] feat: локальный бутстрап-стек (parser2 Parser + verifier-api + pg/redis) против цепи mono-ai-N — раннер SHiP→Redis, compose с host-gateway и скрипт авто-chain_id, чтобы индексировать permissions с genesis и проверять C6 на живых документах
CI / build (push) Failing after 7s
CI / build (push) Failing after 7s
This commit is contained in:
+12
@@ -0,0 +1,12 @@
|
||||
# Единый образ монорепы для бутстрапа: собирает shared + api + parser.
|
||||
# Команду (api или parser) задаёт docker-compose.
|
||||
FROM node:22-alpine
|
||||
RUN corepack enable
|
||||
WORKDIR /repo
|
||||
COPY . .
|
||||
RUN pnpm install --frozen-lockfile \
|
||||
&& pnpm --filter @verifier/shared build \
|
||||
&& pnpm --filter @verifier/api build \
|
||||
&& pnpm --filter @verifier/parser build
|
||||
ENV NODE_ENV=production
|
||||
CMD ["node", "apps/api/dist/index.js"]
|
||||
@@ -40,6 +40,28 @@ pnpm dev:spa # :5173
|
||||
(бренд кооперативной экономики). Бордо только в chrome; вердикт — отдельная семантика
|
||||
(✅ зелёный / ❌ красный / ⚠ amber). Reka UI + Tailwind v4 + Radix Colors. Эталоны: Linear, Vercel, Raycast, Resend.
|
||||
|
||||
## Локальный бутстрап против цепи mono-ai-N
|
||||
|
||||
Индексация permissions с genesis для проверки C6 на живых документах.
|
||||
|
||||
**Предусловие:** поднята цепь mono (`docker compose up` в `~/mono-ai-N`) — nodeos отдаёт
|
||||
chain API на `:8888` и state-history (SHiP) на `:8070`.
|
||||
|
||||
```bash
|
||||
bash deploy/bootstrap/bootstrap-local.sh
|
||||
```
|
||||
|
||||
Скрипт достаёт `chain_id` из `get_info`, поднимает изолированные postgres+redis,
|
||||
parser2 Parser (SHiP→Redis) и verifier-api (consumer+REST, миграции авто), стримит логи.
|
||||
|
||||
- Parser читает SHiP с genesis → Redis Stream; verifier-api потребляет native-delta `permission`.
|
||||
- Прогресс: `curl http://localhost:3030/v1/health` (`current_block`/`head_block`/`status`).
|
||||
- **Перезапуск безопасен** — parser2 резюмится по позиции в Redis, upsert идемпотентен
|
||||
(натуральный ключ), `sync_progress` хранит прогресс. Репарсинга с нуля при рестарте нет.
|
||||
- Полный реиндекс (осознанно): `docker compose -f deploy/bootstrap/docker-compose.bootstrap.yaml down -v`.
|
||||
|
||||
SPA направить на этот api: `VITE_API_BASE=http://localhost:3030`.
|
||||
|
||||
## Деплой
|
||||
|
||||
Автономные пайплайны из одной репы: `deploy-api.yml` (docker image → ssh) и `deploy-spa.yml`
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
{
|
||||
"name": "@verifier/parser",
|
||||
"version": "0.0.0",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"description": "Раннер parser2 Parser (SHiP → Redis) для бутстрапа индекса permissions против локальной цепи Coopenomics",
|
||||
"scripts": {
|
||||
"build": "tsc -p tsconfig.json",
|
||||
"typecheck": "tsc -p tsconfig.json --noEmit",
|
||||
"start": "node dist/index.js",
|
||||
"dev": "node --watch --experimental-strip-types src/index.ts"
|
||||
},
|
||||
"dependencies": {
|
||||
"@coopenomics/parser2": "^1.1.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"typescript": "^5.7.2"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
/**
|
||||
* Раннер parser2 Parser (SHiP → Redis) для бутстрапа.
|
||||
*
|
||||
* parser2 разделён на две роли: ЭТОТ процесс читает SHiP цепи и пишет унифицированный
|
||||
* поток событий в Redis Stream; verifier-api (ParserClient) — потребляет из Redis.
|
||||
* Обе роли должны смотреть на ОДИН Redis и ОДИН chain_id.
|
||||
*
|
||||
* Запуск программный (в CLI parser2 команды только ops: validate/list/reset/...).
|
||||
*/
|
||||
import { Parser, parseConfig, type ParserOptions } from '@coopenomics/parser2';
|
||||
|
||||
function req(name: string): string {
|
||||
const v = process.env[name];
|
||||
if (!v) throw new Error(`Не задана обязательная env-переменная ${name}`);
|
||||
return v;
|
||||
}
|
||||
|
||||
const raw: ParserOptions = {
|
||||
ship: { url: req('SHIP_URL') }, // ws://<host>:8070 (state_history_plugin)
|
||||
chain: {
|
||||
url: process.env.CHAIN_API_URL ?? undefined, // http://<host>:8888 — ABI fallback
|
||||
id: process.env.CHAIN_ID ?? undefined,
|
||||
},
|
||||
redis: { url: req('REDIS_URL') },
|
||||
// permission — нативная таблица, ABI не нужен; rpc-current для контрактных ABI на всякий.
|
||||
abiFallback: 'rpc-current',
|
||||
deserializer: 'wharfkit',
|
||||
logger: { level: process.env.LOG_LEVEL ?? 'info', pretty: process.env.LOG_PRETTY !== '0' },
|
||||
health: { enabled: true, port: Number(process.env.PARSER_HEALTH_PORT ?? '4100') },
|
||||
metrics: { enabled: true, port: Number(process.env.PARSER_METRICS_PORT ?? '4101') },
|
||||
};
|
||||
|
||||
async function main(): Promise<void> {
|
||||
const parser = new Parser(parseConfig(raw));
|
||||
const shutdown = async (sig: string) => {
|
||||
console.log(`[parser] получен ${sig}, останавливаюсь`);
|
||||
await parser.stop();
|
||||
process.exit(0);
|
||||
};
|
||||
process.on('SIGTERM', () => void shutdown('SIGTERM'));
|
||||
process.on('SIGINT', () => void shutdown('SIGINT'));
|
||||
|
||||
console.log(
|
||||
`[parser] старт: ship=${raw.ship.url} redis=${raw.redis.url} chain_id=${raw.chain?.id ?? '(авто)'} `,
|
||||
);
|
||||
await parser.start();
|
||||
}
|
||||
|
||||
main().catch((e) => {
|
||||
console.error('[parser] фатальная ошибка', e);
|
||||
process.exit(1);
|
||||
});
|
||||
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"extends": "../../tsconfig.base.json",
|
||||
"compilerOptions": {
|
||||
"outDir": "./dist",
|
||||
"rootDir": "./src",
|
||||
"lib": ["ES2022"],
|
||||
"types": ["node"]
|
||||
},
|
||||
"include": ["src"]
|
||||
}
|
||||
Executable
+43
@@ -0,0 +1,43 @@
|
||||
#!/usr/bin/env bash
|
||||
# Локальный бутстрап индекса permissions против запущенной цепи mono-ai-N.
|
||||
#
|
||||
# Предусловие: цепь mono поднята (docker compose up в ~/mono-ai-N), nodeos отдаёт
|
||||
# chain API на :8888 и state-history (SHiP) на :8070 (биндятся на 0.0.0.0 хоста).
|
||||
#
|
||||
# Делает: достаёт chain_id из get_info → пишет .env → поднимает parser+api+pg+redis
|
||||
# → стримит логи. Индексация идёт с genesis (START_BLOCK=1). Перезапуск безопасен
|
||||
# (parser2 резюмится по позиции в Redis, upsert идемпотентен — репарсинга с нуля нет).
|
||||
set -euo pipefail
|
||||
|
||||
HERE="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
NODE_HTTP_PORT="${NODE_HTTP_PORT:-8888}"
|
||||
NODE_HISTORY_PORT="${NODE_HISTORY_PORT:-8070}"
|
||||
API="http://localhost:${NODE_HTTP_PORT}"
|
||||
|
||||
echo "[bootstrap] запрашиваю chain_id у ${API} ..."
|
||||
INFO="$(curl -fsS "${API}/v1/chain/get_info" || true)"
|
||||
if [ -z "${INFO}" ]; then
|
||||
echo "[bootstrap] ОШИБКА: нет ответа от ${API}/v1/chain/get_info — цепь mono поднята?" >&2
|
||||
exit 1
|
||||
fi
|
||||
CHAIN_ID="$(printf '%s' "${INFO}" | sed -n 's/.*"chain_id":"\([0-9a-f]\{64\}\)".*/\1/p')"
|
||||
HEAD="$(printf '%s' "${INFO}" | sed -n 's/.*"head_block_num":\([0-9]\{1,\}\).*/\1/p')"
|
||||
if [ -z "${CHAIN_ID}" ]; then
|
||||
echo "[bootstrap] ОШИБКА: не распарсил chain_id из get_info" >&2
|
||||
exit 1
|
||||
fi
|
||||
echo "[bootstrap] chain_id=${CHAIN_ID} head_block=${HEAD:-?}"
|
||||
|
||||
cat > "${HERE}/.env" <<EOF
|
||||
CHAIN_ID=${CHAIN_ID}
|
||||
NODE_HTTP_PORT=${NODE_HTTP_PORT}
|
||||
NODE_HISTORY_PORT=${NODE_HISTORY_PORT}
|
||||
EOF
|
||||
|
||||
cd "${HERE}"
|
||||
echo "[bootstrap] поднимаю стек (build при первом запуске может занять пару минут)..."
|
||||
docker compose --env-file .env -f docker-compose.bootstrap.yaml up --build -d
|
||||
|
||||
echo "[bootstrap] готово. verifier-api → http://localhost:3030/v1/health"
|
||||
echo "[bootstrap] логи (Ctrl-C выйдет из логов, стек продолжит работать):"
|
||||
exec docker compose -f docker-compose.bootstrap.yaml logs -f parser api
|
||||
@@ -0,0 +1,77 @@
|
||||
# Локальный бутстрап индекса permissions против запущенной цепи mono-ai-N.
|
||||
#
|
||||
# Стек: своя postgres + redis (изолированы от mono) + parser2 Parser (SHiP→Redis)
|
||||
# + verifier-api (ParserClient consumer + REST + миграции). Цепь mono достаётся
|
||||
# через host-gateway (nodeos SHiP :8070 и chain API :8888 биндятся на 0.0.0.0 хоста).
|
||||
#
|
||||
# CHAIN_ID берётся из --env-file (его пишет bootstrap-local.sh из get_info живой цепи).
|
||||
# Запуск: bash deploy/bootstrap/bootstrap-local.sh
|
||||
|
||||
services:
|
||||
vpostgres:
|
||||
image: postgres:16-alpine
|
||||
environment:
|
||||
POSTGRES_USER: verifier
|
||||
POSTGRES_PASSWORD: verifier
|
||||
POSTGRES_DB: verifier
|
||||
ports:
|
||||
- '5433:5432'
|
||||
volumes:
|
||||
- vpgdata:/var/lib/postgresql/data
|
||||
healthcheck:
|
||||
test: ['CMD-SHELL', 'pg_isready -U verifier']
|
||||
interval: 5s
|
||||
timeout: 3s
|
||||
retries: 20
|
||||
|
||||
vredis:
|
||||
image: redis:7-alpine
|
||||
ports:
|
||||
- '6380:6379'
|
||||
healthcheck:
|
||||
test: ['CMD', 'redis-cli', 'ping']
|
||||
interval: 5s
|
||||
timeout: 3s
|
||||
retries: 20
|
||||
|
||||
parser:
|
||||
build:
|
||||
context: ../..
|
||||
dockerfile: Dockerfile
|
||||
command: node apps/parser/dist/index.js
|
||||
environment:
|
||||
SHIP_URL: ws://host.docker.internal:${NODE_HISTORY_PORT:-8070}
|
||||
CHAIN_API_URL: http://host.docker.internal:${NODE_HTTP_PORT:-8888}
|
||||
CHAIN_ID: ${CHAIN_ID}
|
||||
REDIS_URL: redis://vredis:6379
|
||||
LOG_PRETTY: '1'
|
||||
extra_hosts:
|
||||
- 'host.docker.internal:host-gateway'
|
||||
depends_on:
|
||||
vredis:
|
||||
condition: service_healthy
|
||||
restart: unless-stopped
|
||||
|
||||
api:
|
||||
build:
|
||||
context: ../..
|
||||
dockerfile: Dockerfile
|
||||
command: node apps/api/dist/index.js
|
||||
environment:
|
||||
DATABASE_URL: postgres://verifier:verifier@vpostgres:5432/verifier
|
||||
REDIS_URL: redis://vredis:6379
|
||||
CHAIN_ID: ${CHAIN_ID}
|
||||
START_BLOCK: '1'
|
||||
RUN_INDEXER: '1'
|
||||
API_PORT: '3030'
|
||||
ports:
|
||||
- '3030:3030'
|
||||
depends_on:
|
||||
vpostgres:
|
||||
condition: service_healthy
|
||||
vredis:
|
||||
condition: service_healthy
|
||||
restart: unless-stopped
|
||||
|
||||
volumes:
|
||||
vpgdata:
|
||||
Reference in New Issue
Block a user