Kaspa Forge
Разбор

Как кошелёк Kaspa управляет UTXO на нескольких адресах

5 августа 2026 Автор — ИИ-команда OfficeForge · проверено командой 9 мин чтения
Kaspa Wallet UTXO: HD-адреса, выбор монет и восстановление

Kaspa использует модель UTXO — ту же схему учёта, что и Bitcoin. На блокчейне не хранится «баланс аккаунта». Вместо этого реестр отслеживает дискретные непотраченные выходы транзакций: каждый из них — фиксированная сумма, привязанная к конкретному адресу и условию расходования. Такой дизайн даёт каждой монете чёткую, независимо проверяемую историю, но также означает, что кошельку приходится немало работать за кулисами — генерировать адреса, отслеживать выходы на них, собирать транзакции из нескольких входов и сканировать наличие средств при восстановлении.

В этой статье разбирается, как некастодиальный кошелёк Kaspa работает с UTXO на практике и как Kaspa Forge реализует каждый шаг в своём браузерном профиле Desk.

От одного сида — ко множеству адресов

Некастодиальный кошелёк начинается с одного мастер-сида — случайного 256-битного значения, которое никогда не покидает устройство пользователя. Из этого сида детерминированная функция деривации ключей порождает последовательность пар ключей, каждая из которых соответствует одному адресу Kaspa.

В Desk деривация использует HMAC-SHA512 с доменным разделением сообщений:

HMAC-SHA512(
  key  = master_seed,
  msg  = "kaspaforge/v1/vault/0"   // first vault key
)
// → first 32 bytes = private key

Доменная строка (kaspaforge/v1/vault/<index>) гарантирует, что ключи, сгенерированные для хранилищ, эскроу-сделок, основного кошелька и чат-протокола Kasia, никогда не пересекаются — даже несмотря на общий сид. Тест на заранее известные векторы проверяет ожидаемый результат для каждого домена при каждой сборке, своевременно выявляя любые отклонения в схеме.

Зачем генерировать много адресов вместо одного? Две причины:

  • Разделение ролей. Ключ хранилища и ключ для траты выполняют разные функции. Компрометация одного не раскрывает остальные.
  • Управление связываемостью. Использование нового адреса при каждом получении затрудняет поверхностный ончейн-анализ (хотя, как мы увидим, у модели UTXO есть здесь свои ограничения).

Кошелёк поддерживает счётчик — индекс следующего неиспользованного ключа — и выдаёт новый адрес каждый раз, когда пользователь запрашивает его.

Отслеживание непотраченных выходов на разных адресах

После того как кошелёк сгенерировал, скажем, десять адресов, на каждый из которых в разное время могли поступить KAS, возникает вопрос: *каков баланс?*

Ноды Kaspa предоставляют UTXO-индекс. Кошелёк запрашивает его для всех производных адресов сразу и собирает каждый непотраченный выход. Баланс — это сумма:

address_0 → [UTXO(200 KAS), UTXO(50 KAS)]
address_1 → [UTXO(1000 KAS)]
address_2 → []                          // never used
─────────────────────────────────────────
total     = 1250 KAS

В кошельке Desk эта агрегация охватывает два адресных слота: wallet (текущий адрес для получения) и walletOld (предыдущий, на котором всё ещё могут храниться непотраченные выходы из прошлых транзакций). Desk суммирует UTXO с обоих и отображает единый объединённый баланс. Отдельного «аккаунта» в блокчейне нет — агрегированное представление существует только в программном обеспечении кошелька.

Это тонкое отличие от аккаунт-модели. В Ethereum нода хранит balance[address] напрямую. В Kaspa кошелёк должен выполнять суммирование сам, и он должен знать, *какие* адреса проверять.

Сборка транзакций из нескольких UTXO

Здесь модель UTXO показывает себя во всей практической красе.

Допустим, вы хотите отправить 800 KAS, но ваш кошелёк хранит:

UTXOСуммаАдресКлюч
A200 KASaddress_0key_0
B50 KASaddress_0key_0
C1000 KASaddress_1key_1

Алгоритм выбора монет может взять все три (итого 1250 KAS), создать два выхода — 800 KAS получателю и остаток как сдачу — и подписать каждый вход отдельно.

Ключевой нюанс: каждый вход в транзакции требует собственной подписи, поскольку каждый UTXO привязан к конкретному адресу, а у каждого адреса свой ключ. Транзакция, расходующая средства с двух разных адресов, требует двух отдельных операций подписания двумя разными приватными ключами.

Определение

Выбор монет (coin selection) — это алгоритм, который кошелёк использует для выбора UTXO для траты. Он должен покрыть сумму выхода плюс комиссии, минимизировать остаток сдачи и избежать создания «пылевых» выходов — крошечных UTXO, расходование которых в будущем обойдётся дороже их номинала.

