9.5 KiB
API для разработчиков: 04 — Запись и чтение блока блокчейна
Документ описывает текущий рабочий формат сетевых вызовов:
AddBlock— запись любого блока в блокчейн пользователя;GetBlockchainBlock— публичное чтение одного конкретного блока по имени цепочки и номеру.
GetBlockchainBlock нужен в том числе для межсерверной синхронизации и для открытого чтения публичного блокчейна по одному блоку.
Важный принцип: на уровне JSON API сейчас есть один универсальный метод записи —
AddBlock. Конкретный смысл записи задаётся типом самого бинарного блока (type/subType/versionв заголовке блока).
1. Что делает AddBlock
AddBlock:
- принимает имя блокчейна и base64 бинарного блока;
- проверяет непрерывность цепочки (
blockNumber,prevHash); - проверяет формат и подпись Ed25519;
- валидирует
bodyпо правилам типа блока; - сохраняет блок и обновляет состояние цепочки.
2. JSON формат запроса
op = "AddBlock".
{
"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. Успешный ответ
{
"op": "AddBlock",
"requestId": "req-1001",
"status": 200,
"ok": true,
"payload": {
"reasonCode": null,
"serverLastGlobalNumber": 12,
"serverLastGlobalHash": "9f0e...a1"
}
}
4. Ошибка (единый формат)
При ошибках сервер отдаёт Net_Exception_Response со стандартными полями и дополнительно с состоянием сервера для ресинка:
{
"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_nameblockchain_state_not_foundbad_block_base64,bad_block_format,bad_block_bodybad_block_number,req_global_mismatch,bad_prev_hashbad_signature,signature_verify_failedprev_line_block_not_found,bad_prev_line_hashlimit_exceededrepost_disabled— репосты временно отключены до будущей реализацииinternal_error
5. Какие блоки реально можно добавлять через AddBlock
Через AddBlock можно писать поддержанные форматы, кроме явно отключённых временных фич:
-
TECH (type=0)
HEADER_COMPAT (subType=0)TECH_CREATE_CHANNEL (subType=1)
-
TEXT (type=1)
TEXT_POST (10)TEXT_EDIT_POST (11)TEXT_REPLY (20)TEXT_EDIT_REPLY (21)TEXT_REPOST (30)— формат зарезервирован, но новые блоки временно отклоняются сrepost_disabled
-
REACTION (type=2)
REACTION_LIKE (1)
-
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)
-
USER_PARAM (type=4)
USER_PARAM_TEXT_TEXT (1)
6. Хватает ли функций сейчас
Коротко: для записи событий в блокчейн — хватает, для полноценного клиентского чтения — пока не хватает.
Что есть:
- единый надёжный write-путь
AddBlock; - есть
GetFriendsListsи API поUserParam; - есть унифицированные коды ошибок и поля для ресинхронизации.
Что пока ограничивает продукт:
- нет полноценного read API для каналов/постов/тредов;
- нет API списка подписок с серверными счётчиками непрочитанного;
- нет ленты событий (новые ответы/лайки/подписки) как отдельного RPC.
7. Рекомендации по клиенту при записи блоков
- Перед отправкой держать локальный
lastNumber/lastHash. - При
bad_prev_hashилиbad_block_number:- взять
serverLastGlobalNumber/serverLastGlobalHashиз ошибки, - пересобрать следующий блок на актуальной вершине.
- взять
- Для edit-блоков всегда ссылаться на оригинальный блок, а не на предыдущий edit.
- Для связей/подписок использовать target на root (HEADER или CREATE_CHANNEL), а не на произвольный пост.
8. USER_PARAM для «личных данных»
Да, на текущем API это можно добавить без изменения серверного кода:
- в
UserParamполеparamсейчас не ограничено фиксированным справочником; - сервер хранит пары
param -> valueкак строки (при наличии корректной подписи иtime_ms); - чтение уже есть через
GetUserParamиListUserParams.
Рекомендуемый стартовый набор ключей для профиля (MVP):
namelast_nameaddress_physicaladdress_webphone
Практическая рекомендация: заранее зафиксировать единый словарь ключей в клиенте/документации, чтобы избежать дублей вида lastname vs last_name, site vs address_web и т.д.
Ограничения, которые важно учесть:
- сейчас нет серверной ACL-политики чтения параметров (в MVP их может читать любой клиент, который знает
login); - нет валидации формата значений для конкретных ключей (телефон, URL и т.д. проверяются только на стороне клиента);
- нет отдельного индекса/поиска по этим полям — только точечное чтение и listing по
login.
9. GetBlockchainBlock
Назначение
Публичное чтение одного конкретного блока из цепочки.
Нужно для:
- открытого чтения блокчейна по одному блоку;
- межсерверной синхронизации;
- восстановления/докачки отсутствующего хвоста цепочки.
JSON формат запроса
op = "GetBlockchainBlock".
{
"op": "GetBlockchainBlock",
"requestId": "req-2001",
"payload": {
"blockchainName": "alice-001",
"blockNumber": 12
}
}
Поля payload:
blockchainName— обязательно, форматlogin-NNN.blockNumber— обязательно, номер блока в цепочке,>= 0.
Успешный ответ
{
"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— внутренняя ошибка сервера.