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
This commit is contained in:
vsecoder
2026-04-17 14:16:44 +03:00
commit 7e7393e4f8
196 changed files with 55947 additions and 0 deletions

291
docs/node/multi-server.md Normal file
View File

@@ -0,0 +1,291 @@
# Деплой на реальные серверы
Руководство по запуску трёх полноценных нод на разных VPS/серверах в интернете.
## Концепция
```
Server A (1.2.3.11) Server B (1.2.3.12) Server C (1.2.3.13)
┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
│ node1 │ │ node2 │ │ node3 │
│ validator │◀────────▶│ validator │◀────────▶│ validator │
│ relay (2000µT) │ │ relay (1500µT) │ │ relay (1000µT) │
│ :4001 :8080 │ │ :4001 :8080 │ │ :4001 :8080 │
└────────┬────────┘ └────────┬────────┘ └────────┬────────┘
│ │ │
└────────────────────────────┴─────────────────────────────┘
libp2p P2P
gossipsub: tx + blocks
streams: PBFT consensus, sync
```
Каждая нода — полноценный **валидатор** (участвует в PBFT-консенсусе) и **relay-провайдер** (хранит и доставляет зашифрованные сообщения).
## Требования
- Ubuntu 22.04 / Debian 12 (или любой Linux)
- Открытый TCP-порт `4001` (P2P) и опционально `8080` (HTTP API)
- Go 1.21+ **только для сборки** (на сервере нужен только бинарник)
## 1. Подготовка ключей
На любой машине (ноутбук / CI):
```bash
# Сгенерировать 3 ключа
./client keygen --out keys/node1.json
./client keygen --out keys/node2.json
./client keygen --out keys/node3.json
# Получить pubkey и peer ID для каждого
./peerid --key keys/node1.json --ip <SERVER_A_IP> --port 4001
./peerid --key keys/node2.json --ip <SERVER_B_IP> --port 4001
./peerid --key keys/node3.json --ip <SERVER_C_IP> --port 4001
```
Вывод `peerid`:
```
pub_key: 26018d40...
peer_id: 12D3KooW...
multiaddr: /ip4/1.2.3.11/tcp/4001/p2p/12D3KooW...
```
Запишите `pub_key` и `peer_id` для каждой ноды — они нужны в конфигурации.
## 2. Сборка бинарника
```bash
git clone https://github.com/your/go-blockchain
cd go-blockchain
CGO_ENABLED=0 GOOS=linux go build -trimpath -o node ./cmd/node
CGO_ENABLED=0 GOOS=linux go build -trimpath -o client ./cmd/client
# Скопировать на серверы
scp node client root@1.2.3.11:/usr/local/bin/
scp node client root@1.2.3.12:/usr/local/bin/
scp node client root@1.2.3.13:/usr/local/bin/
```
## 3. Копирование ключей
```bash
# Каждый сервер получает ТОЛЬКО свой ключ
scp keys/node1.json root@1.2.3.11:/etc/dchain/node.json
scp keys/node2.json root@1.2.3.12:/etc/dchain/node.json
scp keys/node3.json root@1.2.3.13:/etc/dchain/node.json
chmod 600 /etc/dchain/node.json # на каждом сервере
```
## 4. Переменные конфигурации
Подставьте реальные значения из шага 1:
```bash
# Validators — все три pubkey через запятую
VALIDATORS="<NODE1_PUB>,<NODE2_PUB>,<NODE3_PUB>"
# Bootstrap multiaddrs для node2 и node3
NODE1_PEER="/ip4/1.2.3.11/tcp/4001/p2p/<NODE1_PEER_ID>"
NODE2_PEER="/ip4/1.2.3.12/tcp/4001/p2p/<NODE2_PEER_ID>"
```
## 5. Запуск нод
### Server A — node1 (genesis + validator + relay)
```bash
node \
--genesis \
--key /etc/dchain/node.json \
--db /var/lib/dchain/chain \
--mailbox-db /var/lib/dchain/mailbox \
--listen /ip4/0.0.0.0/tcp/4001 \
--announce /ip4/1.2.3.11/tcp/4001 \
--stats-addr :8080 \
--validators "$VALIDATORS" \
--heartbeat=true \
--register-relay \
--relay-fee 2000
```
### Server B — node2 (validator + relay)
```bash
node \
--key /etc/dchain/node.json \
--db /var/lib/dchain/chain \
--mailbox-db /var/lib/dchain/mailbox \
--listen /ip4/0.0.0.0/tcp/4001 \
--announce /ip4/1.2.3.12/tcp/4001 \
--stats-addr :8080 \
--validators "$VALIDATORS" \
--peers "$NODE1_PEER" \
--heartbeat=true \
--register-relay \
--relay-fee 1500
```
### Server C — node3 (validator + relay)
```bash
node \
--key /etc/dchain/node.json \
--db /var/lib/dchain/chain \
--mailbox-db /var/lib/dchain/mailbox \
--listen /ip4/0.0.0.0/tcp/4001 \
--announce /ip4/1.2.3.13/tcp/4001 \
--stats-addr :8080 \
--validators "$VALIDATORS" \
--peers "$NODE1_PEER,$NODE2_PEER" \
--heartbeat=true \
--register-relay \
--relay-fee 1000
```
## 6. systemd unit
Создайте `/etc/systemd/system/dchain.service` на каждом сервере:
```ini
[Unit]
Description=DChain Node
After=network-online.target
Wants=network-online.target
[Service]
Type=simple
User=dchain
ExecStart=/usr/local/bin/node \
--key /etc/dchain/node.json \
--db /var/lib/dchain/chain \
--mailbox-db /var/lib/dchain/mailbox \
--listen /ip4/0.0.0.0/tcp/4001 \
--announce /ip4/YOUR_PUBLIC_IP/tcp/4001 \
--stats-addr :8080 \
--validators "V1_PUB,V2_PUB,V3_PUB" \
--peers "/ip4/SEED_IP/tcp/4001/p2p/SEED_PEER_ID" \
--heartbeat=true \
--register-relay \
--relay-fee 1000
Restart=on-failure
RestartSec=5s
LimitNOFILE=65536
[Install]
WantedBy=multi-user.target
```
```bash
# Применить
sudo systemctl daemon-reload
sudo systemctl enable --now dchain
# Логи
sudo journalctl -u dchain -f
```
## 7. Деплой контрактов
После запуска всех трёх нод:
```bash
# С любой машины имеющей client и ключ node1
export NODE_URL=http://1.2.3.11:8080
export KEY=/etc/dchain/node.json # или локальная копия
# Задеплоить username_registry
CONTRACT_ID=$(client deploy-contract \
--key $KEY \
--wasm contracts/username_registry/username_registry.wasm \
--abi contracts/username_registry/username_registry_abi.json \
--node $NODE_URL | grep contract_id | awk '{print $2}')
echo "username_registry: $CONTRACT_ID"
# Залинковать governance на всех трёх нодах
for NODE in http://1.2.3.11:8080 http://1.2.3.12:8080 http://1.2.3.13:8080; do
curl -sX POST "$NODE/api/governance/link" \
-H "Content-Type: application/json" \
-d "{\"governance\":\"$GOV_ID\"}"
done
```
## 8. Как работает сеть
### Bootstrap и discovery
```
node2 старт:
1. --peers → connectWithRetry("/ip4/1.2.3.11/tcp/4001/p2p/...")
Подключается к node1 (бесконечный retry с backoff 1→30s)
2. При connect → syncOnConnect()
Запрашивает все блоки которых нет у node2
3. Kademlia DHT bootstrap (через node1)
DHT узнаёт о node3 → DiscoverPeers() подключается
4. mDNS (только LAN/Docker) — игнорируется в интернете
5. connectWithRetry keep-alive: каждые 30s проверяет связь,
автоматически переподключает при обрыве
```
### Консенсус
PBFT 3-of-3, fault tolerance f=1:
- Для коммита блока нужны подписи **2 из 3** валидаторов
- Если одна нода упала → сеть продолжает работать
- Если упали две → сеть ждёт (не производит блоки)
### --announce и адреса
Без `--announce` libp2p рекламирует **все** адреса интерфейсов:
- `0.0.0.0` → раскрывается в loopback и внутренние адреса
- Другие ноды получают `127.0.0.1:4001` → не могут подключиться
С `--announce /ip4/1.2.3.11/tcp/4001`:
- Единственный рекламируемый адрес — публичный IP сервера
- `AddrStrings()` возвращает только этот адрес
- DHT propagates этот адрес другим нодам в сети
## 9. Firewall
```bash
# UFW
ufw allow 4001/tcp # P2P — обязательно
ufw allow 8080/tcp # HTTP API — опционально (для Explorer, деплоя контрактов)
# iptables
iptables -A INPUT -p tcp --dport 4001 -j ACCEPT
iptables -A INPUT -p tcp --dport 8080 -j ACCEPT
```
## 10. Добавление новой ноды в сеть
Новый участник (не валидатор, только синхронизация и relay):
```bash
node \
--key /etc/dchain/node.json \
--db /var/lib/dchain/chain \
--mailbox-db /var/lib/dchain/mailbox \
--listen /ip4/0.0.0.0/tcp/4001 \
--announce /ip4/YOUR_IP/tcp/4001 \
--stats-addr :8080 \
--validators "$VALIDATORS" \
--peers "$NODE1_PEER" \
--heartbeat=false \
--register-relay \
--relay-fee 500
```
Нода автоматически:
1. Подключится к node1 через `--peers`
2. Синхронизирует всю историю блоков
3. Через DHT найдёт node2 и node3
4. Начнёт получать и пересылать relay-сообщения
Чтобы сделать её валидатором — нужна `ADD_VALIDATOR` транзакция от существующего валидатора.