Архивация в Arweave

This commit is contained in:
AidarKC
2026-09-12 10:17:23 +03:00
parent ef068eca81
commit c3253dceac
48 changed files with 6681 additions and 1227 deletions
+415
View File
@@ -0,0 +1,415 @@
# Деплой SHiNE Archive Publisher v1.0 на тестовый сервер
Документ рассчитан на человека или автономного coding/deploy агента. Выполнять шаги по порядку. Не включать publisher до проверки Solana-программы и ключей.
## 0. Что именно меняется
Нужны изменения одновременно в:
1. серверном Java-коде;
2. PostgreSQL schema v22;
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 v22 сделать backup тестовой БД. Например:
```bash
pg_dump -Fc -d '<DATABASE_URL_OR_NAME>' -f shine-before-archive-v22.dump
```
Точная команда зависит от текущей схемы доступа PostgreSQL.
При старте сервер сам применит `migration_v22.sql`, если `db_schema_version < 22`. Вручную migration выполнять обычно не нужно.
После старта проверить:
```sql
SELECT * FROM db_schema_version WHERE id=1;
```
Ожидается:
```text
schema_version = 22
```
И наличие:
```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` действительно обновлена этой версией.