Wstęp

Bitcoin jest czasami określany jako programowalny pieniądz. Ze względu na swój cyfrowy charakter zapewnia użytkownikom dużą elastyczność w zakresie ustalania warunków wydatkowania środków.

Omawiając Bitcoin, mówimy o portfelach i monetach. Ale portfele możemy też traktować jako klucze, monety jako czeki, a blockchain jako rzędy zamkniętych sejfów. Każdy sejf ma cienką szczelinę, dzięki której każdy może zdeponować czeki lub zajrzeć do środka i sprawdzić, ile wartości jest w sejfie. Jednak tylko posiadacz klucza będzie mógł uzyskać dostęp do wnętrza.

Kiedy posiadacz kluczy chce przekazać pieniądze komuś innemu, otwiera swoją skrzynkę. Sporządzają nowy czek nawiązujący do starszego (który następnie ulega zniszczeniu) i zamykają go w pudełku, które odbiorca może otworzyć. Aby je wydać, nowy odbiorca powtarza proces.

W tym artykule przyjrzymy się bliżej Skryptowi, językowi programowania interpretowanemu przez węzły w sieci Bitcoin. Skrypt zarządza mechanizmem blokowania/odblokowywania wspomnianym w przypadku sejfów.


Jak działa Bitcoin?

Kierując się naszą analogią z góry, można powiedzieć, że każda transakcja składa się z dwóch części – klucza (do odblokowania pudełka) i kłódki. Za pomocą klucza otwierasz skrzynkę zawierającą czek, który chcesz wysłać, a następnie dodajesz nowy do nowej skrzynki z innym zamkiem. Aby wydać z nowego pudełka, potrzebujesz innego klucza.

Wystarczająco proste. Można również uzyskać pewne różnice w typach zamków w systemie. Być może niektóre sejfy wymagają dostarczenia wielu kluczy, a być może inne wymagają udowodnienia, że ​​znasz sekret. Istnieje wiele warunków, które ludzie mogą ustawić. 

Naszym kluczem jest to, co nazywamy scriptSig. Zamek to nasz skryptPubKey. Jeśli przyjrzymy się tym komponentom nieco bardziej szczegółowo, odkryjemy, że w rzeczywistości składają się one z fragmentów danych i bloków kodu. Po połączeniu tworzą niewielki program.

Dokonując transakcji, transmitujesz tę kombinację do sieci. Każdy węzeł, który go otrzyma, sprawdzi program, który poinformuje go, czy transakcja jest ważna. Jeśli nie, zostanie po prostu odrzucony i nie będziesz mógł wydać zablokowanych środków.

Trzymane przez Ciebie czeki (monety) nazywane są niewydanymi wynikami transakcji (UTXO). Ze środków może skorzystać każdy, kto dostarczy klucz pasujący do zamka. W szczególności kluczem jest scriptSig, a zamkiem jest scriptPubKey.

Jeśli UTXO znajdują się w Twoim portfelu, prawdopodobnie będą miały warunek mówiący, że tylko osoba, która może udowodnić, że jest właścicielem tego klucza publicznego, może odblokować te środki. Aby go odblokować, dostarczasz skryptSig zawierający podpis cyfrowy, używając klucza prywatnego, który jest mapowany na klucz publiczny określony w scriptPubKey. Wszystko to wkrótce się wyjaśni.


Zrozumienie stosu Bitcoin

Skrypt jest tak zwanym językiem opartym na stosie. Oznacza to tylko tyle, że kiedy czytamy zestaw instrukcji, umieszczamy je w czymś, co można uznać za pionową kolumnę. Na przykład lista A, B, C spowoduje utworzenie stosu z A na dole i C na górze. Kiedy instrukcje każą nam coś zrobić, operujemy na jednym lub większej liczbie elementów, zaczynając od szczytu stosu.


Elements A, B, and C being added and “popped” from the stack.

Elementy A, B i C są dodawane i „zrzucane” ze stosu.


