# Система обновлений и версионирование DChain поставляется с полноценной системой update-detection, которая включает **пять слоёв**: build-time версия в бинаре, HTTP-эндпоинты для обнаружения, peer-gossip версий соседей, `update-check` от Gitea, и rolling-restart скрипт. Ниже — как это работает и как использовать. ## Слой 1. Build-time версия Бинарь хранит 4 поля, инжектимые через `-ldflags -X`: - `Tag` — человекочитаемый тег, обычно `git describe --tags --always --dirty` - `Commit` — полный 40-символьный SHA коммита - `Date` — RFC 3339 timestamp сборки (UTC) - `Dirty` — `"true"` если сборка была из грязного worktree Печать: ```bash node --version # dchain-node v0.0.1 (commit=abc1234 date=2026-04-17T10:00:00Z dirty=false) client --version # тот же формат ``` Все 4 образа (`Dockerfile` и `deploy/prod/Dockerfile.slim`) принимают эти значения через `--build-arg VERSION_TAG=…` и т.д. `update.sh` вычисляет их автоматически перед ребилдом. ## Слой 2. `/api/well-known-version` ```bash curl -s http://localhost:8080/api/well-known-version | jq . ``` ```json { "node_version": "v0.0.1", "build": { "tag": "v0.0.1", "commit": "abc1234…", "date": "2026-04-17T10:00:00Z", "dirty": "false" }, "protocol_version": 1, "features": [ "access_token", "chain_id", "channels_v1", "contract_logs", "fan_out", "identity_registry", "native_username_registry", "onboarding_api", "payment_channels", "relay_mailbox", "ws_submit_tx" ], "chain_id": "dchain-ddb9a7e37fc8" } ``` Клиент использует это для feature-detection: зная `features[]`, он знает какие экраны/флоу рендерить. Пример в `client-app/lib/api.ts` — функция `checkNodeVersion()`. **Protocol version** — отдельная ось от `node_version`. Меняется только при несовместимых изменениях wire-протокола (новый формат PBFT-message, breaking change в tx encoding). Клиент, который ожидает `protocol_version: 1`, не должен работать с нодой `protocol_version: 2`. ## Слой 3. Peer-gossip версий Каждая нода публикует своё `{peer_id, tag, commit, protocol_version, timestamp}` в gossipsub-топик `dchain/version/v1` раз в 60 секунд. Другие ноды эту информацию получают, хранят 15 минут, и отдают через `/api/peers`: ```bash curl -s http://localhost:8080/api/peers | jq . ``` ```json { "peers": [ { "id": "12D3KooW…", "addrs": ["/ip4/…/tcp/4001/p2p/12D3KooW…"], "version": { "tag": "v0.0.1", "commit": "abc1234…", "protocol_version": 1, "timestamp": 1745000000, "received_at": "2026-04-17T10:01:00Z" } } ] } ``` Зачем это: - Operator видит «какая версия у моих соседей» одним запросом. - Client видит «стоит ли переключиться на другую ноду». - Feature-flag activation (например, `EventChannelBan`) можно запускать только когда ≥80% сети на новой версии. ## Слой 4. `/api/update-check` Оператор настраивает `DCHAIN_UPDATE_SOURCE_URL` на ссылку вида: ``` https:///api/v1/repos///releases/latest ``` Нода опрашивает этот URL (15 мин cache, 5 сек timeout) и возвращает: ```bash curl -s http://localhost:8080/api/update-check | jq . ``` ```json { "current": { "tag": "v0.0.1", "commit": "…", "date": "…", "dirty": "false" }, "latest": { "tag": "v0.0.2", "commit": "…", "url": "https://…", "published_at": "…" }, "update_available": true, "checked_at": "2026-04-17T11:00:00Z", "source": "https://git.vsecoder.vodka/api/v1/repos/vsecoder/dchain/releases/latest" } ``` - 503 — не настроен `DCHAIN_UPDATE_SOURCE_URL`. - 502 — upstream (Gitea) недоступен или ответил non-2xx. - `update_available: false` — либо HEAD совпадает, либо Gitea вернула draft/prerelease (оба игнорируются). Токен для приватного репо: `DCHAIN_UPDATE_SOURCE_TOKEN=` (scope: `read:repository` достаточно). ## Слой 5. `update.sh` + systemd timer Скрипт в `deploy/single/update.sh`. Флоу: 1. Если `DCHAIN_UPDATE_SOURCE_URL` задан — сначала спрашивает `/api/update-check`. Если `update_available: false` — выход с кодом 0. 2. `git fetch --tags`. 3. **Semver guard:** если `UPDATE_ALLOW_MAJOR != true` и major-версия меняется (v1.x → v2.y) — блокирует обновление с exit code 4. 4. `git checkout ` (в detached HEAD) или ff-merge на `origin/main`. 5. Ребилд образа с правильными `--build-arg VERSION_*`. 6. Smoke-test: `docker run --rm … node --version` — должен напечатать новую версию без ошибок. 7. `docker compose up -d --force-recreate node`. 8. Polling `/api/netstats` до 60 сек — если не ожил, `exit 1`. Systemd-интеграция — в `deploy/single/systemd/`: ```bash sudo cp deploy/single/systemd/dchain-update.{service,timer} /etc/systemd/system/ sudo systemctl daemon-reload sudo systemctl enable --now dchain-update.timer ``` Таймер: `OnUnitActiveSec=1h` + `RandomizedDelaySec=15min` — чтобы федерация не рестартовала вся одновременно и не уронила PBFT quorum. ## Schema migrations (BadgerDB) Отдельный слой, относящийся к on-disk формату данных. См. `blockchain/schema_migrations.go`: - `CurrentSchemaVersion` — const в Go-коде, bumpается с каждой миграцией. - `schemaMetaKey = "schema:ver"` — ключ в BadgerDB хранит фактическую версию данных. - `runMigrations(db)` вызывается при `NewChain()`, применяет каждый шаг форвард-миграций атомарно (data rewrite + version bump в одной badger.Update транзакции). - Если stored version > CurrentSchemaVersion — ошибка (запускаете старый бинарь на новом DB). Fix: обновите бинарь или восстановите из бэкапа. На текущий релиз `CurrentSchemaVersion = 0`, миграций нет — scaffold живёт и готов к первому реальному изменению формата. ## Forward-compat для EventType В `blockchain/chain.go` → `applyTx()` добавлен `default:` case для неизвестных `EventType`: - Fee дебитуется с отправителя (не спам-вектор). - Tx применяется как **no-op**. - В логе warning «unknown event type … — binary is older than this tx». Это значит: новую `EventType` можно подать в сеть, она будет обработана на новых нодах и проигнорирована на старых, без split'а консенсуса. Full design — `deploy/UPDATE_STRATEGY.md` → §5.1. ## Checklist при релизе 1. В Git `git tag -a vX.Y.Z -m "release notes"` + `git push origin vX.Y.Z`. 2. В Gitea UI: `Releases → New Release → Tag: vX.Y.Z → Publish`. 3. На всех нодах с настроенным `update.sh`: - systemd-таймер подхватит через ~1 час (± 15 мин jitter). - Operator может форсить: `sudo systemctl start dchain-update.service`. 4. Проверка: ```bash curl -s https:///api/well-known-version | jq .build.tag # должно вернуть vX.Y.Z ```