# Деплой на реальные серверы Руководство по запуску трёх полноценных нод на разных 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 --port 4001 ./peerid --key keys/node2.json --ip --port 4001 ./peerid --key keys/node3.json --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=",," # Bootstrap multiaddrs для node2 и node3 NODE1_PEER="/ip4/1.2.3.11/tcp/4001/p2p/" NODE2_PEER="/ip4/1.2.3.12/tcp/4001/p2p/" ``` ## 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` транзакция от существующего валидатора.