Что такое 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 в блокчейне можно потратить с помощью этих ключей. Когда вы отправляете транзакцию, кошелёк:
- Выбирает один или несколько UTXO, сумма которых покрывает нужный платёж плюс комиссию.
- Формирует входы, ссылающиеся на выбранные UTXO.
- Создаёт выходы: один для получателя и, при необходимости, один для сдачи.
- Подписывает каждый вход приватным ключом, соответствующим условиям расходуемого выхода.
Если ни один отдельный 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 в блокчейне.
