SHA256
Очень сильно переделать формат блоков
Внимание: версия ещё не проверена.
This commit is contained in:
@@ -114,3 +114,10 @@ Slug входит в подпись DataItem и не может быть изм
|
||||
7. проверить `blockNumber == last + 1`;
|
||||
8. проверить `prevHash32 == lastBlockHash`;
|
||||
9. записать DataItem и новое состояние атомарно в PostgreSQL.
|
||||
|
||||
|
||||
## Нормативное правило версий body
|
||||
|
||||
После запуска layout существующей тройки `(type, subType, version)` неизменяем. Любое изменение порядка, размера или смысла подписываемых байтов требует новой `version`. В текущем чистом запуске используется только новый канонический layout; legacy-body не поддерживаются.
|
||||
|
||||
Для внешних target-полей fork является исторической меткой, а не частью логической identity. Identity определяется `toLogin + toBlockGlobalNumber + toBlockHash32`.
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
Базовый идентификатор цепочки пользователя:
|
||||
|
||||
- `blockchainName = <login>-<NNN>`
|
||||
- `NNN` — реальный номер fork строго `001..999`; `000` и `1000+` недопустимы;
|
||||
- пример: `alice-001`
|
||||
|
||||
Обычно это одна основная цепочка пользователя.
|
||||
|
||||
@@ -6,7 +6,8 @@ TECH-тип покрывает системные записи цепочки.
|
||||
|
||||
1. `subType=0` — `HEADER_COMPAT`
|
||||
- стартовый блок цепочки;
|
||||
- payload: tag `SHiNE` + login владельца.
|
||||
- payload: tag `SHiNE` + login владельца + `initialBlockchainKey32`;
|
||||
- `initialBlockchainKey32` — public blockchain-signing key, которым был создан fork №1; это историческая точка происхождения и при последующих fork сохраняется в скопированном HEADER байт-в-байт.
|
||||
|
||||
2. `subType=1` — `TECH_CREATE_CHANNEL`
|
||||
- создание нового канала;
|
||||
|
||||
@@ -10,20 +10,20 @@ TEXT-тип хранит сообщения, материалы и редакт
|
||||
|
||||
2. `subType=11` — `TEXT_EDIT_POST`
|
||||
- редактирование поста;
|
||||
- line-поля + target на оригинальный POST + новый текст.
|
||||
- line-поля + compact target (`toBlockGlobalNumber`, `toBlockHash32`) на оригинальный POST + новый текст.
|
||||
|
||||
3. `subType=20` — `TEXT_REPLY`
|
||||
- ответ на сообщение;
|
||||
- target (`toLogin`, `toBlockGlobalNumber`, `toBlockHash32`) + текст.
|
||||
- target (`toLogin`, `toForkNumber`, `toBlockGlobalNumber`, `toBlockHash32`) + текст.
|
||||
|
||||
4. `subType=21` — `TEXT_EDIT_REPLY`
|
||||
- редактирование ответа;
|
||||
- target на исходный REPLY + новый текст.
|
||||
- compact target (`toBlockGlobalNumber`, `toBlockHash32`) на исходный REPLY + новый текст.
|
||||
- допускается пустой `text` для логического удаления сообщения (без физического удаления блока).
|
||||
|
||||
5. `subType=30` — `TEXT_RATING`
|
||||
- target-based отзыв на конкретный блок;
|
||||
- содержит target (`toLogin`, `toBlockGlobalNumber`, `toBlockHash32`) + текст отзыва;
|
||||
- содержит target (`toLogin`, `toForkNumber`, `toBlockGlobalNumber`, `toBlockHash32`) + текст отзыва;
|
||||
- не является сообщением линии канала.
|
||||
|
||||
6. `subType=50` — `TEXT_REPOST`
|
||||
@@ -58,18 +58,28 @@ TEXT-тип хранит сообщения, материалы и редакт
|
||||
Подробная спецификация: [16_TEXT_Channel_Meta.md](./16_TEXT_Channel_Meta.md).
|
||||
|
||||
|
||||
## Общий target-формат TEXT
|
||||
## Канонический target-формат TEXT
|
||||
|
||||
Для `TEXT_EDIT_POST`, `TEXT_REPLY`, `TEXT_EDIT_REPLY`, `TEXT_RATING` и `TEXT_REPOST` ссылка на цель хранится как:
|
||||
Внешние цели (`TEXT_REPLY`, `TEXT_RATING`, `TEXT_REPOST`) используют:
|
||||
|
||||
```text
|
||||
[1] toLoginLen (uint8)
|
||||
[N] toLogin UTF-8
|
||||
[2] toForkNumber (uint16, BigEndian)
|
||||
[4] toBlockGlobalNumber
|
||||
[32] toBlockHash32
|
||||
```
|
||||
|
||||
`blockchainName`/номер fork в подписываемые байты target не входит. Одинаковые `login + blockNumber + blockHash` считаются одной логической целью после перепубликации сохранённого префикса при fork.
|
||||
`toForkNumber`: `1..999` — fork, который видел автор действия; `0` зарезервирован как unknown/legacy. Поле информационное и **не входит в логическую идентичность цели**. Цель определяется только `toLogin + toBlockGlobalNumber + toBlockHash32`; несовпадение текущего fork само по себе не инвалидирует ссылку.
|
||||
|
||||
Собственные edit (`TEXT_EDIT_POST`, `TEXT_EDIT_REPLY`) используют компактный target:
|
||||
|
||||
```text
|
||||
[4] toBlockGlobalNumber
|
||||
[32] toBlockHash32
|
||||
```
|
||||
|
||||
Login/fork для edit не подписываются: edit может ссылаться только на собственный блок текущей цепочки.
|
||||
|
||||
## Правило для edit
|
||||
|
||||
|
||||
@@ -4,10 +4,10 @@
|
||||
|
||||
1. `subType=1` — `REACTION_LIKE`
|
||||
- лайк на целевой блок;
|
||||
- хранит target: `toLogin`, `toBlockGlobalNumber`, `toBlockHash32`.
|
||||
- хранит target: `toLogin`, `toForkNumber`, `toBlockGlobalNumber`, `toBlockHash32`.
|
||||
2. `subType=2` — `REACTION_UNLIKE`
|
||||
- снятие лайка с целевого блока;
|
||||
- хранит target: `toLogin`, `toBlockGlobalNumber`, `toBlockHash32`.
|
||||
- хранит target: `toLogin`, `toForkNumber`, `toBlockGlobalNumber`, `toBlockHash32`.
|
||||
|
||||
## Назначение
|
||||
|
||||
@@ -16,13 +16,12 @@
|
||||
|
||||
## Формат target
|
||||
|
||||
В подписанных байтах target больше не хранит имя fork/blockchain. Формат:
|
||||
|
||||
```text
|
||||
[1] toLoginLen (uint8)
|
||||
[N] toLogin UTF-8
|
||||
[2] toForkNumber (uint16, BigEndian)
|
||||
[4] toBlockGlobalNumber
|
||||
[32] toBlockHash32
|
||||
```
|
||||
|
||||
Логическая идентичность цели: `toLogin + toBlockGlobalNumber + toBlockHash32`. Поэтому ссылка остаётся той же после fork, если номер и hash исходного блока сохранены.
|
||||
`toForkNumber` — только историческая метка (`1..999`, `0` reserved unknown/legacy). Логическая идентичность реакции: `toLogin + toBlockGlobalNumber + toBlockHash32`. При fork номер fork может измениться; если number+hash сохранены в новой ветке, LIKE/UNLIKE продолжает указывать на тот же логический блок.
|
||||
|
||||
@@ -18,18 +18,19 @@ CONNECTION-тип описывает социальные связи и подп
|
||||
## Общий формат payload
|
||||
|
||||
- line-поля (`lineCode`, `prevLineNumber`, `prevLineHash32`, `thisLineNumber`)
|
||||
- target (`toLogin`, `toBlockGlobalNumber`, `toBlockHash32`)
|
||||
- target (`toLogin`, `toForkNumber`, `toBlockGlobalNumber`, `toBlockHash32`)
|
||||
|
||||
## Бинарный target
|
||||
|
||||
```text
|
||||
[1] toLoginLen (uint8)
|
||||
[N] toLogin UTF-8
|
||||
[2] toForkNumber (uint16, BigEndian)
|
||||
[4] toBlockGlobalNumber
|
||||
[32] toBlockHash32
|
||||
```
|
||||
|
||||
Имя fork/blockchain в target не хранится.
|
||||
`toForkNumber` хранит fork, который видел автор связи (`1..999`), но не участвует в identity. `0` зарезервирован как unknown/legacy; `1000+` недопустим. Для связи на пользователя используется **реальный HEADER hash**: `toBlockGlobalNumber=0`, `toBlockHash32=SHA-256(Frame HEADER)`. Нулевой hash запрещён.
|
||||
|
||||
## Правила target
|
||||
|
||||
|
||||
@@ -38,6 +38,7 @@
|
||||
```text
|
||||
[1] toLoginLen (uint8)
|
||||
[N] toLogin UTF-8
|
||||
[2] toForkNumber uint16 (BigEndian)
|
||||
[4] toBlockGlobalNumber
|
||||
[32] toBlockHash32
|
||||
[2] textLenBytes (uint16)
|
||||
@@ -46,7 +47,8 @@
|
||||
|
||||
Где:
|
||||
|
||||
- `toLogin` — login владельца целевого блока; номер fork в target не хранится;
|
||||
- `toLogin` — login владельца целевого блока;
|
||||
- `toForkNumber` — историческая метка fork (`1..999`, `0` reserved unknown/legacy), не часть identity;
|
||||
- `toBlockGlobalNumber` — номер целевого блока;
|
||||
- `toBlockHash32` — хэш целевого блока;
|
||||
- `text` — опциональное пояснение пользователя к статусу.
|
||||
|
||||
@@ -0,0 +1,77 @@
|
||||
# Key rotation, fork и логические ссылки
|
||||
|
||||
Этот документ фиксирует протокольную семантику fork. API-последовательность ротации описана отдельно в `docs/API/19_Key_Rotation_API.md`.
|
||||
|
||||
## 1. Идентичности
|
||||
|
||||
- Пользователь: `login`.
|
||||
- Физическая ветка: `login-forkNumber` (`1..999`, формат имени строго три цифры: `001..999`; fork `1000` и выше запрещён).
|
||||
- Активный fork определяется текущим PDA.
|
||||
- Исторические fork остаются проверяемыми.
|
||||
|
||||
## 2. HEADER
|
||||
|
||||
Block 0 новой пользовательской истории — `HEADER`:
|
||||
|
||||
```text
|
||||
SHiNE + login + initialBlockchainKey32
|
||||
```
|
||||
|
||||
`initialBlockchainKey32` — public blockchain-signing key fork №1. При смене ключа сохранённый префикс, включая HEADER, перепубликуется с тем же Frame; поэтому это поле остаётся исходным ключом, а новый ключ конкретного fork определяется подписью/owner и PDA.
|
||||
|
||||
## 3. Внешний target
|
||||
|
||||
Для REPLY, RATING, REPOST, LIKE/UNLIKE, CONNECTION, STATUS_ACTION:
|
||||
|
||||
```text
|
||||
[1] toLoginLen
|
||||
[N] toLogin UTF-8
|
||||
[2] toForkNumber uint16
|
||||
[4] toBlockGlobalNumber
|
||||
[32] toBlockHash32
|
||||
```
|
||||
|
||||
`toForkNumber` — информационная историческая метка: fork, на который смотрел автор действия. `0` зарезервирован как unknown/legacy и не является реальным fork. Поле не участвует в identity и не должно сравниваться с текущим active fork как условие валидности.
|
||||
|
||||
Логическая identity цели:
|
||||
|
||||
```text
|
||||
toLogin + toBlockGlobalNumber + toBlockHash32
|
||||
```
|
||||
|
||||
Если сохранённый префикс перепубликован в новом fork байт-в-байт, номер блока и SHA-256(Frame) совпадают, поэтому внешняя ссылка продолжает указывать на тот же логический блок.
|
||||
|
||||
## 4. Собственный edit
|
||||
|
||||
EDIT_POST и EDIT_REPLY относятся только к собственному blockchain и используют:
|
||||
|
||||
```text
|
||||
[4] toBlockGlobalNumber
|
||||
[32] toBlockHash32
|
||||
```
|
||||
|
||||
Login/fork не хранятся. Целевой оригинальный блок должен существовать в текущей ветке с тем же hash. Блок, отброшенный rollback и отсутствующий в новом active fork, редактировать из новой ветки нельзя.
|
||||
|
||||
## 5. CONNECTION на пользователя
|
||||
|
||||
Связь на пользователя всегда указывает на его реальный HEADER:
|
||||
|
||||
```text
|
||||
toLogin = target login
|
||||
toBlockGlobalNumber = 0
|
||||
toBlockHash32 = SHA-256(target HEADER Frame)
|
||||
```
|
||||
|
||||
Нулевой hash как sentinel запрещён.
|
||||
|
||||
## 6. Что переносится при fork
|
||||
|
||||
Для сохранённого префикса Frame не меняется. Могут измениться внешняя ANS-104 подпись, owner/DataItem ID, но SHiNE block hash (`SHA-256(Frame)`) остаётся прежним. Поэтому `number + hash` является устойчивой частью ссылки.
|
||||
|
||||
`toForkNumber` старого действия не переписывается после fork: это исторический факт момента создания действия.
|
||||
|
||||
## 7. Серверная модель Stage 2
|
||||
|
||||
Stage 2 больше не хранит physical target name как identity. `blocks_store` хранит физическую ветку как `(login, fork_number)`, а `reactions_state`, `message_stats`, `connections_state` и просмотры адресуют цель логически через `login + blockNumber + hash`. Поэтому при смене active fork никакого массового rebind `old_bch_name -> new_bch_name` не выполняется.
|
||||
|
||||
Если `number + hash` сохранились после fork, внешние состояния продолжают относиться к той же цели автоматически. Если hash изменился после rollback, это новая логическая цель.
|
||||
@@ -0,0 +1,62 @@
|
||||
# Stage 2 — logical targets and numeric fork storage
|
||||
|
||||
## Canonical identities
|
||||
|
||||
Physical fork identity is `(login, fork_number)`, where `fork_number` is strictly `1..999`. `login-NNN` is a derived presentation value only; `1000+` is invalid.
|
||||
|
||||
A logical external target is `(to_login, to_block_number, to_block_hash)`. `to_fork_number` remains signed historical metadata but MUST NOT participate in equality, validity, LIKE aggregation, CONNECTION identity, or fork rebinding.
|
||||
|
||||
## Tables
|
||||
|
||||
- `blocks_store`: stores `login + fork_number`; does not store `bch_name` or `to_bch_name`.
|
||||
- `blockchain_state_store`: keyed by `(login,fork_number)`.
|
||||
- compatibility SQL views `blocks` and `blockchain_state` derive `login-NNN` for old read/API paths; the name is not persisted.
|
||||
- `reactions_state`: current actor LIKE/UNLIKE state keyed by actor login + logical target.
|
||||
- `message_stats`: logical target counters. It may exist before the target block is locally available.
|
||||
- `connections_state`: logical targets only.
|
||||
- `message_views_state`: viewer + logical target.
|
||||
|
||||
## LIKE before target
|
||||
|
||||
A valid LIKE is projected even when the target block has not arrived. `message_stats` is created for the logical target. When the target later arrives, it reads the already existing counters by `login + blockNumber + hash`.
|
||||
|
||||
## Fork behaviour
|
||||
|
||||
If a prefix is republished unchanged, its Frame hash remains unchanged, so incoming social state is automatically reused. No rebind is performed.
|
||||
|
||||
If rollback replaces a block with the same number but a different hash, the new block has separate stats. Old stats may remain as historical/orphaned state and do not attach to the replacement.
|
||||
|
||||
## Atomic cleanup before replay
|
||||
|
||||
`REBUILDING_SERVER` is set before cleanup/replay. Cleanup is one SQL transaction:
|
||||
|
||||
1. collect active LIKE targets of the actor;
|
||||
2. remove actor rows from `reactions_state`;
|
||||
3. recount only affected LIKE counters (all/official/shining);
|
||||
4. remove actor outgoing `connections_state`, refresh affected target-user/channel stats, and reset actor-derived profile/state;
|
||||
5. delete physical blocks for `(login,fork_number)`;
|
||||
6. delete physical blockchain state for `(login,fork_number)`;
|
||||
7. commit.
|
||||
|
||||
Incoming `message_stats` for the user's targets are never deleted. Candidate blocks are then replayed normally. A crash leaves rotation in `REBUILDING_SERVER`, so rebuild can be retried.
|
||||
|
||||
## REPLY
|
||||
|
||||
Stage 2 does not redesign REPLY. Only the unavoidable database-column adaptation uses the logical target key after `to_bch_name` removal; no new REPLY UI/resolver/cleanup behaviour is introduced.
|
||||
|
||||
## EDIT
|
||||
|
||||
EDIT remains own-chain only. EDIT blocks disappear with their physical fork and return through replay. `edits_count` is not part of Stage 2 message aggregates.
|
||||
|
||||
## Database bootstrap / DB v2 marker
|
||||
|
||||
Stage 2 uses a new database generation explicitly marked as **`SHiNE_DB_V2`** (`database_generation=2`) in `shine_database_metadata`. The runtime schema revision is `29`.
|
||||
|
||||
Stage 2 is installed only on a clean PostgreSQL schema. The final schema is created directly by `schema_v1.sql`; there is no `migration_v29.sql`. Both the server bootstrapper and the SQL bootstrap script reject a non-empty/legacy database instead of modifying or migrating it.
|
||||
|
||||
At every server start, both conditions are required:
|
||||
|
||||
- `shine_database_metadata.id=1`, `database_format='SHiNE_DB_V2'`, `database_generation=2`;
|
||||
- `db_schema_version.id=1`, `schema_version=29`.
|
||||
|
||||
If an old SHiNE database is configured accidentally, server startup fails with an explicit legacy/non-v2 database error.
|
||||
Reference in New Issue
Block a user