Перейти к содержанию
Learning Platform
Продвинутый
35 минут
P2PKH P2SH SegWit P2WPKH P2WSH Taproot P2TR Weight Units

Требуемые знания:

  • 04-bitcoin-script

Типы транзакций Bitcoin

Зачем это нужно в блокчейне

За 15 лет Bitcoin прошел путь от простых P2PKH-транзакций до Taproot, где все выходы выглядят одинаково независимо от сложности условий траты. Каждый шаг решал конкретную проблему:

  • P2SH — сложные скрипты (мультиподпись)
  • SegWit — масштабирование и fix malleability
  • Taproot — приватность и гибкость

Понимание эволюции типов транзакций — это понимание того, как Bitcoin решает фундаментальные проблемы масштабируемости, приватности и программируемости без хард-форков.

P2PKH (Pay-to-Public-Key-Hash)

Оригинальный тип транзакций Bitcoin, используется с 2009 года.

scriptPubKey:

OP_DUP OP_HASH160 <pubKeyHash> OP_EQUALVERIFY OP_CHECKSIG

scriptSig:

<sig> <pubKey>

Характеристики:

  • Адреса начинаются с 1 (Base58Check)
  • Подробный разбор выполнения скрипта — в предыдущем уроке (BTC-04)
  • Размер типичной транзакции (1-in, 2-out): ~226 bytes
  • Подпись и публичный ключ находятся внутри scriptSig (часть txid)

Проблема malleability: Поскольку подпись входит в данные, которые хешируются для txid, третья сторона может незначительно изменить формат подписи (не меняя её валидность) и изменить txid транзакции до её подтверждения. Это делает невозможными зависимые цепочки неподтвержденных транзакций.

P2SH (Pay-to-Script-Hash)

BIP 16 (2012). Революционная идея: вместо полного скрипта в выходе, записываем только хеш скрипта.

scriptPubKey:

OP_HASH160 <scriptHash> OP_EQUAL

scriptSig:

<sig1> <sig2> ... <redeemScript>

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

Пример: 2-of-3 мультиподпись

redeemScript: OP_2 <pubKey1> <pubKey2> <pubKey3> OP_3 OP_CHECKMULTISIG
scriptPubKey: OP_HASH160 hash160(redeemScript) OP_EQUAL
  • Адреса начинаются с 3 (Base58Check)
  • Отправитель платит на короткий адрес 3..., не зная структуры мультиподписи
  • При трате получатель раскрывает полный redeemScript

SegWit v0: P2WPKH и P2WSH

BIP 141 (Segregated Witness, 2017). Фундаментальное обновление Bitcoin.

Что такое Segregated Witness

Segregated = отделенный. Witness = свидетельство (подпись).

SegWit перемещает подписи из основного тела транзакции в отдельное поле witness. Это решает:

  1. Transaction malleability — witness данные НЕ входят в txid
  2. Масштабирование — witness данные получают скидку на комиссию
  3. Безопасные цепочки транзакций — Lightning Network стал возможен

P2WPKH (Pay-to-Witness-Public-Key-Hash)

scriptPubKey: OP_0 <20-byte-hash>
witness:      <sig> <pubKey>
  • Адреса: bc1q... (bech32)
  • scriptSig ПУСТ (всё в witness)
  • Размер: ~143.5 vB (~37% экономии vs P2PKH)

P2WSH (Pay-to-Witness-Script-Hash)

scriptPubKey: OP_0 <32-byte-hash>
witness:      <sig1> <sig2> ... <witnessScript>
  • Адреса: bc1q... (bech32, длиннее чем P2WPKH)
  • SegWit-версия P2SH для сложных скриптов

Формат SegWit-транзакции

Ключевое отличие SegWit — новые поля в формате транзакции. Нажимайте на поля, чтобы увидеть описание:

Формат транзакции SegWit
Legacy формат
Version
4 B
Input Count
varint B
Inputs
~148 B
Output Count
varint B
Outputs
~68 B
Locktime
4 B
~226 bytes (P2PKH)
SegWit формат
Version
4 B
NEW
Marker
1 B
NEW
Flag
1 B
Input Count
varint B
Inputs
~41 B
Output Count
varint B
Outputs
~63 B
NEW
Witness
~107 B
Locktime
4 B
~141 bytes (P2WPKH), 574 WU
Ключевое отличие: В SegWit подпись и публичный ключ перенесены из scriptSig в отдельное поле witness. Witness данные НЕ входят в вычисление txid, что решает проблему transaction malleability.

