Files
dchain/docs/update-system.md
vsecoder 1a8731f479 docs: update README + api docs + architecture for v2.0.0 feed
README
  - Mention social feed in the one-line description and feature bullets
  - Add relay + feed endpoint tables to the API overview (was
    previously empty on messaging)
  - List media/ package in the repo structure

docs/api/
  - New docs/api/feed.md: full reference for /feed/publish, fetch,
    stats, view, author, timeline, trending, foryou, hashtag; all
    on-chain CREATE_POST / DELETE_POST / FOLLOW / LIKE payloads;
    fee economics; server-side scrubbing contract.
  - docs/api/relay.md rewritten: /relay/broadcast is now the primary
    E2E path with a complete envelope schema; /relay/send kept but
    flagged ⚠ NOT E2E; DELETE /relay/inbox/{id} documented with the
    new Ed25519 signed-auth body.
  - docs/api/README.md index: added feed.md row.

docs/architecture.md
  - L2 Transport layer description updated to include the feed
    mailbox alongside the 1:1 relay mailbox.
  - New "Социальная лента (v2.0.0)" section right after the 1:1
    message flow: ASCII diagram of publish + on-chain commit +
    timeline fetch, economic summary, metadata-scrub summary.

docs/node/README.md
  - Removed stale chan:/chan-member: keys from the BadgerDB schema
    reference; replaced with the v2.0.0 feed keys (post:,
    postbyauthor:, follow:, followin:, like:, likecount:).

docs/update-system.md
  - Example features[] array updated to match the actual node output
    (channels_v1 removed, feed_v2 / media_scrub / relay_broadcast added).

Node feature flags
  - api_well_known_version.go: dropped channels_v1 tag (the
    /api/channels/:id endpoint was removed in the feed refactor);
    added feed_v2, media_scrub, relay_broadcast so clients can
    feature-detect the v2.0.0 surface.
  - Comment example updated channels_v2/v1 → feed_v3/v2.

Client
  - CLIENT_REQUIRED_FEATURES expanded to include the v2.0.0 feature
    flags the client now depends on (feed_v2, media_scrub,
    relay_broadcast); checkNodeVersion() will flag older nodes as
    unsupported and surface an upgrade prompt.

All 7 Go test packages green; tsc --noEmit clean.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-18 22:06:06 +03:00

202 lines
8.3 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Система обновлений и версионирование
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", "contract_logs",
"fan_out", "feed_v2", "identity_registry", "media_scrub",
"native_username_registry", "onboarding_api", "payment_channels",
"relay_broadcast", "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://<your-gitea>/api/v1/repos/<owner>/<repo>/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=<Gitea PAT>`
(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 <tag>` (в 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://<node>/api/well-known-version | jq .build.tag
# должно вернуть vX.Y.Z
```