Ships the client side of the v2.0.0 feed feature. Folds client-app/
into the monorepo (was previously .gitignored as "tracked separately"
but no separate repo ever existed — for v2.0.0 the client is
first-class).
Feed screens
app/(app)/feed.tsx — Feed tab
- Three-way tab strip: Подписки / Для вас / В тренде backed by
/feed/timeline, /feed/foryou, /feed/trending respectively
- Default landing tab is "Для вас" — surfaces discovery without
requiring the user to follow anyone first
- FlatList with pull-to-refresh + viewability-driven view counter
bump (posts visible ≥ 60% for ≥ 1s trigger POST /feed/post/…/view)
- Floating blue compose button → /compose
- Per-post liked_by_me fetched in batches of 6 after list load
app/(app)/compose.tsx — post composer modal
- Fullscreen, Twitter-like header (✕ left, Опубликовать right)
- Auto-focused multiline TextInput, 4000 char cap
- Hashtag preview chips that auto-update as you type
- expo-image-picker + expo-image-manipulator pipeline: resize to
1080px max-dim, JPEG Q=50 (client-side first-pass compression
before the mandatory server-side scrub)
- Live fee estimate + balance guard with a confirmation modal
("Опубликовать пост? Цена: 0.00X T · Размер: N KB")
- Exif: false passed to ImagePicker as an extra privacy layer
app/(app)/feed/[id].tsx — post detail
- Full PostCard rendering + detailed info panel (views, likes,
size, fee, hosting relay, hashtags as tappable chips)
- Triggers bumpView on mount
- 410 (on-chain soft-delete) routes back to the feed
app/(app)/feed/tag/[tag].tsx — hashtag feed
app/(app)/profile/[address].tsx — rebuilt
- Twitter-ish profile: avatar, name, address short-form, post count
- Posts | Инфо tab strip
- Follow / Unfollow button for non-self profiles (optimistic UI)
- Edit button on self profile → settings
- Secondary actions (chat, copy address) when viewing a known contact
Supporting library
lib/feed.ts — HTTP wrappers + tx builders for every /feed/* endpoint:
- publishPost (POST /feed/publish, signed)
- publishAndCommit (publish → on-chain CREATE_POST)
- fetchPost / fetchStats / bumpView
- fetchAuthorPosts / fetchTimeline / fetchForYou / fetchTrending /
fetchHashtag
- buildCreatePostTx / buildDeletePostTx
- buildFollowTx / buildUnfollowTx
- buildLikePostTx / buildUnlikePostTx
- likePost / unlikePost / followUser / unfollowUser / deletePost
(high-level helpers that bundle build + submitTx)
- formatFee, formatRelativeTime, formatCount — Twitter-like display
helpers
components/feed/PostCard.tsx — core card component
- Memoised for performance (N-row re-render on every like elsewhere
would cost a lot otherwise)
- Optimistic like toggle with heart-bounce spring animation
- Hashtag highlighting in body text (tappable → hashtag feed)
- Long-press context menu (Delete, owner-only)
- Views / likes / share-link / reply icons in footer row
Navigation cleanup
- NavBar: removed the SOON pill on the Feed tab (it's shipped now)
- (app)/_layout: hide NavBar on /compose and /feed/* sub-routes
- AnimatedSlot: treat /feed/<id>, /feed/tag/<t>, /compose as
sub-routes so back-swipe-right closes them
Channel removal (client side)
- lib/types.ts: ContactKind stripped to 'direct' | 'group'; legacy
'channel' flag removed. `kind` field kept for backward compat with
existing AsyncStorage records.
- lib/devSeed.ts: dropped the 5 channel seed contacts.
- components/ChatTile.tsx: removed channel kindIcon branch.
Dependencies
- expo-image-manipulator added for client-side image compression.
- expo-file-system/legacy used for readAsStringAsync (SDK 54 moved
that API to the legacy sub-path; the new streaming API isn't yet
stable).
Type check
- npx tsc --noEmit — clean, 0 errors.
Next (not in this commit)
- Direct attachment-bytes endpoint on the server so post-detail can
actually render the image (currently shows placeholder with URL)
- Cross-relay body fetch via /api/relays + hosting_relay pubkey
- Mentions (@username) with notifications
- Full-text search
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
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
- Система обновлений: 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.
Продакшен деплой
Два варианта, по масштабу.
🔸 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 с NaCl-envelopes |
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/ws— WebSocket (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) — без.
Docs / UI
GET /swagger— Swagger 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 слоя) |