SHA256
157 lines
7.3 KiB
Markdown
157 lines
7.3 KiB
Markdown
# ANS-104 / Arweave transport для пользовательских блоков SHiNE
|
|
|
|
## Цель
|
|
|
|
Каждый пользовательский блок SHiNE уже на клиенте является самостоятельным подписанным ANS-104 DataItem. Сервер проверяет и хранит **точно эти signed bytes** и может публиковать их одним из двух транспортов: через Turbo по одному DataItem либо через прямую Arweave L1-транзакцию в составе стандартного большого ANS-104 bundle.
|
|
|
|
Способ публикации — локальная политика конкретного сервера. Формат пользовательского блока и импорт от него не зависят.
|
|
|
|
## User DataItem tags
|
|
|
|
Для тестового контура обязательно:
|
|
|
|
```text
|
|
App=test5590
|
|
```
|
|
|
|
Для блоков конкретного канала дополнительно:
|
|
|
|
```text
|
|
c_test5590=<canonical_channel_slug>
|
|
```
|
|
|
|
Теги входят в ANS-104 подпись пользователя. Старый тестовый тег `c` новым кодом не создаётся и не принимается как channel tag.
|
|
|
|
## Publisher modes
|
|
|
|
Настройка:
|
|
|
|
```text
|
|
arweave.blocks.publish.mode=turbo | arweave | none
|
|
```
|
|
|
|
### `turbo`
|
|
|
|
```text
|
|
blocks.arweave_publish_pending=true
|
|
↓
|
|
готовый signed user DataItem из blocks.block_bytes
|
|
↓
|
|
POST в Turbo как application/octet-stream
|
|
↓
|
|
Turbo bundling / Arweave
|
|
```
|
|
|
|
DataItem **не переподписывается** сервером. Его `data_item_id = SHA-256(user signature)` до и после загрузки должен оставаться тем же.
|
|
|
|
Для Turbo можно задать публичный payer address напрямую:
|
|
|
|
```text
|
|
arweave.blocks.publish.turbo.paidByAddress=...
|
|
```
|
|
|
|
либо путь к серверному Arweave JWK:
|
|
|
|
```text
|
|
arweave.blocks.publish.turbo.walletJwkPath=/path/to/server-turbo-wallet.json
|
|
```
|
|
|
|
Из JWK локально вычисляется только публичный Arweave address для `x-paid-by`; приватный ключ Turbo upload endpoint не получает.
|
|
|
|
Важно: если upload уже требует оплаты, а signed DataItem принадлежит другому signer, Turbo Credits серверного кошелька используются через Credit Share Approval в пользу signer-адреса. Для маленьких DataItem, попадающих под действующий free tier Turbo, payer может не понадобиться. Код не должен рассчитывать на вечное существование free tier: HTTP `402` считается ошибкой оплаты и блок остаётся pending.
|
|
|
|
### `arweave`
|
|
|
|
Сохраняется прежний fallback:
|
|
|
|
```text
|
|
pending user DataItems
|
|
↓
|
|
standard ANS-104 binary bundle
|
|
↓
|
|
server Arweave RSA/JWK signature
|
|
↓
|
|
Arweave L1
|
|
```
|
|
|
|
Root transaction содержит только стандартные bundle tags:
|
|
|
|
```text
|
|
Bundle-Format=binary
|
|
Bundle-Version=2.0.0
|
|
Content-Type=application/octet-stream
|
|
```
|
|
|
|
Специальный `App=test5590-batch` больше не используется. Важны вложенные user DataItems, у которых уже есть `App=test5590`.
|
|
|
|
### `none`
|
|
|
|
Сервер принимает и хранит блоки локально, но publisher не отправляет их в Arweave/Turbo. Importer при этом может работать независимо.
|
|
|
|
## Состояние публикации в БД
|
|
|
|
После успешной публикации:
|
|
|
|
- `arweave_publish_pending=false`;
|
|
- заполняется `arweave_published_at_ms`.
|
|
|
|
`arweave_root_tx_id` больше не хранится: один и тот же пользовательский DataItem может быть физически упакован разными bundler-ами, а стабильным сетевым идентификатором SHiNE является именно `data_item_id`.
|
|
|
|
## Importer: только individual DataItems
|
|
|
|
Importer всегда выполняет один discovery-запрос:
|
|
|
|
```text
|
|
App=test5590
|
|
```
|
|
|
|
Он **не ищет root bundles** и не зависит от `publish.mode`.
|
|
|
|
Это одинаково работает для:
|
|
|
|
- DataItem, отправленного через Turbo;
|
|
- DataItem, находящегося внутри большого direct-Arweave ANS-104 bundle сервера.
|
|
|
|
После того как AR.IO gateway распаковал/indexed bundle, child DataItem присутствует в GraphQL как отдельная сущность со своим `id` и собственными tags.
|
|
|
|
### Получение полного signed DataItem
|
|
|
|
Обычная выдача DataItem по gateway URL может представлять только payload, а SHiNE для криптографической проверки нужны полные serialized ANS-104 bytes.
|
|
|
|
Поэтому importer:
|
|
|
|
1. получает `data_item_id` через GraphQL `App=test5590`;
|
|
2. запрашивает `GET /ar-io/offsets/{data_item_id}`;
|
|
3. получает `rootTxId`, `rootOffset`, `size`;
|
|
4. делает range-read `GET /raw/{rootTxId}` ровно по этому диапазону;
|
|
5. разбирает полученные bytes как `Ans104DataItem`;
|
|
6. проверяет, что `SHA-256(signature) == data_item_id`;
|
|
7. проверяет Ed25519 ANS-104 signature;
|
|
8. определяет пользователя по `owner`;
|
|
9. импортирует через обычную логику `AddBlock` без повторной публикации.
|
|
|
|
Если GraphQL уже увидел DataItem, но gateway ещё не подготовил offsets, checkpoint не продвигается за этот height и DataItem будет повторён в следующем цикле.
|
|
|
|
## Очередь и порядок блоков
|
|
|
|
`arweave_block_import_queue` хранит:
|
|
|
|
- `data_item_id`;
|
|
- `block_height`;
|
|
- полный `raw_data_item`;
|
|
- status/error/timestamps.
|
|
|
|
`root_tx_id` очереди больше не нужен.
|
|
|
|
Если block N+1 увиден раньше N, он остаётся `PENDING`; после появления предыдущего блока очередь повторно проигрывается.
|
|
|
|
## Дедупликация
|
|
|
|
`blocks.data_item_id` уникален. Один signed DataItem остаётся одним логическим SHiNE-блоком независимо от того, сколько серверов или bundler-ов физически включили его в Arweave.
|
|
|
|
Импортированный блок записывается через `AddBlock` с отключённой повторной публикацией, поэтому серверы не создают цикл переархивирования.
|
|
|
|
## Локальное хранение
|
|
|
|
Полный serialized signed DataItem хранится в `blocks.block_bytes` PostgreSQL. Пользовательские `.bch`-файлы не являются источником истины.
|