Możemy rozróżnić dane (takie jak podpisy, skróty i klucze publiczne) od instrukcji (lub kodów operacji). Instrukcje usuwają dane i coś z nimi robią. Oto bardzo prosty przykład tego, jak mógłby wyglądać skrypt:

<xyz> <md5 hasher> <d16fb36f0911f878998c136191af705e> <sprawdź, czy jest równy>

Na czerwono mamy dane, a na niebiesko kody operacji. Czytamy od lewej do prawej, więc najpierw umieszczamy ciąg <xyz> na stosie. Następny w kolejności jest kod operacji <md5 hasher>. Ten nie istnieje w Bitcoinie, ale powiedzmy, że usuwa górny element stosu (<xyz>) i miesza go za pomocą algorytmu MD5. Następnie dane wyjściowe są ponownie dodawane na stos. Tak się składa, że ​​wyjściem jest d16fb36f0911f878998c136191af705e.

Co za zbieg okoliczności! Naszym kolejnym elementem do dodania jest <d16fb36f0911f878998c136191af705e>, więc teraz nasz stos ma dwa identyczne elementy. Na koniec <sprawdź, czy równe> usuwa dwa elementy z góry i sprawdza, czy są równe. Jeśli tak, dodaje <1> do stosu. Jeśli nie, dodaje <0>. 

Dotarliśmy do końca naszej listy instrukcji. Nasz skrypt mógł zawieść na dwa sposoby – jeśli pozostałym elementem było zero lub jeśli jeden z operatorów spowodował awarię, gdy nie zostały spełnione pewne warunki. W tym przykładzie nie mieliśmy żadnych takich operatorów i otrzymaliśmy niezerowy element (<1>), więc nasz skrypt był prawidłowy. Zasady te dotyczą również prawdziwych transakcji Bitcoin.

To był tylko wymyślony program. Przyjrzyjmy się teraz niektórym rzeczywistym.


Płatność do Pubkey (P2PK)

Pay-to-Pubkey (P2PK) jest niezwykle proste. Polega na zablokowaniu środków na konkretnym kluczu publicznym. Jeśli chciałbyś otrzymać środki w ten sposób, przekazałbyś nadawcy swój klucz publiczny, a nie adres Bitcoin. 

Pierwszą transakcją pomiędzy Satoshim Nakamoto i Halem Finneyem w 2009 roku była transakcja P2PK. Struktura ta była intensywnie używana w początkach istnienia Bitcoina, ale obecnie w dużej mierze ją zastąpiła funkcja Pay-to-Pubkey-Hash (P2PKH). 

Skrypt blokujący dla transakcji P2PK ma format <klucz publiczny> OP_CHECKSIG. Wystarczająco proste. Być może zgadłeś, że OP_CHECKSIG sprawdza podpis pod podanym kluczem publicznym. W związku z tym nasz scriptSig będzie prostym <signature>. Pamiętaj, skryptSig jest kluczem do zamka.


A signature gets added to the stack, followed by a public key. OP_CHECKSIG pops them both and verifies the signature against the public key. If they match, it adds a <1> to the stack. Otherwise, it adds a <0>


Nie ma nic prostszego. Do stosu dodawany jest podpis, po którym następuje klucz publiczny. OP_CHECKSIG wyświetla oba i weryfikuje podpis względem klucza publicznego. Jeśli pasują, dodaje <1> do stosu. W przeciwnym razie dodaje <0>.

Z powodów, które omówimy w następnej sekcji, P2PK nie jest już tak naprawdę używany.


Hash płatności do Pubkey (P2PKH)

Pay-to-Pubkey-Hash (P2PKH) jest obecnie najpopularniejszym typem transakcji. Jeśli nie starasz się pobierać archaicznego oprogramowania, Twój portfel prawdopodobnie robi to domyślnie.

SkryptPubKey w P2PKH jest następujący:

OP_DUP OP_HASH160 <hash klucza publicznego> OP_EQUALVERIFY OP_CHECKSIG

Zanim przedstawimy skryptSig, przyjrzyjmy się, co będą robić nowe kody operacji:


OP_DUP

