Конспект: что обсуждали и где остановились 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 (для поиска), если он будет нужен.