Files
dchain/README.md
vsecoder a75cbcd224 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
2026-04-19 13:14:47 +03:00

24 KiB
Raw Blame History

DChain

Блокчейн-стек для децентрализованного мессенджера + социальной ленты:

  • PBFT консенсус с multi-sig validator governance и equivocation slashing
  • Native Go контракты рядом с WASM (wazero) — нулевая задержка для системных сервисов типа username_registry
  • WebSocket push API — клиент не опрашивает, все события прилетают на соединение
  • E2E-шифрованный relay mailbox на libp2p gossipsub с TTL live-detection (1:1 чаты через NaCl box; посты в ленте — plaintext-публичные)
  • Социальная лента v2.0.0 (заменила каналы): публичные посты с оплатой за размер (автор платит, хостящая релей-нода получает); on-chain граф подписок + лайки; off-chain просмотры + хэштеги; мандаторный server-side scrubber метаданных (EXIF/GPS-стрип + FFmpeg sidecar для видео); share-to-chat c embedded post-карточкой
  • Система обновлений: build-time версия → /api/well-known-version, peer-version gossip, /api/update-check против Gitea releases, update.sh с semver guard
  • Prometheus /metrics, Caddy auto-HTTPS, observer mode, load-test

Содержание


Быстрый старт

Одна нода в Docker, HTTP API на localhost:8080, Explorer UI и Swagger открыты:

# 1. Собираем prod-образ
docker build -t dchain-node-slim -f deploy/prod/Dockerfile.slim .

# 2. Ключ ноды (один раз)
mkdir -p keys
docker run --rm --entrypoint /usr/local/bin/client \
  -v "$PWD/keys:/out" dchain-node-slim \
  keygen --out /out/node.json

# 3. Запуск (genesis-валидатор)
docker run -d --name dchain --restart unless-stopped \
  -p 4001:4001 -p 8080:8080 \
  -v dchain_data:/data \
  -v "$PWD/keys:/keys:ro" \
  -e DCHAIN_GENESIS=true \
  -e DCHAIN_ANNOUNCE=/ip4/127.0.0.1/tcp/4001 \
  dchain-node-slim \
  --db=/data/chain --mailbox-db=/data/mailbox --key=/keys/node.json \
  --relay-key=/data/relay.json --listen=/ip4/0.0.0.0/tcp/4001 --stats-addr=:8080

# 4. Проверка
open http://localhost:8080/            # Explorer
open http://localhost:8080/swagger     # Swagger UI
curl -s http://localhost:8080/api/well-known-version | jq .

3-node dev-кластер (для тестов PBFT кворума, slashing, federation): docker compose up --build -d — см. docs/quickstart.md.

Поднятие ноды — пошагово

Ниже — полный минимум для двух сценариев, которые покрывают 99% случаев: первая нода сети (genesis) и присоединение к существующей сети. Все флаги читаются также из соответствующего DCHAIN_* env-var (CLI > env > default).

Шаг 1. Ключи

# Ключ identity ноды (Ed25519 — подпись блоков + tx)
./client keygen --out keys/node.json
# relay-ключ (X25519 — E2E-mailbox) создаётся нодой сам при первом старте,
# но можно задать путь заранее через --relay-key.

Шаг 2a. Первая нода (genesis)

Поднимает новую сеть с одним валидатором. --genesis=true только для самой первой ноды и только один раз — если блок 0 уже есть в --db, флаг игнорируется.

./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 и синхронизирует цепь):

./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 (если есть прямой мульти-адрес):

./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.

Продакшен деплой

Два варианта, по масштабу.

🔸 Single-node (deploy/single/)

Рекомендуется для личного/первого узла. Один узел + Caddy TLS + опциональный Prometheus. Полный runbook с 6 сценариями (публичная с UI, headless, полностью приватная, genesis, joiner, auto-update) — в deploy/single/README.md.

Модели доступа

Режим DCHAIN_API_TOKEN DCHAIN_API_PRIVATE Поведение
Public (default) не задан Все могут читать и писать
Token writes задан false Читать — любой; submit tx — только с токеном
Fully private задан true Всё требует Authorization: Bearer <token>

