back32hash 5591: готово к тестам

Вроде как всё готово к тестам.
This commit is contained in:
AidarKC
2026-10-02 01:32:37 +03:00
parent e101e5c5f4
commit de8700f8e0
51 changed files with 337 additions and 18091 deletions
+20 -172
View File
@@ -1,28 +1,30 @@
# TODO — резервные ссылки `back32Hash` для SHiNE blockchain
# `back32Hash32` — глобальная резервная ссылка SHiNE
Статус: **TODO / не реализовано**.
Статус: **реализовано для общей пользовательской цепочки**. Отдельный `back32` для логических линий намеренно не добавляется.
Цель этой идеи — повысить устойчивость проверки SHiNE blockchain и отдельных логических линий к ситуации, когда один или несколько DataItem временно или постоянно недоступны у конкретного Arweave gateway, CDN, сервера или другого источника.
## Правило
Это **не замена** обычным ссылкам на предыдущий блок. Основная цепочка по-прежнему строится через `prevHash32` / `prevLineHash32`. `back32...` — только дополнительная резервная ссылка назад.
---
## 1. Глобальная цепочка пользователя
В общий Frame в будущем добавить одно поле:
Каждый SHiNE Frame содержит:
```text
[32] prevHash32
[32] back32Hash32
```
Смысл:
`prevHash32` остаётся основной соседней связью `N -> N-1`.
`back32Hash32` — дополнительная резервная связь:
```text
back32Hash32 = HASH(global block N - 32)
N < 32 -> ZERO_HASH_32
N >= 32 -> SHA256(Frame блока N-32)
```
То есть блок `N` дополнительно содержит hash глобального блока `N-32`.
Номер блока для этой ссылки отдельно не хранится: он всегда равен `blockNumber - 32`. Поэтому дополнительных 4 байта номера нет. Стоимость механизма — **ровно +32 байта на каждый глобальный блок**.
## Зачем
Если соседний DataItem недоступен у конкретного gateway/CDN/сервера, обычная проверка через `prevHash32` прерывается. `back32Hash32` даёт второй криптографический мост к более ранней части истории. Это не восстанавливает отсутствующий блок и не доказывает его содержимое, но позволяет связать доступный последующий участок с историей на 32 блока раньше.
Пример:
@@ -32,172 +34,18 @@ block #100
back32Hash32 -> HASH(#68)
```
### Для первых блоков
Если блока `N-32` ещё не существует, поле содержит 32 нулевых байта:
Для первых 32 блоков:
```text
#0 ... #31 -> back32Hash32 = ZERO_HASH_32
#32 -> HASH(#0)
#33 -> HASH(#1)
...
```
### Номер блока отдельно НЕ хранить
Сервер при `AddBlock` обязан сам проверить это поле по сохранённому блоку `N-32`; клиентское значение не принимается на доверии.
Поле вида `back32BlockNumber` не нужно.
## Почему без `back32` внутри линий
Номер однозначно вычисляется:
CHANNEL / TECH / CONNECTION / USER_PROFILE уже имеют собственные `prev...BlockNumber`, `prev...Hash32` и sequence. Эти линии — дополнительный способ выборочной загрузки и проверки поверх основной пользовательской цепочки. Если в выборочно скачанной линии обнаружена дырка, блоки всё равно можно криптографически проверить через глобальную цепочку, где уже есть `prevHash32 + back32Hash32`.
```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`.
Поэтому добавлять ещё +32 байта в каждый line-based body сейчас нецелесообразно. Если когда-нибудь появится требование полностью проверять отдельный канал/профиль без доступа к глобальной цепочке даже через недоступный line-блок, line-back32 можно рассмотреть отдельной новой версией body.