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
9.8 KiB
9.8 KiB
Деплой на реальные серверы
Руководство по запуску трёх полноценных нод на разных 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):
# Сгенерировать 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. Сборка бинарника
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. Копирование ключей
# Каждый сервер получает ТОЛЬКО свой ключ
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:
# 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)
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)
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)
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 на каждом сервере:
[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
# Применить
sudo systemctl daemon-reload
sudo systemctl enable --now dchain
# Логи
sudo journalctl -u dchain -f
7. Деплой контрактов
После запуска всех трёх нод:
# С любой машины имеющей 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
# 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):
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
Нода автоматически:
- Подключится к node1 через
--peers - Синхронизирует всю историю блоков
- Через DHT найдёт node2 и node3
- Начнёт получать и пересылать relay-сообщения
Чтобы сделать её валидатором — нужна ADD_VALIDATOR транзакция от существующего валидатора.