SHA256
Дополнить дизайн ИТХ: форки, списки доверия, децентрализация
- Раздел 6: правило признания — правило чтения (дефолт rota PDA, наблюдатель может считать по своему списку доверия); параллельные группы закрытий разрешены by design. - Новый раздел 10 «Форки пользовательских цепочек»: fork-choice дежурного (длиннейшая ветка + tie-break), зачекпоинченное побеждает, заморозка chain_frozen только при противоречии архивов двух групп, рестарт с login-002, байт-в-байт повтор для клиентов. - Шаг 9.9 проверки: конфликт -> принять версию чекпоинта (один пользователь больше не срывает закрытие дня). - TODO: хэш-выбор дежурного, вход по депозиту, механизм цепочки -002. - CHANGELOG блокчейна дополнен; формат блоков и AddBlock не менялись. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Fable 5
parent
4cb98f7ca0
commit
172f007e1e
@@ -1,5 +1,24 @@
|
||||
# История изменений документации блокчейна
|
||||
|
||||
## 2026-07-14 18:43:18 +0400
|
||||
- Базовый коммит-ориентир: `4cb98f7`.
|
||||
- Дизайн ИТХ дополнен по итогам обсуждения (`docs/ИТХ/README.md`, `docs/ИТХ/Спецификация_ИТХ_v1.md`):
|
||||
- правило признания явно объявлено правилом чтения: дефолт — rota PDA, но наблюдатель
|
||||
может считать голоса по собственному списку доверия («запись — по общему списку,
|
||||
чтение — по любому»); параллельные группы закрытий разрешены by design;
|
||||
- новый раздел 10 «Форки пользовательских цепочек»: fork-choice дежурного
|
||||
(длиннейшая ветка от зачекпоинченной вершины + tie-break по меньшему `hash32`),
|
||||
зачекпоинченное всегда побеждает локальные ветки, заморозка цепочки (`chain_frozen`)
|
||||
только при противоречии между архивами двух групп закрытий, рестарт с `login-002`;
|
||||
- шаг 9.9 проверки изменён с «конфликт → отказ» на «конфликт → принять версию
|
||||
чекпоинта»: один пользователь больше не может сорвать закрытие дня;
|
||||
- правило для клиентов: повтор отправки блока — только байт-в-байт (дедупликация,
|
||||
а не форк);
|
||||
- TODO дополнен: детерминированный выбор дежурного через hash, вход в график
|
||||
по депозиту, механизм новой цепочки `-002`.
|
||||
- Формат блоков и правила `AddBlock` по-прежнему не изменены (код не реализован);
|
||||
при реализации дописать `chain_frozen` в `docs/API/04_Add_Block_to_Blockchain_API.md`.
|
||||
|
||||
## 2026-07-13 14:04:59 +0400
|
||||
- Базовый коммит-ориентир: `af12d7b`.
|
||||
- Добавлена новая папка документации `docs/ИТХ/` — ежедневное закрытие блокчейна (чекпоинты):
|
||||
|
||||
@@ -60,6 +60,22 @@ Arweave почти не читается, это гарантия, а не ра
|
||||
каждый сервер публикует только своё мнение, а наблюдатель считает голоса сам.
|
||||
Сервер, который систематически ошибается, DAO просто исключает из списка.
|
||||
|
||||
Правило работает относительно списка: по умолчанию считают по DAO-списку,
|
||||
но любой наблюдатель вправе считать голоса по **собственному списку доверенных
|
||||
серверов**. Коротко: запись — по общему списку, чтение — по любому.
|
||||
|
||||
## Форки и параллельные группы
|
||||
|
||||
- Пользователь раздвоил свою цепочку до чекпоинта — дежурный возьмёт самую
|
||||
длинную ветку, проигравшая отбросится; пользователь не наказывается.
|
||||
- Ветка против уже зачекпоинченного — побеждает чекпоинт, ветка отбрасывается.
|
||||
- Умудрился дописать противоречащие ветки в архивы **двух разных групп закрытий** —
|
||||
цепочка замораживается навсегда (два неизменных архива слить нельзя),
|
||||
дальше пользователь начинает новую цепочку `login-002`.
|
||||
- Любая другая группа серверов может вести свою параллельную цепочку чекпоинтов
|
||||
над теми же данными — это разрешено by design: подделать блоки они не могут,
|
||||
а независимых «нотариусов» у истории становится больше.
|
||||
|
||||
## Восстановление сервера с нуля
|
||||
|
||||
1. Прочитать DAO PDA → список серверов графика.
|
||||
|
||||
@@ -70,6 +70,11 @@ RotaV1
|
||||
- Полнота относительно других серверов **не требуется**: блоки, которых у дежурного
|
||||
не было, войдут в следующий чекпоинт. Проверяющие не считают «у меня есть больше»
|
||||
причиной несогласия.
|
||||
- **Выбор ветки (fork-choice дежурного)**: если из вершины `prevState[c]` растут
|
||||
несколько валидных веток (пользователь подписал противоречащие блоки), дежурный
|
||||
берёт самую длинную валидную; при равной длине — ветку с меньшим `hash32` первого
|
||||
расходящегося блока (байтовое сравнение). Ветки, не растущие из `prevState[c]`,
|
||||
кандидатами не являются. Подробнее о форках — раздел 10.
|
||||
|
||||
## 5. Формат чекпоинта (один файл / одна Arweave-транзакция)
|
||||
|
||||
@@ -198,6 +203,23 @@ CheckpointStateBlock (block_type = 60, block_version = 0)
|
||||
> из rota PDA. Рекомендация клиентам: до достижения половины считать актуальным
|
||||
> предыдущий признанный.
|
||||
|
||||
Правило признания — правило **чтения**, а не записи:
|
||||
|
||||
- дефолтное множество для подсчёта — список rota PDA;
|
||||
- любой наблюдатель (клиент, сторонний сервер, восстановление) вправе применять то же
|
||||
правило к **собственному списку доверенных серверов**; DAO-список — рекомендация
|
||||
по умолчанию (конфиг сервера: `checkpoint.trust.logins`; пусто = rota PDA);
|
||||
- серверы графика при закрытии и проверке обязаны использовать общий DAO-список,
|
||||
иначе ротация теряет общую точку отсчёта. Коротко: **запись — по общему списку,
|
||||
чтение — по любому**.
|
||||
|
||||
Параллельные группы закрытий допустимы by design: любая другая группа серверов может
|
||||
вести собственную цепочку чекпоинтов над теми же данными (свой генезис, свои PDA-слоты,
|
||||
свои Arweave-транзакции). Группы механически не пересекаются (разные `prev`-цепочки)
|
||||
и не могут подделать содержимое блоков — только заверять историю или не включать её
|
||||
часть. Запрещать это кодом сознательно не планируется; «официальность» DAO-группы
|
||||
держится только на том, что её список — дефолт в клиентах.
|
||||
|
||||
## 7. Канал закрытий в Сиянии
|
||||
|
||||
- У каждого сервера графика — свой публичный канал `type=1`, slug `checkpoints`
|
||||
@@ -222,7 +244,8 @@ CheckpointStateBlock (block_type = 60, block_version = 0)
|
||||
1. В окне `D+1 00:00–06:00` убедиться по rota PDA, что дежурный — я.
|
||||
2. Определить предыдущий признанный чекпоинт (свой слот + слоты остальных, раздел 6);
|
||||
загрузить его `state` (локальный кэш или Arweave). Для генезиса — пустой.
|
||||
3. Зафиксировать срез: для каждой цепочки — локальная вершина `(lastNumber, lastHash)`.
|
||||
3. Зафиксировать срез: для каждой цепочки — вершина выбранной ветки
|
||||
`(lastNumber, lastHash)` по правилу fork-choice из раздела 4.
|
||||
4. Собрать бандл по разделу 4, отсортировать по 5.4, посчитать `bundleRoot`.
|
||||
5. Сформировать `state` по срезу, отсортировать, посчитать `stateRoot` (ИТХ).
|
||||
6. Собрать preimage, `checkpointHash`, подписать серверным ключом.
|
||||
@@ -254,19 +277,58 @@ CheckpointStateBlock (block_type = 60, block_version = 0)
|
||||
владельца цепочки, действующим на день закрытия.
|
||||
8. Пересчитать `stateRoot` по `state`; сверить (это и есть проверка ИТХ).
|
||||
9. **Конфликты с локальными данными**: если локально для `(цепочка, номер)` есть блок
|
||||
с другим `hash32` — отказ (v1 форки автоматически не разруливает; см. TODO).
|
||||
«У меня есть блоки, которых нет в бандле» — НЕ отказ.
|
||||
с другим `hash32` — побеждает версия чекпоинта: локальная ветка отбрасывается
|
||||
(реорганизация), согласие НЕ отклоняется. Отказ по конфликту возможен только когда
|
||||
чекпоинт противоречит уже признанному прошлому — это ловится шагом 7 (мостик не
|
||||
соединится с `prevState`). «У меня есть блоки, которых нет в бандле» — тоже НЕ отказ.
|
||||
10. Импортировать недостающие блоки бандла в локальное хранилище тем же валидационным
|
||||
путём, что и межсерверная синхронизация (`sync-between-servers.md`).
|
||||
11. Успех → обновить свой PDA-слот (`role=2`) и поставить лайк на пост S.
|
||||
Отказ → не делать ничего on-chain; подробно залогировать причину
|
||||
(рекомендуемый префикс лога: `CHECKPOINT_REJECT`).
|
||||
|
||||
Проверка детерминирована: два честных сервера с любым набором локальных блоков
|
||||
приходят к одному вердикту, кроме шага 9 (локальный конфликт), который сигналит
|
||||
о реальном форке пользовательской цепочки.
|
||||
Проверка детерминирована: два честных сервера с любым набором локальных блоков приходят
|
||||
к одному вердикту. Проверяется валидность выбора дежурного и стыковка с прошлым
|
||||
чекпоинтом, но не «длиннейшесть» выбранной ветки — её никто, кроме дежурного, проверить
|
||||
не может, и условием согласия она не является.
|
||||
|
||||
## 10. Восстановление сервера с нуля
|
||||
## 10. Форки пользовательских цепочек
|
||||
|
||||
Форк = два блока одной цепочки с одинаковым `blockNumber`, разным `hash32` и валидными
|
||||
подписями владельца. Случайно-честно такое не возникает: каждый блок подписывается
|
||||
владельцем и ссылается на `prevHash`. Пара таких блоков — самодостаточная
|
||||
криптографическая улика, проверяемая любым сервером локально, без арбитра и голосования.
|
||||
|
||||
Лесенка разруливания:
|
||||
|
||||
| Ситуация | Арбитр | Исход |
|
||||
| --- | --- | --- |
|
||||
| Ветки разошлись до чекпоинта | Дежурный (длиннейшая + tie-break, раздел 4) | Проигравшая ветка отбрасывается, цепочка живёт |
|
||||
| Локальная ветка против зачекпоинченной в своей группе | Цепочка чекпоинтов | Локальная ветка отбрасывается (шаг 9.9) |
|
||||
| Чекпоинт противоречит признанному прошлому | Проверяющие | Согласий нет, день пропущен |
|
||||
| Противоречие между архивами двух групп закрытий | Никто — улика | Заморозка цепочки |
|
||||
|
||||
Заморозка применяется **только** в последнем случае — когда обе ветки уже зачекпоинчены
|
||||
разными группами закрытий и неизменны в Arweave: слить два неизменных архива невозможно
|
||||
в принципе.
|
||||
|
||||
- Улика: два конфликтующих блока, каждый из которых входит в валидный чекпоинт
|
||||
своей группы.
|
||||
- Сервер, проверивший улику, перестаёт принимать `AddBlock` в эту цепочку
|
||||
(код отказа: `chain_frozen`); улика синхронизируется партнёрам как обычные данные,
|
||||
каждый проверяет и замораживает независимо.
|
||||
- Уже записанная история цепочки остаётся валидной и читаемой навсегда.
|
||||
- Пользователь продолжает с новой цепочкой `<login>-<NNN+1>` (например, `login-002`);
|
||||
`BlockchainRegistryBlock` в `user_pda` уже поддерживает несколько цепочек.
|
||||
Старые связи/подписки указывают на корни старой цепочки — репутационная история
|
||||
не переносится, это осознанная часть последствий.
|
||||
|
||||
Обязательное правило для клиентов (защищает честных пользователей от гонок):
|
||||
повтор отправки блока после таймаута/ошибки — только **байт-в-байт** тем же блоком.
|
||||
Байт-идентичный дубль — дедупликация, а не форк. Пересборка блока с новым `timestamp`
|
||||
на тот же номер создаёт форк на ровном месте.
|
||||
|
||||
## 11. Восстановление сервера с нуля
|
||||
|
||||
1. Прочитать rota PDA → список серверов.
|
||||
2. Прочитать их PDA-слоты → признанный чекпоинт (правило раздела 6).
|
||||
@@ -274,14 +336,14 @@ CheckpointStateBlock (block_type = 60, block_version = 0)
|
||||
от генезиса вверх, валидируя каждый чекпоинт по разделу 9 (шаги 2–8).
|
||||
4. Хвост после последнего чекпоинта добрать живой синхронизацией с серверами.
|
||||
|
||||
## 11. Стоимость и ключи
|
||||
## 12. Стоимость и ключи
|
||||
|
||||
- Каждый сервер платит сам: Arweave — за свои дежурные дни, Solana — за свои слоты.
|
||||
- Arweave JWK сервера хранится только на хосте (например,
|
||||
`/home/player/SHiNE/secrets/…`), путь задаётся конфигом; в git не попадает —
|
||||
по той же схеме, что `test.freeAvatar.walletJwkPath`.
|
||||
|
||||
## 12. Ориентир для реализации на сервере (не нормативно)
|
||||
## 13. Ориентир для реализации на сервере (не нормативно)
|
||||
|
||||
- `CheckpointScheduler` — таймер окон 00:00/06:00 UTC, определение роли по rota PDA.
|
||||
- `CheckpointBuilder` — срез, бандл, меркл, preimage, подпись (разделы 4–5, 8).
|
||||
@@ -294,13 +356,21 @@ CheckpointStateBlock (block_type = 60, block_version = 0)
|
||||
- Локально хранить: `state` последнего признанного чекпоинта + его
|
||||
`(dayIndex, hash, arweaveTxId)` — чтобы не ходить в Arweave на каждое закрытие.
|
||||
|
||||
## 13. TODO / сознательно отложено
|
||||
## 14. TODO / сознательно отложено
|
||||
|
||||
- **История ключей при ротации**: если сервер/пользователь меняет ключ несколько раз
|
||||
за день, для проверки старых подписей нужна история версий ключей. v1 живёт с
|
||||
«ключ, актуальный на день закрытия»; при внедрении ротации — хранить версии.
|
||||
- **Разруливание форков** пользовательских цепочек (шаг 9.9): правило «наиболее
|
||||
длинная валидная цепочка» + детерминированный tie-break. v1 — отказ и лог.
|
||||
- **Механизм новой цепочки `-002`**: пользовательский flow «продолжить с новой
|
||||
цепочкой» после заморозки (регистрация в `BlockchainRegistryBlock`, UI) пока
|
||||
не реализован — см. раздел 10.
|
||||
- **Детерминированный выбор дежурного**:
|
||||
`дежурный = SHA-256(prevCheckpointHash || dayIndex) mod N` по байтово отсортированным
|
||||
логинам — убирает порядок списка как рычаг управления, DAO остаётся только
|
||||
вход/выход участников.
|
||||
- **Вход в график по депозиту** вместо редактирования списка DAO: permissionless
|
||||
rota PDA, вступление под залог SOL, выход с возвратом после таймаута — сибил-фильтр
|
||||
становится экономическим (инфраструктурно близко к `shine_payments`).
|
||||
- **Автопропуск штрафника** в ротации (2 подряд закрытия без единого согласия).
|
||||
- **On-chain кворум** вместо правила чтения «>половины» — если понадобится.
|
||||
- **Сжатие бандла** (gzip) и **чанкование** очень больших бандлов на несколько
|
||||
@@ -308,11 +378,13 @@ CheckpointStateBlock (block_type = 60, block_version = 0)
|
||||
- Экономия Solana-транзакций: считать согласия только по лайкам канала — возможно
|
||||
после обкатки v1.
|
||||
|
||||
## 14. Связанные документы (обновлять при реализации)
|
||||
## 15. Связанные документы (обновлять при реализации)
|
||||
|
||||
- `docs/Blockchain/01_Common_Block_Format.md` — формат блока (используется в 5.4, 9.7).
|
||||
- `docs/Blockchain/02_Channel_Commands.md` — дописать `/.checkpoint`.
|
||||
- `docs/Blockchain/sync-between-servers.md` — путь импорта блоков (9.10).
|
||||
- `shine-solana/shine/doc/formats/shine-user-pda-format-v.1.0.md` — дописать
|
||||
`CheckpointStateBlock` и rota PDA при реализации Solana-части.
|
||||
- `docs/API/04_Add_Block_to_Blockchain_API.md` — при реализации дописать код отказа
|
||||
`chain_frozen` (раздел 10).
|
||||
- `docs/Blockchain/CHANGELOG.md` — фиксировать изменения.
|
||||
|
||||
Reference in New Issue
Block a user