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:
291
docs/node/multi-server.md
Normal file
291
docs/node/multi-server.md
Normal 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` транзакция от существующего валидатора.
|
||||
Reference in New Issue
Block a user