Добавить линии связей и параметров пользователя

This commit is contained in:
AidarKC
2026-10-02 00:33:13 +03:00
parent 8d22602761
commit e101e5c5f4
33 changed files with 1293 additions and 568 deletions
@@ -10,7 +10,7 @@
- `11_TEXT_Blocks.md` — текстовые блоки (`type=1`).
- `12_REACTION_Blocks.md` — реакции (`type=2`).
- `13_CONNECTION_Blocks.md` — связи/подписки (`type=3`).
- `14_USER_PARAM_Blocks.md` — пользовательские параметры (`type=4`).
- `14_USER_PROFILE_Blocks.md` — профиль пользователя (`type=4`).
- `15_STATUS_ACTION_Blocks.md` — статусные действия (`type=5`).
## Быстрая карта типов
@@ -19,7 +19,7 @@
- `type=1` — TEXT: POST/EDIT_POST/REPLY/EDIT_REPLY/RATING/REPOST/CHANNEL_META/ENTRYPOINT/EXERCISE/SERVICE/COURSE.
- `type=2` — REACTION: LIKE/UNLIKE.
- `type=3` — CONNECTION: FRIEND/CONTACT/FOLLOW/SPOUSE/PARENT/CHILD/SIBLING и обратные операции.
- `type=4` — USER_PARAM: key/value-параметры пользователя.
- `type=4` — USER_PROFILE: история полей профиля пользователя.
- `type=5` — STATUS_ACTION: DONE_ONCE/LEARNED/SERVICE_PASSED/CONFIRMED/INTERESTED/STARTED/IN_STUDY/ABANDONED/COMPLETED.
## Примечание
+21 -7
View File
@@ -77,6 +77,18 @@ App = test5590
Это временное namespace-значение для разработки. Перед реальным запуском оно будет заменено отдельным изменением протокола/кода.
### Индексный тег фиксированного потока
Для трёх фиксированных потоков используется короткий подписанный тег:
```text
t=tech # TECH (HEADER / CREATE_CHANNEL / FORK)
t=conn # CONNECTION
t=prof # USER_PROFILE
```
Для TEXT, REACTION и STATUS_ACTION тег `t` отсутствует. Сервер проверяет точное соответствие значения `t` фактическому `msg_type`.
### Канальный тег
Если блок относится к конкретному каналу, он дополнительно содержит:
@@ -107,13 +119,15 @@ Slug входит в подпись DataItem и не может быть изм
1. распарсить полный ANS-104 DataItem;
2. проверить `App=test5590`;
3. проверить `c_test5590`, если тип блока требует канал;
4. проверить ANS-104 Ed25519 подпись;
5. проверить, что `owner` равен текущему blockchain public key пользователя;
6. распарсить Frame v1 и body;
7. проверить `blockNumber == last + 1`;
8. проверить `prevHash32 == lastBlockHash`;
9. записать DataItem и новое состояние атомарно в PostgreSQL.
3. проверить `t`, если тип блока требует фиксированный индексный поток;
4. проверить `c_test5590`, если тип блока требует канал;
5. проверить ANS-104 Ed25519 подпись;
6. проверить, что `owner` равен текущему blockchain public key пользователя;
7. распарсить Frame v1 и body;
8. проверить `blockNumber == last + 1`;
9. проверить `prevHash32 == lastBlockHash`;
10. проверить строгую непрерывность логической линии, если body line-based;
11. записать DataItem и новое состояние атомарно в PostgreSQL.
## Нормативное правило версий body
@@ -2,47 +2,87 @@
## 1. Именованный блокчейн
Базовый идентификатор цепочки пользователя:
Базовый идентификатор физической цепочки пользователя:
- `blockchainName = <login>-<NNN>`
- `NNN` — реальный номер fork строго `001..999`; `000` и `1000+` недопустимы;
- пример: `alice-001`
- `blockchainName = <login>-<NNN>`;
- `NNN` — номер fork `001..999`;
- пример: `alice-001`.
Обычно это одна основная цепочка пользователя.
## 2. Логические линии внутри пользовательской цепочки
## 2. Логические линии внутри одной цепочки
Глобально все блоки пользователя идут одной последовательностью `blockNumber` и `prevHash32`. Дополнительно некоторые типы образуют собственные проверяемые линии.
Физически цепочка одна, но внутри есть независимые логические последовательности (линии), которые ведутся через поля:
Актуальные линии:
- `lineCode`
- `prevLineNumber`
- `prevLineHash32`
- `thisLineNumber`
- `TECH` — системная история: `TECH_CREATE_CHANNEL`, `TECH_FORK`; root — `HEADER`;
- `TEXT` — отдельная линия каждого канала; root — `HEADER` для канала `0` или `TECH_CREATE_CHANNEL` для пользовательского канала;
- `CONNECTION` — единая история изменений связей пользователя; root — `HEADER`;
- `USER_PROFILE` — единая история изменений профиля пользователя; root — `HEADER`.
Линии используются для:
- TECH-событий;
- каналов с текстовыми постами;
- связей и подписок;
- пользовательских параметров.
`STATUS_ACTION` в line-модель сейчас не входит.
## 3. Правила line-полей (фактическая серверная валидация)
## 3. Два формата line-prefix
Line-поля: `lineCode`, `prevLineNumber`, `prevLineHash32`, `thisLineNumber`.
### 3.1. Линии с явным `lineCode`
- Line-поля разрешены только для `msg_type`: `0`, `1`, `3`, `4`.
- Если передано хотя бы одно line-поле, должны быть переданы все 4.
- `prevLineNumber/prevLineHash32` должны указывать на существующий блок этой же цепочки.
- Для первого шага после root (`prevLineNumber == lineCode`):
- `TEXT (msg_type=1)`: `thisLineNumber = 0`;
- `TECH/CONNECTION/USER_PARAM (0/3/4)`: `thisLineNumber = 1`.
- Для обычного шага:
- `TEXT`: `thisLineNumber` допускает `same` или `+1` от предыдущего блока линии;
- `TECH/CONNECTION/USER_PARAM`: строго `+1`.
`TECH` и `TEXT` хранят:
## 4. Root-идея для каналов и подписок
```text
[4] lineCode
[4] prevLineNumber
[32] prevLineHash32
[4] thisLineNumber
```
Для ссылок вида follow/friend/contact принято ссылаться на корневые блоки:
- `HEADER` для базовой сущности пользователя/канала `0`;
- `CREATE_CHANNEL` для пользовательских каналов.
- для TECH `lineCode=0`;
- для канала `lineCode = global blockNumber` его root-блока (`HEADER #0` либо `TECH_CREATE_CHANNEL`).
Так ссылки остаются стабильными, даже когда в канале появляются новые сообщения.
### 3.2. Фиксированные линии
`CONNECTION` и `USER_PROFILE` имеют по одной линии на пользователя, поэтому `lineCode` в body не хранится. Их префикс:
```text
[4] prevLineNumber
[32] prevLineHash32
[4] thisLineNumber
```
Логический `lineCode` этих линий всегда `0`.
## 4. Что означают номера
`prevLineNumber` — **глобальный `blockNumber` предыдущего блока этой линии**.
`thisLineNumber` — локальный порядковый номер внутри линии:
- первый TEXT-блок канала: `0`, далее `1,2,3...`;
- первый TECH после HEADER: `1`, далее `2,3,4...`;
- первый CONNECTION: `1`, далее `2,3,4...`;
- первый USER_PROFILE: `1`, далее `2,3,4...`.
То есть `prevLineNumber` и `thisLineNumber` — принципиально разные числа.
## 5. Строгая серверная валидация
Для каждого line-блока сервер определяет **текущий фактический хвост той же линии** и требует:
1. `prevLineNumber` равен глобальному номеру текущего хвоста (либо root для первого блока);
2. `prevLineHash32` равен hash этого хвоста/root;
3. `thisLineNumber` равен предыдущему sequence `+1` (для первого TEXT — `0`, для остальных линий — `1`);
4. root существует и имеет правильный тип.
Ссылка просто на любой существующий блок больше не считается допустимой. Это запрещает случайные или намеренные боковые ветки линии.
Для канала в одну линию входят все line-based события этого канала, включая обычные посты, `EDIT_POST`, `REPOST`, `CHANNEL_META` и контентные типы канала. Поэтому редактирование не создаёт отдельную боковую ветку.
## 6. Индексные ANS-104 теги
Фиксированные системные потоки дополнительно индексируются подписанным тегом:
```text
t=prof # USER_PROFILE
t=conn # CONNECTION
t=tech # TECH, включая HEADER / CREATE_CHANNEL / FORK
```
Тег является индексом для выборочной загрузки; криптографическая непрерывность обеспечивается line-полями внутри подписанного Frame/DataItem.
+77 -28
View File
@@ -1,26 +1,76 @@
# TECH блоки (`type=0`, `version=1`)
TECH-тип покрывает системные записи цепочки.
TECH-тип покрывает системные записи пользовательской цепочки. Все TECH DataItem имеют подписанный индексный тег:
```text
t=tech
```
`HEADER` является root TECH-линии. Следующие line-based TECH-события (`TECH_CREATE_CHANNEL`, `TECH_FORK`) образуют одну последовательность с `lineCode=0`, ссылкой на предыдущий TECH-событийный блок и sequence `1..N`.
## Подтипы
1. `subType=0` — `HEADER_COMPAT`
- стартовый блок цепочки;
- payload: tag `SHiNE` + login владельца + `initialBlockchainKey32`;
- `initialBlockchainKey32` — public blockchain-signing key, которым был создан fork №1; это историческая точка происхождения и при последующих fork сохраняется в скопированном HEADER байт-в-байт.
### `subType=0` — `HEADER_COMPAT`
2. `subType=1` — `TECH_CREATE_CHANNEL`
- создание нового канала;
- хранит line-поля + `channelName` + `channelDescription` + `channelType` + `channelTypeVersion`.
Стартовый блок цепочки (`block #0`). Payload содержит tag `SHiNE`, login владельца и `initialBlockchainKey32`.
3. `subType=2` — `TECH_FORK`
- первый новый блок после точной перепубликации выбранного префикса предыдущего fork новым blockchain key;
- связывает новую активную цепочку с предыдущей и фиксирует точку rollback/продолжения.
`initialBlockchainKey32` — public blockchain-signing key, которым был создан fork №1; это историческая точка происхождения. При последующих fork значение не меняется.
### `TECH_FORK` body (`version=1`)
HEADER сам не хранит line-prefix, но является root TECH-линии.
### `subType=1` — `TECH_CREATE_CHANNEL`
Создание нового канала. Блок одновременно:
- является очередным шагом TECH-линии;
- является root нового канала;
- имеет `t=tech`;
- имеет `c_test5590=<canonical_channel_slug>`.
Начало body:
```text
[4] lineCode = 0
[4] prevTechBlockNumber
[32] prevTechBlockHash32
[4] techSequence
```
Далее идут `channelName`, `channelDescription`, `channelType`, `channelTypeVersion` согласно формату CREATE_CHANNEL.
### `subType=2` — `TECH_FORK`
`TECH_FORK` фиксирует создание нового fork и является обычным следующим шагом TECH-линии.
#### `TECH_FORK` body (`version=1`)
Big-endian:
```text
[4] lineCode = 0
[4] prevTechBlockNumber
[32] prevTechBlockHash32
[4] techSequence
[32] parentBlockchainKey
[4] forkPointBlockNumber
[32] forkPointBlockHash32
[8] forkPointTimestampMs
[4] parentTipBlockNumber
[32] parentTipBlockHash32
[8] parentTipTimestampMs
[4] discardedBlocksCount
[1] reasonCode
[2] commentUtf8Length
[N] comment UTF-8
```
- `prevTechBlockNumber` — глобальный blockNumber предыдущего TECH-события; если до fork не было CREATE_CHANNEL/FORK, это `HEADER #0`;
- `prevTechBlockHash32` — hash этого блока;
- `techSequence` — предыдущий TECH sequence + 1; первый TECH-событийный блок после HEADER имеет `1`.
Остальная fork-часть:
- `parentBlockchainKey[32]` — public key предыдущего fork;
- `forkPointBlockNumber[4]` — последний блок старой цепочки, сохранённый в новом fork;
- `forkPointBlockHash32[32]`;
@@ -28,28 +78,27 @@ Big-endian:
- `parentTipBlockNumber[4]` — tip старой цепочки на момент начала ротации;
- `parentTipBlockHash32[32]`;
- `parentTipTimestampMs[8]`;
- `discardedBlocksCount[4]` — `parentTipBlockNumber - forkPointBlockNumber`;
- `discardedBlocksCount[4] = parentTipBlockNumber - forkPointBlockNumber`;
- `reasonCode[1]`;
- `commentUtf8Length[2]`;
- `comment[N]` — произвольный комментарий пользователя, максимум 1024 UTF-8 байт.
- `comment[N]` — максимум 1024 UTF-8 байт.
`reasonCode`:
- `1` — `ROUTINE_ROTATION`: обычная смена пароля/ключей, компрометация не предполагается;
- `2` — `POSSIBLE_COMPROMISE`: возможная компрометация, неизвестные записи не подтверждены;
- `3` — `CONFIRMED_COMPROMISE_ROLLBACK`: обнаружены нежелательные/чужие записи и выполнен rollback;
- `4` — `RECOVERY`: восстановление доступа recovery-механизмом.
- `1` — `ROUTINE_ROTATION`;
- `2` — `POSSIBLE_COMPROMISE`;
- `3` — `CONFIRMED_COMPROMISE_ROLLBACK`;
- `4` — `RECOVERY`.
Правила:
Текущая схема ротации перепубликует выбранный префикс `0..forkPointBlockNumber` новым blockchain key и затем добавляет `TECH_FORK`. Перепубликованные Frame сохраняются байт-в-байт; внешняя ANS-104 owner/signature меняется. Новый blockchain key в body не дублируется: он определяется owner/signature нового DataItem.
- блоки `0..forkPointBlockNumber` в новом fork должны быть точными Frame-копиями выбранного префикса предыдущей цепочки;
- `TECH_FORK` идёт сразу после этого префикса и является первым действительно новым Frame нового fork;
- если история сохранена полностью, `forkPointBlockNumber == parentTipBlockNumber` и `discardedBlocksCount == 0`;
- если сохраняется только genesis, новый fork содержит прежний `block 0`, а `block 1` является `TECH_FORK`;
- новый blockchain key в body не дублируется: он определяется owner/signature нового ANS-104 DataItem.
## Серверная проверка TECH-линии
## Назначение
Для `TECH_CREATE_CHANNEL` и `TECH_FORK` сервер требует:
- инициализация блокчейна;
- управление набором каналов пользователя;
- фиксация происхождения нового fork и причины ротации/rollback.
1. `lineCode=0`;
2. первый TECH-событийный блок ссылается на HEADER и имеет sequence `1`;
3. каждый следующий ссылается на фактический текущий хвост TECH-линии;
4. номер предыдущего блока, его hash и sequence должны совпадать точно.
Таким образом CREATE_CHANNEL и FORK образуют единый проверяемый технический позвоночник пользователя.
+51 -24
View File
@@ -1,41 +1,68 @@
# CONNECTION блоки (`type=3`, `version=1`)
CONNECTION-тип описывает социальные связи и подписки.
CONNECTION описывает историю социальных связей и подписок пользователя.
## Подтипы
• `10/11` — `close_friend / unclose_friend` (близкий друг)
• `20/21` — `contact / uncontact` (контакт)
• `30/31` — `follow / unfollow` (подписан)
• `40/41` — `spouse / unspouse` (супруг/супруга)
• `50/51` — `parent / unparent` (родитель)
• `52/53` — `child / unchild` (ребёнок)
• `54/55` — `sibling / unsibling` (брат/сестра)
• `60/61` — `known_person / unknown_person` (знаю этого человека)
• `70/71` — `shine_confirmed / shine_unconfirmed` (точно уверен, что сияющий)
• `74/75` — `shine_seen / shine_unseen` (мало знаком, но видел сияющим)
• `10/11` — `close_friend / unclose_friend` (близкий друг)
• `14/15` — `friend / unfriend` (друг)
• `20/21` — `contact / uncontact` (контакт)
• `30/31` — `follow / unfollow` (подписка)
• `40/41` — `spouse / unspouse`
• `50/51` — `parent / unparent`
• `52/53` — `child / unchild`
• `54/55` — `sibling / unsibling`
• `70/71` — `shine_confirmed / shine_unconfirmed`
• `74/75` — `shine_seen / shine_unseen`
• `80/81` — `official_account / unofficial_account`
## Общий формат payload
`60/61` — legacy/reserved и новым UI не создаются.
- line-поля (`lineCode`, `prevLineNumber`, `prevLineHash32`, `thisLineNumber`)
- target (`toLogin`, `toForkNumber`, `toBlockGlobalNumber`, `toBlockHash32`)
## Линия связей
## Бинарный target
У пользователя существует ровно одна линия `CONNECTION`. Отдельный `lineCode` в body не хранится: логический код линии всегда `0`.
Первый CONNECTION ссылается на `HEADER #0` и имеет `connectionSequence=1`. Каждый следующий обязан ссылаться на фактический текущий хвост CONNECTION-линии и увеличивать sequence ровно на `1`.
## Body (`version=1`)
Big-endian:
```text
[1] toLoginLen (uint8)
[4] prevConnectionBlockNumber
[32] prevConnectionBlockHash32
[4] connectionSequence
[1] toLoginLen
[N] toLogin UTF-8
[2] toForkNumber (uint16, BigEndian)
[2] toForkNumber
[4] toBlockGlobalNumber
[32] toBlockHash32
```
`toForkNumber` хранит fork, который видел автор связи (`1..999`), но не участвует в identity. Значения `0` и `1000+` недопустимы. Для связи на пользователя используется **реальный HEADER hash**: `toBlockGlobalNumber=0`, `toBlockHash32=SHA-256(Frame HEADER)`. Нулевой hash запрещён.
- `prevConnectionBlockNumber` — глобальный `blockNumber` предыдущего CONNECTION-блока.
- `prevConnectionBlockHash32` — SHA-256 Frame предыдущего CONNECTION-блока.
- `connectionSequence` — порядковый номер изменения связей `1..N`.
## Правила target
Сервер проверяет номер, hash и sequence относительно текущего хвоста CONNECTION-линии. Это позволяет выгрузить только связи пользователя и проверить, что внутри выбранной истории нет пропущенного шага.
- FRIEND/CONTACT обычно указывают на `HEADER` цели (`block 0`).
- FOLLOW указывает на root канала:
- `HEADER` для канала `0`;
- `CREATE_CHANNEL` для пользовательского канала.
- Для остальных типов связи (`SPOUSE/PARENT/CHILD/SIBLING`) используется тот же target-формат.
## Target
`toForkNumber` хранит fork, который видел автор связи (`1..999`), но не входит в логическую identity цели. `0` зарезервирован как unknown/legacy; `1000+` недопустим.
Для связи на пользователя обычно используется его HEADER:
```text
toBlockGlobalNumber=0
toBlockHash32=SHA-256(Frame HEADER)
```
Для FOLLOW на канал target указывает на root канала: HEADER для канала `0` либо `TECH_CREATE_CHANNEL` для пользовательского канала.
## ANS-104 тег
Каждый CONNECTION обязан иметь подписанный тег:
```text
t=conn
```
-14
View File
@@ -1,14 +0,0 @@
# USER_PARAM блоки (`type=4`, `version=1`)
## Подтипы
1. `subType=1` — `USER_PARAM_TEXT_TEXT`
- хранит line-поля + `paramKey` + `paramValue`.
## Назначение
- сохранение пользовательского состояния (настройки клиента, синк-метки, курсоры чтения и т.д.).
## Практика
Для сложных структур удобно хранить JSON-строку в `paramValue` с версией схемы.
+45
View File
@@ -0,0 +1,45 @@
# USER_PROFILE блоки (`type=4`, `version=1`)
`USER_PROFILE` хранит только данные, которыми пользователь описывает собственный профиль.
> В текущем Java/JS коде историческое внутреннее имя класса/метода может оставаться `UserParamBody` / `addBlockUserParam`. На уровне протокола и документации тип называется `USER_PROFILE`.
## Подтип
`subType=1` — текстовое поле профиля: `paramKey + paramValue`.
Примеры полей: имя, фамилия, `about`, аватар, web, телефон, роль аккаунта и другие свойства профиля, определённые приложением.
## Линия профиля
У пользователя существует ровно одна линия `USER_PROFILE`. Отдельный `lineCode` для неё не нужен и в body не хранится: логический код линии всегда `0`.
Первый `USER_PROFILE` ссылается на `HEADER #0` и имеет `profileSequence=1`. Каждый следующий блок обязан ссылаться на фактический текущий хвост профильной линии и увеличивать sequence ровно на `1`.
## Body (`version=1`)
Big-endian:
```text
[4] prevProfileBlockNumber
[32] prevProfileBlockHash32
[4] profileSequence
[2] paramKeyLen
[N] paramKey UTF-8
[2] paramValueLen
[M] paramValue UTF-8
```
- `prevProfileBlockNumber` — **глобальный `blockNumber`** предыдущего блока профильной линии, а не локальный sequence.
- `prevProfileBlockHash32` — SHA-256 Frame предыдущего блока профильной линии.
- `profileSequence` — порядковый номер изменения профиля `1..N`.
Сервер проверяет одновременно номер предыдущего блока, его hash и непрерывность sequence. Поэтому выборка всех блоков `USER_PROFILE` позволяет обнаружить пропуск или боковую ветку.
## ANS-104 тег
Каждый `USER_PROFILE` обязан иметь подписанный тег:
```text
t=prof
```
+11 -1
View File
@@ -14,13 +14,23 @@
App=test5590
```
Для фиксированных потоков:
```text
t=tech # TECH: HEADER / CREATE_CHANNEL / FORK
t=conn # CONNECTION
t=prof # USER_PROFILE
```
Для блоков конкретного канала дополнительно:
```text
c_test5590=<canonical_channel_slug>
```
Теги входят в ANS-104 подпись пользователя. Старый тестовый тег `c` новым кодом не создаётся и не принимается как channel tag.
`TECH_CREATE_CHANNEL` несёт оба индекса: `t=tech` и `c_test5590=<slug>`. `STATUS_ACTION` не получает `t`-тег.
Теги входят в ANS-104 подпись пользователя. Сервер проверяет соответствие `t` фактическому `msg_type` и отклоняет лишний/неверный `t`. Старый тестовый тег `c` новым кодом не создаётся и не принимается как channel tag.
## Publisher modes
+11
View File
@@ -1,3 +1,14 @@
## 2026-10-01 — Проверяемые USER_PROFILE / CONNECTION / TECH линии и signed `t` index
- Тип `4` в документации называется `USER_PROFILE`; внутренние исторические имена классов могут сохраняться. USER_PROFILE предназначен только для данных профиля.
- `USER_PROFILE` и `CONNECTION` получили обязательную фиксированную line-схему без сериализованного `lineCode`: `prevBlockNumber + prevBlockHash32 + sequence`. Первый шаг ссылается на HEADER и имеет sequence `1`.
- `TECH_FORK` включён в общую TECH-линию вместе с `TECH_CREATE_CHANNEL`; оба используют `lineCode=0`, предыдущий TECH block/hash и `techSequence`.
- Серверная line-валидация стала строгой: новый блок обязан продолжать фактический текущий хвост той же линии и иметь sequence `+1`; произвольная ссылка на существующий блок больше не принимается. Это также устраняет боковую ветку канала после `EDIT_POST`.
- Добавлены подписанные ANS-104 индексы: `t=prof`, `t=conn`, `t=tech`. `STATUS_ACTION` не изменён.
- В отдельном `shine-solana-arweave-viewer-v3` исправлен legacy-фильтр канала `c` → канонический `c_test5590`.
- `back32Hash` и дополнительные skip-ссылки не добавлялись.
- Формат USER_PROFILE/CONNECTION/TECH_FORK несовместим с предыдущей тестовой схемой; проект находится до production и миграция старых блоков не предусмотрена.
## 2026-09-27 — TECH_FORK v1
- Добавлен `type=0 / subType=2 / version=1` (`TECH_FORK`).
@@ -9,6 +9,7 @@
- Importer всегда ищет только individual `App=test5590` DataItems.
- `App=test5590-batch` больше не используется.
- Channel tag: `c_test5590=<canonical_channel_slug>` вместо `c=...`.
- Фиксированные signed indexes: `t=tech`, `t=conn`, `t=prof`.
- Удалены `blocks.arweave_root_tx_id` и `arweave_block_import_queue.root_tx_id`.
- Схема PostgreSQL: v25.
+1 -1
View File
@@ -14,7 +14,7 @@
```text
User
-> создаёт Frame v1
-> tags: App=test5590, при канале c_test5590=<slug>
-> tags: App=test5590; t=tech/conn/prof для фиксированных потоков; при канале c_test5590=<slug>
-> Ed25519 подписывает ANS-104 deep-hash
-> готовый DataItem
-> AddBlock
+203
View File
@@ -0,0 +1,203 @@
# TODO — резервные ссылки `back32Hash` для SHiNE blockchain
Статус: **TODO / не реализовано**.
Цель этой идеи — повысить устойчивость проверки SHiNE blockchain и отдельных логических линий к ситуации, когда один или несколько DataItem временно или постоянно недоступны у конкретного Arweave gateway, CDN, сервера или другого источника.
Это **не замена** обычным ссылкам на предыдущий блок. Основная цепочка по-прежнему строится через `prevHash32` / `prevLineHash32`. `back32...` — только дополнительная резервная ссылка назад.
---
## 1. Глобальная цепочка пользователя
В общий Frame в будущем добавить одно поле:
```text
[32] back32Hash32
```
Смысл:
```text
back32Hash32 = HASH(global block N - 32)
```
То есть блок `N` дополнительно содержит hash глобального блока `N-32`.
Пример:
```text
block #100
prevHash32 -> HASH(#99)
back32Hash32 -> HASH(#68)
```
### Для первых блоков
Если блока `N-32` ещё не существует, поле содержит 32 нулевых байта:
```text
#0 ... #31 -> back32Hash32 = ZERO_HASH_32
#32 -> HASH(#0)
#33 -> HASH(#1)
...
```
### Номер блока отдельно НЕ хранить
Поле вида `back32BlockNumber` не нужно.
Номер однозначно вычисляется:
```text
back32BlockNumber = blockNumber - 32
```
Поэтому хранить ещё 4 байта номера в каждом блоке бессмысленно.
Дополнительный размер глобального блока: **ровно +32 байта**.
---
## 2. Логические линии
Для line-based блоков в будущем добавить ещё одно поле:
```text
[32] back32LineHash32
```
Оно относится не к глобальной последовательности блоков, а к конкретной логической линии.
Используется для:
- `TEXT` — линия конкретного канала;
- `TECH` — техническая линия пользователя;
- `CONNECTION` — линия изменений связей;
- `USER_PROFILE` — линия изменений профиля.
Смысл:
```text
back32LineHash32 = HASH(line item with sequence = currentSequence - 32)
```
Пример для канала:
```text
channel sequence 100
prevLineHash32 -> HASH(channel sequence 99)
back32LineHash32 -> HASH(channel sequence 68)
```
Пример для профиля:
```text
profileSequence = 50
prevProfileBlockHash32 -> HASH(profile sequence 49)
back32LineHash32 -> HASH(profile sequence 18)
```
Если элемента линии с `sequence - 32` ещё нет, используется:
```text
ZERO_HASH_32
```
### Номер элемента `-32` отдельно НЕ хранить
Он вычисляется из текущего sequence:
```text
back32LineSequence = currentSequence - 32
```
А глобальный номер нужного старого блока при необходимости определяется по уже загруженной/проиндексированной линии.
Дополнительный размер line-based блока:
```text
+32 байта global back32Hash32
+32 байта back32LineHash32
= +64 байта
```
---
## 3. Зачем это нужно
Обычная цепочка имеет только соседнюю связь:
```text
N -> N-1
```
Если блок `N-1` недоступен, проверить обычную связь следующего блока назад уже невозможно, хотя остальные данные могут быть доступны.
С дополнительной ссылкой получается:
```text
N -> N-1
N -> N-32
```
Поэтому даже если часть соседних блоков недоступна, можно получить дополнительную криптографическую связь с более ранней частью истории.
То же самое для отдельной линии:
```text
line N -> line N-1
line N -> line N-32
```
Это особенно полезно для каналов: если конкретный пост оказался недоступен или заблокирован одним источником, отсутствие этого DataItem не должно автоматически делать всю последующую историю канала полностью непроверяемой.
---
## 4. Что этот механизм НЕ решает
`back32Hash` не означает, что отсутствующий блок восстановлен или проверен.
Если блока нет, его содержимое остаётся неизвестным.
Механизм даёт только дополнительный проверяемый мост между доступными частями истории.
Он также не заменяет:
- `prevHash32`;
- `prevLineHash32`;
- sequence логической линии;
- подпись ANS-104 DataItem;
- проверку текущего хвоста линии;
- отдельный механизм доказательства того, что скачан самый последний существующий блок/элемент линии.
---
## 5. Почему шаг именно 32
Шаг `32` выбран как простой компромисс:
- всего 32 дополнительных байта на глобальную цепочку;
- ещё 32 байта только для line-based блоков;
- позволяет делать длинный резервный переход без сложной структуры skip-list;
- номер ссылки не надо хранить — он вычисляется арифметически;
- реализация и проверка остаются очень простыми.
В будущем шаг можно пересмотреть только через новую версию Frame/body, если появится убедительная причина.
---
## 6. План реализации в будущем
Когда будет принято решение реализовать TODO:
1. добавить `back32Hash32` в новую версию общего Frame;
2. при создании блока вычислять hash глобального блока `N-32`;
3. добавить `back32LineHash32` в новые версии всех line-based body;
4. вычислять его по элементу той же линии с sequence `currentSequence-32`;
5. серверу проверять эти hashes при `AddBlock`;
6. импортерам/Arweave sync/viewer использовать резервные ссылки при проверке частично доступной истории;
7. обновить тесты бинарного формата и документацию;
8. не добавлять отдельные поля номера для ссылок `-32`.
До выполнения этих пунктов текущий канонический формат SHiNE остаётся без `back32Hash32` и `back32LineHash32`.
@@ -55,7 +55,7 @@
- `type=1` — `TEXT`
- `type=2` — `REACTION`
- `type=3` — `CONNECTION`
- `type=4` — `USER_PARAM`
- `type=4` — `USER_PROFILE`
## Верхнеуровневые типы первой итерации
@@ -65,7 +65,7 @@
- `1` — `TEXT`
- `2` — `REACTION`
- `3` — `CONNECTION`
- `4` — `USER_PARAM`
- `4` — `USER_PROFILE`
- `5` — `STATUS_ACTION`
Отдельно:
@@ -652,7 +652,7 @@
| 1 | TEXT | старый код, новое расширенное смысловое описание |
| 2 | REACTION | старый |
| 3 | CONNECTION | старый |
| 4 | USER_PARAM | старый |
| 4 | USER_PROFILE | старый |
| 5 | STATUS_ACTION | первая итерация |
| 6 | CHANNEL_MEMBERSHIP | вынесено в отдельный отложенный черновик |