Расположение:
docs/api/· Спецификация:openapi.json(OpenAPI 3.0.3), отдаётсяGET /openapi.json; минимальный Swagger UI —GET /docs.
Спецификация публичного API — openapi.json (OpenAPI 3.0.3),
доступна в рантайме по GET /openapi.json; минимальный Swagger UI — GET /docs.
Публичные эндпоинты не требуют токена. Внутренние (/add, /remove_heavy_nodes,
/load-genesis, /raft/*, /mng/*) требуют заголовок x-internal-token и в
спецификации не документируются.
| Метод | Путь | Назначение |
|---|---|---|
POST |
/ |
Принять подписанную транзакцию |
GET |
/pool?limit=&offset= |
Узлы-кандидаты к очистке (по числу родителей) |
GET |
/full?limit=&offset= |
Граф с глубинами (по возрастанию глубины) |
GET |
/metrics |
Метрики Prometheus |
GET |
/health |
Liveness |
GET |
/ready |
Readiness (лидер выбран, Redis достижим) |
GET |
/openapi.json |
OpenAPI-спецификация |
GET |
/docs |
Swagger UI |
limit — по умолчанию 100, максимум 1000; offset — по умолчанию 0.
Тело запроса ограничено MAX_REQUEST_BYTES (по умолчанию 1 МиБ, ответ 413).
Публичный POST / ограничен по частоте (429 при превышении).
func входит в подписываемый и хэшируемый контент. Известные значения:
transferToken. Подмена func меняет канонический хэш и ломает подпись.
| Поле | Тип | Правило |
|---|---|---|
ca |
string | непустой адрес-источник |
to |
string | непустой адрес-получатель |
val |
integer ≥ 0 | сумма |
msg |
string? | не длиннее 2500 символов |
- Берётся JSON-представление
txи в него добавляетсяfunc. - Выполняется каноническая сериализация: ключи всех объектов рекурсивно сортируются, порядок элементов массивов сохраняется.
hash = blake3(canonical_json).sign— ed25519-подпись байтов хэша ключомaddr.
Правила валидации одинаковы на всех репликах и не зависят от сети/времени:
prnts: 2..100 элементов, непустые, уникальные; на границе API.- Генезис-узлы (пустой список родителей) допустимы только во внутренней команде.
funcдолжен быть известен.- структура
varобязана соответствоватьfunc. - подпись обязана проверяться против адреса.
- узел с таким хэшем не должен существовать (в DAG или реестре
added). - все родители должны существовать в живом DAG; родитель, оставшийся только в
реестре
added(удалённый), отклоняется (V15). seqадреса обязан строго возрастать (анти-replay; пустойaddrгенезиса освобождён) (V18). Монотонность проверяется в рамках одного адреса: порядок применения в логе не обязан совпадать с порядком отправки, поэтому клиент обязан сериализоватьseqодного аккаунта (следующийseqслать только после ответа на предыдущий). Для конкурентной отправки используйте разные адреса (аккаунты) — ихseqнезависимы.
Подпись и отправка (фрагмент на Rust):
let hash = ordered_sum(&tx, "transferToken")?; // blake3 канонического контента
let sign = hex::encode(signing_key.sign(hash.as_bytes()).to_bytes());
let body = json!({ "tx": tx, "sign": sign, "func": "transferToken" });
reqwest::Client::new().post("http://127.0.0.1:21001/").json(&body).send().await?;Чтение графа:
curl 'http://127.0.0.1:21001/full?limit=50&offset=0'
curl 'http://127.0.0.1:21001/pool?limit=50'
{ "tx": { "prnts": ["<hash>", "<hash>"], // 2..100 уникальных непустых хэшей "addr": "<ed25519 pubkey base58>", "seq": 0, "var": { "ca": "<addr>", "to": "<addr>", "val": 100, "msg": "optional" } }, "sign": "<ed25519 signature, hex, 64 bytes>", "func": "transferToken" }