chore(release): clean up repo for v0.0.1 release

Excluded from release bundle:
- CONTEXT.md, CHANGELOG.md (agent/project working notes)
- client-app/ (React Native messenger — tracked separately)
- contracts/hello_go/ (unused standalone example)

Kept contracts/counter/ and contracts/name_registry/ as vm-test fixtures
(referenced by vm/vm_test.go; NOT production contracts).

Docs refactor:
- docs/README.md — new top-level index with cross-references
- docs/quickstart.md — rewrite around single-node as primary path
- docs/node/README.md — full rewrite, all CLI flags, schema table
- docs/api/README.md — add /api/well-known-version, /api/update-check
- docs/contracts/README.md — split native (Go) vs WASM (user-deployable)
- docs/update-system.md — new, full 5-layer update system design
- README.md — link into docs/, drop CHANGELOG/client-app references

Build-time version system (inherited from earlier commits this branch):
- node --version / client --version with ldflags-injected metadata
- /api/well-known-version with {build, protocol_version, features[]}
- Peer-version gossip on dchain/version/v1
- /api/update-check against Gitea release API
- deploy/single/update.sh with semver guard + 15-min systemd jitter
This commit is contained in:
vsecoder
2026-04-17 14:37:00 +03:00
parent 7e7393e4f8
commit 546d2c503f
55 changed files with 702 additions and 17381 deletions

320
README.md
View File