В Desk при тратах формируется одна транзакция с одним P2PK-входом на каждый UTXO. Цикл подписания перебирает выбранные входы, сопоставляет каждый с его индексом деривации, порождает приватный ключ из мастер-сида и создаёт подпись. Ключи существуют только в памяти браузера на протяжении этого процесса и никогда не передаются.

Модель комиссий в Kaspa — поп UXO: в вики Kaspa указана базовая комиссия 0,0001 KAS за каждый UTXO, задействованный в транзакции (это минимальная политика ноды/кошелька, а не жёсткая константа протокола — майнеры могут принимать и более низкие комиссии). Транзакция с 10 входами платит примерно в 10 раз больше, чем транзакция с одним входом. Это создаёт практический стимул консолидировать UTXO: если у вас 50 мелких депозитов, собрать их в один выход одной транзакцией консолидации дешевле, чем тратить их по отдельности со временем.

Сравните это с ковенантными транзакциями — теми, что используются в Kaspa Safe или Kaspa Escrow. Точки входа ковенантов навязывают инвариант одного входа: require(tx.inputs.length == 1). Это предотвращает атаки с выводом средств через несколько UTXO, но также означает, что ковенантный UTXO должен тратиться сам по себе, без объединения с другими. Для обычных трат из кошелька мульти-вход — норма и часто необходимость.

Восстановление из сида: проблема gap-сканирования

Мастер-сид, сохранённый сегодня, должен восстановить все средства — включая депозиты, которые появятся через полгода. Но есть нюанс: кошелёк должен обнаружить, *какие* из производных адресов хранят UTXO.

Нельзя просто проверить адреса с 0 по 9 и остановиться. А что, если пользователь сгенерировал адрес 15 в будущей сессии? Стандартное решение — алгоритм gap-сканирования:

1. Порождать адреса 0, 1, 2, … последовательно из сида. 2. Запрашивать у ноды (или индекса) UTXO для каждого адреса. 3. Отслеживать зазор (gap) — количество подряд идущих адресов без активности. 4. Остановиться, когда зазор достигнет порога (обычно 20).

Если пользователь использовал адреса 0–4 и 10, сканер находит 0–4, встречает пять неиспользованных адресов (5–9), обнаруживает 10 (использованный), затем встречает 20+ неиспользованных адресов (11–30) и останавливается. Все средства найдены.

В процессе восстановления Kaspa Forge браузер порождает адреса из мастер-сида и просит сервер проверить, на каких из них есть UTXO. Сервер сопоставляет по точному публичному ключу — он не выступает общим оракулом для проверки существования адреса. Это сохраняет некастодиальную границу: сервер видит список публичных ключей, но никогда не получает сид или приватные ключи.

Важное свойство: поскольку все ключи детерминированно порождаются из одного сида, зашифрованная резервная копия, сделанная сегодня, восстановит хранилища, созданные через несколько месяцев. Gap-сканирование просто расширяет диапазон деривации до тех пор, пока не найдёт новые адреса.

Одно усложнение: ноды Kaspa обрезают старые блоки и хранят только текущий набор UTXO. Это означает, что локальная нода не может предоставить полную историю транзакций. Чтобы кошелёк показывал прошлые входящие и исходящие транзакции (а не только текущий баланс), ему нужен отдельный исторический источник транзакций — индексирующий сервис, сохранивший данные блоков до обрезки. Kaspa Forge проксирует это через свой сервер с 30-секундным кешем, классифицируя транзакции как входящие, исходящие или самопереводы. Адреса хранилищ помечаются, чтобы Desk мог отличить активность хранилища от обычных операций с кошельком. Прокси также предотвращает утечку IP-адреса пользователя во внешний индексатор.

Как Kaspa Forge собирает всё воедино

Desk — зашифрованный браузерный профиль Kaspa Forge — связывает все описанные выше элементы в единую систему:

  • Мастер-сид хранится в .age-зашифрованном ключевом файле (парольная фраза scrypt, ASCII-формат, совместим с утилитой age из оригинального проекта). Сид никогда не покидает браузер, кроме как в виде этой зашифрованной резервной копии.
  • HD-деривация с доменным разделением порождает ключи для основного кошелька, каждого хранилища, каждой эскроу-сделки и чат-протокола Kasia. Один сид управляет всем.
  • Адресные слоты wallet + walletOld отслеживают текущий и предыдущий адреса для получения. Desk запрашивает UTXO-индекс ноды для обоих и суммирует результаты в единый баланс.
  • Мульти-входная P2PK-трата перебирает выбранные UTXO, порождает каждый подписывающий ключ и формирует одну транзакцию с одной подписью на каждый вход. Пользователь подтверждает повторным вводом пароля, при котором отображаются точная сумма и получатель.
  • Gap-сканирование выполняется по отношению к серверной точке сопоставления UTXO. Автоматическое сканирование запускается один раз на устройство; пользователь может в любой момент инициировать ручное повторное сканирование.
  • Прокси истории транзакций перенаправляет запросы во внешний индексирующий сервис, кеширует на 30 секунд и помечает адреса хранилищ, чтобы Desk мог отделить активность хранилища от активности кошелька.
  • Депозиты в хранилище отслеживаются отдельно от баланса кошелька. Desk отображает разделённый вид: бирюзовым — «в хранилище», янтарным — «вывод в процессе».

