Úvod do Scriptu – programovacího jazyka Bitcoinu
Domů
Články
Úvod do Scriptu – programovacího jazyka Bitcoinu

Úvod do Scriptu – programovacího jazyka Bitcoinu

Středně pokročilí
Zveřejněno Jul 10, 2020Aktualizováno Jan 18, 2022
13m

Úvod

Bitcoinu se občas přezdívá programovatelné peníze. Vzhledem ke své digitální povaze je v nastavení podmínek, jak je možné finanční prostředky utrácet, neuvěřitelně flexibilní. 
Když mluvíme o Bitcoinu, používáme výrazy jako peněženky a coiny. Zároveň ale můžeme o peněženkách uvažovat jako o klíčích a o coinech jak šecích. Blockchain by pak byly dlouhé řady zamčených sejfů. Každý sejf má úzkou škvíru, kterou může kdokoliv vložit šek nebo se jí podívat, jakou hodnotu sejf uchovává. K hodnotě uvnitř sejfu se ale dostane jen držitel klíče.

Když chce držitel klíče dát peníze někomu jinému, odemkne svůj sejf, vytvoří nový šek, který odkazuje na ten starý (ten se pak zničí), a uzamkne ho do sejfu, který může otevřít jen příjemce. Když ho bude chtít nový příjemce utratit, celý proces zopakuje.

V tomto článku se podíváme podrobněji na Script, což je programovací jazyk interpretovaný uzly na bitcoinové síti. Script je mechanismus, který spravuje uzamykání a odemykání zmíněných sejfů.


Jak Bitcoin funguje?

Když budeme pokračovat v naší analogii, dalo by se říct, že každá transakce má dvě části – klíč (k odemčení sejfu) a zámek. Svůj klíč použijete k otevření sejfu, kde je šek, který chcete odeslat, a pak nový sejf s jiným zámkem opatříte novým klíčem. Když budete chtít utratit šek z nového sejfu, budete potřebovat jiný klíč.
To je celkem jednoduché. Zároveň si v systému můžete vybrat z různých typů zámků. Některé sejfy by po vás mohly například požadovat více klíčů a jiné by zase mohly chtít dokázat, že znáte tajný klíč. Podmínek, které si můžete nastavit, je spousta. 
Náš klíč je takzvaný scriptSig a náš zámek je scriptPubKey. Když se na tyto komponenty podíváme trochu podrobněji, zjistíme, že jsou ve skutečnosti tvořené útržky dat a bloky kódu. Dohromady vytváří mini program.

Když pošlete transakci, vysíláte tuto kombinaci do sítě. Každý uzel, který ji obdrží, program zkontroluje, což mu řekne, jestli je transakce platná, nebo ne. Pokud není, bude prostě vyřazena a vy tyto uzamčené prostředky nebudete moci utratit.

Šekům (coinům), které držíte, se říká neutracené transakční výstupy (UTXO – unspent transaction output). Tyto prostředky může použít kdokoli, kdo disponuje klíčem, který pasuje do zámku. Klíčem je konkrétně scriptSig a zámkem je scriptPubKey.
Pokud máte v peněžence neutracené transakční výstupy, pravděpodobně u nich bude podmínka, která říká, že tyto finanční prostředky může odemknout jen osoba, která prokáže vlastnictví jejich veřejného klíče. Pokud chcete peněženku odemknout, musíte poskytnout scriptSig s digitálním podpisem a použít soukromý klíč, který je přiřazený k veřejnému klíči ve scriptPubKey. Zní to asi trochu složitě, ale za chvíli vám to bude jasné.


Vysvětlení bitcoinového zásobníku

Script je takzvaný zásobníkový jazyk. Znamená to, že když čteme soubor instrukcí, můžeme si představit, že tyto instrukce vkládáme do svislého sloupce. Například seznam A, B, C by v zásobníku měl A dole a C nahoře. Když nám instrukce říkají, že máme něco udělat, pracujeme na jednom nebo více prvcích a začínáme shora.


Prvky A, B a C přidávané do zásobníku a vyjímané z něj.


