SHA256
Архивация в Arweave
This commit is contained in:
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,98 @@
|
||||
# Карта реализации SHiNE Archive Publisher v1.0
|
||||
|
||||
Этот документ связывает протокол с конкретными файлами проекта. Он нужен, чтобы другой агент мог быстро понять, где искать каждую часть реализации.
|
||||
|
||||
## 1. Новый Java-модуль `shine-server-archive`
|
||||
|
||||
Путь: `SHiNE-server/shine-server-archive/`.
|
||||
|
||||
Основные классы:
|
||||
|
||||
- `ArchivePublisherScheduler` — включает publisher только при `archive.publish.enabled=true`, сразу продолжает незавершённый job после рестарта и планирует новый snapshot один раз в сутки в `archive.publish.time`. Следующая дата вычисляется по `ZoneId`, а не как `+24h`, поэтому DST не сдвигает локальную полночь.
|
||||
- `ArchivePublisherService` — state machine: snapshot → локальный файл → Arweave → confirmations → User PDA → Solana finalized → cursor commit.
|
||||
- `ArchivePublisherConfig` — читает настройки. Для Solana RPC отдельного archive URL нет: используется `solana.users.sync.rpcUrl`, затем fallback на `solana.rpcUrl`.
|
||||
- `ShineArchiveWriter` — сериализует бинарный big block `SHINE-ARCHIVE v1.0`, FULL reference table, по одному chunk на `blockchain_name`, footer/hash/signature.
|
||||
- `ArchiveFileNames` — временное и финальное локальные имена.
|
||||
- `ArweaveArchiveService` + `ArweaveMerkle` — Arweave v2 transaction + chunk upload + polling confirmations.
|
||||
- `SolanaArchiveHeadWriter` — обычный `update_user_pda`: root signature + текущая last-block signature + client key fee payer, затем ожидание `finalized`.
|
||||
- `ArchiveKeyLoader` — читает Ed25519 seed/keypair из raw 32/64 bytes, Solana JSON 32/64 или Base64/PKCS8.
|
||||
|
||||
## 2. Локальное состояние PostgreSQL
|
||||
|
||||
Миграция: `SHiNE-server/shine-server-db/src/main/resources/postgres/migration_v22.sql`.
|
||||
|
||||
Таблицы:
|
||||
|
||||
### `archive_chain_cursor`
|
||||
Одна строка на `blockchain_name`. Хранит только **последнее окончательно опубликованное** состояние:
|
||||
|
||||
- последний source block number/hash;
|
||||
- big block number/hash, где находится последний chunk;
|
||||
- offset/size последнего chunk.
|
||||
|
||||
Если blockchain не попала в новый big block, эта строка не меняется.
|
||||
|
||||
### `archive_publish_job`
|
||||
Crash-safe state одной большой публикации и путь к локальному файлу.
|
||||
|
||||
Основные состояния:
|
||||
`SNAPSHOT_CREATED → FILE_BUILT → ARWEAVE_UPLOADED → ARWEAVE_CONFIRMED → SOLANA_SUBMITTED → SOLANA_FINALIZED → CURSORS_COMMITTED`.
|
||||
|
||||
### `archive_publish_job_chain`
|
||||
Frozen range каждой blockchain текущего job + старые и новые координаты chunk. Пока job не finalized, `archive_chain_cursor` не двигается.
|
||||
|
||||
`DatabaseInitializer` автоматически применяет migration v22 при старте существующей БД. Новая БД создаётся уже со схемой v22.
|
||||
|
||||
## 3. Как считается первая дельта
|
||||
|
||||
`ArchivePublisherService.createFrozenJob()` проходит по `BlockchainStateDAO.listAll()`.
|
||||
|
||||
- Если cursor для `blockchain_name` отсутствует: `from = 0`, поэтому первый архив содержит всё локально известное состояние `0..head`.
|
||||
- Если cursor существует: `from = last_archived + 1`.
|
||||
- Перед продолжением проверяется hash cursor-блока.
|
||||
|
||||
Папка `data/archive` сама по себе **не является источником истины** о том, был ли первый архив. Источник истины — БД cursor/job. Поэтому удаление локального файла не приводит к ошибочной повторной полной публикации.
|
||||
|
||||
## 4. Локальный lifecycle файла
|
||||
|
||||
До появления Arweave TX ID:
|
||||
|
||||
`<login>.<00001>.<dd.MM.yy>.tmp.SHiNE-archive`
|
||||
|
||||
После полной успешной загрузки transaction header + chunks в Arweave:
|
||||
|
||||
`<login>.<00001>.<dd.MM.yy>.<ARWEAVE_TX_ID>.SHiNE-archive`
|
||||
|
||||
Дата — реальная дата freeze snapshot в timezone archive publisher-а. Номер начинается с `00001`. Пять цифр — минимальная ширина, а не лимит.
|
||||
|
||||
После rename файл остаётся локально. При crash после сохранения TX ID, но до rename, recovery переименует тот же файл и не загрузит его повторно.
|
||||
|
||||
## 5. User PDA block type `100`
|
||||
|
||||
Содержимое:
|
||||
|
||||
```text
|
||||
u8 block_type = 100
|
||||
u8 block_version = 0
|
||||
bytes[32] archive_tx_id
|
||||
bytes[32] archive_hash
|
||||
```
|
||||
|
||||
Используется существующий `update_user_pda`; отдельной instruction нет.
|
||||
|
||||
Совместимость:
|
||||
- legacy update без archive extension должен сохранить старый archive head;
|
||||
- новый update может заменить/очистить block `100`;
|
||||
- Java/JS codecs и PostgreSQL Solana sync умеют читать новый блок.
|
||||
|
||||
Ключевой Rust-файл: `shine-solana/shine/programs/shine_users/src/lib.rs`.
|
||||
|
||||
## 6. Startup сервера
|
||||
|
||||
`WsServer` после текущего Solana/users sync и inter-server blockchain sync вызывает `ArchivePublisherScheduler.startOrLog()`.
|
||||
|
||||
При `archive.publish.enabled=false` scheduler пишет лог о выключенной функции и больше ничего не делает. Ключи/Arweave wallet на обычном сервере тогда не требуются.
|
||||
|
||||
## 7. Legacy TestFreeAvatar
|
||||
|
||||
Старый временный `TestFreeAvatarArweaveService` больше не является частью активного WS-протокола. Registry/API документация убраны. При наложении changed-files ZIP поверх старого дерева старые исходники физически останутся, поэтому их список для удаления находится в `05_PATCH_CONTENTS_AND_REMOVALS.md`.
|
||||
@@ -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` действительно обновлена этой версией.
|
||||
@@ -0,0 +1,86 @@
|
||||
# Проверка и эксплуатация Archive Publisher
|
||||
|
||||
## Перед ночным тестом
|
||||
|
||||
- [ ] Новый `shine_users` уже развёрнут на том Solana-кластере, который использует сервер.
|
||||
- [ ] Серверный JAR собран из этого пакета.
|
||||
- [ ] БД забэкаплена.
|
||||
- [ ] `archive.publish.enabled=true`.
|
||||
- [ ] `archive.publish.time=00:00`.
|
||||
- [ ] `archive.publish.zoneId` соответствует желаемой локальной полуночи.
|
||||
- [ ] `server.SHiNE.login` соответствует root/client keys.
|
||||
- [ ] Arweave JWK читается пользователем процесса.
|
||||
- [ ] На Arweave wallet достаточно AR.
|
||||
- [ ] `data/archive` доступна на запись.
|
||||
- [ ] В логе есть `Archive publisher включён` и точное время следующего запуска.
|
||||
|
||||
## Во время job
|
||||
|
||||
Нормальная последовательность логов/статусов:
|
||||
|
||||
```text
|
||||
SNAPSHOT_CREATED
|
||||
FILE_BUILT
|
||||
ARWEAVE_UPLOADED
|
||||
ARWEAVE_CONFIRMED
|
||||
SOLANA_SUBMITTED
|
||||
SOLANA_FINALIZED
|
||||
CURSORS_COMMITTED
|
||||
```
|
||||
|
||||
После `FILE_BUILT` существует `.tmp.SHiNE-archive`.
|
||||
После полного Arweave upload имя уже содержит настоящий TX ID.
|
||||
|
||||
## После успешного первого job
|
||||
|
||||
Проверить:
|
||||
|
||||
```bash
|
||||
find data/archive -maxdepth 1 -type f -name '*.SHiNE-archive' -ls
|
||||
```
|
||||
|
||||
```sql
|
||||
SELECT big_block_number, status, local_archive_path, arweave_confirmations
|
||||
FROM archive_publish_job ORDER BY id DESC LIMIT 1;
|
||||
```
|
||||
|
||||
```sql
|
||||
SELECT count(*) AS archived_blockchains FROM archive_chain_cursor;
|
||||
```
|
||||
|
||||
```sql
|
||||
SELECT login, archive_head_tx_id, archive_head_hash
|
||||
FROM solana_user_pda_current
|
||||
WHERE login='<SERVER_LOGIN>';
|
||||
```
|
||||
|
||||
## Проверка второй публикации
|
||||
|
||||
До следующей полуночи добавить несколько новых SHiNE records только в часть blockchain. После следующего job:
|
||||
|
||||
- в новый big block должны попасть только изменившиеся blockchain;
|
||||
- одна blockchain в новом big block должна иметь один chunk независимо от числа новых records;
|
||||
- cursor blockchain, которая не изменилась, должен остаться на старом big block/chunk;
|
||||
- backlink изменившегося chunk должен указывать на предыдущий chunk этой же blockchain;
|
||||
- FULL reference table нового big block должна содержать все предыдущие finalized big blocks.
|
||||
|
||||
## Crash/restart сценарии
|
||||
|
||||
### Restart после FILE_BUILT
|
||||
Должен использоваться тот же frozen job и тот же локальный файл.
|
||||
|
||||
### Restart после ARWEAVE_UPLOADED
|
||||
Не должно быть повторной оплаты/upload. Если TX сохранён, но rename не успел произойти, recovery переименует `.tmp` в имя с TX ID.
|
||||
|
||||
### Restart после SOLANA_FINALIZED
|
||||
При совпадении PDA head с job сервер должен только commit cursors.
|
||||
|
||||
## Обычный сервер без публикации
|
||||
|
||||
Проверить отдельно:
|
||||
|
||||
```properties
|
||||
archive.publish.enabled=false
|
||||
```
|
||||
|
||||
Сервер должен запускаться без Arweave/root/client archive key files и не создавать `archive_publish_job`.
|
||||
@@ -0,0 +1,60 @@
|
||||
# Состав patch-пакета и удаление legacy-файлов
|
||||
|
||||
ZIP `SHINE_archive_changed_files_with_docs.zip` предназначен для распаковки **поверх исходного дерева той версии сервера, из которой он был сделан**. Внутри находятся только новые и изменённые файлы, пути сохранены относительно корня репозитория.
|
||||
|
||||
## Важное ограничение ZIP-overlay
|
||||
|
||||
Распаковка ZIP может добавить/заменить файлы, но не удалит старые. Поэтому после распаковки нужно удалить legacy test-free-avatar исходники ниже. Они больше не зарегистрированы в `JsonHandlerRegistry`, однако физическое удаление сохраняет дерево в точном состоянии новой версии и не оставляет старый тестовый Arweave-код рядом с production archive publisher.
|
||||
|
||||
## Удалить после распаковки
|
||||
|
||||
```text
|
||||
SHiNE-server/shine-server-db/src/main/java/shine/db/dao/TestFreeAvatarUploadsDAO.java
|
||||
SHiNE-server/shine-server-db/src/main/java/shine/db/entities/TestFreeAvatarUploadEntry.java
|
||||
SHiNE-server/shine-server-net-protocol/src/main/java/server/logic/ws_protocol/JSON/handlers/tempToTest/Net_TestGetFreeAvatarQuota_Handler.java
|
||||
SHiNE-server/shine-server-net-protocol/src/main/java/server/logic/ws_protocol/JSON/handlers/tempToTest/Net_TestUploadFreeAvatar_Handler.java
|
||||
SHiNE-server/shine-server-net-protocol/src/main/java/server/logic/ws_protocol/JSON/handlers/tempToTest/TestFreeAvatarArweaveService.java
|
||||
SHiNE-server/shine-server-net-protocol/src/main/java/server/logic/ws_protocol/JSON/handlers/tempToTest/entyties/Net_TestGetFreeAvatarQuota_Request.java
|
||||
SHiNE-server/shine-server-net-protocol/src/main/java/server/logic/ws_protocol/JSON/handlers/tempToTest/entyties/Net_TestGetFreeAvatarQuota_Response.java
|
||||
SHiNE-server/shine-server-net-protocol/src/main/java/server/logic/ws_protocol/JSON/handlers/tempToTest/entyties/Net_TestUploadFreeAvatar_Request.java
|
||||
SHiNE-server/shine-server-net-protocol/src/main/java/server/logic/ws_protocol/JSON/handlers/tempToTest/entyties/Net_TestUploadFreeAvatar_Response.java
|
||||
docs/API/14_Test_Free_Avatar_Upload_API.md
|
||||
```
|
||||
|
||||
Linux-команда из корня репозитория:
|
||||
|
||||
```bash
|
||||
rm -f \
|
||||
'SHiNE-server/shine-server-db/src/main/java/shine/db/dao/TestFreeAvatarUploadsDAO.java' \
|
||||
'SHiNE-server/shine-server-db/src/main/java/shine/db/entities/TestFreeAvatarUploadEntry.java' \
|
||||
'SHiNE-server/shine-server-net-protocol/src/main/java/server/logic/ws_protocol/JSON/handlers/tempToTest/Net_TestGetFreeAvatarQuota_Handler.java' \
|
||||
'SHiNE-server/shine-server-net-protocol/src/main/java/server/logic/ws_protocol/JSON/handlers/tempToTest/Net_TestUploadFreeAvatar_Handler.java' \
|
||||
'SHiNE-server/shine-server-net-protocol/src/main/java/server/logic/ws_protocol/JSON/handlers/tempToTest/TestFreeAvatarArweaveService.java' \
|
||||
'SHiNE-server/shine-server-net-protocol/src/main/java/server/logic/ws_protocol/JSON/handlers/tempToTest/entyties/Net_TestGetFreeAvatarQuota_Request.java' \
|
||||
'SHiNE-server/shine-server-net-protocol/src/main/java/server/logic/ws_protocol/JSON/handlers/tempToTest/entyties/Net_TestGetFreeAvatarQuota_Response.java' \
|
||||
'SHiNE-server/shine-server-net-protocol/src/main/java/server/logic/ws_protocol/JSON/handlers/tempToTest/entyties/Net_TestUploadFreeAvatar_Request.java' \
|
||||
'SHiNE-server/shine-server-net-protocol/src/main/java/server/logic/ws_protocol/JSON/handlers/tempToTest/entyties/Net_TestUploadFreeAvatar_Response.java' \
|
||||
'docs/API/14_Test_Free_Avatar_Upload_API.md'
|
||||
```
|
||||
|
||||
## Что пакет принципиально добавляет
|
||||
|
||||
- новый Gradle module `shine-server-archive`;
|
||||
- migration/schema v22;
|
||||
- archive state DAO/entities;
|
||||
- server startup scheduler;
|
||||
- Arweave chunk uploader;
|
||||
- Solana User PDA writer;
|
||||
- PDA block type `100` в Rust/Java/JS;
|
||||
- обновлённую документацию формата User PDA;
|
||||
- отдельную папку `docs/Archive/` с полным protocol/deploy/runbook.
|
||||
|
||||
## После overlay + удаления
|
||||
|
||||
Минимально проверить:
|
||||
|
||||
```bash
|
||||
./gradlew shadowJar
|
||||
```
|
||||
|
||||
И отдельно собрать/задеплоить изменённую Solana `shine_users` согласно `03_DEPLOY_TEST_SERVER.md`.
|
||||
@@ -0,0 +1,73 @@
|
||||
# Manifest changed/new files
|
||||
|
||||
Основа сравнения: последний исходный ZIP пользователя, на который рассчитан этот пакет.
|
||||
|
||||
- Изменённых файлов: 20
|
||||
- Новых файлов до добавления этого manifest: 25
|
||||
- Удаляемых legacy-файлов: 10
|
||||
|
||||
## Изменённые файлы
|
||||
|
||||
- `SHiNE-server/shine-server-config/src/main/java/utils/config/AppConfig.java`
|
||||
- `SHiNE-server/shine-server-db/src/main/java/shine/db/DatabaseInitializer.java`
|
||||
- `SHiNE-server/shine-server-db/src/main/resources/postgres/schema_v1.sql`
|
||||
- `SHiNE-server/shine-server-net-protocol/src/main/java/server/logic/ws_protocol/JSON/JsonHandlerRegistry.java`
|
||||
- `SHiNE-server/shine-server-solana-users-sync/src/main/java/sync/codec/ShineUsersCodec.java`
|
||||
- `SHiNE-server/shine-server-solana-users-sync/src/main/java/sync/storage/postgres/PostgresStorageRepository.java`
|
||||
- `SHiNE-server/src/main/java/server/ws/WsServer.java`
|
||||
- `SHiNE-server/src/main/resources/application.properties`
|
||||
- `build.gradle`
|
||||
- `docs/API/09_Operations_Index.md`
|
||||
- `docs/SHINE_ARCHIVE_PROTOCOL_v1.0_RU.md`
|
||||
- `docs/SHINE_ARCHIVE_PROTOCOL_v1.0_RU_FINAL.md`
|
||||
- `docs/Solana/user_pda/README.md`
|
||||
- `docs/Solana_Architecture/details/shine_users.md`
|
||||
- `settings.gradle`
|
||||
- `shine-UI/js/services/auth-service.js`
|
||||
- `shine-UI/js/services/shine-user-pda-service.js`
|
||||
- `shine-solana/shine/doc/formats/shine-user-pda-format-v.1.0.md`
|
||||
- `shine-solana/shine/doc/programs/shine_users.md`
|
||||
- `shine-solana/shine/programs/shine_users/src/lib.rs`
|
||||
|
||||
## Новые файлы
|
||||
|
||||
- `SHiNE-server/shine-server-archive/build.gradle`
|
||||
- `SHiNE-server/shine-server-archive/src/main/java/server/archive/ArchiveFileNames.java`
|
||||
- `SHiNE-server/shine-server-archive/src/main/java/server/archive/ArchiveKeyLoader.java`
|
||||
- `SHiNE-server/shine-server-archive/src/main/java/server/archive/ArchivePublisherConfig.java`
|
||||
- `SHiNE-server/shine-server-archive/src/main/java/server/archive/ArchivePublisherScheduler.java`
|
||||
- `SHiNE-server/shine-server-archive/src/main/java/server/archive/ArchivePublisherService.java`
|
||||
- `SHiNE-server/shine-server-archive/src/main/java/server/archive/ArweaveArchiveService.java`
|
||||
- `SHiNE-server/shine-server-archive/src/main/java/server/archive/ArweaveMerkle.java`
|
||||
- `SHiNE-server/shine-server-archive/src/main/java/server/archive/ShineArchiveWriter.java`
|
||||
- `SHiNE-server/shine-server-archive/src/main/java/server/archive/SolanaArchiveHeadWriter.java`
|
||||
- `SHiNE-server/shine-server-archive/src/test/java/server/archive/ArchiveFileNamesTest.java`
|
||||
- `SHiNE-server/shine-server-archive/src/test/java/server/archive/ShineArchiveWriterTest.java`
|
||||
- `SHiNE-server/shine-server-db/src/main/java/shine/db/archive/ArchiveBigBlockRef.java`
|
||||
- `SHiNE-server/shine-server-db/src/main/java/shine/db/archive/ArchiveChainCursor.java`
|
||||
- `SHiNE-server/shine-server-db/src/main/java/shine/db/archive/ArchivePublishJob.java`
|
||||
- `SHiNE-server/shine-server-db/src/main/java/shine/db/archive/ArchivePublishJobChain.java`
|
||||
- `SHiNE-server/shine-server-db/src/main/java/shine/db/dao/ArchivePublicationDAO.java`
|
||||
- `SHiNE-server/shine-server-db/src/main/resources/postgres/migration_v22.sql`
|
||||
- `docs/Archive/01_PROTOCOL_v1.0.md`
|
||||
- `docs/Archive/02_IMPLEMENTATION_MAP.md`
|
||||
- `docs/Archive/03_DEPLOY_TEST_SERVER.md`
|
||||
- `docs/Archive/04_TEST_AND_OPERATIONS.md`
|
||||
- `docs/Archive/05_PATCH_CONTENTS_AND_REMOVALS.md`
|
||||
- `docs/Archive/README.md`
|
||||
- `docs/Archive/archive-publisher.example.properties`
|
||||
|
||||
## Legacy-файлы, которые ZIP сам не удаляет
|
||||
|
||||
- `SHiNE-server/shine-server-db/src/main/java/shine/db/dao/TestFreeAvatarUploadsDAO.java`
|
||||
- `SHiNE-server/shine-server-db/src/main/java/shine/db/entities/TestFreeAvatarUploadEntry.java`
|
||||
- `SHiNE-server/shine-server-net-protocol/src/main/java/server/logic/ws_protocol/JSON/handlers/tempToTest/Net_TestGetFreeAvatarQuota_Handler.java`
|
||||
- `SHiNE-server/shine-server-net-protocol/src/main/java/server/logic/ws_protocol/JSON/handlers/tempToTest/Net_TestUploadFreeAvatar_Handler.java`
|
||||
- `SHiNE-server/shine-server-net-protocol/src/main/java/server/logic/ws_protocol/JSON/handlers/tempToTest/TestFreeAvatarArweaveService.java`
|
||||
- `SHiNE-server/shine-server-net-protocol/src/main/java/server/logic/ws_protocol/JSON/handlers/tempToTest/entyties/Net_TestGetFreeAvatarQuota_Request.java`
|
||||
- `SHiNE-server/shine-server-net-protocol/src/main/java/server/logic/ws_protocol/JSON/handlers/tempToTest/entyties/Net_TestGetFreeAvatarQuota_Response.java`
|
||||
- `SHiNE-server/shine-server-net-protocol/src/main/java/server/logic/ws_protocol/JSON/handlers/tempToTest/entyties/Net_TestUploadFreeAvatar_Request.java`
|
||||
- `SHiNE-server/shine-server-net-protocol/src/main/java/server/logic/ws_protocol/JSON/handlers/tempToTest/entyties/Net_TestUploadFreeAvatar_Response.java`
|
||||
- `docs/API/14_Test_Free_Avatar_Upload_API.md`
|
||||
|
||||
Подробная команда удаления находится в `05_PATCH_CONTENTS_AND_REMOVALS.md`.
|
||||
@@ -0,0 +1,28 @@
|
||||
# SHiNE Archive Publisher — документация
|
||||
|
||||
Эта папка — **актуальная точка входа** для механизма серверной архивации SHiNE в Arweave с фиксацией archive head в Solana User PDA.
|
||||
|
||||
Если задачу выполняет другая нейронка/агент, читать документы нужно в таком порядке:
|
||||
|
||||
1. `01_PROTOCOL_v1.0.md` — бинарный формат `SHINE-ARCHIVE`, big-block references, `UserBlockchainChunk`, подписи, PDA block `100`, crash-safety.
|
||||
2. `02_IMPLEMENTATION_MAP.md` — как спецификация разложена по Java/Rust/JS/SQL файлам текущего проекта.
|
||||
3. `03_DEPLOY_TEST_SERVER.md` — полный порядок установки на тестовый сервер, включая обязательный апгрейд `shine_users`, конфиг, ключи, сборку и запуск.
|
||||
4. `04_TEST_AND_OPERATIONS.md` — что проверять до полуночи, после полуночи и при сбоях.
|
||||
5. `05_PATCH_CONTENTS_AND_REMOVALS.md` — какие файлы содержит пакет и какие legacy test-free-avatar файлы нужно удалить при наложении ZIP поверх старого исходника.
|
||||
6. `archive-publisher.example.properties` — минимальный конфиг архиватора.
|
||||
|
||||
## Коротко
|
||||
|
||||
- Архиватор **по умолчанию выключен**: `archive.publish.enabled=false`.
|
||||
- При включении создаёт новый snapshot **один раз в сутки в заданное локальное время**, по умолчанию `00:00`.
|
||||
- При первом успешном запуске, когда архивных курсоров ещё нет, в первый big block попадает **всё локально известное состояние всех blockchain, начиная с source block 0**.
|
||||
- Далее публикуется только дельта.
|
||||
- Один `blockchain_name` в одном big block представлен максимум одним `UserBlockchainChunk`; внутри него лежат все новые raw SHiNE records этой цепочки.
|
||||
- В конце chunk одна ссылка на предыдущий chunk этой же blockchain. Если blockchain в текущем big block отсутствует, её cursor/head не меняется.
|
||||
- Готовый файл сначала существует локально как `<login>.<00001>.<dd.MM.yy>.tmp.SHiNE-archive`. После успешной загрузки в Arweave он переименовывается в `<login>.<00001>.<dd.MM.yy>.<REAL_ARWEAVE_TX_ID>.SHiNE-archive` и остаётся локально.
|
||||
- После Arweave confirmations обычным `update_user_pda` обновляется PDA block type `100`: `archive_tx_id[32] + archive_hash[32]`.
|
||||
- Cursor commit выполняется только после Solana `finalized`.
|
||||
|
||||
## Важно перед тестом
|
||||
|
||||
Изменён формат/парсер `shine_users`. **Нельзя просто заменить серверный JAR и включить archive publisher, если целевая Solana-программа `shine_users` ещё не обновлена кодом из этого пакета.** Сначала обновить программу на нужном кластере, затем сервер.
|
||||
@@ -0,0 +1,23 @@
|
||||
# Минимальный пример для archive-capable сервера.
|
||||
# Добавлять во внешний application.properties; существующие DB/Solana/server настройки не удалять.
|
||||
|
||||
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 RPC НЕ задаётся.
|
||||
# Используется solana.users.sync.rpcUrl, иначе solana.rpcUrl.
|
||||
archive.solana.rootKeyPath=/home/player/SHiNE/secrets/server-root.key
|
||||
archive.solana.clientKeyPath=/home/player/SHiNE/secrets/server-client.key
|
||||
# Эти файлы могут содержать Base58 seed 32 bytes или Base58 Solana secret key 64 bytes.
|
||||
archive.solana.confirmPollSeconds=5
|
||||
archive.solana.confirmTimeoutMinutes=30
|
||||
archive.solana.commitment=finalized
|
||||
Reference in New Issue
Block a user