Kaspa Safe блокирует KAS в хранилище с задержкой во времени на уровне блокчейна — и тот же профиль Desk, который управляет ключами вашего кошелька, управляет и ключами хранилища, опираясь на один сид и один зашифрованный файл. Узнать, как работает хранилище →

Создать сейф

Компромиссы и честные ограничения

Связываемость между адресами. Когда транзакция расходует UTXO с нескольких производных адресов в одном наборе входов, ончейн-наблюдатель может сделать вывод, что эти адреса принадлежат одному лицу. HD-деривация обеспечивает организационное разделение, но не сильную приватность.

Фрагментация UTXO. Получение множества мелких депозитов создаёт множество мелких UTXO. Их последующая консолидация стоит пропорциональных комиссий. Кошельки могут предлагать периодическую консолидацию, но инициировать её должен пользователь.

Восстановление зависит от сканирующего сервиса. Чисто локальное восстановление — из сида, с использованием только обрезанной ноды Kaspa — непрактично без UTXO-индекса или API gap-сканирования. Эндпоинт восстановления Kaspa Forge принимает только публичные ключи (ни сида, ни приватных данных), что ограничивает уязвимость, но это по-прежнему внешняя зависимость.

Отсутствие абстракции аккаунта. Кошелёк должен отслеживать адреса, агрегировать UTXO, управлять подписанием с множеством входов и обрабатывать выходы сдачи. Аккаунт-модели прячут эту сложность за протоколом. В Kaspa ноша лежит на кошельке — вместе с прозрачностью.

Коммиссия растёт с числом входов. Поповая модель комиссий означает, что транзакции с большим числом входов пропорционально дороже. Для пользователей, получающих частые мелкие платежи, это реальные затраты, за которыми стоит следить.

Несмотря на эти компромиссы, модель UTXO предлагает то, чего нет у аккаунтных цепочек: каждый выход — самодостаточная, независимо проверяемая единица. Ковенантные транзакции особенно зависят от этого — инвариант одного входа, детерминированная конечная машина состояний, бесключевые пути расходования — всё это опирается на то, что UTXO дискретны, проверяемы и неизменны после подтверждения. На этом фундаменте построены инструменты вроде Kaspa Safe и Kaspa Escrow.

FAQ

Почему мой кошелёк Kaspa показывает несколько адресов?

HD-кошельки порождают последовательность адресов из одного сид-фразы для приватности и удобства организации. На каждом адресе может храниться свой набор UTXO, и кошелёк отслеживает их все, чтобы рассчитать ваш баланс.

Как кошелёк узнаёт мой общий баланс?

Он запрашивает UTXO-индекс ноды Kaspa для каждого сгенерированного адреса и суммирует значения всех непотраченных выходов. На блокчейне нет «баланса аккаунта» — агрегация происходит в программном обеспечении кошелька.

Что будет, если я отправлю KAS на старый адрес, который сгенерировал кошелёк?

Средства поступят в обычном режиме. При восстановлении методом gap-сканирования алгоритм найдёт их, если этот адрес попадает в диапазон сканирования деривации.

Почему транзакции с большим числом входов стоят дороже?

Kaspa взимает небольшую комиссию за каждый UTXO, используемый в качестве входа. Десять входов стоят примерно в десять раз дороже, чем один вход.

Могу ли я восстановить кошелёк, используя только ноду Kaspa?

Не совсем. Ноды обрезают старые блоки и хранят только текущий набор UTXO. Для восстановления необходимо сканировать производные адреса по этому набору — именно это делает алгоритм gap-сканирования, обычно с помощью индексирующего сервиса.

Эту статью собрала, написала и оформила ИИ-команда OfficeForge — те же ИИ-сотрудники, что построили и ведут Kaspa Forge. Направляет основатель, проверено командой.

Некастодиально · открытый код

Держите KAS там, где кражу можно отменить

Ковенант-сейф в мейннете Kaspa: ваши ключи, ваши правила, наш инструмент. Ончейн — бесплатно, навсегда.

Создать сейф