Můžeme rozlišovat mezi daty (podpisy, hashe a veřejné klíče) a instrukcemi (operačními kódy nebo opkódy). Instrukce vyjímají data a něco s nimi dělají. Tady je velmi jednoduchý příklad toho, jak může takový skript vypadat:
<xyz> <md5 hasher> <d16fb36f0911f878998c136191af705e> <check if equal>
Červenou barvu mají data a modrou barvu mají opkódy. Skript se čte se zleva doprava, takže nejdřív do zásobníku vložíme řetězec <xyz>. Pak následuje opkód <md5 hasher>. Tento konkrétní opkód sice na Bitcoinu neexistuje, ale řekněme, že vyjímá horní prvek zásobníku (<xyz>) a pomocí algoritmu MD5 provádí hashování. Výstup se pak přidá zpět do zásobníku. V tomto případě je výstupem d16fb36f0911f878998c136191af705e.
To je ale náhoda! Naším dalším přidaným prvkem je <d16fb36f0911f878998c136191af705e>, takže náš zásobník má teď dva identické prvky. Nakonec řetězec <check if equal> vyjme dva horní prvky a zkontroluje, jestli se shodují. Pokud ano, přidá do zásobníku <1>. Pokud ne, přidá <0>
Dostali jsme se na konec našeho seznamu instrukcí. Náš skript mohl selhat dvěma způsoby – kdyby posledním prvkem byla nula, nebo kdyby nebyly splněny nějaké podmínky a skript kvůli jednomu z operátorů selhal. Žádné takové operátory jsme v tomto příkladu neměli a posledním prvkem nebyla nula (výsledek byl <1>), takže náš skript je platný. Tato pravidla platí i pro skutečné bitcoinové transakce.

Tohle byl jen vymyšlený program, teď se podíváme na nějaké skutečné.


Pay-to-Pubkey (P2PK)

Pay-to-Pubkey (P2PK) je neuvěřitelně přímočarý proces. Funguje tak, že prostředky uzamknete k určitému veřejnému klíči. Kdybyste chtěli obdržet prostředky tímto způsobem, dali byste odesílateli místo bitcoinové adresy svůj veřejný klíč. 

Vůbec první transakce v roce 2009 mezi Satoshi Nakamotem a Halem Finneyem byla P2PK. Tato struktura se hojně používala v raných počátcích Bitcoinu, ale dnes už ji do značné míry nahradila struktura Pay-to-Pubkey-Hash (P2PKH). 
Tento skript k uzamčení prostředků P2PK transakce používá formát <public key> OP_CHECKSIG. To je celkem jednoduché. Možná jste uhodli, že OP_CHECKSIG srovnává podpis a poskytnutý veřejný klíč. Náš scriptSig proto bude jednoduše <signature>. Připomínáme, že scriptSig je klíčem k zámku.



Jednodušší už to snad ani být nemůže. Podpis se přidá do zásobníku a následuje ho veřejný klíč. Oba je pak vyjme OP_CHECKSIG a podpis a veřejný klíč porovná. Pokud se shodují, přidá do zásobníku <1>. V opačném případě přidá <0>.

Proč už se P2PK tolik nepoužívá, si vysvětlíme v další části.


Pay-to-Pubkey-Hash (P2PKH)

Nejběžnějším typem transakce je teď Pay-to-Pubkey-Hash (P2PKH). Pokud jste si schválně nestáhli nějaký zastaralý software, pravděpodobně ho ve výchozím stavu zpracovává i vaše peněženka.

U P2PKH vypadá scriptPubKey následovně:

OP_DUP OP_HASH160 <public key hash> OP_EQUALVERIFY OP_CHECKSIG

Než si tento scriptPubKey představíme, musíme si nejdřív vysvětlit, co dělají nové opkódy:


OP_DUP

OP_DUP vyjme první prvek a duplikuje ho. Pak je oba vrátí do zásobníku. Dělá se to obvykle proto, abychom mohli operaci provést na duplikátu, aniž bychom jakkoli ovlivnili originál.


OP_HASH160

Tento opkód vyjme první prvek a provede u něj dvojité hashování. V prvním kole použije algoritmus SHA-256 a výstup pak zahashuje algoritmem RIPEMD-160. Výsledný výstup se přidá zpět do zásobníku.


OP_EQUALVERIFY

OP_EQUALVERIFY kombinuje dva operátory – OP_EQUAL a OP_VERIFY. OP_EQUAL vyjme dva prvky a zkontroluje, jestli jsou totožné. Pokud jsou, přidá do zásobníku 1. Pokud nejsou, přidá do zásobníku 0. OP_VERIFY vyjme horní prvek a zkontroluje, jestli je pravdivý (tj. není nulový). Pokud není, transakce selže. Takže pokud se dva horní prvky neshodují, opkód OP_EQUALVERIFY způsobí selhání transakce.

Tentokrát scriptSig vypadá takto:

<signature> <public key>

Když chcete odemknout výstupy P2PKH, musíte poskytnout podpis a odpovídající veřejný klíč.



Jak vypadá celý proces, vidíte na uvedeném GIF obrázku. Od skriptu P2PK se to příliš neliší. Přidáváme akorát jeden další krok, kterým ověříme, jestli veřejný klíč odpovídá hashi ve skriptu.

