# Как устроены каналы в блокчейне SHiNE ## 1) Коротко: что такое “канал” в текущей реализации В SHiNE канал — это не отдельная таблица сообщений, а **линия блоков** внутри блокчейна пользователя: - канал создается TECH-блоком `CreateChannelBody` (`msg_type=0`, `msg_sub_type=1`); - сообщения канала — это `TEXT_POST` (`msg_type=1`, `msg_sub_type=10`) с `line_code = rootBlockNumber канала`; - ответы (треды) — это `TEXT_REPLY` (`msg_sub_type=20`) с target-ссылкой на конкретный блок-сообщение. То есть канал = “корневой блок канала” + все посты в его линии + связанные ответы. --- ## 2) Как канал появляется Создание канала идет через `AddBlock`: 1. UI собирает `CreateChannelBody` (v2, а при legacy-ошибке fallback на v1). 2. UI подписывает блок приватным blockchain-ключом на устройстве. 3. UI отправляет на сервер `AddBlock` с `blockBytesB64` (полный бинарный блок: preimage + sigMarker + signature). 4. Сервер: - проверяет цепочку (`prevHash`, `blockNumber=last+1`); - парсит body; - валидирует подпись; - валидирует имя канала; - сохраняет блок и обновляет state. Дополнительно сервер поддерживает `channel_names_state` как нормализованное состояние названий каналов. --- ## 3) Правила имени и описания канала ### Имя канала (`ChannelNameRules`) - длина: `3..32` символов (code points); - допустимые символы: Latin/Cyrillic, цифры, пробел, `_`, `-`; - имя нормализуется (trim + схлопывание пробелов); - канонический slug строится в lower-case, `ё -> е`, разделители -> `-`. ### Уникальность Проверяется по slug. При конфликте сервер возвращает `channel_name_already_exists`. ### Описание канала В `CreateChannelBody v2` описание хранится прямо в блоке (до 200 байт UTF-8). Для совместимости с legacy-v1 есть fallback: описание может сохраняться как `USER_PARAM` ключа вида: `channel_desc:{ownerBlockchainName}:{rootBlockNumber}:{rootBlockHash}` В UI при чтении описание берется из ответа канала и при наличии override — перекрывается значением из `USER_PARAM`. --- ## 4) Канал “0” `rootBlockNumber=0` — технический root-канал. Публикации `TEXT_POST` в канал `0` сейчас отключены (на сервере есть явный запрет). --- ## 5) Как идут сообщения в канале ### Публикация поста UI вызывает `addBlockTextPost` -> `AddBlock` с `TEXT_POST`. Ограничения: - писать можно только в **свой** блокчейн и свои каналы; - для поста задается `line_code` канала; - пост в канале — это новый неизменяемый блок. ### Ответы Ответы (`TEXT_REPLY`) не обязаны лежать в той же линии. Они ссылаются на целевой блок через target (`to_bch_name`, `to_block_number`, `to_block_hash`). Это позволяет отвечать и из других блокчейнов (межпользовательский тред). --- ## 6) Редактирование и удаление сообщений ### Редактирование Поддержано на уровне протокола: - `TEXT_EDIT_POST` (11) — правка поста; - `TEXT_EDIT_REPLY` (21) — правка ответа. Правка — это **новый блок**, ссылающийся на оригинал. Оригинальный блок не меняется. Серверные read-API уже собирают `versions[]` и `versionsTotal`. ### Удаление Сейчас отдельного subtype “delete post/reply” нет. Физического удаления блоков из цепочки нет (блоки иммутабельны). Итог: - изменить можно через edit-блок; - удалить “как в чате” сейчас нельзя. --- ## 7) Как UI получает канал Основные read-API: - `ListSubscriptionsFeed` — список каналов/подписок; - `GetChannelMessages` — посты канала; - `GetMessageThread` — тред вокруг выбранного сообщения. Важно: UI получает **JSON-представление**, собранное сервером из блоков БД, а не сырые блоки по умолчанию. В JSON возвращаются: - `messageRef` (номер и hash блока), - автор, - текущий текст, - `versions[]` (оригинал + правки), - counters (`likesCount`, `repliesCount`). --- ## 8) Как строится тред `GetMessageThread`: 1. Находит focus-сообщение по `(blockchainName, blockNumber)`. 2. Строит `ancestors` вверх по target-ссылкам. 3. Строит `descendants` вниз: replies, где target = focus. Запросы в БД идут по `to_bch_name + to_block_number + to_block_hash`, поэтому ответы из других блокчейнов тоже связываются. --- ## 9) Что проверяется криптографически При записи (`AddBlock`) сервер проверяет: - корректность формата блока; - непрерывность цепочки; - `SHA-256(preimage)` и Ed25519-подпись; - соответствие публичного blockchain-ключа пользователя. На чтении (`GetChannelMessages`, `GetMessageThread`) сервер отдает уже сохраненные данные (JSON из БД). Повторная верификация каждой записи при каждом чтении не делается. --- ## 10) UI-статус на сегодня (важно) На момент этого документа: - в UI нет полноценного экрана истории правок сообщения (хотя `versions` уже приходят); - нет операции удаления сообщений (и на протоколе нет delete subtype); - канал читается как JSON-слой поверх блоков, а не как “сырой бинарный блок-объект”. --- ## 11) Практический вывод по модели данных Каналы в SHiNE — это append-only модель: - каждое действие = новый подписанный блок; - “изменение” = добавление новой версии, не перезапись старой; - целостность и авторство обеспечиваются подписью и связностью цепочки; - UI может показывать удобный “чатовый” вид, но источник истины — блоки.