Plan canonical history reconciliation on the shared Merkle engine
This commit is contained in:
1 parent
5ae5fd066d
commit
d20f31c165
2 files changed
+177
-4
No files matched your search
@@ -624,3 +624,171 @@ BAD_FORMAT, DEFERRED, ERROR), сохранение корректной суще
|
||||
Эти места не включены в доказанное покрытие текущего исправления. GUI/Android/Windows/FreeBSD не запускались.
|
||||
Следующий этап аудита требует отдельного исправления финального критерия; по AGENTS.md
|
||||
дальнейшее расширение текущей реализации остановлено на этом замечании.
|
||||
|
||||
12. План устранения ложной сходимости истории и проверка предпосылок — 26.10.2026
|
||||
|
||||
Запрос пользователя: продумать исправление и его корректность. Runtime-код в этом этапе не менялся.
|
||||
Повторно прочитаны относящиеся к обмену структуры/функции db_sync, общий merkle_sync,
|
||||
контракт data_ops, запуск/остановка chat_sync, создание канала, callback докачки медиа и sleep policy.
|
||||
|
||||
Почему заменить одну ветку на restart недостаточно:
|
||||
1. db_handle_send_data объявляет sync_state=2/done сразу после отправки собственного SYNC_DONE,
|
||||
ещё до получения подтверждённого равенства. db_handle_init_resp имеет отдельный путь завершения.
|
||||
2. db_handle_init_resp исследует только последние51 позицию через16 интервалов.
|
||||
Самая ранняя несовпавшая проба не является первым отличием или доказанным общим префиксом.
|
||||
3. chain_hash включает id, который не входит в ключ записи или подпись автора.
|
||||
Разные id одного подписанного сообщения сохраняются при duplicate и не исправляются пересылкой.
|
||||
4. OFFSET относится к изменяемой таблице; поздний PUSH/DELETE сдвигает позиции.
|
||||
В старом wire нет идентификатора раунда, запросы/ответы не проверяются по фазе.
|
||||
5. Сравнение8 байт не заменяет проверку полного SHA256 при объявлении успеха.
|
||||
|
||||
Дополнительный изолированный стенд /tmp/db-sync-completion-design.c/.mk, сборка через tests/Makefile:
|
||||
использованы настоящие SQLite/OpenSSL/uasync и private-функции из штатного integrity test.
|
||||
Только собственные временные записи, вызовы локальных обработчиков, без сетевых пакетов.
|
||||
- Две таблицы одного group_id содержат одинаковые timestamp/author/data/signature, но id1 и900.
|
||||
Обе db_sync_chain_verify возвращают0, последние хеши различны. Передача локальному обработчику
|
||||
count1/чужого хеша вызывает done1 и state2: ложное завершение подтверждено runtime.
|
||||
- По200 записей, различие только в первой; остальные199 записей и id совпадают.
|
||||
Фактические хеши по текущим sparse-пробам дают fm148. Весь хвост148..199 — дубликаты;
|
||||
его повторная вставка в обе таблицы сохраняет различие корней. Простое повторение старого обмена
|
||||
не имеет условия прогресса. Симулировался выбор sparse-проб и повтор хвоста, не полный сетевой раунд.
|
||||
- Exit0, tracked allocations восстановлены. /tmp/db-sync-completion-design-build.log и
|
||||
/tmp/db-sync-completion-design.log. Это диагностика существующего кода, не тест новой реализации.
|
||||
|
||||
Варианты:
|
||||
А. Сохранить собственный bulk-протокол: потребуются канонический хеш без id, поиск настоящего общего
|
||||
префикса либо полный fallback с0, устойчивый курсор, два явных прохода, round/request/state,
|
||||
проверка revision и подтверждённого корня, backpressure и корректная отмена.
|
||||
Это второй самостоятельный автомат с теми же обязанностями, что уже выполняет merkle_sync.
|
||||
Б. Рекомендуемый: история как MT_DATA_MESSAGES в общем merkle_sync. db_sync остаётся моделью хранения,
|
||||
публичным API истории и PUSH/ACK. Старые INIT/RESP/SEND_DATA/SYNC_DONE и цепной recalc удаляются
|
||||
после подключения новой модели. Два bulk-протокола одновременно не поддерживаются.
|
||||
Это архитектурный перенос, а не локальная замена ветки SYNC_DONE; отдельное одобрение реализации
|
||||
не подразумевается самим запросом продумать план.
|
||||
|
||||
Конкретный план вариантаБ:
|
||||
|
||||
1. Канонический набор истории.
|
||||
Namespace — числовой channel_id; dataset отдельный от MEMBERS/FEEDBACK.
|
||||
Ключ — существующий message_id[32], проверяемый вычислением из group_id/timestamp/signature.
|
||||
Лист и страница используют один и тот же отбор записей и порядок message_id по полным32 байтам.
|
||||
Канонические байты записи: timestamp(BE64),author(BE64),data_len(BE32),точные data,signature64;
|
||||
message_id связывает запись с каналом. Хеш листа включает ключ и эти однозначно кодируемые байты.
|
||||
id,flags,local_attrs,delivery_chain/delivered_peers и прочие локальные поля в корень не входят.
|
||||
Существующие подписи и идентичности сообщений не меняются; переподписывать историю не нужно.
|
||||
Авторство старой записи не фильтруется текущим ACTIVE-правилом feedback. Допуск передающего пира
|
||||
и проверка исторической подписи — разные проверки; действующие права не расширяются.
|
||||
|
||||
2. Индекс и границы SQL-транзакций.
|
||||
Добавить индекс для выбора листа и keyset-страниц; bucket — старшие25 бит ключа.
|
||||
Первая активация/restart восстанавливает производное дерево из сохранённых записей до снятия gate.
|
||||
Индекс строится ограниченными порциями, без долгой SQLite-транзакции между сетевыми событиями;
|
||||
ошибка оставляет канал неготовым, не публикует неполный корень как пустой.
|
||||
Ожидание неизвестного ключа автора — отдельное от операционного отказа состояние: строки сохраняются,
|
||||
готовность истории откладывается, но запуск чата не падает. После поступления общего ключа, в том числе
|
||||
через другой канал, индексация/попытка возобновляется без перезапуска сервиса.
|
||||
Каждый путь изменения содержимого (локальная вставка, PUSH, bulk page, доказанная порча, TTL)
|
||||
сохраняет строки и пересчитывает затронутые Merkle-пути в одной транзакции.
|
||||
Только после COMMIT меняются runtime-состояние/next_id и вызываются changed/on_insert.
|
||||
flags/local_attrs/ACK не меняют набор и не запускают Merkle.
|
||||
Перестройка формата должна сохранять подписанные строки и локальные атрибуты; DROP истории недопустим.
|
||||
|
||||
3. Adapter data_ops.
|
||||
get_page — WHERE bucket=? AND message_id>after ORDER BY message_id LIMIT..., с учётом размера пакета.
|
||||
Применение проверяет весь формат страницы, ключи/курсоры, подписи и достоверность identity до COMMIT.
|
||||
Одна страница атомарна: частичная запись/индекс/события при SQL или OpenSSL failure запрещены.
|
||||
apply_items не вызывает каскад PUSH и не отправляет пакеты из callback. Для локальной вставки/PUSH
|
||||
после COMMIT вызывается changed; bulk тоже уведомляет о реальном изменении, чтобы оно дошло другим пирам.
|
||||
Неизвестный ключ/ошибка операции прерывают попытку без удаления и ложной пустой страницы.
|
||||
BAD_SIGNATURE/BAD_FORMAT относится к проверенным сохранённым байтам и допускает согласованную очистку.
|
||||
Хеширование/чтение страницы сами не удаляют строки из открытого курсора и не запускают рекурсивный update.
|
||||
Если там найдена сохранённая порча, чтение завершается ошибкой; очистка выполняется отдельно
|
||||
после закрытия курсора в проверяемой транзакции, обновляет индекс и запускает повтор.
|
||||
|
||||
4. Управление раундом и успехом.
|
||||
Используются существующие round/request/state, два pull-прохода, CHECK/DONE, полный32-байтовый корень,
|
||||
revision, deadline и очередь с waiter. Ошибка или повтор неизменной пары разных корней — не успех.
|
||||
done для db_sync/media поступает только от MT_OK; постановка пакета в очередь и конец страницы
|
||||
не подтверждают завершение истории. Последующие изменения вновь делают сессию dirty.
|
||||
Успех означает подтверждённую контрольную точку данного раунда, не вечную глобальную синхронность
|
||||
при продолжающейся записи. Старый round/request не изменяет данные/позиции, не продлевает deadline
|
||||
и не завершает новый запрос. Эти свойства нужно проверить именно для подключённой модели истории.
|
||||
|
||||
5. Интеграция, права и владение.
|
||||
Регистрировать MESSAGES после создания общего движка при chat startup; data_ctx — стабильный inst,
|
||||
канал ищется по namespace, указатель на DB_SYNC_INSTANCE не удерживается движком после remove.
|
||||
Операционный отказ регистрации/индексации диагностируется и откатывает незавершённое подключение;
|
||||
ожидание ключа не приравнивается к ошибке. При restart заново восстановить дерево и подписки,
|
||||
даже если ETCP уже UP и повторного события UP не будет. До MEMBERS и READY история остаётся gated.
|
||||
validate_peer проверяет активную таблицу/готовность/членство. Изменение допуска после COMMIT
|
||||
переоценивает и MESSAGES, отменяя недопущенный раунд без потери чужих datasets.
|
||||
Нужна узкая отмена по(dataset,namespace), а для sleep — по(dataset,peer): cancel_ns/cancel_peer сейчас
|
||||
затрагивают сразу MEMBERS/FEEDBACK. Remove канала отменяет запросы истории до освобождения состояния.
|
||||
Порядок stop учитывает, что member_sync_destroy уничтожает общий движок раньше удаления db_sync instances.
|
||||
Публичные проверки цепочки заменяются явными проверкой истории/чтением полного Merkle-корня;
|
||||
тесты обновляются, старые chain API с неожиданно изменённой семантикой не сохраняются.
|
||||
Мост старых done callbacks требует безопасного удаления подписок во время dispatch; кешировать
|
||||
next на освобождаемом элементе нельзя. Проверить удаление текущего/следующего callback и канала.
|
||||
|
||||
6. Sleep/sound и PUSH/ACK — обязательная часть, не скрытое изменение поведения.
|
||||
Сейчас общий движок запрещает start при peer_sleep_phase, а chat_sync при sleep отменяет все datasets.
|
||||
db_sync допускает важный чат при sound_on=1. При переносе это нельзя молча потерять.
|
||||
Ввести предикат разрешённой работы модели: default для MEMBERS/FEEDBACK сохраняет нынешний запрет сна;
|
||||
для MESSAGES использует существующий db_sync_peer_throttled. Проверять его при старте, автоповторе
|
||||
после changed и обработке события sleep/sound, отменяя только запрещённые сессии.
|
||||
Awake и включение sound_on повторно подключают допустимые READY-сессии, даже без нового UP;
|
||||
одного changed недостаточно, если предыдущая отмена освободила подписку.
|
||||
PUSH и ACK(message_id) продолжают текущую адресную доставку; собственный round не требуется ACK,
|
||||
потому что он подтверждает конкретную неизменяемую запись. Очередь не считается доставкой.
|
||||
Отказ PUSH не теряет dirty-изменение Merkle. Bulk-совпадение корня само по себе не увеличивает
|
||||
delivered_peers: этот счётчик сохраняет текущую семантику индивидуальных ACK, без подтверждения
|
||||
более поздних записей старым результатом раунда.
|
||||
|
||||
7. TTL и очистка.
|
||||
До удаления старой цепочки исправить сравнение timestamp(ms) с cutoff сейчас в микросекундах;
|
||||
использовать то же определение времени, что при создании timestamp, и исключить unsigned underflow.
|
||||
Сохранить отдельную политику удаления локальных неподтверждённых записей, без глобальных tombstones.
|
||||
TTL удаляет строки и обновляет MESSAGES-пути атомарно; изменившаяся история уведомляет движок после COMMIT.
|
||||
Удаление хорошей копии из-за ошибки проверки запрещено прежним контрактом.
|
||||
|
||||
Почему этот план логически сходится:
|
||||
- Равенство набора записей даёт одинаковые корни независимо от локальных id, порядка получения,
|
||||
delivery counters или local_attrs. Изменение подписанного содержимого меняет канонические байты.
|
||||
- В пределах листа after — полный ключ неизменяемой записи, а не OFFSET; вставка до курсора не сдвигает
|
||||
уже читаемый хвост. Если её пропустил текущий проход, различие финальных корней требует нового раунда.
|
||||
- При конечном наборе допустимых записей, прекращении внешних изменений, доступных ключах/ресурсах,
|
||||
доставке пакетов и отсутствии криптографических коллизий первый pull добавляет записи второго узла
|
||||
первому, обратный — объединение второму. Пропущенные из-за изменения дерева листья дочитываются
|
||||
следующим раундом; принимать разные корни для окончания не требуется.
|
||||
- Ошибки формата/операций и неизвестные зависимости не кодируются совпадением; repeated-root conflict
|
||||
завершает попытку ошибкой, сохраняя данные. Поэтому нет бесконечного успешного restart без прогресса.
|
||||
- Сохранённые данные и индекс меняются атомарно. Предположение доказательства — все изменения модели
|
||||
проходят этот путь и производный индекс согласован; произвольная порча SQLite вне модели не становится
|
||||
автоматически обнаружимой без чтения/проверки соответствующих записей. Startup и читаемые страницы
|
||||
проверяются явно; непрерывная проверка всех байтов хранилища этим планом не обещается.
|
||||
- Контрольная точка допускает последующую запись/отзыв/TTL: они помечают дерево dirty или отменяют
|
||||
доступ, а не используют старый MT_OK для подтверждения новых данных.
|
||||
|
||||
Проверки при реализации (требования, сейчас не запускались для новой модели):
|
||||
- Равный count и разные наборы: отличие в начале/середине/конце истории, >200 и несколько тысяч записей;
|
||||
исходные ложные завершения воспроизводятся до исправления и исчезают после него.
|
||||
- Полностью одинаковые подписанные записи с разными id/local_attrs/доставкой: одинаковый полный корень.
|
||||
- Пустые таблицы; по одному сообщению; два автора с одним timestamp; несколько страниц одного листа,
|
||||
пакет заполнен раньше лимита записей, дубликаты и повтор последней страницы.
|
||||
- PUSH/вставка до и после курсора; третий узел; удаление/TTL; изменения между CHECK и отправкой DONE.
|
||||
- Старые round/request, неожиданные фазы, отмена/повтор, DOWN/REINIT/restart, старый UP без нового события.
|
||||
- SQL prepare/bind/step/commit, BLOB NOMEM, хеш/VerifyInit, очередь/таймер/waiter: нет частичных данных,
|
||||
ложного MT_OK, потери корректных строк или callback после cancel/free.
|
||||
- ACTIVE-допуск пира, отзыв/возврат, сохранение старых сообщений исключённого автора; различие sound_on/off
|
||||
при сне, изменение sound в ходе раунда, восстановление после пробуждения.
|
||||
- Недостающий исторический ключ не роняет startup и не стирает записи; его получение через другой
|
||||
канал возобновляет индексацию и обмен без restart. Операционный SQL/crypto error имеет отдельный исход.
|
||||
- Сохранность прежней истории/подписей/локальных атрибутов при смене схемы, удаление только derived-chain
|
||||
формата, startup index failure, остановка и повторный запуск чата с работающим UTUN.
|
||||
- Корректные индивидуальные ACK без двойного счётчика; media backfill вызывается только при MT_OK;
|
||||
callback отписывает себя/следующий callback и удаляет канал без UAF.
|
||||
- Общий check.sh со STUN и целевые ASAN/UBSan/LSan после реализации.
|
||||
|
||||
Статус: план вариантаБ сформирован и логически проверен при указанных предположениях;
|
||||
новая модель и её тесты ещё не реализованы. Перенос нельзя объявлять проверенным текущими203/203
|
||||
и8/8: эти результаты относятся к уже выполненному исправлению раздела11.
|
||||
+9
-4
@@ -98,10 +98,15 @@
|
||||
|
||||
[ ] **db_sync: финальная сверка принимает разные хеши при равном count** — замечено при исправлении26.10.2026.
|
||||
db_handle_sync_done явно выставляет synced и вызывает done даже при chain_hash mismatch.
|
||||
Нужно определить корректный повтор/поиск расхождения, проверить старые пакеты после reset;
|
||||
wire не содержит ID раунда. Отдельно остаётся аудит TTL (единицы времени и recalc) и callbacks.
|
||||
Нового runtime-воспроизведения этих случаев нет; текущие исправления удаления/доставки ниже завершены.
|
||||
Расширение остановлено по AGENTS.md; [member_merkle_audit_findings.txt](member_merkle_audit_findings.txt), раздел11.
|
||||
Дополнительный локальный стенд подтвердил ложный done и разные корни одинаковых подписанных записей
|
||||
с разными неподписанными id. Для200 записей с отличием в первой sparse-поиск даёт fm148;
|
||||
выбранный хвост состоит из дубликатов, простой повтор не сходится. Стенд exit0, без сетевых пакетов,
|
||||
/tmp/db-sync-completion-design.c/.mk, лог /tmp/db-sync-completion-design.log.
|
||||
План: история как MT_DATA_MESSAGES в общем Merkle, канонический набор без local id, атомарный индекс,
|
||||
полный корень/раунды/курсор; оставить PUSH/ACK. Учесть startup/stop, права, callback dispatch и sleep/sound
|
||||
(общий движок сейчас запрещает сон, db_sync допускает sound_on), исправить TTL ms/us и индекс после DELETE.
|
||||
План отдельно обосновывает сходимость, предпосылки и регрессии; runtime не менялся, перенос не реализован.
|
||||
[member_merkle_audit_findings.txt](member_merkle_audit_findings.txt), раздел12.
|
||||
|
||||
[+] **db_sync: отказ проверки/битый дубликат удаляли корректную историю** — исправлено26.10.2026 после rebase на03b05094.
|
||||
VALID/BAD_SIGNATURE/BAD_FORMAT/DEFERRED/ERROR разделены; перед DELETE проверяется сама сохранённая копия.
|
||||
|
||||
Reference in new issue
Block a user