5.3 KiB
member_sync — адаптер участников каналов
Поверх merkle_sync синхронизирует source=0 записи таблиц peers_<channel_id>. Транспортный движок не занимается подписями и версиями участников.
Использование
- member_sync_init вызывается при инициализации chat_sync и перестраивает производный индекс.
- member_sync_start подключает канал к пиру и запрашивает подтверждение совпадения данных.
- member_sync_put изменяет локальную запись, атомарно обновляет индекс и после commit уведомляет движок.
- Прямые broadcast/send_to не нужны: локальная версия возвращается второму узлу при обратном проходе.
- cancel/destroy снимают ожидания; отдельного публичного API рассылки нет.
Записи и применение
У записи два независимо версионируемых блока: участник (join_ts, update_ts) и владелец (adm_tags.ver). Удаление используется для повреждённых записей. Конфликт одинаковых версий с разным содержимым не разрешается порядком доставки: отсутствие прогресса завершает Merkle-раунд ошибкой конфликта.
Входящая страница сначала целиком проверяется на корректность раскладки, длин и строк. Затем записи применяются под savepoint member_page. Ошибка откатывает всю страницу вместе с индексом. Уведомления GUI/топологии и changed выполняются после commit. Каждый member_sync_apply_record также имеет savepoint, поэтому ошибка пересчёта не оставляет запись без индекса. При внешней транзакции вызывающая сторона отвечает за changed после commit.
Проверяются привязка node_id к X25519, доверенный Ed25519, подписи блока участника и владельца. Для дерева приглашений родитель может прийти позже ребёнка; finish повторно проверяет зависимости перед подтверждением корня. Это не отдельная карантинная таблица: промежуточные записи существуют в БД до finish, поэтому MT_OK нельзя заменять фактом их присутствия.
Канонический хеш
SHA256 по полям: node_id:8, x25519:32, ed25519:32, join_sig:64, join_ts:8, update_sig:64, update_ts:8, userinfo_len:1, userinfo, adm_tags_len:2, adm_tags, adm_tags_sig:64, signed_by:8, signature:64.
Целые big-endian; отсутствующие подписи представлены нулями. userinfo ограничен 255 байтами, adm_tags — 8192 байтами UTF-8 без NUL. Длина adm_tags — uint16 big-endian. Хеш и подпись владельца покрывают весь adm_tags без обрезания. Хеш включает userinfo и дерево приглашений. Формат сообщений, подписываемых моделью, определяется build_join_msg/build_update_msg/build_sign_msg отдельно.
Страница на проводе
Начинается с count:2 big-endian. Далее count записей: node_id:8, x25519:32, ed25519:32, flags:1, при HAS_JOIN — join_sig:64 и join_ts:8, update_sig:64, update_ts:8, userinfo_len:1, userinfo, adm_tags_len:2, adm_tags, adm_tags_sig:64, signed_by:8, signature:64.
Целые big-endian. Встроенные NUL и хвостовые байты запрещены. get_page перечисляет только один лист, в возрастающем порядке node_id, строго после курсора. SQLite использует signed INTEGER; внутри одного листа знак ключей одинаков, поэтому SQL-порядок совпадает с unsigned. Следующая запись, не помещающаяся в буфер, остаётся для следующей страницы. Ошибки SQL и повреждённые размеры BLOB возвращаются вызывающему коду.
Диагностика
Категория member_sync: ошибки содержат канал, node_id и причину отказа. DEBUG показывает применение версий и размеры страниц, TRACE — входы и расчёт листа. Хеши родителей вычисляет merkle_tree; адаптер никогда не перечисляет все записи для внутреннего узла.