DChain single-node blockchain + React Native messenger client. Core: - PBFT consensus with multi-sig validator admission + equivocation slashing - BadgerDB + schema migration scaffold (CurrentSchemaVersion=0) - libp2p gossipsub (tx/v1, blocks/v1, relay/v1, version/v1) - Native Go contracts (username_registry) alongside WASM (wazero) - WebSocket gateway with topic-based fanout + Ed25519-nonce auth - Relay mailbox with NaCl envelope encryption (X25519 + Ed25519) - Prometheus /metrics, per-IP rate limit, body-size cap Deployment: - Single-node compose (deploy/single/) with Caddy TLS + optional Prometheus - 3-node dev compose (docker-compose.yml) with mocked internet topology - 3-validator prod compose (deploy/prod/) for federation - Auto-update from Gitea via /api/update-check + systemd timer - Build-time version injection (ldflags → node --version) - UI / Swagger toggle flags (DCHAIN_DISABLE_UI, DCHAIN_DISABLE_SWAGGER) Client (client-app/): - Expo / React Native / NativeWind - E2E NaCl encryption, typing indicator, contact requests - Auto-discovery of canonical contracts, chain_id aware, WS reconnect on node switch Documentation: - README.md, CHANGELOG.md, CONTEXT.md - deploy/single/README.md with 6 operator scenarios - deploy/UPDATE_STRATEGY.md with 4-layer forward-compat design - docs/contracts/*.md per contract
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
- Prometheus
/metrics, Caddy auto-HTTPS, observer mode, load-test - React Native / Expo мессенджер (
client-app/)
Содержание
- Быстрый старт (dev)
- Продакшен деплой
- Клиент
- Архитектура
- Контракты
- REST / WebSocket API
- CLI
- Мониторинг
- Тесты
- История изменений
Быстрый старт (dev)
3 валидатора в docker-compose с замоканной «интернет» топологией:
docker compose up --build -d
open http://localhost:8081 # Explorer главной ноды
curl -s http://localhost:8081/api/netstats # синхронность ноды
После поднятия нативный username_registry уже доступен — отдельный
--profile deploy больше не нужен. Системные контракты регистрируются
в Go-коде при запуске (см. blockchain/native.go).
Продакшен деплой
Два варианта, по масштабу:
🔸 Single-node (deploy/single/)
Рекомендуется для личного/первого узла. Один узел + Caddy TLS + опциональный Prometheus.
cd deploy/single
# 1. Ключ ноды (один раз, сохранить в безопасном месте)
docker build -t dchain-node-slim -f ../prod/Dockerfile.slim ../..
mkdir -p keys
docker run --rm --entrypoint /usr/local/bin/client \
-v "$PWD/keys:/out" dchain-node-slim \
keygen --out /out/node.json
# 2. Конфиг
cp node.env.example node.env && $EDITOR node.env
# минимум: DCHAIN_ANNOUNCE=<public ip>, DOMAIN=<fqdn>, ACME_EMAIL=<your>
# 3. Вверх
docker compose up -d
# 4. Проверка
curl -s https://$DOMAIN/api/netstats
curl -s https://$DOMAIN/api/well-known-version
Модели доступа
| Режим | DCHAIN_API_TOKEN |
DCHAIN_API_PRIVATE |
Поведение |
|---|---|---|---|
| Public (default) | не задан | — | Все могут читать и писать |
| Public reads / token writes | задан | false |
Читать — любой; submit tx — только с токеном |
| Fully private | задан | true |
Всё требует Authorization: Bearer <token> |
UI / Swagger — включать или нет?
| Нужно | DCHAIN_DISABLE_UI |
DCHAIN_DISABLE_SWAGGER |
Где что открыто |
|---|---|---|---|
| Публичная с эксплорером + живой docs | не задано | не задано | / Explorer, /swagger UI, /api/*, /metrics |
| Headless API-нода с открытой OpenAPI | true |
не задано | /swagger UI, /api/*, /metrics (Explorer выкл.) |
| Личная 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
Скрипт deploy/single/update.sh читает /api/update-check, делает
semver-guarded git checkout tag, ребилдит образ с injected версией,
smoke-test node --version, recreate, health poll.
Подробные сценарии (первая нода, joiner, приватная, headless) +
полный API reference + systemd-интеграция + troubleshooting — в
deploy/single/README.md.
🔹 Multi-validator (deploy/prod/)
3 validator'а в PBFT-кворуме, Caddy с ip_hash для WS-стикинесса и
least-conn для REST. Для федераций / консорциумов — см.
deploy/prod/README.md.
Клиент
cd client-app
npm install
npx expo start # Expo Dev Tools — iOS / Android / Web
React Native + Expo + NativeWind. Ключевые экраны:
| Экран | Описание |
|---|---|
| Welcome / Create Account | Генерация Ed25519 + X25519 keypair |
| Chat List | Диалоги + real-time via WS (inbox:<x25519>) |
| Chat | E2E NaCl, typing-индикатор, day-separators |
| Contact Requests | Входящие запросы (push через addr:<pub>) |
| Add Contact | Поиск по @username (native registry) или hex |
| Wallet | Баланс, история (push), кошельковые action buttons |
| Settings | Нода, @username покупка, экспорт ключа |
Клиент подсоединяется к одной ноде через HTTP + WebSocket:
- WS для всего real-time (balance, inbox, contacts, tx commit).
- HTTP fallback через 15 s после обрыва, автоматически.
- Auto-discovery канонического
username_registryчерез/api/well-known-contracts.
Архитектура
┌────────────┐ libp2p ┌────────────┐ libp2p ┌────────────┐
│ node1 │◄─────pubsub──►│ node2 │◄─────pubsub──►│ node3 │
│ validator │ │ validator │ │ validator │
│ + relay │ │ + relay │ │ + relay │
└─────┬──────┘ └─────┬──────┘ └─────┬──────┘
│ │ │
│ HTTPS / wss (via Caddy) │ │
▼ ▼ ▼
mobile / web / CLI clients (load-balanced ip_hash for WS)
Слои (blockchain/):
chain.go— блочная машина (applyTx, AddBlock, BadgerDB)native.go— системные Go-контракты (интерфейс + registry)native_username.go— реализация username_registryequivocation.go— проверка evidence для SLASHtypes.go— транзакции, payloads
Сети (p2p/):
- gossipsub topics
dchain/tx/v1,dchain/blocks/v1 - стрим-протокол
/dchain/sync/1.0.0для catch-up - mDNS + DHT для peer discovery
Консенсус (consensus/pbft.go):
- Pre-prepare → Prepare → Commit, 2/3 quorum
- liveness tracking, equivocation detection (
recordVote,TakeEvidence) - per-sender FIFO мемпул + round-robin drain до
MaxTxsPerBlock
Node service layer (node/):
- HTTP API + SSE + WebSocket hub с auth и topic-based fanout
- Prometheus
/metrics(zero-dep) - event bus (
events.go) — SSE + WS + future consumers с одного emit'а - rate-limiter + body-size cap на tx submit
Relay (relay/):
- encrypted envelope routing через gossipsub
- BadgerDB mailbox для offline-получателей (TTL 7 дней)
SetOnStorehook push'ит новые envelopes в WS
Контракты
Системные (native Go) — зарегистрированы при запуске ноды:
| ID | Назначение | ABI |
|---|---|---|
native:username_registry |
@username → адрес |
register, resolve, lookup, transfer, release |
Пользовательские (WASM) — деплоятся через DEPLOY_CONTRACT tx.
TinyGo SDK + host functions (get_state, transfer, get_caller, log,
call_contract, …). Ручной деплой из scripts/deploy_contracts.sh или
CLI client deploy-contract --wasm ....
Обзор ABI / примеры — docs/contracts/ (отдельные файлы на auction,
escrow, governance, username_registry).
REST / WebSocket API
Chain
| Endpoint | Описание |
|---|---|
GET /api/netstats |
total_blocks, tx_count, supply, peer count |
GET /api/blocks?limit=N |
Последние блоки |
GET /api/block/{index} |
Конкретный блок |
GET /api/tx/{id} |
Транзакция по ID |
GET /api/txs/recent?limit=N |
Последние tx (O(limit)) |
GET /api/address/{pubkey} |
Баланс + история tx |
GET /api/validators |
Активный validator set |
GET /api/network-info |
One-shot bootstrap payload (chain_id, genesis, peers, validators, contracts) |
GET /api/peers |
Живые libp2p peer'ы |
GET /api/well-known-contracts |
Канонические контракты (native + WASM) |
GET /api/contracts/{id} |
Метаданные контракта, "native": true/false |
GET /api/contracts/{id}/state/{key} |
Прямое чтение state |
GET /api/relays |
Список relay-нод (filtered TTL) |
POST /api/tx |
Submit signed tx (rate-limited, size-capped) |
Real-time
GET /api/events— Server-Sent Events (classic, 1-way)GET /api/ws— WebSocket (bidirectional, recommended)
WS protocol — см. node/ws.go:
{ "op": "auth", "pubkey": "...", "sig": "..." }
{ "op": "subscribe", "topic": "addr:..." | "inbox:..." | "typing:..." | "blocks" | "tx" }
{ "op": "unsubscribe", "topic": "..." }
{ "op": "submit_tx", "tx": {...}, "id": "client-req-id" }
{ "op": "typing", "to": "<x25519>" }
{ "op": "ping" }
Server push:
{ "event": "hello", "chain_id": "...", "auth_nonce": "..." }
{ "event": "block", "data": {...} }
{ "event": "tx", "data": {...} }
{ "event": "inbox", "data": { id, recipient_pub, sender_pub, sent_at } }
{ "event": "typing", "data": { from, to } }
{ "event": "submit_ack", "id": "...", "status": "accepted|rejected", "reason": "..." }
Scoped топики (addr:, inbox:, typing:) требуют auth. Без auth
доступны только публичные (blocks, tx, contract_log).
CLI
client keygen --out key.json
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 --args '["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 remove-validator --key key.json --target <pub>
# ... полный список — `client` без аргументов
Node flags (все читают DCHAIN_* env fallbacks):
--db,--listen,--announce,--peers,--validators--join http://seed1:8080,http://seed2:8080(multi-seed, persisted)--genesis,--observer,--register-relay--log-format text|json,--allow-genesis-mismatch
Мониторинг
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 dashboard + provisioning — deploy/prod/grafana/ (create as
needed; Prometheus data source is auto-wired in compose profile
monitor).
Тесты
go test ./... # blockchain + consensus + relay + identity + vm
go run ./cmd/loadtest \
--node http://localhost:8081 \
--funder testdata/node1.json \
--clients 50 --duration 60s # end-to-end WS + submit_tx + native contract path
История изменений
Подробный список того, что сделано за последнюю итерацию (стабилизация
чейна, governance, WS gateway, observability, native contracts,
deployment) — CHANGELOG.md.