# Общий формат пользовательского блока SHiNE — Frame v1 / ANS-104 Актуальный формат не поддерживает старый Frame v0. Новый пользовательский блок сразу создаётся как готовый подписанный ANS-104 DataItem. ## 1. Два уровня формата Полный объект, который клиент отправляет в `AddBlock`, хранится в PostgreSQL и затем архивируется в Arweave: ```text ANS-104 DataItem signature_type = 2 (generic Ed25519) signature = 64 bytes owner = 32-byte blockchain public key target = absent anchor = absent tags data = SHiNE Frame v1 ``` Цепочка SHiNE **не зависит от Arweave**. Arweave DataItem ID хранится отдельно и используется для дедупликации/поиска, но не является `prevHash`. ## 2. SHiNE Frame v1 Все целые поля Frame v1 — BigEndian. | Поле | Размер | Описание | |---|---:|---| | `frameCode` | 2 | `0x0001` | | `prevHash32` | 32 | SHA-256 полного Frame v1 предыдущего SHiNE-блока; для блока 0 — нули | | `back32Hash32` | 32 | SHA-256 Frame блока `N-32`; для `N<32` — 32 нулевых байта | | `blockSize` | 4 | точный размер Frame v1, включая header и body | | `blockNumber` | 4 | номер блока, начиная с 0 | | `timestamp` | 8 | Unix time seconds | | `type` | 2 | тип сообщения | | `subType` | 2 | подтип | | `version` | 2 | версия body | | `body` | N | данные конкретного типа | `FRAME_HEADER_SIZE = 88` bytes. ```text blockHash32 = SHA256(FrameV1Bytes) next.prevHash32 = blockHash32 blockN.back32Hash32 = (N < 32 ? ZERO_HASH_32 : HASH(block N-32)) ``` Подписи внутри Frame v1 нет. Единственная подпись пользователя — подпись окружающего ANS-104 DataItem. ## 3. ANS-104 DataItem Для тестового контура используется generic Ed25519 signature type `2`: подпись 64 bytes, owner 32 bytes. Это отдельный generic Ed25519 signer type; Solana-specific signer в текущем Turbo/arbundles имеет другой type. Подписывается стандартный ANS-104 deep-hash: ```text [ "dataitem", "1", "2", owner, target(empty), anchor(empty), rawAvroTags, FrameV1Bytes ] ``` `rawAvroTags` — ровно те Avro-serialized bytes тегов, которые лежат внутри DataItem. `dataItemId32 = SHA256(signature64)`. ### Обязательный тестовый тег Каждый блок: ```text App = test5591 ``` Это временное namespace-значение для разработки. Перед реальным запуском оно будет заменено отдельным изменением протокола/кода. ### Индексный тег фиксированного потока Для трёх фиксированных потоков используется короткий подписанный тег: ```text t=tech # TECH (HEADER / CREATE_CHANNEL / FORK) t=conn # CONNECTION t=prof # USER_PROFILE ``` Для TEXT, REACTION и STATUS_ACTION тег `t` отсутствует. Сервер проверяет точное соответствие значения `t` фактическому `msg_type`. ### Канальный тег Если блок относится к конкретному каналу, он дополнительно содержит: ```text c = ``` Slug входит в подпись DataItem и не может быть изменён сервером после подписи. ## 4. Что хранится в PostgreSQL `blocks.block_bytes` содержит **полный serialized ANS-104 DataItem**, а не только Frame. Отдельно индексируются: - `block_hash` — SHA-256(Frame v1); - `block_signature` — 64-byte Ed25519 signature из DataItem; - `data_item_id` — SHA-256(signature), UNIQUE; - `block_number`, `bch_name`, message fields; - состояние публикации в Arweave. Локальные `.bch`, `.tmp_bch` и marker-файлы для пользовательских blockchain больше не используются. ## 5. Проверка AddBlock Сервер обязан: 1. распарсить полный ANS-104 DataItem; 2. проверить `App=test5591`; 3. проверить `t`, если тип блока требует фиксированный индексный поток; 4. проверить `c`, если тип блока требует канал; 5. проверить ANS-104 Ed25519 подпись; 6. проверить, что `owner` равен текущему blockchain public key пользователя; 7. распарсить Frame v1 и body; 8. проверить `blockNumber == last + 1`; 9. проверить `prevHash32 == lastBlockHash`; 10. проверить `back32Hash32`: нули для `N<32`, иначе hash блока `N-32`; 11. проверить строгую непрерывность логической линии, если body line-based; 12. записать DataItem и новое состояние атомарно в PostgreSQL. ## Нормативное правило версий body После запуска layout существующей тройки `(type, subType, version)` неизменяем. Любое изменение порядка, размера или смысла подписываемых байтов требует новой `version`. В текущем чистом запуске используется только новый канонический layout; legacy-body не поддерживаются. Для внешних target-полей fork является исторической меткой, а не частью логической identity. Identity определяется `toLogin + toBlockGlobalNumber + toBlockHash32`.