Files
SHiNE-server/docs/Archive/03_DEPLOY_TEST_SERVER.md
T

467 lines
16 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Деплой SHiNE Archive Publisher v1.0 на тестовый сервер
Документ рассчитан на человека или автономного coding/deploy агента. Выполнять шаги по порядку. Не включать publisher до проверки Solana-программы и ключей.
## 0. Что именно меняется
Нужны изменения одновременно в:
1. серверном Java-коде;
2. PostgreSQL schema v23;
3. Solana-программе `shine_users` (PDA block type `100` + backward-compatible update parser);
4. Java/JS User PDA codecs.
**Критично:** новый серверный writer отправляет расширенный обычный `update_user_pda`. Если в целевом кластере работает старая `shine_users`, включать publisher нельзя.
---
# 1. Применить пакет к исходникам
ZIP из этой поставки содержит только новые/изменённые файлы с путями относительно корня репозитория.
Сделать backup текущего проекта, затем распаковать ZIP поверх рабочего дерева.
После распаковки удалить legacy-файлы из списка `05_PATCH_CONTENTS_AND_REMOVALS.md`.
Проверить:
```bash
git status --short
```
или, если это не git checkout, сравнить список файлов с manifest из той же документации.
---
# 2. Обязательно обновить `shine_users` в нужном Solana-кластере
## 2.1. Проверить целевой кластер
Не деплоить вслепую. Сначала:
```bash
solana config get
```
и проверить RPC/кластер, upgrade authority и Program ID. В проекте `shine_users` использует Program ID:
```text
SHiNEPr1APdAgNBteUyBXcNovaHctpSjUu8oH2ZJdN6
```
Если тестовый сервер использует mainnet RPC, обновляется именно mainnet-программа. Если тестовый контур использует devnet — сначала убедиться, что программа с нужным ID действительно существует в devnet.
## 2.2. Собрать Solana program
```bash
cd shine-solana/shine
anchor build
```
Минимальная host-проверка Rust, если Anchor/SBF toolchain временно недоступен:
```bash
cargo build -p shine_users
```
Но для реального deploy нужен SBF/Anchor build.
## 2.3. Обновить существующую программу
Использовать существующий project deploy/upgrade authority. Типовой вариант:
```bash
solana program deploy target/deploy/shine_users.so \
--program-id target/deploy/shine_users-keypair.json \
--upgrade-authority /PATH/TO/UPGRADE_AUTHORITY.json \
--url <TARGET_RPC_URL>
```
Если в проекте используется рабочий Anchor deploy workflow, допустимо использовать его вместо прямого `solana program deploy`; главное — сохранить тот же Program ID.
После обновления:
```bash
solana program show SHiNEPr1APdAgNBteUyBXcNovaHctpSjUu8oH2ZJdN6 --url <TARGET_RPC_URL>
```
---
# 3. Собрать серверный JAR
Из корня репозитория:
```bash
./gradlew clean shadowJar
```
Ожидаемый файл:
```text
SHiNE-server/build/libs/shine-server.jar
```
Если Gradle wrapper не может скачать зависимости, сборку выполнять на машине/CI с доступом к Maven/Gradle или с уже заполненным cache.
---
# 4. Подготовить PostgreSQL backup
Перед первым стартом версии со schema v23 сделать backup тестовой БД. Например:
```bash
pg_dump -Fc -d '<DATABASE_URL_OR_NAME>' -f shine-before-archive-v22.dump
```
Точная команда зависит от текущей схемы доступа PostgreSQL.
При старте сервер последовательно применит `migration_v22.sql` и `migration_v23.sql`, если это требуется текущей версии БД. Вручную migrations выполнять обычно не нужно.
После старта проверить:
```sql
SELECT * FROM db_schema_version WHERE id=1;
```
Ожидается:
```text
schema_version = 23
```
И наличие:
```sql
SELECT to_regclass('public.archive_chain_cursor');
SELECT to_regclass('public.archive_publish_job');
SELECT to_regclass('public.archive_publish_job_chain');
```
---
# 5. Подготовить секреты на тестовом сервере
Пример:
```bash
sudo -u player mkdir -p /home/player/SHiNE/secrets
sudo chmod 700 /home/player/SHiNE/secrets
```
Положить:
```text
/home/player/SHiNE/secrets/archive-arweave-wallet.json
/home/player/SHiNE/secrets/server-root.key
/home/player/SHiNE/secrets/server-client.key
```
Права:
```bash
sudo chown player:player /home/player/SHiNE/secrets/*
sudo chmod 600 /home/player/SHiNE/secrets/*
```
### Форматы root/client key
Поддерживаются:
- raw seed 32 bytes;
- raw keypair 64 bytes;
- Solana JSON array на 32/64 байта;
- Base58 seed на 32 байта или Solana secret key на 64 байта;
- Base64 raw/PKCS8, где seed извлекается из последних 32 bytes.
### Arweave wallet
Ожидается RSA JWK с полями `n,e,d,p,q,dp,dq,qi`. Кошелёк должен иметь достаточно AR для размера первого полного архива.
---
# 6. Настроить внешний `application.properties`
Сервер читает внешний `application.properties` из **WorkingDirectory процесса** и накладывает его поверх встроенного конфига. Сохранять существующие DB/Solana/server параметры и добавить archive-секцию.
Минимум:
```properties
archive.publish.enabled=true
archive.publish.time=00:00
archive.publish.zoneId=Europe/Warsaw
archive.workDir=data/archive
archive.maxFileBytes=4000000000
archive.arweave.gateway=https://arweave.net
archive.arweave.walletJwkPath=/home/player/SHiNE/secrets/archive-arweave-wallet.json
archive.arweave.minConfirmations=1
archive.arweave.confirmPollSeconds=30
archive.arweave.confirmTimeoutMinutes=180
archive.solana.rootKeyPath=/home/player/SHiNE/secrets/server-root.key
archive.solana.clientKeyPath=/home/player/SHiNE/secrets/server-client.key
archive.solana.confirmPollSeconds=5
archive.solana.confirmTimeoutMinutes=30
archive.solana.commitment=finalized
```
`archive.publish.zoneId` выбрать осознанно. Если оставить пустым, используется timezone JVM/машины. Для ежедневного запуска ровно в нужную локальную полночь лучше задать ZoneId явно.
### Solana RPC
**Отдельного archive RPC нет.** Writer использует:
1. `solana.users.sync.rpcUrl`, если он задан;
2. иначе `solana.rpcUrl`.
Поэтому существующий рабочий RPC не дублировать в archive settings.
---
# 7. Убедиться, что server login соответствует ключам
`server.SHiNE.login` должен быть тем User PDA, чей archive head будет обновляться.
На startup `SolanaArchiveHeadWriter` проверяет:
```text
derive(root private) == UserPDA.root_key
derive(client private) == UserPDA.client_key
```
При несовпадении archive publisher не стартует.
---
# 8. Развернуть JAR
Можно использовать существующий `deploy/scripts/deploy_server.sh`. Он:
- собирает `shadowJar`;
- копирует JAR;
- создаёт/обновляет systemd unit;
- перезапускает сервис.
Типовой запуск задаётся уже существующими переменными проекта. Либо вручную заменить `shine-server.jar` в рабочей директории и перезапустить systemd service.
После deploy убедиться, что WorkingDirectory содержит внешний `application.properties`.
---
# 9. Первый startup
Смотреть лог:
```bash
sudo journalctl -u <SERVICE_NAME> -f
```
Ожидаемые события:
1. DB migration до v22;
2. обычный Solana users sync;
3. обычный server-to-server blockchain sync;
4. archive publisher preflight;
5. строка примерно:
```text
Archive publisher включён: login=... dir=data/archive dailyAt=00:00 zone=...
Следующая архивная публикация запланирована на ...
```
Если остался незавершённый job, он будет продолжен **сразу после старта**, не ожидая полуночи. Новый snapshot создаётся только по расписанию.
---
# 10. Что произойдёт в первую полночь
Если `archive_chain_cursor` пуст:
- сервер проходит все локально известные `blockchain_name`;
- для каждой берёт range `0..current_head`;
- создаёт первый big block `#1`;
- для каждой blockchain создаёт максимум один `UserBlockchainChunk`;
- внутри chunk лежат все её raw records из frozen range;
- backlink первого chunk пустой (`previous_big_block_ref = 0xFFFFFFFF`);
- создаёт локальный файл, например:
```text
data/archive/archive01.00001.12.09.26.tmp.SHiNE-archive
```
- загружает его в Arweave;
- после успешной загрузки переименовывает тот же файл, например:
```text
data/archive/archive01.00001.12.09.26.<REAL_TX_ID>.SHiNE-archive
```
- ждёт confirmations;
- обычным `update_user_pda` записывает block type `100`;
- ждёт Solana `finalized`;
- только затем commit-ит cursors.
Если новых данных нет, пустой big block не создаётся.
---
# 11. Проверка результата
## Локальные файлы
```bash
ls -lah data/archive/
```
После успешного upload `.tmp.SHiNE-archive` для завершённого job оставаться не должен; должен быть файл с реальным TX ID в имени.
## Job DB
```sql
SELECT id, big_block_number, status, created_at_ms, local_archive_path,
arweave_confirmations, solana_signature, error_text
FROM archive_publish_job
ORDER BY id DESC
LIMIT 10;
```
Успех:
```text
status = CURSORS_COMMITTED
```
## Cursors
```sql
SELECT blockchain_name,
last_archived_source_block_number,
last_archive_big_block_number,
last_chunk_offset,
last_chunk_size
FROM archive_chain_cursor
ORDER BY blockchain_name;
```
## Локальная проекция User PDA
После очередной Solana sync:
```sql
SELECT login, record_number, archive_head_tx_id, archive_head_hash
FROM solana_user_pda_current
WHERE login = '<SERVER_LOGIN>';
```
`archive_head_tx_id` и `archive_head_hash` должны быть непустыми.
## Arweave
TX берётся прямо из имени финального файла. Проверить:
```bash
curl -sS 'https://arweave.net/tx/<TX_ID>/status'
```
---
# 12. Быстрый тест до полуночи
Если не хочется ждать 00:00, на тестовом сервере временно установить `archive.publish.time` на ближайшие 5–10 минут в будущем в выбранной `archive.publish.zoneId`, затем перезапустить сервис.
После проверки вернуть:
```properties
archive.publish.time=00:00
```
Не использовать интервал в минутах: scheduler специально работает по календарному локальному времени один раз в сутки.
---
# 13. Откат / выключение
Самый безопасный функциональный rollback:
```properties
archive.publish.enabled=false
```
и рестарт сервера. Тогда обычная серверная работа продолжается, archive scheduler ничего не публикует.
Не удалять `archive_chain_cursor`/job таблицы без причины: они нужны, чтобы после повторного включения publisher продолжил дельту, а не загрузил всю историю заново.
Уже опубликованные Arweave данные являются постоянными и обычным rollback сервера не удаляются.
---
# 14. Наиболее вероятные ошибки
### `Root key archive publisher-а не совпадает с User PDA`
Положен неправильный root key или неверный `server.SHiNE.login`.
### `Client key archive publisher-а не совпадает с User PDA`
Неверный client key.
### `Недостаточно AR`
Пополнить Arweave wallet. Первый архив может быть существенно больше ежедневных дельт.
### Arweave upload прошёл, Solana update не прошёл
Не удалять локальный файл/job. После исправления RPC/program/key причины restart продолжит незавершённый job.
### `archive cursor hash не совпадает`
Локальная blockchain изменилась относительно уже зафиксированного cursor. Не форсировать публикацию; сначала разобраться с resync/fork.
### Старый `shine_users`
Если новый update payload отклоняется программой, проверить, что целевая Solana `shine_users` действительно обновлена этой версией.
## Trusted archive importer
На обычном тестовом сервере publisher можно оставить выключенным, но разрешить импорт от конкретного архиватора:
```properties
archive.publish.enabled=false
archive.import.allowedPublishers=<LOGIN_ARCHIVE_SERVER>
archive.import.intervalMinutes=60
archive.import.workDir=data/archive-import
```
Несколько логинов:
```properties
archive.import.allowedPublishers=server-a,server-b
```
Пустая строка означает, что importer не запускается.
После старта проверить логи:
```text
Archive importer включён. approvedPublishers=...
```
Если сервер подключается к publisher впервые, importer скачает head, прочитает FULL reference table и обработает все ещё не известные big blocks от старых к новым.
Проверка БД:
```sql
SELECT login, archive_head_tx_id, archive_imported, archive_last_imported_tx_id
FROM solana_user_pda_current
WHERE is_server=TRUE AND archive_head_tx_id<>''
ORDER BY login;
SELECT blockchain_name, publisher_login, arweave_tx_id,
big_block_number, chunk_offset, chunk_size, source_last_block_number
FROM archive_blockchain_location
ORDER BY updated_at_ms DESC
LIMIT 20;
```
После деплоя UI файл должен быть доступен по:
```text
https://<UI_HOST>/Blockchain-Viewer.html
```
В приложении: `Настройки → Архив блокчейна`.