SHA256
Новая схема работы Arweave через Turbo
This commit is contained in:
@@ -82,7 +82,7 @@ App = test5590
|
||||
Если блок относится к конкретному каналу, он дополнительно содержит:
|
||||
|
||||
```text
|
||||
c = <canonical_channel_slug>
|
||||
c_test5590 = <canonical_channel_slug>
|
||||
```
|
||||
|
||||
Slug входит в подпись DataItem и не может быть изменён сервером после подписи.
|
||||
@@ -107,7 +107,7 @@ Slug входит в подпись DataItem и не может быть изм
|
||||
|
||||
1. распарсить полный ANS-104 DataItem;
|
||||
2. проверить `App=test5590`;
|
||||
3. проверить `c`, если тип блока требует канал;
|
||||
3. проверить `c_test5590`, если тип блока требует канал;
|
||||
4. проверить ANS-104 Ed25519 подпись;
|
||||
5. проверить, что `owner` равен текущему blockchain public key пользователя;
|
||||
6. распарсить Frame v1 и body;
|
||||
|
||||
@@ -2,96 +2,155 @@
|
||||
|
||||
## Цель
|
||||
|
||||
Каждый пользовательский блок уже на клиенте является самостоятельным подписанным ANS-104 DataItem. Сервер не переподписывает пользовательский контент: он проверяет его, хранит в PostgreSQL и объединяет готовые DataItems в стандартный ANS-104 bundle.
|
||||
Каждый пользовательский блок SHiNE уже на клиенте является самостоятельным подписанным ANS-104 DataItem. Сервер проверяет и хранит **точно эти signed bytes** и может публиковать их одним из двух транспортов: через Turbo по одному DataItem либо через прямую Arweave L1-транзакцию в составе стандартного большого ANS-104 bundle.
|
||||
|
||||
## Child DataItem tags
|
||||
Способ публикации — локальная политика конкретного сервера. Формат пользовательского блока и импорт от него не зависят.
|
||||
|
||||
Обязательно для тестового контура:
|
||||
## User DataItem tags
|
||||
|
||||
Для тестового контура обязательно:
|
||||
|
||||
```text
|
||||
App=test5590
|
||||
```
|
||||
|
||||
Дополнительно для блоков конкретного канала:
|
||||
Для блоков конкретного канала дополнительно:
|
||||
|
||||
```text
|
||||
c=<canonical_channel_slug>
|
||||
c_test5590=<canonical_channel_slug>
|
||||
```
|
||||
|
||||
Теги входят в ANS-104 подпись пользователя.
|
||||
Теги входят в ANS-104 подпись пользователя. Старый тестовый тег `c` новым кодом не создаётся и не принимается как channel tag.
|
||||
|
||||
## Publisher
|
||||
## Publisher modes
|
||||
|
||||
По умолчанию цикл — раз в 15 минут.
|
||||
Настройка:
|
||||
|
||||
```text
|
||||
arweave.blocks.publish.mode=turbo | arweave | none
|
||||
```
|
||||
|
||||
### `turbo`
|
||||
|
||||
```text
|
||||
blocks.arweave_publish_pending=true
|
||||
↓
|
||||
готовые serialized DataItems
|
||||
готовый signed user DataItem из blocks.block_bytes
|
||||
↓
|
||||
ANS-104 binary bundle
|
||||
POST в Turbo как application/octet-stream
|
||||
↓
|
||||
обычная Arweave L1 transaction
|
||||
Turbo bundling / Arweave
|
||||
```
|
||||
|
||||
Если pending-блоков нет, транзакция не создаётся.
|
||||
DataItem **не переподписывается** сервером. Его `data_item_id = SHA-256(user signature)` до и после загрузки должен оставаться тем же.
|
||||
|
||||
Root transaction содержит стандартные bundle tags:
|
||||
Для 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
|
||||
```
|
||||
|
||||
`App=test5590-batch` намеренно отличается от child `App=test5590`, чтобы discovery-запрос находил пользовательские блоки, а не root bundles.
|
||||
Специальный `App=test5590-batch` больше не используется. Важны вложенные user DataItems, у которых уже есть `App=test5590`.
|
||||
|
||||
После успешной L1-загрузки сервер ставит child-блокам:
|
||||
### `none`
|
||||
|
||||
Сервер принимает и хранит блоки локально, но publisher не отправляет их в Arweave/Turbo. Importer при этом может работать независимо.
|
||||
|
||||
## Состояние публикации в БД
|
||||
|
||||
После успешной публикации:
|
||||
|
||||
- `arweave_publish_pending=false`;
|
||||
- `arweave_published_at_ms`;
|
||||
- `arweave_root_tx_id`.
|
||||
- заполняется `arweave_published_at_ms`.
|
||||
|
||||
## Importer
|
||||
`arweave_root_tx_id` больше не хранится: один и тот же пользовательский DataItem может быть физически упакован разными bundler-ами, а стабильным сетевым идентификатором SHiNE является именно `data_item_id`.
|
||||
|
||||
Каждый сервер может независимо искать:
|
||||
## Importer: только individual DataItems
|
||||
|
||||
Importer всегда выполняет один discovery-запрос:
|
||||
|
||||
```text
|
||||
App=test5590
|
||||
```
|
||||
|
||||
через GraphQL gateway с cursor pagination.
|
||||
Он **не ищет root bundles** и не зависит от `publish.mode`.
|
||||
|
||||
Для каждого нового DataItem:
|
||||
Это одинаково работает для:
|
||||
|
||||
1. взять `id` и `bundledIn.id`;
|
||||
2. получить root bundle;
|
||||
3. извлечь точные serialized bytes child DataItem по bundle index;
|
||||
4. проверить `dataItemId == SHA256(signature)`;
|
||||
5. проверить ANS-104 Ed25519 подпись;
|
||||
6. определить пользователя по `owner`;
|
||||
7. применить обычные проверки `AddBlock`;
|
||||
8. записать в PostgreSQL с `arweave_publish_pending=false`.
|
||||
- DataItem, отправленного через Turbo;
|
||||
- DataItem, находящегося внутри большого direct-Arweave ANS-104 bundle сервера.
|
||||
|
||||
### Блоки могут прийти не по порядку
|
||||
После того как AR.IO gateway распаковал/indexed bundle, child DataItem присутствует в GraphQL как отдельная сущность со своим `id` и собственными tags.
|
||||
|
||||
Discovery/import использует persistent queue `arweave_block_import_queue`. Если, например, block 102 увиден раньше block 101, block 102 остаётся `PENDING`; после появления 101 очередь повторно проигрывается.
|
||||
### Получение полного signed DataItem
|
||||
|
||||
## Дедупликация и несколько серверов
|
||||
Обычная выдача DataItem по gateway URL может представлять только payload, а SHiNE для криптографической проверки нужны полные serialized ANS-104 bytes.
|
||||
|
||||
Один и тот же готовый DataItem имеет один `data_item_id = SHA256(signature)`. Если несколько серверов включили его в разные root bundles, локально это всё равно один логический блок: `blocks.data_item_id` уникален.
|
||||
Поэтому importer:
|
||||
|
||||
Импортированный из Arweave блок **не ставится обратно в publish queue**. Это предотвращает бесконечное переархивирование между серверами.
|
||||
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` с отключённой повторной публикацией, поэтому серверы не создают цикл переархивирования.
|
||||
|
||||
## Локальное хранение
|
||||
|
||||
Пользовательские blockchain-файлы на диске больше не используются. Полный serialized DataItem находится в `blocks.block_bytes` PostgreSQL.
|
||||
|
||||
## Настройки
|
||||
|
||||
См. `application.properties` и `CODEX_APPLY_ANS104_TEST5590_PATCH.md`.
|
||||
|
||||
## Что намеренно не входит в этот патч
|
||||
|
||||
Remote/homeserver signing path, связанный с внешним homeserver/ESP32 signer, не мигрируется этим патчем. Каталог `ESP32/` не изменяется. До отдельной миграции новый Frame v1/ANS-104 production path рассчитан на клиент, у которого локально доступен blockchain Ed25519 key.
|
||||
Полный serialized signed DataItem хранится в `blocks.block_bytes` PostgreSQL. Пользовательские `.bch`-файлы не являются источником истины.
|
||||
|
||||
@@ -1,5 +1,13 @@
|
||||
# История изменений документации блокчейна
|
||||
|
||||
## 2026-09-23 — Turbo transport для individual ANS-104 DataItems
|
||||
- Базовый коммит-ориентир: `3483a0a`; изменения подготовлены как patch без нового git-коммита.
|
||||
- Publisher получил режимы `turbo | arweave | none`: Turbo отправляет каждый исходный user-signed DataItem отдельно, direct Arweave fallback сохраняет standard ANS-104 bundle, `none` отключает внешнюю публикацию.
|
||||
- Удалён технический namespace `App=test5590-batch`: importer всегда ищет только individual `App=test5590` DataItems независимо от способа их физической упаковки.
|
||||
- Channel tag тестового контура изменён с `c` на `c_test5590`; новый тег является частью пользовательской ANS-104 подписи.
|
||||
- Importer получает точные serialized signed DataItem bytes через AR.IO offsets + range-read root transaction и проверяет `data_item_id`/Ed25519 signature перед `AddBlock`.
|
||||
- Из PostgreSQL удалены `blocks.arweave_root_tx_id` и `arweave_block_import_queue.root_tx_id`; добавлена migration v25.
|
||||
|
||||
## 2026-09-23 — Тестовые каналы и Arweave-only синхронизация
|
||||
- Базовый коммит-ориентир: `3483a0a`.
|
||||
- Добавлены тестовые каналы и publisher для генерации пользовательских POST-блоков через обычный `AddBlock`.
|
||||
|
||||
@@ -1,108 +1,79 @@
|
||||
# Инструкция Codex: применить ANS-104 test5590 patch
|
||||
# Применение patch: Turbo + direct Arweave для `App=test5590`
|
||||
|
||||
## Цель
|
||||
## Что меняется
|
||||
|
||||
Перевести пользовательский blockchain SHiNE на Frame v1 внутри готовых ANS-104 DataItems и убрать старый SHINE-ARCHIVE/файловое хранение цепочек.
|
||||
- `arweave.blocks.publish.mode=turbo|arweave|none` вместо boolean publisher switch.
|
||||
- `turbo`: каждый готовый user-signed ANS-104 DataItem отправляется в Turbo отдельно.
|
||||
- `arweave`: сохранён прямой L1 fallback — несколько user DataItems собираются в standard ANS-104 bundle.
|
||||
- `none`: наружу ничего не публикуется.
|
||||
- Importer всегда ищет только individual `App=test5590` DataItems.
|
||||
- `App=test5590-batch` больше не используется.
|
||||
- Channel tag: `c_test5590=<canonical_channel_slug>` вместо `c=...`.
|
||||
- Удалены `blocks.arweave_root_tx_id` и `arweave_block_import_queue.root_tx_id`.
|
||||
- Схема PostgreSQL: v25.
|
||||
|
||||
## Жёсткое ограничение
|
||||
|
||||
**Не изменять ничего в `ESP32/`.** В этом patch нет ни одного файла `ESP32/**`.
|
||||
|
||||
Remote/homeserver signer, завязанный на устройство, намеренно не мигрирован. Не пытаться «заодно исправить» его в рамках этого patch.
|
||||
|
||||
## Применение
|
||||
|
||||
1. Распаковать patch поверх корня репозитория, сохраняя относительные пути.
|
||||
2. Удалить все пути из корневого `DELETE_FILES.txt`.
|
||||
3. Проверить, что `git diff -- ESP32` пуст.
|
||||
4. Использовать чистую/dev test DB. `migration_v24.sql` намеренно откажется мигрировать непустую blockchain DB, потому что backward compatibility со старым block format не требуется.
|
||||
|
||||
## Arweave config
|
||||
|
||||
Минимально для публикации:
|
||||
## Минимальная настройка Turbo
|
||||
|
||||
```properties
|
||||
arweave.blocks.publish.enabled=true
|
||||
arweave.blocks.publish.intervalMinutes=15
|
||||
arweave.blocks.publish.gateway=https://arweave.net
|
||||
arweave.blocks.publish.walletJwkPath=/ABSOLUTE/SECRET/PATH/arweave-wallet.json
|
||||
arweave.blocks.publish.mode=turbo
|
||||
arweave.blocks.publish.turbo.uploadUrl=https://turbo.ardrive.io/tx
|
||||
```
|
||||
|
||||
JWK не коммитить.
|
||||
Для действующего free tier маленьких DataItem этого может быть достаточно.
|
||||
|
||||
Для discovery/import:
|
||||
Если upload платный и расходы должны идти с server Turbo Credits:
|
||||
|
||||
```properties
|
||||
arweave.blocks.publish.turbo.walletJwkPath=/home/player/SHiNE/secrets/turbo-wallet.json
|
||||
# либо вместо JWK сразу публичный адрес:
|
||||
# arweave.blocks.publish.turbo.paidByAddress=<server payer address>
|
||||
```
|
||||
|
||||
JWK не отправляется Turbo: из него вычисляется публичный address для `x-paid-by`.
|
||||
Для чужого signed DataItem платные Turbo Credits требуют действующего Credit Share Approval от server payer к signer-адресу DataItem. Если его нет, Turbo вернёт HTTP 402, а блок останется pending для повторной попытки.
|
||||
|
||||
## Direct Arweave fallback
|
||||
|
||||
```properties
|
||||
arweave.blocks.publish.mode=arweave
|
||||
arweave.blocks.publish.walletJwkPath=/home/player/SHiNE/secrets/arweave-wallet.json
|
||||
arweave.blocks.publish.gateway=https://arweave.net
|
||||
```
|
||||
|
||||
Root bundle больше не получает `App=test5590-batch`; child DataItems уже содержат `App=test5590` и именно их индексирует importer.
|
||||
|
||||
## Отключение публикации
|
||||
|
||||
```properties
|
||||
arweave.blocks.publish.mode=none
|
||||
```
|
||||
|
||||
Это не отключает `arweave.blocks.sync.enabled`: read/import и publish независимы.
|
||||
|
||||
## Importer
|
||||
|
||||
```properties
|
||||
arweave.blocks.sync.enabled=true
|
||||
arweave.blocks.sync.intervalMinutes=15
|
||||
arweave.blocks.sync.gateway=https://turbo-gateway.com
|
||||
arweave.blocks.sync.startBlockHeight=0
|
||||
arweave.blocks.sync.maxDataItemBytes=8388608
|
||||
```
|
||||
|
||||
На тестах желательно установить `startBlockHeight` на высоту начала `test5590`, чтобы не сканировать лишнюю историю.
|
||||
Importer:
|
||||
|
||||
## Test namespace
|
||||
1. GraphQL `App=test5590`;
|
||||
2. `/ar-io/offsets/<dataItemId>`;
|
||||
3. range `GET /raw/<rootTxId>`;
|
||||
4. проверка exact signed DataItem ID + signature;
|
||||
5. обычный `AddBlock` import.
|
||||
|
||||
Child DataItem:
|
||||
## Миграция БД
|
||||
|
||||
```text
|
||||
App=test5590
|
||||
```
|
||||
При старте schema v24 автоматически применит `migration_v25.sql`, которая удаляет два root-tx поля и ставит version 25.
|
||||
|
||||
Channel child:
|
||||
## Проверка после применения
|
||||
|
||||
```text
|
||||
App=test5590
|
||||
c=<canonical_channel_slug>
|
||||
```
|
||||
|
||||
Root bundle:
|
||||
|
||||
```text
|
||||
Bundle-Format=binary
|
||||
Bundle-Version=2.0.0
|
||||
App=test5590-batch
|
||||
```
|
||||
|
||||
Перед production-start test namespace должен быть заменён отдельным осознанным изменением.
|
||||
|
||||
## Проверки после применения
|
||||
|
||||
Из корня репозитория:
|
||||
|
||||
```bash
|
||||
node --check shine-UI/js/services/ans104-data-item.js
|
||||
node --check shine-UI/js/services/auth-service.js
|
||||
node --check shine-UI/js/app.js
|
||||
node --check shine-UI/js/pages/settings-view.js
|
||||
```
|
||||
|
||||
Java/Gradle:
|
||||
|
||||
```bash
|
||||
./gradlew testClasses
|
||||
./gradlew test
|
||||
```
|
||||
|
||||
Затем локальный smoke test по штатной инструкции проекта, например `./gradlew startLocal`.
|
||||
|
||||
В среде, где готовился patch, Gradle wrapper не смог скачать Gradle 8.14 из-за отсутствия внешнего сетевого доступа к `services.gradle.org`. Поэтому полный Gradle compile/test обязательно прогнать после применения в обычной dev-среде.
|
||||
|
||||
## Smoke scenario
|
||||
|
||||
1. Создать/использовать тестового пользователя с локальным blockchain Ed25519 key.
|
||||
2. Добавить обычный block и убедиться, что `blocks.block_bytes` начинается с ANS-104 DataItem, а `data_item_id` заполнен.
|
||||
3. Создать channel и post; проверить `c=<canonical slug>`.
|
||||
4. Включить publisher, дождаться цикла или вызвать сервис тестом; проверить root Arweave tx.
|
||||
5. На второй чистой test DB включить importer и убедиться, что `App=test5590` blocks восстанавливаются в правильном порядке.
|
||||
6. Убедиться, что imported blocks имеют `arweave_publish_pending=false`.
|
||||
7. Проверить, что повторный discovery не создаёт дублей.
|
||||
|
||||
## Не делать в этом patch
|
||||
|
||||
- не добавлять backward compatibility Frame v0;
|
||||
- не возвращать `.bch` storage;
|
||||
- не возвращать SHINE-ARCHIVE;
|
||||
- не менять ESP32;
|
||||
- не мигрировать remote/homeserver signing без отдельного решения пользователя;
|
||||
- не заменять `prevHash` на Arweave DataItem ID.
|
||||
1. Создать новый channel/post и проверить signed tag `c_test5590=<canonical slug>`.
|
||||
2. В `mode=turbo` убедиться, что `blocks.data_item_id` совпадает с Turbo response `id` и pending становится false.
|
||||
3. На втором сервере включить sync и убедиться, что DataItem находится GraphQL-запросом `App=test5590` и импортируется без прямой server-to-server связи.
|
||||
4. Переключить первый сервер в `mode=arweave`, создать ещё несколько блоков и убедиться, что тот же importer второго сервера видит child DataItems без знания root bundle ID.
|
||||
5. Проверить `mode=none`: новые локальные блоки остаются pending, наружу ничего не отправляется.
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
```text
|
||||
User
|
||||
-> создаёт Frame v1
|
||||
-> tags: App=test5590, при канале c=<slug>
|
||||
-> tags: App=test5590, при канале c_test5590=<slug>
|
||||
-> Ed25519 подписывает ANS-104 deep-hash
|
||||
-> готовый DataItem
|
||||
-> AddBlock
|
||||
@@ -22,8 +22,9 @@ User
|
||||
Server
|
||||
-> verify DataItem + SHiNE chain
|
||||
-> PostgreSQL
|
||||
-> каждые ~15 минут ANS-104 bundle
|
||||
-> Arweave L1
|
||||
-> publish.mode=turbo: каждый signed DataItem через Turbo
|
||||
ИЛИ publish.mode=arweave: большой standard ANS-104 bundle -> Arweave L1
|
||||
ИЛИ publish.mode=none: наружу не публиковать
|
||||
|
||||
Other servers
|
||||
-> GraphQL App=test5590
|
||||
|
||||
Reference in New Issue
Block a user