SHA256
399 lines
30 KiB
Markdown
399 lines
30 KiB
Markdown
# Спецификация ИТХ v1 — ежедневное закрытие блокчейна SHiNE
|
||
|
||
Статус: дизайн согласован пользователем, реализации в коде нет.
|
||
Краткое описание для людей: [README.md](./README.md).
|
||
|
||
Документ рассчитан на то, чтобы по нему можно было написать код без дополнительных
|
||
уточнений. Все байтовые порядки — big-endian (BE), все хэши — SHA-256 (32 байта),
|
||
все подписи — Ed25519, все времена — UTC.
|
||
|
||
---
|
||
|
||
## 1. Термины
|
||
|
||
| Термин | Значение |
|
||
| --- | --- |
|
||
| **День D** | Календарные сутки UTC `[D 00:00:00; D+1 00:00:00)`. |
|
||
| **dayIndex** | Порядковый номер суток от эпохи графика: `dayIndex = (началоСуток_D − epochStart) / 86400_000`. У `epochStart` dayIndex = 0. |
|
||
| **Дежурный** | Сервер, закрывающий день D: `rota.servers[dayIndex mod rota.servers.length]`. |
|
||
| **Чекпоинт** | Артефакт закрытия дня: контейнер (заголовок + state-список + бандл), одним файлом в Arweave. |
|
||
| **ИТХ** | Итоговый хэш дня = `stateRoot` — меркл-корень по вершинам всех цепочек. |
|
||
| **Бандл** | Все блоки, не покрытые предыдущим признанным чекпоинтом. |
|
||
| **checkpointHash** | SHA-256 канонического preimage заголовка (раздел 5.3). Идентификатор чекпоинта. |
|
||
| **Признанный чекпоинт** | Последний чекпоинт, на который указывают PDA-слоты больше половины серверов графика. |
|
||
|
||
## 2. График дежурств (rota PDA, DAO)
|
||
|
||
Отдельный PDA, создаётся и обновляется **только DAO authority**
|
||
(точная реализация — в Solana-модуле `shine-solana/shine/`, отдельным решением;
|
||
предлагаемые seeds: `["checkpoint_rota"]`).
|
||
|
||
Логическое содержимое:
|
||
|
||
```
|
||
RotaV1
|
||
- version: u8 = 1
|
||
- epoch_start_utc_day: u32 // число суток от unix-эпохи (00:00 UTC)
|
||
- servers_count: u8
|
||
- servers: [ login_len: u8, login: UTF-8 ] * servers_count // упорядоченный список
|
||
```
|
||
|
||
Правила:
|
||
|
||
- Дежурный дня D определяется по состоянию rota PDA на момент `00:00 UTC дня D+1`
|
||
(момент начала окна закрытия). Изменение списка не пересчитывает прошлые дни.
|
||
- Вход в график — **по доверию**, не за деньги: DAO ведёт список как временный
|
||
уровень, пока не сформировано сообщество сияющих; целевое состояние —
|
||
приём/исключение серверов через голосование сияющих (см. TODO).
|
||
- При изменении состава серверов будущее распределение сдвигается автоматически —
|
||
это допустимо, календарь «дата → сервер» не ведётся.
|
||
|
||
## 3. Расписание суток (UTC)
|
||
|
||
| Окно | Действие |
|
||
| --- | --- |
|
||
| `D+1 00:00 – 06:00` | Дежурный строит чекпоинт дня D, заливает в Arweave, обновляет свой PDA-слот (`role=closed`), публикует пост в канале закрытий. |
|
||
| `D+1 06:00 – 24:00` | Остальные серверы проверяют; при успехе — свой PDA-слот (`role=agreed`) + лайк на пост. Проверять можно и раньше 06:00, как только чекпоинт появился. |
|
||
|
||
- Нет валидного чекпоинта дня D к началу следующего окна закрытия → день D **пропущен**:
|
||
никто не меняет свои слоты; дежурный дня D+1 включает блоки за все непокрытые дни
|
||
и ссылается `prev`-полями на последний признанный чекпоинт.
|
||
- Сервер, отстававший несколько дней, догоняет **последовательно**: проверяет цепочку
|
||
чекпоинтов по одному (каждый — относительно предыдущего) и в конце ставит свой слот
|
||
на последний проверенный. Опоздавшее согласие допустимо в любой момент.
|
||
|
||
## 4. Что попадает в бандл (правило среза)
|
||
|
||
- Срез = момент начала сборки чекпоинта дежурным (внутри окна `00:00–06:00`).
|
||
- В бандл входят все блоки, известные дежурному на момент среза и **не покрытые
|
||
предыдущим признанным чекпоинтом**: для каждой цепочки `c` — блоки с номера
|
||
`prevState[c].lastNumber + 1` до локальной вершины; новые цепочки — целиком,
|
||
с первого блока (номер `0`).
|
||
- Блоки, созданные уже утром D+1 до среза, допустимо включать — это не ошибка.
|
||
- Полнота относительно других серверов **не требуется**: блоки, которых у дежурного
|
||
не было, войдут в следующий чекпоинт. Проверяющие не считают «у меня есть больше»
|
||
причиной несогласия.
|
||
- **Выбор ветки (fork-choice дежурного)**: если из вершины `prevState[c]` растут
|
||
несколько валидных веток (пользователь подписал противоречащие блоки), дежурный
|
||
берёт самую длинную валидную; при равной длине — ветку с меньшим `hash32` первого
|
||
расходящегося блока (байтовое сравнение). Ветки, не растущие из `prevState[c]`,
|
||
кандидатами не являются. Подробнее о форках — раздел 10.
|
||
|
||
## 5. Формат чекпоинта (один файл / одна Arweave-транзакция)
|
||
|
||
### 5.1. Контейнер
|
||
|
||
```
|
||
magic: 16 байт ASCII "SHiNE-CHECKPOINT" (без завершающего нуля)
|
||
headerLen: u32 BE — длина headerJson в байтах
|
||
headerJson: UTF-8 JSON (раздел 5.2)
|
||
bundle: записи бандла подряд (раздел 5.4), суммарной длиной до конца файла
|
||
```
|
||
|
||
Магик читаемый — открыв файл в hex-редакторе, видно, что это (по образцу
|
||
`"SQLite format 3\0"`). Версия формата в магик не входит: она в поле `v`
|
||
заголовка и в первой строке preimage (`SHiNE-CHECKPOINT-V1`).
|
||
|
||
Рекомендуемые Arweave-теги: `App-Name: SHiNE`, `Type: checkpoint`,
|
||
`Day-Index: <dayIndex>` (теги информационные, доверия к ним нет — истина в подписи).
|
||
|
||
### 5.2. headerJson
|
||
|
||
```json
|
||
{
|
||
"v": 1,
|
||
"dayIndex": 123,
|
||
"dayDate": "2026-07-12",
|
||
"closedBy": "serverlogin",
|
||
"closedAtMs": 1789200000000,
|
||
"serverPubKeyB58": "…",
|
||
"prevCheckpointHashHex": "…64 hex… | null",
|
||
"prevArweaveTxId": "… | null",
|
||
"stateRootHex": "…64 hex…",
|
||
"stateCount": 3500,
|
||
"bundleRootHex": "…64 hex…",
|
||
"bundleCount": 4200,
|
||
"state": [
|
||
{ "name": "alice-001", "lastNumber": 17, "lastHashHex": "…64 hex…" }
|
||
],
|
||
"signatureB64": "…"
|
||
}
|
||
```
|
||
|
||
- `state` отсортирован по `name` **байтово по UTF-8, по возрастанию**, без дублей.
|
||
- `dayDate` — дата дня D (для читаемости; проверяется соответствие `dayIndex`).
|
||
- Для генезис-чекпоинта `prevCheckpointHashHex` и `prevArweaveTxId` равны `null`,
|
||
`prevState` считается пустым, бандл содержит всю историю.
|
||
- Все hex — в нижнем регистре.
|
||
|
||
### 5.3. Канонический preimage, checkpointHash и подпись
|
||
|
||
Preimage — UTF-8 строка из 9 строк, разделитель `\n` (без завершающего `\n`;
|
||
`null`-значения кодируются как `-`):
|
||
|
||
```
|
||
SHiNE-CHECKPOINT-V1
|
||
<dayIndex>
|
||
<dayDate>
|
||
<closedBy>
|
||
<prevCheckpointHashHex | ->
|
||
<prevArweaveTxId | ->
|
||
<stateRootHex>
|
||
<bundleRootHex>
|
||
<closedAtMs>
|
||
```
|
||
|
||
- `checkpointHash = SHA-256(preimage)`.
|
||
- `signatureB64 = Ed25519(preimage)` актуальным клиентским ключом дежурного сервера
|
||
(ключ из его `user_pda`, действующий на момент закрытия; `serverPubKeyB58` его дублирует).
|
||
- `checkpointHash` не зависит от форматирования JSON — только от полей preimage.
|
||
|
||
### 5.4. Запись бандла
|
||
|
||
Записи идут подряд, отсортированы по `(name байтово, blockNumber)` по возрастанию:
|
||
|
||
```
|
||
nameLen: u16 BE
|
||
name: UTF-8 (blockchainName)
|
||
blockNumber: u64 BE
|
||
blockLen: u32 BE
|
||
blockBytes: полный блок как в хранилище: preimage + sigMarker + signature64
|
||
```
|
||
|
||
`bundleCount` в заголовке = число записей; парсер обязан проверить, что записи
|
||
заканчиваются ровно на конце файла.
|
||
|
||
### 5.5. Меркл-правила (общие для state и бандла)
|
||
|
||
- Лист: `SHA-256(0x00 || данные листа)`.
|
||
- Узел: `SHA-256(0x01 || left32 || right32)`.
|
||
- При нечётном числе узлов на уровне последний **поднимается без изменения**.
|
||
- Пустое дерево → 32 нулевых байта.
|
||
|
||
Данные листа:
|
||
|
||
- **state** (порядок листьев = порядок `state`):
|
||
`nameBytes || 0x00 || lastNumber u64 BE || lastHash32`.
|
||
Корень = `stateRoot` = **ИТХ**.
|
||
- **бандл** (порядок листьев = порядок записей): полные байты записи из 5.4
|
||
(включая nameLen/name/blockNumber/blockLen). Корень = `bundleRoot`.
|
||
|
||
## 6. Слот чекпоинта в PDA сервера
|
||
|
||
Новый типизированный блок в `user_pda` сервера (рядом с `ServerProfileBlock (30)`;
|
||
финальный номер `block_type` и правки `shine-user-pda-format-v.1.0.md` —
|
||
при реализации Solana-части, отдельным решением). Предложение:
|
||
|
||
```
|
||
CheckpointStateBlock (block_type = 60, block_version = 0)
|
||
- day_index: u32
|
||
- checkpoint_hash: [32]
|
||
- arweave_tx_len: u8, arweave_tx: ASCII
|
||
- closed_by_len: u8, closed_by: UTF-8
|
||
- my_role: u8 // 1 = closed (я закрывал), 2 = agreed (я согласен)
|
||
- updated_at_ms: u64
|
||
```
|
||
|
||
Правила:
|
||
|
||
- Слот **один**, перезаписывается на месте; истории в PDA нет
|
||
(история — цепочка чекпоинтов в Arweave и посты в канале).
|
||
- Дежурный после заливки ставит свой чекпоинт с `my_role=1`.
|
||
- Проверивший и согласный сервер ставит тот же `(day_index, checkpoint_hash,
|
||
arweave_tx, closed_by)` с `my_role=2`.
|
||
- **Несогласие = не трогать слот.** Отдельной записи «против» нет.
|
||
|
||
Правило признания (для наблюдателей и восстановления):
|
||
|
||
> Актуальный чекпоинт = последний (максимальный `day_index`), на который указывают
|
||
> одинаковые `(day_index, checkpoint_hash)` в слотах **больше половины** серверов
|
||
> из rota PDA. Рекомендация клиентам: до достижения половины считать актуальным
|
||
> предыдущий признанный.
|
||
|
||
Правило признания — правило **чтения**, а не записи:
|
||
|
||
- дефолтное множество для подсчёта — список rota PDA;
|
||
- любой наблюдатель (клиент, сторонний сервер, восстановление) вправе применять то же
|
||
правило к **собственному списку доверенных серверов**; DAO-список — рекомендация
|
||
по умолчанию (конфиг сервера: `checkpoint.trust.logins`; пусто = rota PDA);
|
||
- серверы графика при закрытии и проверке обязаны использовать общий DAO-список,
|
||
иначе ротация теряет общую точку отсчёта. Коротко: **запись — по общему списку,
|
||
чтение — по любому**.
|
||
|
||
Параллельные группы закрытий допустимы by design: любая другая группа серверов может
|
||
вести собственную цепочку чекпоинтов над теми же данными (свой генезис, свои PDA-слоты,
|
||
свои Arweave-транзакции). Группы механически не пересекаются (разные `prev`-цепочки)
|
||
и не могут подделать содержимое блоков — только заверять историю или не включать её
|
||
часть. Запрещать это кодом сознательно не планируется; «официальность» DAO-группы
|
||
держится только на том, что её список — дефолт в клиентах.
|
||
|
||
## 7. Канал закрытий в Сиянии
|
||
|
||
- У каждого сервера графика — свой публичный канал `type=1`, slug `checkpoints`
|
||
(создаётся обычным `TECH_CREATE_CHANNEL`).
|
||
- При закрытии дежурный пишет в свой канал `TEXT_POST`:
|
||
|
||
```
|
||
/.checkpoint <dayIndex> <checkpointHashHex> <arweaveTxId>
|
||
```
|
||
|
||
- Согласие другого сервера — `REACTION_LIKE`, таргетирующий блок этого поста.
|
||
Отзыв согласия — `REACTION_UNLIKE`. Комментарии не требуются.
|
||
- Смысл: человекочитаемое зеркало + криптографическая проверяемость через Arweave
|
||
(пост и лайки подписаны ключами серверов, зарегистрированными в Solana), с лагом в
|
||
один день (попадут в следующий бандл).
|
||
- Машинный якорь «здесь и сейчас» — PDA-слоты; канал вторичен.
|
||
- При реализации обязательно дописать команду `/.checkpoint` в
|
||
`docs/Blockchain/02_Channel_Commands.md`.
|
||
|
||
## 8. Алгоритм дежурного (закрытие дня D)
|
||
|
||
1. В окне `D+1 00:00–06:00` убедиться по rota PDA, что дежурный — я.
|
||
2. Определить предыдущий признанный чекпоинт (свой слот + слоты остальных, раздел 6);
|
||
загрузить его `state` (локальный кэш или Arweave). Для генезиса — пустой.
|
||
3. Зафиксировать срез: для каждой цепочки — вершина выбранной ветки
|
||
`(lastNumber, lastHash)` по правилу fork-choice из раздела 4.
|
||
4. Собрать бандл по разделу 4, отсортировать по 5.4, посчитать `bundleRoot`.
|
||
5. Сформировать `state` по срезу, отсортировать, посчитать `stateRoot` (ИТХ).
|
||
6. Собрать preimage, `checkpointHash`, подписать серверным ключом.
|
||
7. Залить контейнер одной Arweave-транзакцией (JWK сервера с хоста, вне git),
|
||
дождаться подтверждения, получить `arweaveTxId`.
|
||
8. Обновить свой PDA-слот: `(dayIndex, checkpointHash, arweaveTxId, closedBy=я, role=1)`.
|
||
9. Опубликовать пост `/.checkpoint …` в своём канале закрытий.
|
||
10. Любая ошибка на шагах 7–9 → повторять до конца окна; не успел — день пропущен,
|
||
ничего не публиковать частично (PDA-слот и пост ставить только после успешного Arweave).
|
||
|
||
## 9. Алгоритм проверяющего
|
||
|
||
Вход: обнаружен новый чекпоинт дня D от сервера S (по его PDA-слоту и/или посту).
|
||
|
||
1. **График**: `S == rota[dayIndex mod N]` по состоянию rota PDA на `00:00 D+1`;
|
||
`dayIndex` больше `day_index` последнего признанного локально чекпоинта.
|
||
2. Скачать Arweave-транзакцию из слота S; проверить `magic`, длины, парсинг.
|
||
3. Пересчитать preimage → `checkpointHash`; сверить со слотом S (и постом, если есть).
|
||
4. Проверить `signatureB64` ключом S (актуальный клиентский ключ из `user_pda` S;
|
||
допускается ключ, действовавший в день закрытия — см. TODO про ротацию).
|
||
5. `prevCheckpointHashHex`/`prevArweaveTxId` == локально признанный крайний чекпоинт.
|
||
Иначе — отказ.
|
||
6. Пересчитать `bundleRoot` по записям; сверить. Проверить сортировку и `bundleCount`.
|
||
7. **Мостик prev→state** (полнота бандла): для каждой цепочки из `state`
|
||
блоки бандла образуют непрерывную последовательность номеров и `prevHash`-ссылок
|
||
от `prevState[c]` (или от блока 0 для новой цепочки) ровно до `state[c]`.
|
||
Для каждого блока: `hash32 == SHA-256(preimage)`, структура валидна по правилам
|
||
`docs/Blockchain/01_Common_Block_Format.md`, подпись Ed25519 валидна ключом
|
||
владельца цепочки, действующим на день закрытия.
|
||
8. Пересчитать `stateRoot` по `state`; сверить (это и есть проверка ИТХ).
|
||
9. **Конфликты с локальными данными**: если локально для `(цепочка, номер)` есть блок
|
||
с другим `hash32` — побеждает версия чекпоинта: локальная ветка отбрасывается
|
||
(реорганизация), согласие НЕ отклоняется. Отказ по конфликту возможен только когда
|
||
чекпоинт противоречит уже признанному прошлому — это ловится шагом 7 (мостик не
|
||
соединится с `prevState`). «У меня есть блоки, которых нет в бандле» — тоже НЕ отказ.
|
||
10. Импортировать недостающие блоки бандла в локальное хранилище тем же валидационным
|
||
путём, что и межсерверная синхронизация (`sync-between-servers.md`).
|
||
11. Успех → обновить свой PDA-слот (`role=2`) и поставить лайк на пост S.
|
||
Отказ → не делать ничего on-chain; подробно залогировать причину
|
||
(рекомендуемый префикс лога: `CHECKPOINT_REJECT`).
|
||
|
||
Проверка детерминирована: два честных сервера с любым набором локальных блоков приходят
|
||
к одному вердикту. Проверяется валидность выбора дежурного и стыковка с прошлым
|
||
чекпоинтом, но не «длиннейшесть» выбранной ветки — её никто, кроме дежурного, проверить
|
||
не может, и условием согласия она не является.
|
||
|
||
## 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).
|
||
3. От него по `prevArweaveTxId` спуститься до генезиса, затем раскатать бандлы
|
||
от генезиса вверх, валидируя каждый чекпоинт по разделу 9 (шаги 2–8).
|
||
4. Хвост после последнего чекпоинта добрать живой синхронизацией с серверами.
|
||
|
||
## 12. Стоимость и ключи
|
||
|
||
- Каждый сервер платит сам: Arweave — за свои дежурные дни, Solana — за свои слоты.
|
||
- Arweave JWK сервера хранится только на хосте (например,
|
||
`/home/player/SHiNE/secrets/…`), путь задаётся конфигом; в git не попадает —
|
||
по той же схеме, что `test.freeAvatar.walletJwkPath`.
|
||
|
||
## 13. Ориентир для реализации на сервере (не нормативно)
|
||
|
||
- `CheckpointScheduler` — таймер окон 00:00/06:00 UTC, определение роли по rota PDA.
|
||
- `CheckpointBuilder` — срез, бандл, меркл, preimage, подпись (разделы 4–5, 8).
|
||
- `ArweaveCheckpointUploader` — заливка контейнера, ожидание подтверждения.
|
||
- `CheckpointVerifier` — раздел 9; переиспользовать валидацию блоков из `AddBlock`/sync.
|
||
- `CheckpointSolanaSlot` — чтение/запись `CheckpointStateBlock`, чтение rota PDA.
|
||
- `CheckpointChannelPublisher` — пост `/.checkpoint` и лайки через обычный `AddBlock`.
|
||
- Конфиги (предложение): `checkpoint.enabled`, `checkpoint.arweave.jwkPath`,
|
||
`checkpoint.rota.pda` (или деривация по seeds), `checkpoint.closeWindowHours=6`.
|
||
- Локально хранить: `state` последнего признанного чекпоинта + его
|
||
`(dayIndex, hash, arweaveTxId)` — чтобы не ходить в Arweave на каждое закрытие.
|
||
|
||
## 14. TODO / сознательно отложено
|
||
|
||
- **История ключей при ротации**: если сервер/пользователь меняет ключ несколько раз
|
||
за день, для проверки старых подписей нужна история версий ключей. v1 живёт с
|
||
«ключ, актуальный на день закрытия»; при внедрении ротации — хранить версии.
|
||
- **Механизм новой цепочки `-002`**: пользовательский flow «продолжить с новой
|
||
цепочкой» после заморозки (регистрация в `BlockchainRegistryBlock`, UI) пока
|
||
не реализован — см. раздел 10.
|
||
- **Детерминированный выбор дежурного**:
|
||
`дежурный = SHA-256(prevCheckpointHash || dayIndex) mod N` по байтово отсортированным
|
||
логинам — убирает порядок списка как рычаг управления, DAO остаётся только
|
||
вход/выход участников.
|
||
- **Передача ведения графика сообществу**: вход в группу закрытий — по доверию,
|
||
не за деньги. Сейчас список ведёт DAO — это временный уровень, пока сообщество
|
||
сияющих не сформировано; в перспективе приём/исключение серверов — через
|
||
голосование сияющих. Депозитный/платный вход сознательно отвергнут.
|
||
- **Автопропуск штрафника** в ротации (2 подряд закрытия без единого согласия).
|
||
- **On-chain кворум** вместо правила чтения «>половины» — если понадобится.
|
||
- **Сжатие бандла** (gzip) и **чанкование** очень больших бандлов на несколько
|
||
Arweave-транзакций с манифестом. v1 — один несжатый файл.
|
||
- Экономия Solana-транзакций: считать согласия только по лайкам канала — возможно
|
||
после обкатки v1.
|
||
|
||
## 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` — фиксировать изменения.
|