UI / Swagger — включать или нет?

Нужно DCHAIN_DISABLE_UI DCHAIN_DISABLE_SWAGGER Открыто
Публичная с эксплорером + docs не задано не задано / Explorer, /swagger, /api/*, /metrics
Headless API-нода с OpenAPI true не задано /swagger, /api/*, /metrics
Личная hardened true true /api/* + /metrics

Флаги читаются и из CLI (--disable-ui, --disable-swagger), и из env. /api/* JSON-поверхность регистрируется всегда — отключить её можно только на уровне Caddy / firewall.

Auto-update

# node.env — когда проект в Gitea
DCHAIN_UPDATE_SOURCE_URL=https://gitea.example.com/api/v1/repos/OWNER/REPO/releases/latest
UPDATE_ALLOW_MAJOR=false
# Hourly systemd timer с 15-мин jitter
sudo cp deploy/single/systemd/dchain-update.{service,timer} /etc/systemd/system/
sudo systemctl daemon-reload
sudo systemctl enable --now dchain-update.timer

Подробно: docs/update-system.md + deploy/UPDATE_STRATEGY.md.

🔹 Multi-validator (deploy/prod/)

3 validator'а в PBFT-кворуме, Caddy с ip_hash для WS-стикинесса и least-conn для REST. Для федераций / консорциумов — см. deploy/prod/README.md и docs/node/multi-server.md.

Архитектура

┌────────────┐    libp2p     ┌────────────┐    libp2p     ┌────────────┐
│   node-A   │◄─────pubsub──►│   node-B   │◄─────pubsub──►│   node-C   │
│ validator  │               │ validator  │               │ validator  │
│  + relay   │               │  + relay   │               │  + relay   │
└─────┬──────┘               └─────┬──────┘               └─────┬──────┘
      │                            │                            │
      │ HTTPS / wss (via Caddy)    │                            │
      ▼                            ▼                            ▼
    mobile / web / CLI clients   (ip_hash для WS, least-conn для REST)

Четыре слоя: network → chain → transport → app. Детали — в docs/architecture.md.

Основные пакеты:

Путь Роль
blockchain/ Блочная машина, applyTx, native-контракты, schema-migrations
consensus/ PBFT (Pre-prepare → Prepare → Commit), мемпул, equivocation
p2p/ libp2p host, gossipsub, sync протокол, peer-version gossip
node/ HTTP + WS API, SSE, metrics, access control
node/version/ Build-time version metadata (ldflags-инжектимый)
vm/ wazero runtime для WASM-контрактов + gas model
relay/ E2E mailbox (1:1 envelopes) + public feed-mailbox (post bodies, view counter, hashtag index)
media/ Server-side metadata scrubber (EXIF strip + FFmpeg sidecar client)
identity/ Ed25519 + X25519 keypair, tx signing
economy/ Fee model, rewards
wallet/ Optional payout wallet (отдельный ключ)

REST / WebSocket API

Обзор (полный reference — docs/api/README.md):

Chain + stats

Endpoint Описание
GET /api/netstats height, total_txs, supply, validator_count
GET /api/network-info chain_id, genesis, peers, validators, contracts
GET /api/blocks?limit=N / /api/block/{index} Блоки
GET /api/tx/{id} / /api/txs/recent?limit=N Транзакции
GET /api/address/{pub_or_addr} Баланс + история
GET /api/validators Validator set
GET /api/peers Connected peers + их версии
POST /api/tx Submit signed tx (rate-limited, size-capped)

Discovery + update

Endpoint Описание
GET /api/well-known-version {node_version, build{}, protocol_version, features[], chain_id}
GET /api/well-known-contracts {name → contract_id} map
GET /api/update-check Diff с Gitea release (см. docs/update-system.md)

Real-time

  • GET /api/wsWebSocket (recommended). Ops: auth, subscribe, unsubscribe, submit_tx, typing, ping. Push: block, tx, inbox, typing, submit_ack.
  • GET /api/events — SSE legacy one-way.

Scoped WS-топики (addr:, inbox:, typing:) требуют auth через Ed25519-nonce; публичные (blocks, tx, contract_log) — без.

Relay (E2E messaging)

Endpoint Описание
POST /relay/broadcast Опубликовать pre-sealed envelope (E2E-путь, рекомендован)
GET /relay/inbox?pub=<x25519> Прочитать входящие конверты
DELETE /relay/inbox/{id} Удалить envelope (требует Ed25519-подписи владельца)

Детали — docs/api/relay.md. /relay/send оставлен для backward-compat, но ломает E2E (nod-релей запечатывает своим ключом) и помечен как non-recommended.

Social feed (v2.0.0)

Endpoint Описание
POST /feed/publish Загрузить тело поста + EXIF-скраб + вернуть fee
GET /feed/post/{id} Тело поста
GET /feed/post/{id}/attachment Сырые байты картинки/видео (cache'able)
GET /feed/post/{id}/stats?me=<pub> {views, likes, liked_by_me?}
POST /feed/post/{id}/view Бамп off-chain счётчика просмотров
GET /feed/author/{pub}?before=<ts>&limit=N Посты автора (пагинация before)
GET /feed/timeline?follower=<pub>&before=<ts>&limit=N Merged лента подписок
GET /feed/trending?window=24&limit=N Топ по likes × 3 + views за окно
GET /feed/foryou?pub=<pub>&limit=N Рекомендации (неподписанные авторы)
GET /feed/hashtag/{tag}?limit=N Посты по хэштегу

Детали + спецификация — docs/api/feed.md.

Docs / UI

  • GET /swaggerSwagger UI (рендерится через swagger-ui-dist).
  • GET /swagger/openapi.json — сырая OpenAPI 3.0 спека.
  • GET / — block-explorer HTML (выключается DCHAIN_DISABLE_UI=true).

CLI

client keygen               --out key.json
client --version            # → dchain-client vX.Y.Z (commit=... date=...)
client balance              --key key.json --node URL
client transfer             --key key.json --to <pub> --amount <µT> --node URL
client call-contract        --key key.json --contract native:username_registry \
                            --method register --arg alice --amount 10000 \
                            --node URL
client add-validator        --key key.json --target <pub> --cosigs pub:sig,pub:sig
client admit-sign           --key validator.json --target <candidate-pub>
client deploy-contract      --key key.json --wasm ./my.wasm --abi ./my_abi.json --node URL
# полный список — `client` без аргументов, или в docs/cli/README.md

Все флаги node — в docs/node/README.md, либо node --help.

Мониторинг

Prometheus endpoint /metrics на каждой ноде. Ключевые метрики:

dchain_blocks_total                  # committed blocks count
dchain_txs_total                     # tx count
dchain_tx_submit_accepted_total
dchain_tx_submit_rejected_total
dchain_ws_connections                # current WS sockets
dchain_peer_count_live               # live libp2p peer count
dchain_max_missed_blocks             # worst validator liveness gap
dchain_block_commit_seconds          # histogram of AddBlock time

Grafana + Prometheus поднимаются вместе с нодой через docker compose --profile monitor up -d (см. deploy/single/docker-compose.yml).

Тесты

# Unit + integration
go test ./...                       # blockchain + consensus + identity + relay + vm
go vet ./...                        # static checks

# End-to-end load (3-node dev cluster должен быть поднят):
docker compose up --build -d
go run ./cmd/loadtest \
  --node http://localhost:8081 \
  --funder testdata/node1.json \
  --clients 50 --duration 60s

Документация

Полный справочник в docs/ — см. docs/README.md как оглавление. Ключевые документы:

Документ О чём
docs/quickstart.md Три пути: локально, single-node prod, федерация
docs/architecture.md 4 слоя, consensus, storage, gas model
docs/update-system.md Versioning + update-check + semver guard
docs/api/README.md REST + WebSocket reference
docs/cli/README.md CLI команды и флаги
docs/node/README.md Запуск ноды (native + Docker)
docs/contracts/README.md Системные + WASM контракты
docs/development/README.md SDK для своих контрактов
deploy/single/README.md Single-node operator runbook
deploy/prod/README.md Multi-validator federation
deploy/UPDATE_STRATEGY.md Forward-compat design (4 слоя)