OP_DUP wyskakuje pierwszy element i powiela go. Następnie dodaje oba z powrotem do stosu. Zwykle robi się to po to, abyśmy mogli wykonać operację na duplikacie bez wpływu na oryginał.


OP_HASH160

To wyskakuje pierwszy element i miesza go dwukrotnie. Pierwsza runda będzie haszowana algorytmem SHA-256. Dane wyjściowe SHA-256 są następnie haszowane za pomocą algorytmu RIPEMD-160. Wynikowy wynik jest dodawany z powrotem na stos.


OP_EQUALVERIFY

OP_EQUALVERIFY łączy w sobie dwa inne operatory – OP_EQUAL i OP_VERIFY. OP_EQUAL wyskakuje dwa elementy i sprawdza, czy są identyczne. Jeśli tak, dodaje 1 do stosu. Jeśli nie, dodaje 0. OP_VERIFY wyświetla górny element i sprawdza, czy jest prawdziwy (tj. niezerowy). Jeśli tak nie jest, transakcja kończy się niepowodzeniem. W połączeniu OP_EQUALVERIFY powoduje niepowodzenie transakcji, jeśli dwa górne elementy nie pasują.

Tym razem scriptSig wygląda następująco:

<podpis> <klucz publiczny>

Aby odblokować wyjścia P2PKH, musisz podać podpis i odpowiedni klucz publiczny.


We’re just adding an extra step to check that the public key matches the hash in the script


Możesz zobaczyć, co się dzieje na powyższym GIF-ie. Nie różni się zbytnio od skryptu P2PK. Po prostu dodajemy dodatkowy krok, aby sprawdzić, czy klucz publiczny pasuje do skrótu w skrypcie.

Jest jednak coś, na co warto zwrócić uwagę. W skrypcie blokującym P2PKH klucz publiczny nie jest widoczny – widzimy jedynie jego skrót. Jeśli przejdziemy do eksploratora blockchain i spojrzymy na wyjście P2PKH, które nie zostało wydane, nie będziemy w stanie określić klucza publicznego. Wyjawia się to dopiero wtedy, gdy odbiorca zdecyduje się przelać środki.

Ma to kilka zalet. Po pierwsze, skrót klucza publicznego jest po prostu łatwiejszy do przekazania niż pełny klucz publiczny. Z tego właśnie powodu Satoshi wypuścił go w 2009 roku. Hash klucza publicznego jest tym, co znamy dziś jako adres Bitcoin.

Drugą korzyścią jest to, że skróty klucza publicznego mogą zapewnić dodatkową warstwę bezpieczeństwa przed obliczeniami kwantowymi. Ponieważ nasz klucz publiczny nie jest znany, dopóki nie wydamy środków, innym osobom będzie jeszcze trudniej obliczyć klucz prywatny. Aby to uzyskać, musieliby odwrócić dwie rundy mieszania (RIPEMD-160 i SHA-256).


➠ Chcesz zacząć przygodę z kryptowalutą? Kup Bitcoin na Binance!


Hash płatności do skryptu (P2SH)

Pay-to-Script-Hash (P2SH) był bardzo interesującym rozwiązaniem dla Bitcoina. Pozwala nadawcy zablokować środki w hashu skryptu – nie musi wiedzieć, co faktycznie robi skrypt. Weź następujący skrót SHA-256:

e145fe9ed5c23aa71fdb443de00c7d9b4a69f8a27a2e4fbb1fe1d0dbfb6583f1

Nie musisz znać danych wejściowych skrótu, aby zablokować w nim środki. Osoba wydająca musi jednak dostarczyć skrypt, który został użyty do jego hashowania i musi spełniać warunki tego skryptu.

Powyższy skrót został utworzony z następującego skryptu:

<pomnóż przez 2> <4> <sprawdź, czy jest równy>

Jeśli chcesz wydać monety powiązane z tym skryptemPubKey, nie tylko udostępniasz te polecenia. Potrzebujesz także skryptu Sig, który sprawi, że ukończony skrypt będzie miał wartość True. W tym przykładzie jest to element, który <mnożysz przez 2>, aby otrzymać wynik <4>. Oczywiście oznacza to, że nasz scriptSig to po prostu <2>.