Сравнение форматов

Legacy:  [version][inputs][outputs][locktime]
SegWit:  [version][marker=0x00][flag=0x01][inputs][outputs][witness][locktime]

Marker byte (0x00) выглядит как “0 входов” для старых нод, поэтому они пропускают транзакцию. Новые ноды распознают 0x00 + 0x01 как SegWit-маркер и парсят witness данные.

Расчет веса транзакции

SegWit ввел новую метрику — weight units (WU) вместо простого подсчета байт. Пройдите все шаги расчета:

Расчет веса транзакции (Weight Units)
weight = non_witness * 4 + witness * 1
vB = weight / 4
0
1
2
3
Шаг 0: Разделяем байты транзакции
SegWit-транзакция (1 вход P2WPKH, 2 выхода) разделяется на non-witness и witness части. Non-witness: version, inputs, outputs, locktime. Witness: подпись + публичный ключ.
Non-witness
100 bytes
Witness
107 bytes
Всего
207 bytes

Формула

weight = non_witness_bytes * 4 + witness_bytes * 1
vB (virtual bytes) = weight / 4

Почему именно так?

  • Legacy-транзакции: все байты “стоят” 4 WU -> vB = raw bytes (обратная совместимость)
  • SegWit: witness данные “стоят” 1 WU -> скидка 75% на подписи
  • Комиссия считается в sat/vB, поэтому SegWit дешевле

Примеры размеров (1 вход, 2 выхода)

ТипBytesWUvBЭкономия
P2PKH~226~904~226
P2WPKH~141~574~143.5~37%
P2TR~154~616~154~32%

Эволюция типов транзакций

Сравнение всех пяти типов Bitcoin-транзакций:

Эволюция типов транзакций Bitcoin
Legacy
SegWit v0
Taproot (v1)
2009
2021+
P2PKH
Legacy
P2SH
Legacy
P2WPKH
SegWit v0
P2WSH
SegWit v0
P2TR
Taproot (v1)
Эпоха
2009+
2012+ (BIP 16)
2017+ (BIP 141)
2017+ (BIP 141)
2021+ (BIP 341)
scriptPubKey
OP_DUP OP_HASH160 <hash> OP_EQUALVERIFY OP_CHECKSIG
OP_HASH160 <scriptHash> OP_EQUAL
OP_0 <20-byte hash>
OP_0 <32-byte hash>
OP_1 <32-byte tweaked pubKey>
Разблокировка
scriptSig: <sig> <pubKey>
scriptSig: <data> <redeemScript>
witness: <sig> <pubKey>
witness: <data> <witnessScript>
Key path: <schnorr sig> Script path: <script> <control block>
Адрес
1... (Base58)
3... (Base58)
bc1q... (bech32)
bc1q... (bech32)
bc1p... (bech32m)
Плюсы
Простой, понятный
Сложные скрипты, мультиподпись
Экономия ~37%, fix malleability
Сложные скрипты + экономия
Приватность, гибкость, Schnorr

Taproot (P2TR) — BIP 341/342

Активирован в ноябре 2021 года. Taproot объединяет преимущества всех предыдущих типов и добавляет приватность.

Tweaked Public Key

Центральная идея Taproot — tweaked public key:

Q = P + t * G

где:

  • P — внутренний публичный ключ (internal key)
  • t = tagged_hash("TapTweak", P || script_root) — tweak
  • G — генератор кривой secp256k1
  • Q — tweaked key (записывается в scriptPubKey)

scriptPubKey:

OP_1 <32-byte tweaked pubKey Q>

Два пути траты

Key path (основной):

  • Подпись одной Schnorr-подписью: <schnorr_sig>
  • Подпись создается tweaked приватным ключом d + t
  • Со стороны наблюдателя выглядит как обычная одиночная подпись
  • Это самый частый и самый дешевый способ траты

Script path (альтернативный):

  • Раскрытие скрипта через Merkle proof: <script> <control_block>
  • Control block содержит: внутренний ключ P + Merkle proof до script_root
  • Позволяет создать дерево из множества скриптов (MAST — Merkelized Abstract Syntax Trees)

Приватность Taproot

