Добавить sync-профиль пользователя и обход Solana RPC

This commit is contained in:
AidarKC
2026-06-25 18:46:47 +04:00
parent f3e4233285
commit 23edad416c
13 changed files with 419 additions and 41 deletions
+80 -12
View File
@@ -39,33 +39,94 @@
- Порядок блоков сохраняется (по глобальному номеру блока и хэшу).
- Дедупликация по глобальному номеру блока и хэшу.
## 4. Протокол синхронизации (целевой, не реализован)
## 4. Текущая реализованная схема
### 4.1 Межсерверное соединение
На текущем этапе сервер уже умеет базовую межсерверную синхронизацию пользовательских блокчейнов.
### 4.1 Что уже сделано
1. При старте сервер читает свой `server.SHiNE.login`.
2. По этому логину он загружает из Solana свою server PDA.
3. Из неё вытаскивает список `sync_servers`.
4. Для каждого логина партнёра сервер читает его PDA и сохраняет локально:
- `login`
- `server_address`
5. После этого:
- новые локальные `AddBlock` рассылаются партнёрам в фоне;
- при старте запускается periodic sync;
- periodic sync повторяется каждые `12` часов после старта.
### 4.2 Какие server-to-server API уже используются
- `ListBlockchainHeads` — список heads всех локальных цепочек партнёра;
- `GetBlockchainBlock` — чтение одного конкретного блока партнёра;
- `GetSyncUserProfile` — минимальный профиль пользователя для локального создания `solana_users + blockchain_state` без обращения в Solana RPC.
### 4.3 Как сейчас работает periodic sync
Для каждого сервера из локальной таблицы `sync_servers`:
1. запрашивается `ListBlockchainHeads`;
2. для каждой удалённой цепочки сравниваются:
- `lastBlockNumber`
- `lastBlockHash`
- локальное состояние;
3. если локальная цепочка слабее, сервер по одному блоку вызывает `GetBlockchainBlock`;
4. каждый скачанный блок локально применяется через существующий `AddBlock`;
5. если у сервера ещё нет локальной записи пользователя/цепочки, перед этим подготавливается локальный `solana_users + blockchain_state`.
### 4.4 Зачем понадобился `GetSyncUserProfile`
Изначально подготовка локальной цепочки делалась через Solana:
- из `blockchainName` извлекался `login`;
- сервер вызывал import пользователя из Solana PDA;
- по данным PDA локально создавались `solana_users + blockchain_state`.
На практике это упёрлось в ограничение внешнего Solana RPC: при чистом старте и массовой подтяжке чужих цепочек сервер мог получать `HTTP 429`.
Поэтому добавлен отдельный обходной режим:
- настройка `sync.importUserProfileFromPartner.enabled=true`
- в этом режиме сервер **не ходит в Solana RPC** для создания локальной цепочки во время sync;
- вместо этого он запрашивает у сервера-партнёра `GetSyncUserProfile` и создаёт локальную запись по данным партнёра.
Это временная практическая заплатка, чтобы clean-start sync не зависел от rate limit внешнего Solana endpoint.
### 4.5 Что делает настройка `sync.importUserProfileFromPartner.enabled`
- `false` — стандартный режим, подготовка локального пользователя идёт через Solana PDA;
- `true` — sync-режим обхода Solana, локальный пользователь создаётся по server-to-server `GetSyncUserProfile`.
Настройка влияет именно на этап подготовки отсутствующей локальной цепочки во время periodic sync.
## 5. Целевой протокол следующего этапа
### 5.1 Межсерверное соединение
- Серверы устанавливают постоянное WebSocket-соединение друг с другом.
- Адрес партнёра определяется по `server_address` из его Solana PDA.
- Аутентификация: подпись Ed25519 корневым ключом сервера (`root_key` из PDA).
- При разрыве — переподключение с экспоненциальным backoff.
### 4.2 Доставка новых данных (push)
### 5.2 Доставка новых данных (push)
- При получении нового блока или DM сервер немедленно пушит его всем подключённым партнёрам.
- Партнёр подтверждает приём (ACK). Без ACK — повтор с backoff.
### 4.3 Начальная синхронизация (backfill)
### 5.3 Начальная синхронизация (backfill)
- При первом подключении к партнёру серверы обмениваются «курсорами» состояния:
последний глобальный номер блока, последний известный DM-ключ.
- Сервер с более полной историей досылает недостающее партнёру.
### 4.4 Разрешение конфликтов
### 5.4 Разрешение конфликтов
- Блоки пользовательского блокчейна: порядок определяется глобальным номером блока.
Конфликтующие ветки (fork) разрешаются по правилам `AddBlock` (см. `Dev_Docs/Blockchain/README.md`).
- DM: конфликтов нет, `message_key` уникален.
## 5. Маршрутизация DM между серверами
## 6. Маршрутизация DM между серверами
При отправке DM от пользователя A к пользователю B:
@@ -78,23 +139,30 @@
Кэш адресов серверов: обновляется раз в сессию (при ошибке соединения).
## 6. Безопасность
## 7. Безопасность
- Все блоки подписаны ключами пользователя на клиенте — сервер не может подделать содержимое.
- Серверы не расшифровывают DM-контент (шифрование — задача следующего этапа).
- При синхронизации каждый блок проходит валидацию подписи на принимающем сервере.
## 7. Статус реализации
## 8. Статус реализации
| Компонент | Статус |
|-----------|--------|
| Регистрация серверной PDA в Solana | ✅ Реализовано |
| Чтение `sync_servers` из PDA | ✅ Реализовано |
| Межсерверный WebSocket-канал | Нужна реализация |
| Локальная таблица `sync_servers` | ✅ Реализовано |
| Публичный `ListBlockchainHeads` | ✅ Реализовано |
| Публичный `GetBlockchainBlock` | ✅ Реализовано |
| Публичный `GetSyncUserProfile` | ✅ Реализовано |
| Плановый blockchain sync при старте + каждые 12 часов | ✅ Реализовано |
| Обход Solana RPC через `sync.importUserProfileFromPartner.enabled` | ✅ Реализовано |
| Межсерверный постоянный WebSocket-канал | Нужна реализация |
| Push новых DM партнёрам | Нужна реализация |
| Push блоков блокчейна партнёрам | ✅ Реализована базовая one-shot версия |
| Backfill при первом подключении | Нужна реализация |
| Periodic backfill отсутствующего хвоста | ✅ Реализовано |
| Разрешение рассинхрона / divergence | Нужна реализация |
| Маршрутизация DM через access_servers | Нужна реализация (заглушка) |
Текущая версия сервера работает без межсерверной синхронизации.
Синхронизация — задача следующего этапа разработки.
Текущая версия сервера уже умеет базовую синхронизацию блокчейнов между партнёрами.
Не реализованы ещё DM-sync, постоянные server-to-server соединения и автоматическое исправление рассинхрона цепочек.