Je ale potřeba zmínit ještě jednu věc. Uzamykací skript P2PKH nemá viditelný veřejný klíč – vidíme jen jeho hash. Když si otevřeme prohlížeč blockchainu a podíváme se na výstup P2PKH, který nebyl utracen, veřejný klíč nezjistíme. Odhalí se, až když se příjemce rozhodne svoje prostředky převést.
To má několik výhod. První výhodou je, že předávání hashe veřejného klíče je prostě jednodušší než předávání celého veřejného klíče. Proto také Satoshi tento skript v roce 2009 zavedl. Hash veřejného klíče je to, čemu dnes říkáme bitcoinová adresa.
Druhou výhodou je, že hashe veřejného klíče by mohly být další vrstvou zabezpečení proti kvantové výpočetní technologii. A vzhledem k tomu, že náš veřejný klíč je neznámý, dokud prostředky neutratíme, je pro ostatní výpočet soukromého klíče ještě obtížnější. Aby se k němu někdo dostal, musel by zpětně dopočítat dvě kola hashování (RIPEMD-160 a SHA-256).



Pay-to-Script-Hash (P2SH)

Pay-to-Script-Hash (P2SH) představoval pro Bitcoin velmi zajímavý vývojový prvek. Umožňuje odesílateli uzamknout prostředky do hashe skriptu – nemusí vědět, co tento skript vlastně dělá. Vezměte si například následující hash SHA-256:

e145fe9ed5c23aa71fdb443de00c7d9b4a69f8a27a2e4fbb1fe1d0dbfb6583f1

Nepotřebujete znát vstup hashe, abyste do něj mohli uzamknout prostředky. Utrácející ale musí poskytnout skript použitý při hashování a musí splnit jeho podmínky.

Výše uvedený hash byl vytvořen z následujícího skriptu:

<multiply by 2> <4> <check if equal>

Pokud chcete utratit coiny navázané na tento scriptPubKey, potřebujete nejen tyto příkazy, ale potřebujete i scriptSig, se kterým bude konečný skript vyhodnocen jako platný. V tomto příkladu je to prvek, který <multiply by 2> (vynásobíte dvěma) a jeho výsledek bude <4>. To samozřejmě znamená, že náš scriptSig je prostě <2>.

Ve skutečném světě vypadá scriptPubKey výstupu P2SH takto:

OP_HASH160 <redeemScript hash> OP_EQUAL

Nejsou tady žádné nové operátory, ale máme nový prvek <redeemScript hash>. Jak název napovídá, je to hash skriptu, který potřebujeme k vyplacení finančních prostředků (proto se nazývá redeemScript). V závislosti na tom, co je v prvku redeemScript, se bude měnit scriptSig. Obecně to ale bývá kombinace podpisů a připojených veřejných klíčů, po kterých následuje (povinný) redeemScript:

<signature> <public key> <redeemScript>

Naše vyhodnocení se teď od dosavadního provedení zásobníku mírně liší. Provádí se ve dvou částech. První část jednoduše zkontroluje, že jste poskytli správný hash. 



Můžete si všimnout, že s prvky, které předchází redeemScriptu, se nic neděje. V tuto chvíli se nepoužívají. Dostali jsme se na konec tohoto mini programu a horní prvek není nulový. To znamená, že je platný.

Ještě jsme ale neskončili. Síťové uzly tuto strukturu rozpoznají jako P2SH, takže mají připravené prvky scriptSig, které čekají v jiném zásobníku. Tam se použije podpis a veřejný klíč.
Do této chvíle jsme s redeemScriptem nakládali jako s prvkem. Teď ale bude interpretován jako instrukce, které mohou vypadat jakkoli. Podíváme se například na skript k uzamčení prostředků P2PKH, kterému musíme poskytnout <signature> (podpis) a <public key> (veřejný klíč), které odpovídají <public key hash> (hash veřejného klíče) uvnitř <redeemScript>.



Jakmile se redeemScript rozbalí, uvidíte, že máme naprosto stejnou situaci jako u běžné transakce P2PKH. Odsud už ho spustíte jako běžný skript.

Ukázali jsme si, jak vypadá P2SH(P2PKH) skript, ale v běžném světě na něj pravděpodobně nenarazíte. Nic vám nebrání v tom, abyste ho vytvořili, ale nepřináší žádné další výhody a zabírá více místa v bloku (a proto je dražší).

P2SH se obecně hodí u transakcí s více podpisy nebo u transakcí kompatibilních s řešením SegWit. Transakce s více podpisy mohou být vzhledem k nutnosti více podpisů opravdu velké. Před implementací procesu Pay-to-Script-Hash by odesílatel musel ve svém skriptu k uzamčení prostředků uvést všechny případné veřejné klíče. 

