UTXO в Bitcoin: откуда берутся входы, сдача и почему баланс не хранится одной цифрой

Что такое UTXO​


UTXO (Unspent Transaction Output) — выход транзакции, который ещё не был потрачен. Когда кошелёк показывает вам баланс, например 10 000 сатоши, это означает, что у вас есть один или несколько UTXO, сумма которых равна этому числу. Баланс не хранится как единая запись в базе данных — он вычисляется как сумма всех неиспользованных выходов, принадлежащих вашим ключам.

Каждая транзакция в Bitcoin состоит из входов и выходов. Вход ссылается на выход предыдущей транзакции и расходует его. Выход создаётся заново и ждёт, пока кто-то потратит его в будущем. Как только выход потрачен, он перестаёт быть UTXO и становится spent output.

Аналогия с наличными​


Модель UTXO ближе всего к работе с наличными деньгами. Если у вас есть купюра номиналом 50 долларов, а нужно заплатить 20, вы отдаёте всю купюру и получаете 30 долларов сдачи. Вы не можете отрезать от банкноты кусок.

В Bitcoin работает тот же принцип: UTXO расходуется целиком. Если у вас есть UTXO на 5 BTC и вы хотите отправить кому-то 2 BTC, транзакция заберёт весь UTXO на 5 BTC, создаст выход на 2 BTC для получателя и выход на оставшуюся сумму (минус комиссия) обратно вам. Этот второй выход и есть сдача — новый UTXO меньшего размера.

Структура транзакции: входы и выходы​


Каждая транзакция содержит как минимум один вход и один выход. Разберём их устройство.

Выход (output)​


Выход состоит из двух элементов:

  • Сумма в сатоши — сколько монет привязано к этому выходу.
  • Pubkey script (scriptPubKey) — набор условий, которые должен выполнить тот, кто хочет потратить этот выход.

Выходы нумеруются по порядку внутри транзакции, начиная с нуля. Этот порядковый номер называется output index (или vout).

Вход (input)​


Вход содержит:

  • txid — идентификатор (хеш) транзакции, в которой находится расходуемый выход.
  • Output index (vout) — номер конкретного выхода внутри той транзакции.
  • Signature script (scriptSig) — данные, которые доказывают право на расходование: подпись и открытый ключ (в случае стандартного P2PKH).

Вход не содержит сумму явно — она определяется по выходу, на который ссылается вход.

Как формируется сдача​


Рассмотрим конкретный сценарий. Допустим, у вас есть UTXO на 5 BTC. Вы хотите отправить 2 BTC другому человеку. Транзакция будет выглядеть так:

| Элемент | Значение |
|---------|----------|
| Вход | UTXO на 5 BTC |
| Выход 1 | 2 BTC получателю |
| Выход 2 | ~2,9999 BTC вам (сдача) |
| Комиссия | Разница между входом и суммой выходов |

Комиссия не указывается явно ни в одном поле. Она вычисляется как разница: сумма всех входов минус сумма всех выходов. Майнеры забирают эту разницу.

Сдача возвращается на новый адрес вашего кошелька. Современные кошельки генерируют для сдачи новый адрес каждый раз — это усложняет анализ цепочки транзакций сторонними наблюдателями.

Почему баланс не хранится одной цифрой​


В банковской системе баланс счёта — это число в базе данных. При переводе система проверяет, что число достаточно велико, уменьшает его у отправителя и увеличивает у получателя.

Bitcoin работает иначе. В блокчейне нет записи вида «адрес X владеет N монет». Вместо этого каждый узел сети поддерживает набор UTXO — все выходы всех транзакций, которые ещё не были потрачены. Чтобы узнать баланс адреса, нужно просканировать весь набор UTXO и сложить выходы, которые можно потратить с помощью ключей этого адреса.

Такой подход имеет несколько следствий:

  • Верификация без доверия. Любой узел может независимо проверить, что вход ссылается на реально существующий и ещё не потраченный выход.
  • Отсутствие двойного расходования. UTXO можно потратить только один раз: как только транзакция, расходующая его, попадает в блок, этот выход исчезает из набора.

UTXO против балансовой модели​


Bitcoin использует модель UTXO. Ethereum и Solana используют балансовую модель (account-based model), где у каждого аккаунта есть числовое поле с текущим балансом.

| Критерий | UTXO (Bitcoin) | Балансовая модель (Ethereum) |
|----------|---------------|------------------------------|
| Хранение состояния | Набор неиспользованных выходов | Баланс на аккаунте |
| Проверка права на расходование | Подпись, удовлетворяющая условиям выхода | Проверка баланса аккаунта |
| Сдача | Обязательна, если UTXO больше нужной суммы | Не нужна — баланс уменьшается на сумму перевода |
| Приватность | Выше: можно создавать новый адрес для каждого UTXO | Ниже: один аккаунт — один адрес |
| Сложность для разработчика | Выше: нужно управлять множеством UTXO | Ниже: работа с одним числом |

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

Как кошелёк управляет UTXO​


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

  1. Выбирает один или несколько UTXO, сумма которых покрывает нужный платёж плюс комиссию.
  2. Формирует входы, ссылающиеся на выбранные UTXO.
  3. Создаёт выходы: один для получателя и, при необходимости, один для сдачи.
  4. Подписывает каждый вход приватным ключом, соответствующим условиям расходуемого выхода.

Если ни один отдельный UTXO не покрывает нужную сумму, кошелёк может объединить несколько UTXO в одной транзакции — создать несколько входов. Это похоже на оплату несколькими купюрами одновременно.

Подпись и верификация​


Каждый вход подписывается приватным ключом владельца. Подпись покрывает:

  • txid и output index предыдущей транзакции;
  • pubkey script расходуемого выхода;
  • pubkey script нового выхода (куда идут монеты);
  • сумму в сатоши.

Это делает транзакцию неизменяемой после подписания: любое изменение данных инвалидирует подпись. Сеть проверяет подпись, выполняя скрипт: scriptSig (подпись + открытый ключ) объединяется с scriptPubKey (условия из предыдущего выхода), и если результат выполнения — true, расходование считается валидным.

Для стандартного P2PKH-выхода скрипт проверки выглядит так:

Код:
OP_DUP OP_HASH160 <PubkeyHash> OP_EQUALVERIFY OP_CHECKSIG

Он проверяет, что предоставленный открытый ключ хешируется в ожидаемый хеш, и что подпись корректна для этого ключа.

Типичные заблуждения​


«Монеты хранятся в кошельке». Кошелёк хранит только ключи. Монеты — это UTXO в блокчейне, которые можно потратить с помощью этих ключей.

«Можно отправить часть UTXO». Нет. UTXO расходуется целиком. Если нужна меньшая сумма, создаётся выход для получателя и выход со сдачей.

«Комиссия указывается в транзакции явно». Комиссия — неявная разница между суммой входов и суммой выходов. Отдельного поля для неё нет.

«Баланс — это число на адресе». Баланс вычисляется как сумма UTXO, привязанных к ключам адреса. Один адрес может иметь десятки UTXO разного размера.

Практический итог​


  • UTXO — это «купюра» в блокчейне Bitcoin: неделимая единица, которая расходуется целиком.
  • Баланс кошелька — сумма всех UTXO, которые вы можете потратить.
  • Сдача — новый UTXO, который возвращается вам, если потраченный вход больше нужной суммы.
  • Комиссия — разница между суммой входов и суммой выходов, без явного поля.
  • Кошелёк не хранит монеты — он хранит ключи и отслеживает UTXO в блокчейне.

Источники​


 
Назад
Верх Низ