Bitcoinový slovník naučný

Anatomie transakce

K popisu anatomie bitcoinové transakce byla náhodně vybrána segwitová transakce 40e285bd2b757bf455f9e3ce92aa8e51910f88a1ca9dd497465d346310e7df11 z bloku č. 676274. Jedná se o typickou transakci s jedním vstupem a dvěma výstupy – to znamená, že transakce utrácí (spotřebovává) jeden UTXO a dva nové UTXO vytváří. Následuje hexadecimální reprezentace serializace transakce:

01000000000101177b550c14d173e1ac3d9987b1c3892572c848381f7ef9d3dd29fbfac09e14610100000000ffffffff02b1a6910000000000160014c3c03280e573ec2c59a8a11c2367368b514ff9d2204e000000000000160014e447450ba6baaf561ea6c3b9d1dc2cd687d961d20247304402201cbbe2ba007b80c6e23ff6c0069b7135580c4f00089474b4c882421408fde92502204e330225ae3a72364662f50a29c2d29db6b7063f71a721af7da905de30df3120012103c0fb6554508be65f82305cab41d97db37e2d5b3ba5920009209f9dfbcb00dbcc00000000

barva hodnota význam formát
1 verze tx 4 bajty LE
0 segwit marker; zavedený segwitem, zatím nevyužitý bajt
1 segwit flag; zavedený segwitem, zatím pevně 1 bajt
1 počet vstupů varint
61149…17 1. vstup – txid (hash) předchozí tx 32 bajtů LE
1 1. vstup – index výstupu předchozí tx 4 bajty LE
0 1. vstup – scriptSig; v předsegwitových tx je na tomto místě podpisový skript script
ffffffff 1. vstup – sequence; zamýšleno pro časté platby, nyní slouží převážně k RBF 4 bajty LE
2 počet výstupů varint
91a6b1 1. výstup – částka v satoshi 8 bajtů LE
script 1. výstup – uzamykací skript (scriptPubKey) script
4e20 2. výstup – částka v satoshi 8 bajtů LE
script 2. výstup – uzamykací skript (scriptPubKey) script
script svědek (witness); segregovaný podpisový skript (scriptSig) script
0 locktime; může udávat č. bloku, případně čas, po kterém teprve může být tx vytěžena 4 bajty LE

Serializace této tx čítá 222 bajtů z čehož je 109 bajtů „segwitových“ (marker, flag, witness). Pro výpočet váhy tx vynásobíme počet bajtů „nesegwitových“ dat čtyřmi a výsledek přičteme k počtu segwitových bajtů (113 × 4 = 452; 452 + 109 = 561 WU). Když poté vydělíme WU čtyřmi, dostaneme tzv. virtuální velikost (561 ÷ 4 = 140,25 vB).

Odečtením součtu částek výstupů od součtu částek vstupů (hodnoty částek vstupů nejsou součástí dat této tx; je potřeba se podívat do předchozích) zjistíme absolutní hodnotu poplatku (9566387 − (9545393 + 20000) = 994). Relativní hodnoty poplatků pak zjistíme už prostým dělením velikostí, resp. virtuální velikostí (994 ÷ 222 = 4,5 satů/bajt; 994 ÷ 140 = 7,1 satů/vBajt).

digram transakcí
Diagram popisované transakce včetně předcházející

Anatomie skriptu

Prostřednictvím skriptovacího jazyka Bitcoinu, který je záměrně co možná nejjednodušší (a turingovsky neúplný) stanovujeme a následně i vyhodnocujeme podmínky utracení každého UTXO. V našem případě útraty druhého výstupu (počítáno od nuly je to výstup číslo jedna) předchozí transakce 61149…17 musela „naše“ transakce dodat takový podpisový skript (scriptSig), který bude vyhodnocen v kombinaci s uzamykacím skriptem (scriptPubKey) utráceného výstupu jako pravdivý. Skriptovací jazyk Bitcoinu pracuje se zásobníkem a samotný skript je složen z operátoru a elementů (dat).

Než zjistíme, jakým způsobem došlo k vyhodnocení skriptů naší rozpitvané segwitové (je utráceno segwitové UTXO) transakce, podíváme se na to, jak tuto transakci vidí předsegwitové uzly. Takový starý uzel vezme scriptPubKey odkazovaného výstupu předešle tx (61149…17:1):

OP_0 OP_PUSHBYTES_20 413879391419d23453c720a1058e959ae663c3d6