W prawdziwym życiu skryptPubKey dla wyjścia P2SH to:

OP_HASH160 Hash <redeemScript> OP_EQUAL

Nie ma tu żadnych nowych operatorów. Ale mamy hash <redeemScript> jako nowy element. Jak sama nazwa wskazuje, jest to skrót skryptu, który musimy udostępnić, aby wykupić środki (zwany skryptem wykupu). SkryptSig zmieni się w zależności od tego, co znajduje się w skrypcie wykupienia. Zwykle jednak okazuje się, że jest to kombinacja podpisów i dołączonych kluczy publicznych, po której następuje (obowiązkowy) skrypt wykupienia:

<podpis> <klucz publiczny> <redeemScript>

Nasza ocena różni się nieco od wykonania stosu, które widzieliśmy do tej pory. Dzieje się to w dwóch częściach. Pierwszy po prostu sprawdza, czy podałeś poprawny skrót. 


We’ve reached the end of this mini-program, and the top element is non-zero. That means it’s valid


Zauważysz, że nie robimy nic z elementami poprzedzającymi skrypt wykupienia. W tym momencie nie są one używane. Dotarliśmy do końca tego miniprogramu, a górny element jest niezerowy. Oznacza to, że jest ważny.

Jednak jeszcze nie skończyliśmy. Węzły sieci rozpoznają tę strukturę jako P2SH, więc w rzeczywistości elementy scriptSig czekają na innym stosie. To tam zostanie użyty podpis i klucz publiczny.

Do tej pory traktowaliśmy skrypt wykupienia jako element. Ale teraz będzie to interpretowane jako instrukcja, która może oznaczać wszystko. Weźmy przykład skryptu blokującego P2PKH, do którego musimy podać <signature> i <public key>, które pasują do skrótu klucza <public key> wewnątrz <redeemScript>.


Once your redeemScript has been expanded, you can see that we have a situation that looks exactly like a regular P2PKH transaction.


Po rozwinięciu Twojego releaseScriptu widać, że mamy sytuację, która wygląda dokładnie tak, jak zwykła transakcja P2PKH. Stamtąd po prostu uruchamiasz go tak, jak normalny.

Zademonstrowaliśmy tutaj tak zwany skrypt P2SH(P2PKH), ale jest mało prawdopodobne, że znajdziesz taki skrypt na wolności. Nic nie stoi na przeszkodzie, aby go zrobić, ale nie daje to żadnych dodatkowych korzyści i ostatecznie zajmuje więcej miejsca w bloku (a zatem kosztuje więcej).

P2SH zazwyczaj przydaje się w przypadku transakcji z wieloma podpisami lub transakcjami zgodnymi z SegWit. Transakcje Multisig mogą mieć bardzo duży rozmiar, ponieważ mogą wymagać wielu kluczy. Przed wdrożeniem Pay-to-Script-Hash nadawca musiałby umieścić listę wszystkich możliwych kluczy publicznych w swoim skrypcie blokującym. 

Ale w przypadku P2SH nie ma znaczenia, jak złożone są warunki wydawania pieniędzy. Hash odkupionego skryptu ma zawsze stały rozmiar. Koszty są zatem przenoszone na użytkownika(ów), który chce odblokować skrypt blokujący.

Kompatybilność z SegWit to kolejny przypadek, w którym przydaje się P2SH (szczegóły dotyczące różnic w strukturze transakcji omówimy w następnej sekcji). SegWit był miękkim forkiem, który spowodował zmianę formatów bloków/transakcji. Ponieważ jest to aktualizacja opcjonalna, nie każde oprogramowanie portfela rozpoznaje zmiany. Nie ma znaczenia, czy klienci zawiną skrót skryptu SegWit w P2SH. Podobnie jak w przypadku wszystkich transakcji tego typu, nie muszą wiedzieć, jaki będzie kod odblokowujący. 


Transakcje SegWit (P2WPKH i P2WSH)

