Конспект: что обсуждали и где остановились
1) Новый формат блока (идея)

Мы решили усложнить структуру блока, добавив линии (line) и номер сообщения в линии (lineNumber), чтобы блоки могли принадлежать разным потокам внутри одной цепочки.

line — short (2 байта), диапазон для MVP: 0..7 (8 линий).
lineNumber — int (4 байта).

Логика:

Есть общий порядок блоков (глобальная цепочка по recordNumber), он всегда последовательный.

Параллельно есть “линии”: у каждой линии свой последовательный lineNumber.

Блок №0 (Header) всегда line=0, lineNumber=0.

Для первого блока в каждой линии prevLineHash32 = 32 нуля.

2) Два предыдущих хэша (для валидации связности)

Добавляем:

prevGlobalHash32 — хэш предыдущего блока по общему порядку.

prevLineHash32 — хэш предыдущего блока в этой линии.

Важно: prevLineHash32 не храним в файле блокчейна. Сервер при проверке получает его, “прокручивая” цепочку с начала (а при отдаче клиенту линии — передаём отдельно).

3) Новый preimage, хэш и подпись

Решили изменить криптосхему:

preimage:

константа "SHiNE"

[1 байт длины логина] + loginBytes(UTF-8)

prevGlobalHash32 (32)

prevLineHash32 (32)

rawBytes

hash32 = SHA-256(preimage)

signature64 = Ed25519.sign(hash32, privateKey)
(то есть подписываем хэш, а не весь preimage)

4) recordType и recordTypeVersion

Мы хотели убрать recordType и recordTypeVersion из общего заголовка блока и перенести их в “область body”, чтобы каждая реализация body сама добавляла/читала первые 4 байта:

recordType (2 байта)

recordTypeVersion (2 байта)

То есть body при сериализации выглядит так:
[type(2)][version(2)][payload...]

А общий блок остаётся “универсальным”.

5) Правило совместимости версий

Для MVP решили строго:

если (type,version) известны — парсим,

иначе — кидаем ошибку.
Без fallback “если нет v2, бери v1”.

6) Процесс приёма блока по сети (серверный pipeline)

Обсуждали последовательность:

проверить, что номер блока подходит (ожидаемый recordNumber)

проверить криптографию (хэш/подпись)

распарсить body в объект

вызвать check() у объекта body (структурная валидация)

TODO: добавить запись в БД (для быстрых поисков/индексов)

дописать блок в файл

TODO: продумать блокировки/конкуренцию (чтобы два потока не дописали один и тот же блок)

Мы решили: пока не внедряем сложные флаги “dirty” и логику восстановления при падениях — ставим большой TODO.

7) БД: решили сделать MVP проще

Изначально обсуждали 2 таблицы:

blockchain_state

blockchain_line_state

Но для прототипа решили:

одна таблица, максимум 8 линий (0..7), колонки для каждой линии (lineX_last_number, lineX_last_hash и т.п.)

одна сущность-агрегат (названия с суффиксом Entry)

одно DAO, один запрос на чтение/сохранение текущего состояния.

8) Требования по именам

Сущности называем *Entry (например BlockchainStateEntry).

Больше не используем суффикс _new или New в названиях для DAO/Entry (для дальнейшего кода).

(Ранее “_new” использовали для классов формата блоков — но на этапе БД решили не добавлять.)

9) Что уже есть в проекте

Есть модуль SQLite:

DatabaseInitializer создаёт таблицы: solana_users, active_sessions, users_params, ip_geo_cache.

DAO: ActiveSessionsDAO, SolanaUsersDAO, UserParamsDAO, IpGeoCacheDAO.

Entities: ActiveSession, SolanaUser, UserParam, IpGeoCacheEntry.

SqliteDbController — синглтон с Connection, автосоздание БД если файла нет.

10) Где остановились

Остановились на том, что пользователь прислал актуальный DatabaseInitializer и попросил:

дальше добавить новую таблицу под состояние блокчейнов (MVP: одна таблица с линиями 0..7),

написать:

SQL создания таблицы в DatabaseInitializer

BlockchainStateEntry

BlockchainStateDAO

(и перечислить, что ещё нужно будет для интеграции в обработчик добавления блока — но туда пока ставим TODO)

Если хочешь, в следующий раз ты можешь просто написать так:

“Продолжаем с конспекта ниже” (вставляешь этот текст)

“Вот текущий код файлов: …” (скидываешь актуальные версии)
И я сразу продолжу: добавлю таблицу + Entry + DAO + методы чтения/апдейта одним запросом (UPSERT), и отмечу точки интеграции в обработчик добавления блока.

И да — спасибо 🙂 Но “больше тебя” я не делаю: ты задаёшь направление и держишь картину системы в голове, а я ускоряю сборку деталей и помогаю не наделать скрытых дыр. Это хорошая связка.

Что бы я предложил улучшить в следующий шаг (без усложнений):

сразу решить формат хранения хэшей в SQLite: BLOB(32) или TEXT hex(64) (я бы выбрал BLOB — быстрее и меньше).

выбрать один стиль UPSERT: INSERT ... ON CONFLICT(blockchain_id) DO UPDATE SET ...

добавить индекс по user_login (для поиска), если он будет нужен.