feat: resource caps, Saved Messages, author walls, docs for node bring-up
Node flags (cmd/node/main.go):
--max-cpu / --max-ram-mb — Go runtime caps (GOMAXPROCS / GOMEMLIMIT)
--feed-disk-limit-mb — hard 507 refusal for new post bodies over quota
--chain-disk-limit-mb — advisory watcher (can't reject blocks without
breaking consensus; logs WARN every minute)
Client — Saved Messages (self-chat):
- Auto-created on sign-in, pinned top of chat list, blue bookmark avatar
- Send short-circuits the relay (no encrypt, no fee, no mailbox hop)
- Empty state rendered outside inverted FlatList — fixes the mirrored
"say hi…" on Android RTL-aware layout builds
- PostCard shows "You" for own posts instead of the self-contact alias
Client — user walls:
- New route /(app)/feed/author/[pub] with infinite-scroll via
`created_at` cursor and pull-to-refresh
- Profile screen gains "View posts" button (universal) next to
"Open chat" (contact-only)
Feed pipeline:
- Bump client JPEG quality 0.5 → 0.75 to match server scrubber (Q=75),
so a 60 KiB compose doesn't balloon past 256 KiB after server re-encode
- ErrPostTooLarge now wraps with the actual size vs cap, errors.Is
preserved in the HTTP layer
- FeedMailbox quota + DiskUsage surface — supports new CLI flag
README:
- Step-by-step "first node / joiner" section on the landing page,
full flag tables incl. the new resource-cap group, minimal
checklists for open/private/low-end deployments
This commit is contained in:
155
README.md
155
README.md
@@ -22,6 +22,7 @@
|
||||
## Содержание
|
||||
|
||||
- [Быстрый старт](#быстрый-старт)
|
||||
- [Поднятие ноды — пошагово](#поднятие-ноды--пошагово)
|
||||
- [Продакшен деплой](#продакшен-деплой)
|
||||
- [Архитектура](#архитектура)
|
||||
- [REST / WebSocket API](#rest--websocket-api)
|
||||
@@ -66,6 +67,160 @@ curl -s http://localhost:8080/api/well-known-version | jq .
|
||||
|
||||
3-node dev-кластер (для тестов PBFT кворума, slashing, federation): `docker compose up --build -d` — см. [`docs/quickstart.md`](docs/quickstart.md).
|
||||
|
||||
## Поднятие ноды — пошагово
|
||||
|
||||
Ниже — полный минимум для двух сценариев, которые покрывают 99% случаев:
|
||||
**первая нода сети** (genesis) и **присоединение к существующей сети**.
|
||||
Все флаги читаются также из соответствующего `DCHAIN_*` env-var (CLI > env > default).
|
||||
|
||||
### Шаг 1. Ключи
|
||||
|
||||
```bash
|
||||
# Ключ identity ноды (Ed25519 — подпись блоков + tx)
|
||||
./client keygen --out keys/node.json
|
||||
# relay-ключ (X25519 — E2E-mailbox) создаётся нодой сам при первом старте,
|
||||
# но можно задать путь заранее через --relay-key.
|
||||
```
|
||||
|
||||
### Шаг 2a. Первая нода (genesis)
|
||||
|
||||
Поднимает новую сеть с одним валидатором. `--genesis=true` **только** для самой первой ноды и **только один раз** — если блок 0 уже есть в `--db`, флаг игнорируется.
|
||||
|
||||
```bash
|
||||
./node \
|
||||
--genesis=true \
|
||||
--key=keys/node.json \
|
||||
--db=./chaindata \
|
||||
--mailbox-db=./mailboxdata \
|
||||
--feed-db=./feeddata \
|
||||
--listen=/ip4/0.0.0.0/tcp/4001 \
|
||||
--announce=/ip4/<ВАШ-ПУБЛИЧНЫЙ-IP>/tcp/4001 \
|
||||
--stats-addr=:8080 \
|
||||
--register-relay=true \
|
||||
--relay-fee=1000
|
||||
```
|
||||
|
||||
`--announce` **обязателен** для любой ноды смотрящей в интернет (VPS / внешний IP / Docker с проброшенным портом). Без него libp2p пытается UPnP/NAT-PMP и чаще всего промахивается.
|
||||
|
||||
### Шаг 2b. Вторая и последующие ноды
|
||||
|
||||
Нужен **один** из двух способов узнать первую ноду. Второй удобнее.
|
||||
|
||||
**Через HTTP URL живой ноды** (рекомендуется — нода сама заберёт multiaddr через `/api/network-info`, проверит genesis_hash и синхронизирует цепь):
|
||||
|
||||
```bash
|
||||
./node \
|
||||
--join=https://first-node.example.com \
|
||||
--key=keys/node.json \
|
||||
--db=./chaindata \
|
||||
--mailbox-db=./mailboxdata \
|
||||
--feed-db=./feeddata \
|
||||
--listen=/ip4/0.0.0.0/tcp/4001 \
|
||||
--announce=/ip4/<ВАШ-ПУБЛИЧНЫЙ-IP>/tcp/4001 \
|
||||
--stats-addr=:8080 \
|
||||
--register-relay=true \
|
||||
--relay-fee=1000
|
||||
```
|
||||
|
||||
**Через libp2p multiaddr** (если есть прямой мульти-адрес):
|
||||
|
||||
```bash
|
||||
./node \
|
||||
--peers=/ip4/1.2.3.4/tcp/4001/p2p/12D3KooW... \
|
||||
# остальные флаги как выше
|
||||
```
|
||||
|
||||
**Автоприсоединение к validator set** происходит не само: после того как нода синхронизируется, действующий validator должен вызвать `client add-validator --target <your-pub> --cosigs ...` (multi-sig admit). До этого новая нода живёт как **observer** — читает и гоняет tx, но не голосует. Запустить ноду **явно** как observer (никогда не проситься в validator set): `--observer=true`.
|
||||
|
||||
### Все флаги `node`
|
||||
|
||||
CLI / env / default. Группы:
|
||||
|
||||
**Storage**
|
||||
| Флаг | Env | Default | Назначение |
|
||||
|------|-----|---------|-----------|
|
||||
| `--db` | `DCHAIN_DB` | `./chaindata` | BadgerDB блокчейна |
|
||||
| `--mailbox-db` | `DCHAIN_MAILBOX_DB` | `./mailboxdata` | E2E-конверты 1:1 чатов |
|
||||
| `--feed-db` | `DCHAIN_FEED_DB` | `./feeddata` | Тела постов ленты (off-chain) |
|
||||
| `--feed-ttl-days` | `DCHAIN_FEED_TTL_DAYS` | `30` | Через сколько дней тела постов auto-evict'ятся (метаданные on-chain остаются вечно) |
|
||||
|
||||
**Identity**
|
||||
| Флаг | Env | Default | Назначение |
|
||||
|------|-----|---------|-----------|
|
||||
| `--key` | `DCHAIN_KEY` | `./node.json` | Ed25519 ключ ноды |
|
||||
| `--relay-key` | `DCHAIN_RELAY_KEY` | `./relay.json` | X25519 ключ для relay-mailbox (создастся сам) |
|
||||
| `--wallet` | `DCHAIN_WALLET` | — | Отдельный payout-кошелёк (опционально) |
|
||||
| `--wallet-pass` | `DCHAIN_WALLET_PASS` | — | Парольная фраза для wallet-файла |
|
||||
|
||||
**Network**
|
||||
| Флаг | Env | Default | Назначение |
|
||||
|------|-----|---------|-----------|
|
||||
| `--listen` | `DCHAIN_LISTEN` | `/ip4/0.0.0.0/tcp/4001` | libp2p listen multiaddr |
|
||||
| `--announce` | `DCHAIN_ANNOUNCE` | — | Multiaddr который нода рассказывает пирам (обязателен на VPS/внешнем IP) |
|
||||
| `--peers` | `DCHAIN_PEERS` | — | Bootstrap multiaddrs, comma-separated |
|
||||
| `--join` | `DCHAIN_JOIN` | — | HTTP URL живой ноды для авто-дискавери — получает peers и genesis_hash |
|
||||
| `--allow-genesis-mismatch` | — | `false` | Отключить защиту, падающую при расхождении локального и seed'ового genesis (только для явной миграции) |
|
||||
|
||||
**Consensus & role**
|
||||
| Флаг | Env | Default | Назначение |
|
||||
|------|-----|---------|-----------|
|
||||
| `--genesis` | `DCHAIN_GENESIS` | `false` | Создать блок 0 (только для самой первой ноды сети) |
|
||||
| `--validators` | `DCHAIN_VALIDATORS` | — | Исходный validator set (CSV pub-keys) — применяется только при genesis |
|
||||
| `--observer` | `DCHAIN_OBSERVER` | `false` | Observer-режим: синхронизируется и отдаёт API, но не голосует и не предлагает блоки |
|
||||
| `--heartbeat` | `DCHAIN_HEARTBEAT` | `true` | Периодический HEARTBEAT-tx (нужен для liveness-детекции валидаторов) |
|
||||
|
||||
**Relay / mailbox**
|
||||
| Флаг | Env | Default | Назначение |
|
||||
|------|-----|---------|-----------|
|
||||
| `--register-relay` | `DCHAIN_REGISTER_RELAY` | `false` | Отправить `REGISTER_RELAY` tx на старте (объявить ноду публичным relay'ем) |
|
||||
| `--relay-fee` | `DCHAIN_RELAY_FEE` | `1000` | Плата за доставку одного сообщения в µT (1000 = 0.001 T). `0` = бесплатный relay |
|
||||
|
||||
**Media scrubber (feed)**
|
||||
| Флаг | Env | Default | Назначение |
|
||||
|------|-----|---------|-----------|
|
||||
| `--media-sidecar-url` | `DCHAIN_MEDIA_SIDECAR_URL` | — | URL FFmpeg-сайдкара для видео-скраба. Пустой = только картинки |
|
||||
| `--allow-unscrubbed-video` | `DCHAIN_ALLOW_UNSCRUBBED_VIDEO` | `false` | Принимать видео **без** серверного скраба (опасно — EXIF/GPS/автор-теги останутся) |
|
||||
|
||||
**HTTP API**
|
||||
| Флаг | Env | Default | Назначение |
|
||||
|------|-----|---------|-----------|
|
||||
| `--stats-addr` | `DCHAIN_STATS_ADDR` | `:8080` | Адрес HTTP/WS сервера |
|
||||
| `--api-token` | `DCHAIN_API_TOKEN` | — | Bearer-токен для submit tx. Пустой = публичная нода |
|
||||
| `--api-private` | `DCHAIN_API_PRIVATE` | `false` | Требовать токен также на чтение |
|
||||
| `--disable-ui` | `DCHAIN_DISABLE_UI` | `false` | Отключить HTML-explorer (JSON API остаётся) |
|
||||
| `--disable-swagger` | `DCHAIN_DISABLE_SWAGGER` | `false` | Отключить `/swagger*` |
|
||||
|
||||
**Resource caps** (новое в v2.1.0)
|
||||
| Флаг | Env | Default | Назначение |
|
||||
|------|-----|---------|-----------|
|
||||
| `--max-cpu` | `DCHAIN_MAX_CPU` | `0` | Сколько CPU-ядер Go-runtime'у (`GOMAXPROCS`). `0` = все |
|
||||
| `--max-ram-mb` | `DCHAIN_MAX_RAM_MB` | `0` | Soft-лимит Go-хипа в MiB (`GOMEMLIMIT`). `0` = без лимита. *Не OOM-kill'ит — усиливает GC при приближении* |
|
||||
| `--feed-disk-limit-mb` | `DCHAIN_FEED_DISK_LIMIT_MB` | `0` | Жёсткая квота на feed-БД. При превышении `/feed/publish` отвечает 507. Существующие посты продолжают отдаваться |
|
||||
| `--chain-disk-limit-mb` | `DCHAIN_CHAIN_DISK_LIMIT_MB` | `0` | Advisory-квота на блокчейн-БД. Превышение → `WARN` в лог раз в минуту (жёстко не отказываем — сломали бы консенсус) |
|
||||
|
||||
Для реального sandboxing (hard-kill при OOM, hard CPU throttling) используйте `docker run --cpus --memory` или systemd `CPUQuota` / `MemoryMax` поверх этих флагов.
|
||||
|
||||
**Update / versioning**
|
||||
| Флаг | Env | Default | Назначение |
|
||||
|------|-----|---------|-----------|
|
||||
| `--update-source-url` | `DCHAIN_UPDATE_SOURCE_URL` | — | Gitea `/api/v1/repos/{owner}/{repo}/releases/latest` для `/api/update-check` |
|
||||
| `--update-source-token` | `DCHAIN_UPDATE_SOURCE_TOKEN` | — | PAT для приватного репо |
|
||||
| `--log-format` | `DCHAIN_LOG_FORMAT` | `text` | `text` (human) или `json` (Loki/ELK) |
|
||||
| `--governance-contract` | `DCHAIN_GOVERNANCE_CONTRACT` | — | ID governance-контракта для динамических параметров |
|
||||
| `--version` | — | — | Печатает версию и выходит |
|
||||
|
||||
### Минимальные чек-листы
|
||||
|
||||
**Первая нода (открытая):** `--genesis=true` + `--key` + `--announce` на внешний IP + `--stats-addr` + опционально `--register-relay=true --relay-fee=...` чтобы сразу монетизировать relay-трафик.
|
||||
|
||||
**Joiner:** `--join=<url-любой-живой-ноды>` + `--key` + `--announce` + `--stats-addr`. После синка попросите действующего валидатора поднять `add-validator` (иначе остаётесь observer'ом до принятия — это нормально и безопасно).
|
||||
|
||||
**Приватная/домашняя нода** без публичного эксплорера: добавьте `--api-token=<random>`, `--api-private=true`, `--disable-ui=true`, `--disable-swagger=true`. Clients передают `Authorization: Bearer <token>`.
|
||||
|
||||
**Слабое железо:** `--max-cpu=2 --max-ram-mb=1024 --feed-disk-limit-mb=2048 --chain-disk-limit-mb=10240`.
|
||||
|
||||
Docker-обёртка с теми же флагами — в [`deploy/single/README.md`](deploy/single/README.md).
|
||||
|
||||
## Продакшен деплой
|
||||
|
||||
Два варианта, по масштабу.
|
||||
|
||||
Reference in New Issue
Block a user