U P2SH ale na tom, jak složité podmínky pro utrácení jsou, nezáleží. Hash redeemScriptu má vždy fixní velikost. Náklady jsou proto přeneseny na uživatele, který chce skript k uzamčení prostředků odemknout.

Dalším případem, kdy se P2SH hodí, je kompatibilita se SegWitem (o rozdílech v jeho struktuře transakcí si řekneme podrobněji v další části). SegWit byl soft fork, který změnil formát bloku/transakcí. Šlo o dobrovolný upgrade, a tak tuto změnu nemusí všechny peněženky podporovat.

Nezáleží na tom, jestli klienti hash skriptu SegWit zabalí do P2SH. Stejně jako u všech transakcí tohoto typu nemusí vědět, jaký redeemScript bude potřeba k odemčení. 


Transakce SegWit (P2WPKH a P2WSH)

Obsáhlejší informace k transakcím SegWit najdete v průvodci protokolem Segregated Witness pro začátečníky.
Pokud chcete porozumět formátu transakce u protokolu SegWit, měli byste vědět, že už nepoužíváme jen skripty scriptSig a scriptPubKey. Máme totiž nové pole witness. Data, která byla uložena ve skriptu scriptSig, se přesunula do skriptu witness, takže scriptSig je teď prázdný.

Pokud jste už narazili na adresy, které mají na začátku „bc1“, jde o takzvané nativní segwitové adresy (na rozdíl od adres, které jsou se SegWitem jen kompatibilní a začínají trojkou (3), protože ve skutečnosti jde o P2SH adresy).


Pay-to-Witness-Pubkey-Hash (P2WPKH)

Pay-to-Witness-Pubkey-Hash (P2WPKH) je segwitová verze P2PKH. Náš skript witness vypadá následovně:

<signature> <public key>

Asi jste si všimli, že je stejný jako scriptSig u P2PKH. Tady je ale scriptSig prázdný a scriptPubKey vypadá následovně:

<OP_0> <public key hash>

To vypadá trochu zvláštně, že? Kde jsou opkódy, kterými bychom porovnali podpis, veřejný klíč a hash?

Nejsou tady uvedené žádné další operátory, protože uzly, které transakci přijmou, podle délky skriptu <public key hash> poznají, co s transakcí mají dělat. Vypočítají délku a pochopí, že se k ní musí chovat stejným způsobem jako ke staré dobré P2PKH transakci.
Uzly bez upgradu neví, jak takovou transakci interpretovat, ale to vůbec nevadí. Ve starých pravidlech žádný skript witness není, takže si takové uzly přečtou jen prázdný scriptSig a nějaká data. Transakci vyhodnotí a označí ji za platnou – takový výstup totiž podle nich může utratit kdokoli. Proto je SegWit považován za zpětně kompatibilní soft fork.


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

Pay-to-Witness-Script-Hash (P2WSH) je nový P2SH. Pokud jste dočetli až sem, asi si dovodíte, jak bude vypadat, ale stejně si to pro jistotu projdeme. Ve skriptu witness je to, co bychom normálně dali do skriptu scriptSig. Transakce P2WSH, která zabalí transakci P2PKH, by to mohla například vypadat nějak takto:

<signature 1> <public key>

Tady je náš scriptPubKey:

<OP_0> <script hash>

Pravidla jsou pořád stejná. Segwitové uzly přečtou délku hashe skriptu a určí, že jde o P2WSH výstup, který se hodnotí podobně jako P2SH. Staré uzly tuto transakci uvidí jako výstup, který může utratit kdokoli.


Závěrem

V tomto článku jsme se dozvěděli něco málo o stavebních kamenech Bitcoinu. Na závěr si je ještě jednou shrneme:


Typ skriptuPopis

Pay-to-Pubkey (P2PK)

Uzamyká finanční prostředky ke konkrétnímu veřejnému klíči

Pay-to-Pubkey-Hash (P2PKH)

Uzamyká finanční prostředky k hashi konkrétního veřejného klíče (tj. k adrese)

Pay-to-Script-Hash (P2SH)

Uzamyká finanční prostředky k hashi skriptu, který může příjemce poskytnout

Pay-to-Witness-Pubkey-Hash (P2WPKH)

Segwitová verze P2PK

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

Segwitová verze P2SH


Jakmile začnete Bitcoin zkoumat podrobněji, začnete chápat, proč má takový potenciál. Transakce se mohou skládat z mnoha různých částí. Manipulací s těmito stavebními kameny získávají uživatelé obrovskou míru flexibility k nastavení podmínek pro to, jak a kdy mohou být finanční prostředky utraceny.