Files
dchain/README.md
vsecoder 7e7393e4f8 chore: initial commit for v0.0.1
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
2026-04-17 14:16:44 +03:00

13 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
  • Prometheus /metrics, Caddy auto-HTTPS, observer mode, load-test
  • React Native / Expo мессенджер (client-app/)

Содержание


Быстрый старт (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_registry
  • equivocation.go — проверка evidence для SLASH
  • types.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 дней)
  • SetOnStore hook 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/wsWebSocket (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.