Транзакция в Kaspa обычно требует подписи. Кто-то владеет закрытым ключом, подписывает, и сеть принимает расход. Это базовое предположение каждого кошелька и каждого контракта.
Но система ковенантов Kaspa, работающая в основной сети с обновления Toccata, ввела категорию путей расходования, где подпись не требуется вовсе. Не потому что безопасность была ослаблена, а потому что ончейн-скрипт уже гарантирует, куда пойдут деньги. Назначение фиксируется в ковенанте в момент создания. Как только выполняется условие по времени, любой — бот-наблюдатель, посторонний, CLI-скрипт на вашем ноутбуке — может транслировать транзакцию, и сеть её примет.
Это и есть безключевые пути. Два ковенант-контракта Kaspa Forge — vault.sil и escrow.sil — определяют в совокупности 17 путей расходования. Одиннадцать требуют одну подпись, один — две, и пять не требуют подписи вовсе. Именно эта последняя категория делает систему по-настоящему не-кастодиальной.
Проблема доверия, которую решают безключевые пути
В кастодиальном эскроу — бот-«гарант» в Telegram, централизованная биржа — сервис хранит и средства, и ключи. Если оператор исчезает, ваши деньги исчезают вместе с ним. Модель доверия бинарна: вы доверяете человеку или уходите.
Ковенант Kaspa инвертирует это. Правила кодируются в ончейн-скрипте: *после N блоков без спора средства идут продавцу*. Скрипт не проверяет, кто транслирует. Он не верифицирует подпись оператора. Он проверяет DAA-оценку (монотонный счётчик блоков Kaspa), подтверждает, что адрес вывода совпадает с сохранённым в состоянии ковенанта, и ограничивает сетевую комиссию. Всё.
Сервер, на котором работает kaspaforge.org, становится слоем удобства, а не привратником. Он следит за цепочкой, формирует транзакцию и транслирует её от вашего имени. Но если он отключится в 3 часа ночи, ковенант не перестанет работать. DAA-оценка продолжает тикать независимо от того, кто какой сервер запускает.
Как работает безключевой путь ковенанта
Каждый ковенант в Kaspa — это программа на Silverscript, скомпилированная в байт-код и встроенная в P2SH-адрес. Когда средства поступают на этот адрес, они могут покинуть его только через один из определённых скриптом *энтрипоинтов*. Каждый путь задаёт предусловия, требование авторизации и ограничения на вывод.
Безключевой энтрипоинт концептуально выглядит так:
entrypoint complete:
require(tx.inputs.length == 1) // инвариант одного входа
require(state.mode == UNVAULTING) // корректное состояние ковенанта
require(utxo.age >= state.delay) // DAA таймлок
require(state.feeBudget >= tx.fee) // сетевая комиссия в пределах лимита
require(outputs[0].address == state.dest) // назначение неизменно
// ← нет проверки подписи нигде
Ключевое понимание: поскольку dest был зафиксирован, когда владелец инициировал вывод, и поскольку DAA-оценка может только увеличиваться, ковенант может проверить, что выполняются нужные условия, не спрашивая разрешения ни у какого держателя ключа. Сам скрипт является авторизацией.
DAA-оценка — монотонный счётчик Kaspa, который увеличивается с каждым принятым блоком в mergeset. В отличие от меток реального времени, он не может быть манипулирован майнерами и обеспечивает надёжную временную ссылку для ончейн-контрактов. Вики Kaspa подробно охватывает DAA-окно и систему оценивания.
Аналогия: представьте ковенант как сейф с таймером и механическими часами. Когда стрелка достигает заданного времени, засов открывается сам — ключ не нужен. Безключевые пути в ковенантах Kaspa работают так же. «Часы» — это DAA-оценка, а «засов» — ограничение вывода скрипта.
Пять безключевых путей в Kaspa Forge
Kaspa Safe — два безключевых пути
Контракт хранилища имеет семь энтрипоинтов. Два из них безключевые:
| Путь | Условие | Назначение | Сервисная комиссия |
|---|---|---|---|
complete() | Хранилище в UNVAULTING, age ≥ delay | Адрес вывода, заданный при initiate | Стандартная |
inheritAuto() | autoInherit == 1, режим VAULT, age ≥ inheritDelay | Адрес наследника (задан при создании) | Стандартная |
complete() — это обычный процесс вывода: владелец инициирует вывод (переключая хранилище в режим UNVAULTING), проходит задержка, и любой может его завершить. Ключ тревоги может отменить в течение окна задержки — это механизм антивора — но как только задержка истекает, вывод необратим.
inheritAuto() — это «мёртвый рубильник». Владелец хранилища периодически вызывает checkin() — путь с подписью, который сбрасывает счётчик возраста UTXO, сигнализируя «я жив». Если владелец перестаёт подтверждать и накопленный возраст превышает inheritDelay, наследник может заявить права. Наблюдатель транслирует это автоматически, но наследник (или любой) может запустить это вручную. Если при создании autoInherit был установлен в 0, наследник должен активно подписывать своим ключом (inheritSigned).
Kaspa Escrow — три безключевых пути
Контракт эскроу имеет десять энтрипоинтов. Три из них безключевые:
| Путь | Условие | Назначение | Сервисная комиссия |
|---|---|---|---|
autoRelease() | ACTIVE, age ≥ disputeWindow | Продавец | Стандартная (feeResolve) |
timeoutToBuyer() | DISPUTED, timeoutTo == 0, age ≥ arbiterDeadline | Покупатель | Ноль |
timeoutToSeller() | DISPUTED, timeoutTo == 1, age ≥ arbiterDeadline | Продавец | Ноль |
autoRelease() — это оптимистичный расчёт. Покупатель профинансировал сделку, никто не подал спор в течение окна (24–168 часов в зависимости от типа сделки), поэтому продавец получает оплату. Это «счастливый путь» — здесь закрывается большинство сделок.
Пути по тайм-ауту — это «мёртвый рубильник» арбитра. Спор был подан, но арбитр не действовал до истечения срока. Сделка разрешается в пользу предварительно согласованной стороны — и платформа взимает нулевую сервисную комиссию, потому что не предоставила обещанного арбитража.
Лимит бюджета комиссии против грифинга
У безключевых путей есть нюанс безопасности. Поскольку они не требуют подписи, *любой* может их транслировать — включая злоумышленника. Что мешает злоумышленнику создать транзакцию, которая заплатит весь баланс хранилища в качестве сетевой комиссии майнерам?
Ответ — feeBudget. Каждый безключевой путь в обоих контрактах включает эту проверку:
require(feeBudget > 0 && feeBudget <= 10_000_000) // максимум 0.1 KAS
require(tx.fee <= feeBudget)
Хранилище или эскроу создаётся с параметром feeBudget — в продакшене, от 0.01 до 0.1 KAS. Любая транзакция, чья сетевая комиссия превышает этот потолок, отклоняется ковенантом независимо от того, кто её транслирует. Это ограничивает максимальный ущерб от грифинга до 0.1 KAS: неприятно для маленького хранилища, незначительно для крупного.
Единственное исключение — migrate, путь, который требует обеих подписей держателей ключей (горячий + тревога для хранилищ, покупатель + продавец для эскроу). При наличии обеих подписей у владельца полные права — он может задать любой вывод, любую комиссию, переводить средства куда угодно. Лимит не нужен, потому что владелец явно авторизует расход.
Наблюдатель как слой удобства, а не привратник
Kaspa Forge запускает наблюдатель — фоновый цикл, который опрашивает набор UTXO узла Kaspa каждые 10 секунд. Для каждого активного хранилища или сделки эскроу он сравнивает накопленную DAA-оценку UTXO с настроенной задержкой или окном спора. Когда условие выполняется:
1. Наблюдатель формирует безключевую транзакцию в памяти. 2. Применяет инвариант одного входа (один UTXO на вход, один канонический вывод + комиссия). 3. Проверяет вывод по сохранённому состоянию ковенанта. 4. Транслирует в сеть Kaspa.
Наблюдатель также отправляет уведомления — оповещения в Telegram, электронную почту и Web Push — чтобы владелец знал, когда срабатывает безключевой путь. Для хранилищ он отправляет напоминания о подтверждении, когда приближается срок наследования (на 80% от inheritDelay), и может отправить письмо наследнику, когда срабатывает «мёртвый рубильник».
Но наблюдатель избыточен по дизайну. Если все серверы Kaspa Forge одновременно сгорят, ковенанты продолжат существовать в цепочке. DAA-оценка продолжит тикать. После истечения задержки любой, у кого есть узел Kaspa, может создать ту же транзакцию. Инструменты командной строки с открытым исходным кодом знают, как построить эти пути с нуля:
vaultctl complete --vault <address> --dest <your-address> \
--rpc node.kaspaforge.org:16110
Вот что на практике означает «не-кастодиальный»: контракт, а не сервис, является источником полномочий.
Хотите увидеть безключевые пути в действии? Создайте хранилище Kaspa Safe и инициируйте небольшой вывод. После истечения задержки транзакция complete() транслируется автоматически — дополнительная подпись от вас не требуется. Вы также можете попробовать эскроу, профинансировав сделку и наблюдая, как autoRelease проведёт расчёт с продавцом после истечения окна спора.
Компромиссы и честные ограничения
Ограничение вывода безключевого пути пока не герметично в v3. Текущий vault.sil проверяет, что outputs[0] соответствует ожидаемому адресу и минимальной стоимости, но не проверяет tx.outputs.length. Транслятор может добавить второй вывод, направляющий остаточную пыль (в рамках лимита feeBudget) себе. Основной вывод — средства хранилища — остаётся защищённым инвариантом стоимости. Точное ограничение вывода запланировано для v4 и потребует миграции существующих хранилищ.
Безключевые пути нельзя отменить, как только выполнены их условия. В хранилище, как только age ≥ delay для хранилища в UNVAULTING, complete() активен. Ключ тревоги может отменить только *в течение* окна задержки. После истечения вывод окончателен. Это по замыслу — задержка является окном безопасности, а её истечение — обязательством.
Выбор autoInherit постоянен для данного хранилища. При создании вы выбираете, будет ли наследование автоматическим (безключевой inheritAuto) или потребует от наследника активной заявки (inheritSigned). Изменение этого требует транзакции migrate, подписанной обоими ключами — горячим и тревоги, — что означает, что оба ключа должны быть доступны, а владелец должен быть активен.
Сервисные комиссии всё равно применяются к большинству безключевых путей. autoRelease и complete несут стандартную комиссию, установленную в ковенанте. Только пути по тайм-ауту эскроу бесплатны — и это намеренно. Когда сервис не может предоставить арбитраж, он не взимает плату.
Вычислительные бюджеты ограничивают сложность ковенанта. Безключевые пути хранилища выделяют 20 вычислительных единиц на виртуальной машине Kaspa. Путь migrate (две операции checkSig) получает 30. Путь взаимной подписи эскроу (до трёх checkSig плюс интроспекция нескольких выходов) получает 40. Эти лимиты ограничивают стоимость исполнения и устанавливаются при компиляции.
---
Безключевые пути — не хак. Это архитектурный механизм, который позволяет системе на основе ковенантов выполнить обещание самостоятельного хранения: ваши средства управляются кодом, который исполняется в цепочке, а не сервером, который может упасть. Пять безключевых путей в Kaspa Safe и Kaspa Escrow охватывают критические сценарии расчёта — завершение вывода, наследование, выпуск сделки и тайм-аут арбитража — без необходимости наличия закрытого ключа на транслирующей машине.
Наблюдатель делает это удобным. Ковенант делает это бездоверительным.
---
*Открытый исходный код: github.com/Kaspaforge/kaspaforge · Автотесты контрактов: 25 проверок в Kaspa VM · Узнайте, как работает хранилище или попробуйте эскроу.*
FAQ
Может ли кто-то украсть мои средства, отправив безключевой путь?
Нет. Безключевые пути жёстко прописывают назначение в скрипте ковенанта. complete() всегда отправляет на адрес вывода владельца, inheritAuto() — всегда наследнику, autoRelease() — всегда продавцу. Деньги могут пойти только туда, куда указано в контракте.
Что произойдёт, если Kaspa Forge навсегда отключится?
Безключевые пути останутся транслируемыми любым, у кого есть узел Kaspa. Инструменты командной строки с открытым исходным кодом vaultctl (для Safe) и escrowctl (для Escrow) могут создавать и транслировать эти транзакции через любой публичный узел. Прекращение работы сервиса не заморозит средства.
Почему на безключевых путях есть ограничение бюджета комиссии?
Поскольку транслировать безключевую транзакцию может любой, злоумышленник мог бы установить огромную сетевую комиссию, сжигая ваши средства как вознаграждение майнеру. Параметр feeBudget — ограниченный 0.1 KAS — задаёт максимальную сетевую комиссию, которую ковенант примет.
Начисляется ли сервисная комиссия на пути по тайм-ауту?
Нет. Пути по тайм-ауту эскроу (timeoutToBuyer, timeoutToSeller) не несут сервисной комиссии. Если сервис или арбитр не действует, платформа не взимает плату.
Можно ли изменить правила безключевых путей после создания хранилища или сделки?
Только через транзакцию migrate, которая требует подписей обоих держателей ключей (горячий + тревога для хранилищ, покупатель + продавец для эскроу). Ончейн-скрипт неизменяем после развёртывания.
Как наблюдатель знает, когда транслировать?
Сервер опрашивает набор UTXO узла каждые 10 секунд, сравнивая накопленную DAA-оценку каждого хранилища или сделки с настроенной задержкой или окном спора. Когда условие выполняется, он транслирует автоматически. Это для удобства — сам блокчейн обеспечивает соблюдение сроков.
Держите KAS там, где кражу можно отменить
Ковенант-сейф в мейннете Kaspa: ваши ключи, ваши правила, наш инструмент. Ончейн — бесплатно, навсегда.
Создать сейф
