Перенести документацию в docs и добавить социальный граф

This commit is contained in:
AidarKC
2026-07-13 12:58:41 +04:00
parent c9cfb394d7
commit af12d7b954
91 changed files with 653 additions and 2 deletions
+239
View File
@@ -0,0 +1,239 @@
# API для разработчиков: 04 — Запись и чтение блока блокчейна
Документ описывает **текущий рабочий формат** сетевых вызовов:
- `AddBlock` — запись любого блока в блокчейн пользователя;
- `GetBlockchainBlock` — публичное чтение одного конкретного блока по имени цепочки и номеру.
`GetBlockchainBlock` нужен в том числе для межсерверной синхронизации и для открытого чтения публичного блокчейна по одному блоку.
> Важный принцип: на уровне JSON API сейчас есть **один универсальный метод** записи — `AddBlock`.
> Конкретный смысл записи задаётся типом самого бинарного блока (`type/subType/version` в заголовке блока).
## 1. Что делает `AddBlock`
`AddBlock`:
- принимает имя блокчейна и base64 бинарного блока;
- проверяет непрерывность цепочки (`blockNumber`, `prevHash`);
- проверяет формат и подпись Ed25519;
- валидирует `body` по правилам типа блока;
- сохраняет блок и обновляет состояние цепочки.
## 2. JSON формат запроса
`op = "AddBlock"`.
```json
{
"op": "AddBlock",
"requestId": "req-1001",
"payload": {
"blockchainName": "alice-001",
"blockNumber": 12,
"prevBlockHash": "ab12...ff",
"blockBytesB64": "AAAB..."
}
}
```
Поля `payload`:
- `blockchainName` — обязательно, формат `login-NNN`.
- `blockNumber` — обязательно (временное legacy-поле для совместимости; должно совпасть с номером внутри бинарного блока).
- `prevBlockHash` — legacy-поле, сейчас сервер использует `prevHash` из бинарного блока и состояние цепочки.
- `blockBytesB64` — обязательно: **полный бинарный блок** (`preimage + sigMarker + signature`) в Base64.
## 3. Успешный ответ
```json
{
"op": "AddBlock",
"requestId": "req-1001",
"status": 200,
"ok": true,
"payload": {
"reasonCode": null,
"serverLastGlobalNumber": 12,
"serverLastGlobalHash": "9f0e...a1"
}
}
```
## 4. Ошибка (единый формат)
При ошибках сервер отдаёт `Net_Exception_Response` со стандартными полями и дополнительно с состоянием сервера для ресинка:
```json
{
"op": "AddBlock",
"requestId": "req-1001",
"status": 400,
"ok": false,
"error": "bad_prev_hash",
"message": "Некорректный prevHash (цепочка не совпадает)",
"payload": {
"serverLastGlobalNumber": 11,
"serverLastGlobalHash": "c3d4...98"
}
}
```
### Основные `reasonCode`
- `empty_blockchain_name`, `bad_blockchain_name`
- `blockchain_state_not_found`
- `bad_block_base64`, `bad_block_format`, `bad_block_body`
- `bad_block_number`, `req_global_mismatch`, `bad_prev_hash`
- `bad_signature`, `signature_verify_failed`
- `prev_line_block_not_found`, `bad_prev_line_hash`
- `limit_exceeded`
- `chain_resync_in_progress` — цепочка временно заблокирована полным resync
- `repost_disabled` — репосты временно отключены до будущей реализации
- `internal_error`
## 5. Какие блоки реально можно добавлять через `AddBlock`
Через `AddBlock` можно писать поддержанные форматы, кроме явно отключённых временных фич:
1. **TECH (type=0)**
- `HEADER_COMPAT (subType=0)`
- `TECH_CREATE_CHANNEL (subType=1)`
2. **TEXT (type=1)**
- `TEXT_POST (10)`
- `TEXT_EDIT_POST (11)`
- `TEXT_REPLY (20)`
- `TEXT_EDIT_REPLY (21)`
- `TEXT_REPOST (30)` — формат зарезервирован, но новые блоки временно отклоняются с `repost_disabled`
3. **REACTION (type=2)**
- `REACTION_LIKE (1)`
4. **CONNECTION (type=3)**
- `CONNECTION_FRIEND (10)`
- `CONNECTION_UNFRIEND (11)`
- `CONNECTION_CONTACT (20)`
- `CONNECTION_UNCONTACT (21)`
- `CONNECTION_FOLLOW (30)`
- `CONNECTION_UNFOLLOW (31)`
- `CONNECTION_SPOUSE (40)`
- `CONNECTION_UNSPOUSE (41)`
- `CONNECTION_PARENT (50)`
- `CONNECTION_UNPARENT (51)`
- `CONNECTION_CHILD (52)`
- `CONNECTION_UNCHILD (53)`
- `CONNECTION_SIBLING (54)`
- `CONNECTION_UNSIBLING (55)`
- `CONNECTION_KNOWN_PERSON (60)`
- `CONNECTION_UNKNOWN_PERSON (61)`
- `CONNECTION_SHINE_CONFIRMED (70)`
- `CONNECTION_SHINE_UNCONFIRMED (71)`
- `CONNECTION_SHINE_SEEN (74)`
- `CONNECTION_SHINE_UNSEEN (75)`
5. **USER_PARAM (type=4)**
- `USER_PARAM_TEXT_TEXT (1)`
## 6. Хватает ли функций сейчас
Коротко: **для записи событий в блокчейн — хватает**, для полноценного клиентского чтения — **пока не хватает**.
Что есть:
- единый надёжный write-путь `AddBlock`;
- есть `GetFriendsLists` и API по `UserParam`;
- есть унифицированные коды ошибок и поля для ресинхронизации.
Что пока ограничивает продукт:
- нет полноценного read API для каналов/постов/тредов;
- нет API списка подписок с серверными счётчиками непрочитанного;
- нет ленты событий (новые ответы/лайки/подписки) как отдельного RPC.
## 7. Рекомендации по клиенту при записи блоков
1. Перед отправкой держать локальный `lastNumber/lastHash`.
2. При `bad_prev_hash` или `bad_block_number`:
- взять `serverLastGlobalNumber/serverLastGlobalHash` из ошибки,
- пересобрать следующий блок на актуальной вершине.
3. Для edit-блоков всегда ссылаться на **оригинальный** блок, а не на предыдущий edit.
4. Для связей/подписок использовать target на **root** (HEADER или CREATE_CHANNEL), а не на произвольный пост.
## 8. USER_PARAM для «личных данных»
Да, на текущем API это можно добавить **без изменения серверного кода**:
- в `UserParam` поле `param` сейчас не ограничено фиксированным справочником;
- сервер хранит пары `param -> value` как строки (при наличии корректной подписи и `time_ms`);
- чтение уже есть через `GetUserParam` и `ListUserParams`.
Рекомендуемый стартовый набор ключей для профиля (MVP):
- `name`
- `last_name`
- `address_physical`
- `address_web`
- `phone`
Практическая рекомендация: заранее зафиксировать единый словарь ключей в клиенте/документации, чтобы избежать дублей вида `lastname` vs `last_name`, `site` vs `address_web` и т.д.
Ограничения, которые важно учесть:
- сейчас нет серверной ACL-политики чтения параметров (в MVP их может читать любой клиент, который знает `login`);
- нет валидации формата значений для конкретных ключей (телефон, URL и т.д. проверяются только на стороне клиента);
- нет отдельного индекса/поиска по этим полям — только точечное чтение и listing по `login`.
---
## 9. `GetBlockchainBlock`
### Назначение
Публичное чтение одного конкретного блока из цепочки.
Нужно для:
- открытого чтения блокчейна по одному блоку;
- межсерверной синхронизации;
- восстановления/докачки отсутствующего хвоста цепочки.
### JSON формат запроса
`op = "GetBlockchainBlock"`.
```json
{
"op": "GetBlockchainBlock",
"requestId": "req-2001",
"payload": {
"blockchainName": "alice-001",
"blockNumber": 12
}
}
```
Поля `payload`:
- `blockchainName` — обязательно, формат `login-NNN`.
- `blockNumber` — обязательно, номер блока в цепочке, `>= 0`.
### Успешный ответ
```json
{
"op": "GetBlockchainBlock",
"requestId": "req-2001",
"status": 200,
"ok": true,
"payload": {
"blockchainName": "alice-001",
"blockNumber": 12,
"blockHash": "9f0eaabbccddeeff00112233445566778899aabbccddeeff0011223344556677",
"blockBytesB64": "AAAB..."
}
}
```
### Ошибки
- `400 / BAD_FIELDS` — некорректные `blockchainName` или `blockNumber`.
- `404 / BLOCK_NOT_FOUND` — такого блока нет.
- `500 / INTERNAL_ERROR` — внутренняя ошибка сервера.