Před tento uzamykací skript (scriptPubKey) předešlé tx je vložen podpisový skript (scriptSig) aktuální tx. ScriptSig naší transakce je ale prázdný! No to nevadí, uzel začne s tím to co má. OP_0 vloží na vrch zásobníku nulu, OP_PUSHBYTES_20 vloží na vrch zásobníku následujících 32 bajtů skriptu. Uzel vykonal celý skript a na vrchu zásobníku má nenulovou hodnotu (hash veřejného klíče). Skript je pravdivý, transakce je platná. I bez podpisu je platná! LOL Není to chyba, je to schválně – předsegwitové uzly neví, že podpisový skript je nyní v poli witness, proto je zajištěno, že se těmto uzlům bude kombinace segwitového uzamykacího skriptu a prázdného podpisového skriptu segwit transakce jevit jako platná. Taky se tomu říká zpětná kompatibilita.

Jak si s vyhodnocením skriptů poradí segwitový uzel? Začátek je stejný, sáhne si do předchozí transakce pro uzamykací skript. Rozpozná strukturu skriptu (p2wpkh) a uplatní speciální pravidlo, které skript modifikuje do podoby:

OP_DUP OP_HASH160 OP_PUSHBYTES_20 413879391419d23453c720a1058e959ae663c3d6 OP_EQUALVERIFY OP_CHECKSIG

Konečně máme skript, který nebude platný s i prázdným podpisovým skriptem! Toto je již mimochodem struktura shodná s předsegwitovým p2pkh. Zkušebně si vyhodnotíme tento skript bez podpisu: OP_DUP duplikuje element na vrchu zásobníku. Zásobník je ale prázdný – skript selhal. Nyní už to bez podpisu nepůjde.

Segwitový uzel ale ví, že v této transakci musí podpisový skript hledat v poli witness. Finální odemykací skript naší transakce (resp. jejího prvního a jediného vstupu) je tedy:

OP_PUSHBYTES_47
304402201cbbe2ba007b80c6e23ff6c0069b7135580c4f00089474b4c882421408fde92502204e330225ae3a72364662f50a29c2d29db6b7063f71a721af7da905de30df312001
OP_PUSHBYTES_21
03c0fb6554508be65f82305cab41d97db37e2d5b3ba5920009209f9dfbcb00dbcc
OP_DUP
OP_HASH160
OP_PUSHBYTES_14
413879391419d23453c720a1058e959ae663c3d6
OP_EQUALVERIFY
OP_CHECKSIG

Vykonáme skript – 71 následujících bajtů (podpis) se vloží na vršek zásob.; 33 následujících bajtů (veřejný klíč) se vloží na vršek zásob.; element na vršku zásob. se zduplikuje; element na vršku zásobníku se nahradí svým vlastním hashem (RIPEMD160(SHA256)). Na zásobníku je nyní pohledem z vrchu hash (adresa), veřejný klíč a podpis; dále se 20 následujících bajtů vloží na vršek zásob. (tj. adresa z uzamykacího skriptu); dva vrchní elementy se odeberou ze zásob. a porovnají se – jsou‐li shodné, skript pokračuje, v opačném případě končí chybou; konečně poslední operátor odebere z vrchu zásob. nejprve veřejný klíč a pak i podpis – zkontroluje podpis proti danému klíči a předobrazu podepisované transakce a vrátí na vrch zásobníku 1 pro platný, 0 pro neplatný podpis. Jsme na konci skriptu a je‐li na vrchu zásobníku 1, transakce je platná.

Bonus: Předobraz transakce pro podpis

V anatomii podpisu se dočtete více o ověřování podpisu. Zde na tomto místě však využijeme výše rozebranou transakci, resp. její předchůdkyni a podíváme se, jakým způsobem vznikl její podepisovaný předobraz.

Před segwitem vznikal předobraz tak, že v případě ověření nejprve došlo k vyprázdnění všech scriptSigů (v případě podpisu není co vyprazdňovat, scriptSig ještě nebyl naplněn). Následně jsou tato prázdná místa – vždy po jednom pro každý podpis – vyplněna skripty scriptPubKey utrácených výstupů. Pro ty je potřeba sáhnout do předchozí(ch) transakce/í. Nakonec jen přidán hashtyp – typicky SIGHASH_ALL (číslo 1 v čtyřbajtovém LE).

Tento přístup má však dvě hlavní nevýhody. Zaprvé – výpočetní náročnost hashování roste kvadraticky s počtem vstupů podepisované transakce. A zadruhé – předobraz v sobě neobsahuje informaci o částce utrácených vstupů, ze kterých by kupříkladu hardwarová peněženka dokázala bez dalších informací vypočíst a zobrazit částku poplatku k potvrzení. Proto byl u v rámci segwitu – konkrétně BIPem 143 – zaveden nový způsob výroby předobrazu pro segwitové transakce. Předobraz výše rozebrané tranasakce bude tedy vypadat následovně (užité hashe jsou vždy dvojité SHA256):

Jak by takové velmi naivní ověření podpisu naší transakce vypadalo lze nahlednout v jazyce python zde.