@@ -1,89 +1,91 @@
# DChain
Блокчейн-стек для децентрализованного мессенджера:
- **PBFT** консенсус с multi-sig validator governance и equivocation slashing
- **Native Go контракты** рядом с WASM (wazero) — нулевая задержка для
системных сервисов типа username registry
системных сервисов типа `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
- React Native / Expo мессенджер (`client-app/`)
## Содержание
- [Быстрый старт (dev)](#быстрый-старт-dev)
- [Быстрый старт](#быстрый-старт)
- [Продакшен деплой](#продакшен-деплой)
- [Клиент](#клиент)
- [Архитектура](#архитектура)
- [Контракты](#контракты)
- [REST / WebSocket API](#rest--websocket-api)
- [CLI](#cli)
- [Мониторинг](#мониторинг)
- [Тесты](#тесты)
- [История изменений](#история-изменений)
- [Документация](#документация)
---
## Быстрый старт (dev)
## Быстрый старт
3 валидатора в docker-compose с замоканной «интернет» топологией:
Одна нода в Docker, HTTP API на `localhost:8080`, Explorer UI и Swagger
открыты:
```bash
docker compose up --build -d
open http://localhost:8081 # Explorer главной ноды
curl -s http://localhost:8081/api/netstats # синхронность ноды
```
# 1. Собираем prod-образ
docker build -t dchain-node-slim -f deploy/prod/Dockerfile.slim .
После поднятия нативный `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 ../..
# 2. Ключ ноды (один раз)
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
# 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. Проверка
curl -s https://$DOMAIN/api/netstats
curl -s https://$DOMAIN/api/well-known-version
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`](docs/quickstart.md).
## Продакшен деплой
Два варианта, по масштабу.
### 🔸 Single-node (`deploy/single/`)
**Рекомендуется для личного/первого узла.** Один узел + Caddy TLS +
опциональный Prometheus. Полный runbook с 6 сценариями (публичная с UI,
headless, полностью приватная, genesis, joiner, auto-update) — в
[`deploy/single/README.md`](deploy/single/README.md).
#### Модели доступа
| Режим | `DCHAIN_API_TOKEN` | `DCHAIN_API_PRIVATE` | Поведение |
|-------|:------------------:|:--------------------:|-----------|
| Public (default) | не задан | — | Все могут читать и писать |
| Public reads / token writes | задан | `false` | Читать — любой; submit tx — только с токеном |
| 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` |
| Нужно | `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-поверхность регистрируется всегда — отключить её можно
@@ -92,7 +94,7 @@ curl -s https://$DOMAIN/api/well-known-version
#### Auto-update
```ini
# node.env — когда проект у вас в Gitea
# node.env — когда проект в Gitea
DCHAIN_UPDATE_SOURCE_URL=https://gitea.example.com/api/v1/repos/OWNER/REPO/releases/latest
UPDATE_ALLOW_MAJOR=false
```
@@ -104,175 +106,102 @@ 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)**.
Подробно: [`docs/update-system.md`](docs/update-system.md) + [`deploy/UPDATE_STRATEGY.md`](deploy/UPDATE_STRATEGY.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`.
3 validator'а в PBFT-кворуме, Caddy с `ip_hash` для WS-стикинесса и
`least-conn` для REST. Для федераций / консорциумов — см.
[`deploy/prod/README.md`](deploy/prod/README.md) и
[`docs/node/multi-server.md`](docs/node/multi-server.md).
## Архитектура
```
┌────────────┐ libp2p ┌────────────┐ libp2p ┌────────────┐
│ node1 │◄─────pubsub──►│ node2 │◄─────pubsub──►│ node3
│ node-A │◄─────pubsub──►│ node-B │◄─────pubsub──►│ node-C
│ validator │ │ validator │ │ validator │
│ + relay │ │ + relay │ │ + relay │
└─────┬──────┘ └─────┬──────┘ └─────┬──────┘
│ │ │
│ HTTPS / wss (via Caddy) │ │
▼ ▼ ▼
mobile / web / CLI clients (load-balanced ip_hash for WS)
mobile / web / CLI clients (ip_hash для WS, least-conn для REST)
```
Слои (`blockchain/`):
- `chain.go` — блочная машина (applyTx, AddBlock, BadgerDB)
- `native.go` — системные Go-контракты (интерфейс + registry)
- `native_username.go` — реализация username_registry
- `equivocation.go` — проверка evidence для SLASH
- `types.go` — транзакции, payloads
Четыре слоя: network → chain → transport → app. Детали — в
[`docs/architecture.md`](docs/architecture.md).
Сети (`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).
| Путь | Роль |
|------|------|
| `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
### Chain
Обзор (полный reference — [`docs/api/README.md`](docs/api/README.md)):
### Chain + stats
| 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) |
| `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`](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.
- `GET /api/events` — Server-Sent Events (classic, 1-way)
- `GET /api/ws`**WebSocket** (bidirectional, recommended)
Scoped WS-топики (`addr:`, `inbox:`, `typing:`) требуют auth через
Ed25519-nonce; публичные (`blocks`, `tx`, `contract_log`) — без.
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`).
### 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
```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` без аргументов
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 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`
Все флаги `node` — в [`docs/node/README.md`](docs/node/README.md), либо
`node --help`.
## Мониторинг
@@ -289,22 +218,39 @@ 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`).
Grafana + Prometheus поднимаются вместе с нодой через
`docker compose --profile monitor up -d` (см. `deploy/single/docker-compose.yml`).
## Тесты
```bash
go test ./... # blockchain + consensus + relay + identity + vm
# 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 # end-to-end WS + submit_tx + native contract path
--clients 50 --duration 60s
```
## История изменений
## Документация
Подробный список того, что сделано за последнюю итерацию (стабилизация
чейна, governance, WS gateway, observability, native contracts,
deployment) — `CHANGELOG.md`.
Полный справочник в `docs/` — см. [`docs/README.md`](docs/README.md) как
оглавление. Ключевые документы:
| Документ | О чём |
|----------|-------|
| [`docs/quickstart.md`](docs/quickstart.md) | Три пути: локально, single-node prod, федерация |
| [`docs/architecture.md`](docs/architecture.md) | 4 слоя, consensus, storage, gas model |
| [`docs/update-system.md`](docs/update-system.md) | Versioning + update-check + semver guard |
| [`docs/api/README.md`](docs/api/README.md) | REST + WebSocket reference |
| [`docs/cli/README.md`](docs/cli/README.md) | CLI команды и флаги |
| [`docs/node/README.md`](docs/node/README.md) | Запуск ноды (native + Docker) |
| [`docs/contracts/README.md`](docs/contracts/README.md) | Системные + WASM контракты |
| [`docs/development/README.md`](docs/development/README.md) | SDK для своих контрактов |
| [`deploy/single/README.md`](deploy/single/README.md) | Single-node operator runbook |
| [`deploy/prod/README.md`](deploy/prod/README.md) | Multi-validator federation |
| [`deploy/UPDATE_STRATEGY.md`](deploy/UPDATE_STRATEGY.md) | Forward-compat design (4 слоя) |