Files
SHiNE-server/docs/Archive/02_IMPLEMENTATION_MAP.md

138 lines
7.9 KiB
Markdown
Raw Permalink 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
Этот документ связывает протокол с конкретными файлами проекта. Он нужен, чтобы другой агент мог быстро понять, где искать каждую часть реализации.
## 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`.
## Trusted importer / location index / Viewer
Server importer:
```text
shine-server-archive/src/main/java/server/archive/ArchiveImportConfig.java
shine-server-archive/src/main/java/server/archive/ArchiveImportScheduler.java
shine-server-archive/src/main/java/server/archive/ArchiveImportService.java
shine-server-archive/src/main/java/server/archive/ShineArchiveReader.java
```
Database:
```text
shine-server-db/src/main/java/shine/db/dao/ArchiveImportDAO.java
shine-server-db/src/main/java/shine/db/archive/ArchiveBlockchainLocation.java
shine-server-db/src/main/java/shine/db/archive/ArchivePublisherHead.java
shine-server-db/src/main/resources/postgres/migration_v23.sql
shine-server-solana-users-sync/src/main/java/sync/storage/postgres/PostgresStorageRepository.java
```
`PostgresStorageRepository` сохраняет `archive_imported=true` при повторном sync того же head и автоматически сбрасывает флаг в `false`, если `archive_head_tx_id` или `archive_head_hash` изменились.
WS API:
```text
GetArchiveBlockchainLocation
```
UI:
```text
shine-UI/js/pages/blockchain-archive-view.js
shine-UI/Blockchain-Viewer.html
```
`Blockchain-Viewer.html` получает `tx + offset + size + blockchain`, идёт назад по `PreviousBlockchainChunkRef` и использует существующий parser каналов старого Viewer-а.