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>
202 lines
8.3 KiB
Markdown
202 lines
8.3 KiB
Markdown
# Система обновлений и версионирование
|
||
|
||
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
|
||
```
|