Bardziej wszechstronne wprowadzenie do SegWit można znaleźć w Przewodniku dla początkujących po świadku segregowanym.

Aby zrozumieć format transakcji w SegWit, musisz tylko wiedzieć, że nie mamy już tylko scriptSig i scriptPubKey. Teraz mamy także nowe pole zwane świadkiem. Dane, które trzymaliśmy w scriptSig, są przenoszone do świadka, więc scriptSig jest pusty.

Jeśli natkniesz się na adresy zaczynające się od „bc1”, nazywamy je adresami natywnymi dla SegWit (w przeciwieństwie do adresów zgodnych z SegWit, które zaczynają się od „3”, ponieważ są to adresy P2SH).


Hash Pubkey Pay-to-Witness (P2WPKH)

Pay-to-Witness-Pubkey-Hash (P2WPKH) to wersja P2PKH SegWit. Nasz świadek wygląda tak:

<podpis> <klucz publiczny>

Zauważysz, że jest to to samo, co scriptSig z P2PKH. Tutaj scriptSig jest pusty. Tymczasem scriptPubKey wygląda następująco:

<OP_0> <skrót klucza publicznego>

Wygląda to trochę dziwnie, prawda? Gdzie są kody operacji, które pozwalają nam porównać podpis, klucz publiczny i jego skrót?

Nie pokazujemy tutaj dodatkowych operatorów, ponieważ węzły odbierające transakcję wiedzą, co z nią zrobić na podstawie długości skrótu <klucza publicznego>. Obliczą długość i zrozumieją, że należy ją przeprowadzić w tym samym stylu, co staroświecka transakcja P2PKH.

Niezaktualizowane węzły nie wiedzą, jak interpretować transakcję w ten sposób, ale to nie ma znaczenia. Według starych zasad nie ma świadka, więc czytają pusty skryptSig i jakieś dane. Oceniają to i oznaczają jako ważne – według nich każdy może wydać uzyskany wynik. Właśnie dlatego SegWit jest uważany za soft fork kompatybilny wstecz.


Hash skryptu Pay-to-Witness (P2WSH)

Hash skryptu Pay-to-Witness (P2WSH) to nowy P2SH. Jeśli dotarłeś tak daleko, prawdopodobnie wiesz, jak to będzie wyglądać, ale i tak to sprawdzimy. Naszym świadkiem jest to, co zwykle umieszczamy w skrypcieSig. Na przykład w P2WSH, który otacza transakcję P2PKH, może to wyglądać mniej więcej tak:

<podpis 1> <klucz publiczny>

Oto nasz skryptPubKey:

<OP_0> <hasz skryptu>

Obowiązują te same zasady. Węzły SegWit odczytują długość skrótu skryptu i ustalają, że jest to wynik P2WSH, który jest oceniany podobnie jak P2SH. Tymczasem stare węzły postrzegają to po prostu jako wynik, który każdy może wydać.


Zamykanie myśli

W tym artykule dowiedzieliśmy się trochę o elementach składowych Bitcoina. Podsumujmy je szybko:


Typ skryptu

Opis

Płatność do Pubkey (P2PK)

Blokuje środki do określonego klucza publicznego

Hash płatności do Pubkey (P2PKH)

Blokuje środki dla określonego skrótu klucza publicznego (tj. adresu)

Hash płatności do skryptu (P2SH)

Blokuje środki w hashu skryptu, który może dostarczyć odbiorca

Hash Pubkey Pay-to-Witness (P2WPKH)

Wersja SegWit P2PK

Hash skryptu Pay-to-Witness (P2WSH)

Wersja SegWit P2SH


Gdy zagłębisz się w Bitcoin, zaczniesz rozumieć, dlaczego ma on tak duży potencjał. Transakcje mogą składać się z wielu różnych elementów. Manipulując tymi elementami, użytkownicy mają dużą elastyczność w zakresie ustalania warunków dotyczących sposobu i czasu wydatkowania środków.


➠ Masz pytania dotyczące skryptu? Udaj się do Akademii Ask!