Если вы храните KAS и используете инструмент самостоятельного хранения вроде Kaspa Safe, вы, вероятно, доверяете сервису в том, что он знает реальное состояние вашего ончейн-хранилища. Но *как* он его узнаёт? Запускает он собственный узел или обращается к чужому API и надеется на честный ответ?
Для нас ответ прост: каждый сервис Kaspa Forge — мониторинг хранилищ, жизненный цикл эскроу-сделок, подтверждение платежей — читает состояние цепочки с экземпляра kaspad, который мы эксплуатируем сами, подключаясь через gRPC. В этой статье мы объясняем почему, как это работает «под капотом» и чего это реально стоит.
Почему бы не просто воспользоваться чужим API?
С публичными API всё в порядке для обозревателей блоков, портфельных трекеров или случайных запросов. Но как только ваше ПО принимает решения на основе этих данных — срабатывает тревога хранилища, освобождаются средства эскроу или платёж помечается как подтверждённый — вы вводите допущение о доверии, которое противоречит самой идее децентрализованного реестра.
Публичный API может вернуть устаревшие UTXO во время перегрузки сети. Он может выйти из строя в критический момент. Его оператор может фильтровать ответы. Для сервиса, где цена ошибочного ответа — чьи-то средства в ковенанте, формулировка «доверьтесь нам, мы проверили» недостаточна. Нужно, чтобы ответ приходил от узла, участвующего в консенсусе, — и этот узел нужно запускать самим.
Как узел Kaspa работает «под капотом»
Kaspa не использует единую цепочку. Его консенсус — это блокDAG — ориентированный ациклический граф, в котором несколько блоков могут создаваться одновременно и объединяться в непротиворечивое представление. Протокол GHOSTDAG упорядочивает эти блоки в «выбранную цепочку»: каждый блок голосует за выбранного родителя; блоки, хорошо связанные с этой цепочкой, считаются синими и получают вознаграждение, а слабо связанные — красными (принимаются, но не вознаграждаются). На вики Kaspa описан полный алгоритм, включая окно корректировки сложности в 2 641 блок.
GHOSTDAG — протокол упорядочивания для блокDAG в Kaspa. Каждый блок выбирает родителя; полученный путь определяет порядок транзакций. Синие блоки хорошо связаны и получают майнинговое вознаграждение; красные блоки объединяются, но не вознаграждаются. Это позволяет поддерживать высокую частоту блоков (сейчас 10 BPS в основной сети) без ущерба для безопасности.
Запущенный узел kaspad поддерживает:
- Полный DAG — каждый проверенный блок, от генезиса до текущего *виртуального блока* (агрегированного представления узла обо всех кончиках графа).
- Набор UTXO — текущее множество непотраченных выходов транзакций, авторитетный источник ответа на вопрос «есть ли средства на этом адресе?».
- Опциональный
utxoindex— обратный индекс от адресов к их UTXO. Без него поиск баланса адреса означает сканирование всего набора UTXO. С ним один gRPC-запрос возвращает все UTXO, принадлежащие адресу. Этот индекс должен быть включён до начала IBD; включение после запуска потребует повторной синхронизации.
Узел предоставляет всё это через gRPC-интерфейс по TCP. Клиенты отправляют типизированные запросы — *получить UTXO по адресам*, *отправить транзакцию*, *запросить данные блока* — и получают структурированные бинарные ответы. Никакого JSON-оверхеда, никакого REST-посредничества. Как отмечается на вики, сетевое взаимодействие Kaspa основано на TCP, и ваш gRPC-клиент подключается наравне с пиринговыми узлами как полноценный участник.
Подтверждения в блокDAG
При скорости 10 блоков в секунду транзакция, включённая в блок, подтверждается за считанные секунды. Глубина подтверждения измеряется в синем скоре — количестве синих блоков в прошлом DAG с точки зрения принимающего блока. Как только разрыв по синему скору превышает настроенный порог, транзакция считается финальной. Для платёчного шлюза Kaspa Forge мы установили этот порог достаточно высоким, чтобы покрыть маловероятный сценарий глубокой реорганизации, но достаточно низким, чтобы покупатели не ждали долго. Запас в несколько секунд обычно достаточен.
Наша конфигурация узла: архитектура, а не реквизиты доступа
Мы запускаем kaspad на выделенной машине, отдельной от веб-сервера, который обслуживает kaspaforge.org. Это разделение намеренное: узел — хранилилище состояния, участник консенсуса, которому необходимы стабильное время работы, быстрый дисковый ввод-вывод для DAG и пропускная способность для пиринговых соединений (по умолчанию 8 исходящих пиров). Совместное использование машины с nginx и приложениями привело бы к конкуренции за ресурсы.
Подключение к серверу приложений
Наш бэкенд — единый процесс на Rust, обслуживающий все сервисы Kaspa Forge (Kaspa Safe, Kasпа Escrow, платежи, маркетплейс) — устанавливает постоянное gRPC-соединение с узлом при запуске. Соединение обёрнуто в цикл переподключения: если узел перезапускается для обновления или перезагрузки машины, сервер обнаруживает разрыв и повторяет попытки с экспоненциальной задержкой. Во время переподключения вотчеры приостанавливаются. Ончейн-контракты продолжают работать на блокDAG; вотчеры наверстывают упущенное при следующем успешном опросе.
Вотчеры: десятисекундный пульс
Основной цикл опроса выполняется каждые 10 секунд. Для каждого зарегистрированного хранилища или эскроу-контракта вотчер:
loop every 10s:
for each registered_address:
utxos = grpc.getUtxosByAddresses([address])
if utxos != snapshot[address]:
diff = analyze(snapshot[address], utxos)
trigger_alerts(diff) # Telegram, email
trigger_actions(diff) # auto-release, auto-inherit
snapshot[address] = utxos
Анализ различий определяет, что произошло: появился новый UTXO (депозит), UTXO был потрачен (инициирован вывод), изменился режим хранилища (отмена или завершение). Каждый тип изменения соответствует конкретному действию — отправить тревогу в Telegram об инициировании, отправить письмо наследнику о бездействии, отправить транзакцию complete без ключа по истечении задержки.
Мы выбрали опрос вместо альтернатив на основе подписок по практической причине: gRPC-стримы могут молча обрываться при сетевых сбоях, а восстановление пропущенных событий требует собственной логики согласования. Опрос с сохранёнными снимками идемпотентен — пропустили цикл, и следующий всё подхватит. Компромисс — до 10 секунд задержки, что приемлемо для тревог хранилищ (временная задержка ковенанта даёт вам часы) и для эскроу с платежами.
Отправка транзакций
Когда пользователь подписывает инициирование хранилища, освобождение эскроу или отправку из кошелька в браузере, подписанная транзакция проходит через наш бэкенд к узлу через gRPC submitTransaction. Узел проверяет её по правилам консенсуса — включая ограничения ковенанта Silverscript — добавляет в мемпул и транслирует пирам. Мы сами не ретранслируем транзакции.
Публичный фронт узла для восстановления
Некастодиальность означает, что сервис должен быть восстановлен без нашего участия. Наш открытый CLI-инструмент vaultctl подключается к любому узлу Kaspa v2+ для управления хранилищами из терминала. Мы также предоставляем публичную gRPC-точку доступа за nginx стрим-прокси, который перенаправляет TCP-соединения к тому же экземпляру kaspad, скрывая прямой адрес узла.
Прокси включает ограничение частоты запросов — лимиты подключений по IP, глобальные ограничения одновременных соединений, тайм-ауты slowloris, — поскольку узел обслуживает продакшн-трафик и должен оставаться отзывчивым для наших вотчеров. Это прагматичный компромисс: полностью публичный узел — цель для DDoS, а ограниченный прокси даёт инструментам восстановления надёжную точку доступа, когда она вам нужна.
Каждое хранилище Kaspa Safe и каждая сделка Kaspa Escrow мониторятся нашим собственным узлом — никакой сторонний API не встаёт между вашим ончейн-контрактом и сервисом, который за ним следит. Если хотите познакомиться с инструментами, вы можете создать хранилище или прочитать о том, как работает хранилище, чтобы увидеть полную некастодиальную архитектуру.
Что узел обслуживает в продакшене
| Сервис | Что запрашивается | Интервал | Почему свой узел |
|---|---|---|---|
| Kaspa Safe | UTXO по адресу хранилища | 10 с на хранилище | Обнаружение депозитов, инициирований, завершений; срабатывание тревог |
| Kaspa Escrow | UTXO по адресу эскроу | 10 с на сделку | Обнаружение пополнения, авто-освобождение после окна оспаривания, обработка тайм-аутов |
| Платежи | UTXO по HD-производному адресу | 10 с на ожидающий заказ | Подтверждение платежа с настраиваемым порогом по синему скору |
| Ретрансляция транзакций | Отправка подписанной транзакции | По запросу | Трансляция подписанных пользователем транзакций в сеть |
Одна вещь, которую узел делает *не* хорошо — это история транзакций. utxoindex отслеживает текущее состояние, а не хронологическую книгу записей. Для списка транзакций в кошельке Desk мы проксируем запросы во внешний индексатор — клиент обращается только к нашему бэкенду, так что его IP никогда не доходит до индексатора. Узел — это движок консенсуса, а не обозреватель блоков. Это честная архитектурная граница.
Аппаратное обеспечение, пропускная способность и практические затраты
Запуск kaspad для продакшн-сервисов — не что-то экзотическое, но и не проект на Raspberry Pi:
- Хранение. Набор UTXO и метаданные DAG растут вместе с цепочкой. При включённом
utxoindexпланируйте больше, чем минимальная установка. Настоятельно рекомендуется SSD — поиск по UTXO ограничен скоростью ввода-вывода. - Оперативная память. kaspad написан на Go и достаточно экономно использует память, но
utxoindexдобавляет нагрузку. Несколько гигабайт рабочей памяти — реалистичный показатель. - Пропускная способность. В установившемся режиме трафик умеренный при 8 исходящих пирах. Начальная загрузка блоков и обнаружение пиров более интенсивны.
- IBD. Синхронизация с генезиса занимает время. Узел загружает и проверяет каждый блок в истории DAG. Пока IBD не завершён, запросы
utxoindexне будут возвращать актуальные данные — ваши сервисы не смогут заработать, пока узел полностью не синхронизирован. - Обновления. Изменения протокола (вроде хардфорка Toccata, который принёс ковенанты в основную сеть) требуют скоординированных обновлений узла. Сначала мы тестируем на тестовой сети и планируем обновления основной сети в периоды низкой нагрузки.
Компромиссы и честные ограничения
Единая точка отказа. Мы запускаем один экземпляр kaspad для продакшна. Если он выходит из строя, вотчеры останавливаются. Ончейн-средства в безопасности — ковенанты обеспечивают свои правила независимо от чего-либо, — но оповещения и автоматические действия приостанавливаются до восстановления узла. Мы смягчаем это с помощью супервизора процессов и мониторинга, но принимаем ограничение. Конфигурация с несколькими узлами добавила бы сложность, которая нам пока не нужна.
Задержка опроса. Десять секунд между ончейн-событием и нашей реакцией. Для тревог хранилищ это погрешность на фоне 24-часовой задержки вывода. Для платежей покупатель видит «подтверждено» через несколько секунд после подтверждения сетью. Мы могли бы сократить интервал, но это умножило бы gRPC-запросы без ощутимой пользы.
Внешняя зависимость для истории. Запросы истории транзакций зависят от отдельного индексатора, который мы не эксплуатируем. Если он выйдет из строя, кошелёк Desk покажет устаревшие записи транзакций, в то время как балансы (от нашего узла) и подписание (в браузере) продолжат работать. Это реальный компромисс, который мы приняли, вместо того чтобы строить и поддерживать собственный индекс истории.
Затраты на ресурсы. Кто-то должен заниматься обновлениями узла, ростом дискового пространства и эпизодическими проблемами с пиринговым подключением. Для одиночного разработчика хорошо поддерживаемый публичный узел может быть более практичным. Мы выбрали запуск собственного, потому что наши сервисы мониторят контракты, в которых хранятся реальные средства — цена доверия неправильному API слишком высока.
Главный вывод
Если вы строите на Kaspa — кастодиальные инструменты, платёжные шлюзы, что угодно, что касается чужих денег — запускайте собственный узел. Протокол даёт вам gRPC-интерфейс, индекс UTXO и прямое участие в консенсусе. Исходный код kaspad открыт, требования к оборудованию управляемы, а база знаний разработчиков на вики описывает все внутренние механизмы.
Альтернатива — доверять чьему-то API как источнику истины. Для Kaspa Forge это было неприемлемо.
FAQ
Что такое gRPC и почему Kaspa его использует?
gRPC — это высокопроизводительный бинарный RPC-фреймворк. Узлы Kaspa предоставляют gRPC-эндпоинты по TCP для запросов состояния цепочки (блоки, UTXO, балансы) и отправки транзакций. По сравнению с REST/JSON он эффективнее для частых опросов, которые выполняют кошельки и сервисное ПО.
Могу ли я запустить узел Kaspa самостоятельно?
Да. Кодовая база Kaspa открыта — вы запускаете kaspad, при необходимости включаете utxoindex для поиска по адресам и ждёте завершения начальной загрузки блоков (IBD). В базе знаний разработчиков на вики Kaspa подробно описаны внутренние механизмы сети.
Если вы запускаете собственный узел, значит ли это, что Kaspa Forge видит мои приватные ключи?
Нет. Наш узел видит только публичные адреса и UTXO. Приватные ключи создаются и хранятся исключительно в вашем браузере через WASM, а резервная копия находится в вашем зашифрованном .age-файле ключа. У узла нет никакого доступа к подписывающим материалам — в разделе как работает хранилище подробно объясняется это разделение.
Что произойдёт с моим хранилищем или эскроу, если ваш узел отключится?
Ончейн-контракты не затронуты — средства находятся в ковенантах на блокDAG, обеспечиваемые правилами консенсуса, а не каким-либо сервером. Приостанавливаются наши вотчеры: оповещения, автоматические завершения и подтверждения платежей возобновятся, как только узел восстановит подключение. Вы всегда можете восстановиться самостоятельно через vaultctl, подключившись к любому публичному узлу Kaspa.
Почему бы не использовать публичный API или размещённый индексатор для всего?
Публичные API могут выходить из строя, возвращать устаревшие данные или фильтровать ответы. Для сервисов, которые мониторят ончейн-хранилища и эскроу-контракты, цена ошибочного или запоздалого ответа — чьи-то средства. Прямой gRPC-доступ к набору UTXO вашего собственного узла устраняет эту необходимость доверять.
В чём разница между состоянием UTXO и историей транзакций?
Узловой utxoindex отслеживает текущие непотраченные выходы по адресам — именно то, что нужно для проверки балансов и обнаружения платежей. Хронологический список прошлых транзакций требует отдельного сервиса индексации блоков, поэтому Kaspa Forge проксирует запросы истории транзакций во внешний индексатор, а запросы балансов обрабатывает нашим собственным узлом.
Держите KAS там, где кражу можно отменить
Ковенант-сейф в мейннете Kaspa: ваши ключи, ваши правила, наш инструмент. Ончейн — бесплатно, навсегда.
Создать сейф