Ключевое преимущество: Все P2TR-выходы выглядят одинаково — OP_1 <32 bytes>. Наблюдатель не может отличить:

  • Простой перевод одному получателю
  • 2-of-3 мультиподпись
  • Lightning Network commitment transaction
  • Timelock-скрипт

Это значительное улучшение приватности по сравнению с P2SH, где тип скрипта раскрывается при трате.

Связь с CRYPTO-12: В уроке о подписях Шнорра мы изучили, как Schnorr signatures позволяют агрегацию ключей (MuSig2). Taproot использует эту возможность: несколько участников могут объединить свои ключи в один tweaked key и подписать одной подписью.

  • Адреса: bc1p... (bech32m)
  • Размер key path spend: ~154 vB

Математический уровень: Taproot Tweaking

Доказательство того, что key path spending работает:

Tweaked key: Q = P + t*G

Подпись создается tweaked приватным ключом:
d_tweaked = d + t  (где d -- приватный ключ для P)

Проверка:
d_tweaked * G = (d + t) * G = d*G + t*G = P + t*G = Q

Schnorr verification: verify(Q, sig) = true

Почему нельзя подделать:

  • Чтобы вычислить t, нужен script_root (Merkle root дерева скриптов)
  • Если script_root публичен, то tweak t детерминирован
  • Если скрипты секретны, наблюдатель не знает t и не может отличить Q от “обычного” публичного ключа

Код на Python

P2WPKH транзакция (python-bitcoinlib)

from bitcoin import SelectParams
from bitcoin.core import (b2x, lx, COIN, COutPoint, CTxOut, CTxIn,
                          CTxInWitness, CTxWitness, CScriptWitness,
                          CMutableTransaction, Hash160)
from bitcoin.core.script import (CScript, OP_0, SignatureHash,
                                 SIGHASH_ALL, SIGVERSION_WITNESS_V0)
from bitcoin.wallet import P2WPKHBitcoinAddress

SelectParams('regtest')

# Создаем P2WPKH scriptPubKey
pubkey_hash = bytes(20)  # Hash160 публичного ключа
script_pubkey = CScript([OP_0, pubkey_hash])

print("P2WPKH scriptPubKey:", b2x(script_pubkey))
# Вывод: 0014 + 20 нулевых байт
# OP_0 (0x00) + push 20 bytes (0x14) + hash

P2TR с bitcoin-utils (концептуальный пример)

# Для Taproot используйте bitcoin-utils==0.7.3
# python-bitcoinlib НЕ поддерживает P2TR

from bitcoinutils.setup import setup
from bitcoinutils.keys import PrivateKey

setup('regtest')

# Генерация ключа
priv = PrivateKey()
pub = priv.get_public_key()

# Получение P2TR адреса (tweaked key)
taproot_address = pub.get_taproot_address()
print(f"P2TR адрес: {taproot_address.to_string()}")
# Вывод: bcrt1p... (bech32m для regtest)

Примечание: python-bitcoinlib не поддерживает Taproot (P2TR). Для работы с Taproot в Python используйте библиотеку bitcoin-utils==0.7.3. Подробнее — в Jupyter notebook.

Практика

Откройте Jupyter notebook 11-bitcoin-script.ipynb для практики:

  • Создание скриптов для всех типов транзакций
  • Расчет weight units и virtual bytes
  • Сравнение размеров P2PKH, P2WPKH и P2TR
  • Taproot-примеры с bitcoin-utils

Для работы с bitcoin-cli на regtest откройте lab-02-script.sh:

  • Создание адресов P2PKH, P2SH, P2WPKH, P2TR
  • Отправка на разные типы адресов и сравнение транзакций
  • Декодирование scriptPubKey для каждого типа
  • Исследование descriptor wallets

Итоги

ТипЭпохаКлючевое улучшениеАдрес
P2PKH2009Оригинальный тип1...
P2SH2012Сложные скрипты3...
P2WPKH2017-37% комиссия, fix malleabilitybc1q...
P2WSH2017Сложные скрипты + SegWitbc1q...
P2TR2021Приватность, Schnorr, MASTbc1p...

Следующий урок: Майнинг и Proof-of-Work — как Bitcoin обеспечивает консенсус без центрального сервера.

Закончили урок?

Отметьте его как пройденный, чтобы отслеживать свой прогресс