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

311 lines
13 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 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)](#быстрый-старт-dev)
- [Продакшен деплой](#продакшен-деплой)
- [Клиент](#клиент)
- [Архитектура](#архитектура)
- [Контракты](#контракты)
- [REST / WebSocket API](#rest--websocket-api)
- [CLI](#cli)
- [Мониторинг](#мониторинг)
- [Тесты](#тесты)
- [История изменений](#история-изменений)
---
## Быстрый старт (dev)
3 валидатора в docker-compose с замоканной «интернет» топологией:
```bash
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.
```bash
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
```ini
# node.env — когда проект у вас в Gitea
DCHAIN_UPDATE_SOURCE_URL=https://gitea.example.com/api/v1/repos/OWNER/REPO/releases/latest
UPDATE_ALLOW_MAJOR=false
```
```bash
# 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`](deploy/single/README.md)**.
### 🔹 Multi-validator (`deploy/prod/`)
3 validator'а в PBFT-кворуме, Caddy с ip_hash для WS-стикинесса и
least-conn для REST. Для федераций / консорциумов — см.
`deploy/prod/README.md`.
## Клиент
```bash
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/ws`**WebSocket** (bidirectional, recommended)
WS protocol — см. `node/ws.go`:
```json
{ "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:
```json
{ "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
```bash
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`).
## Тесты
```bash
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`.