Eine Einführung in Bitcoin Script
Startseite
Artikel
Eine Einführung in Bitcoin Script

Eine Einführung in Bitcoin Script

Fortgeschritten
Veröffentlicht Jul 10, 2020Aktualisiert Jan 18, 2022
13m

Einführung

Bitcoin wird manchmal als programmierbares Geld bezeichnet. Aufgrund seines digitalen Charakters ermöglicht es den Benutzern ein hohes Maß an Flexibilität, wenn es darum geht, die Bedingungen, wie Geld ausgegeben werden kann festzulegen. 
Wir sprechen von Wallets und Coins, wenn wir über Bitcoin sprechen. Wir könnten uns aber auch Wallets als Schlüssel, Coins als Schecks und die Blockchain als Aneinanderreihung von verschlossenen Tresoren vorstellen. In jedem Tresor befindet sich ein dünner Schlitz, so dass jeder Schecks einwerfen oder hineinschauen kann, um zu sehen, wie viel Wert der Tresor fasst. Allerdings hat nur der Schlüsselinhaber Zugang zum Inneren des Tresors.

Wenn ein Schlüsselinhaber jemandem Geld geben will, schließt er sein Fach auf. Er stellt einen neuen Scheck aus, der sich auf den älteren Scheck bezieht (der dann vernichtet wird), und schließt ihn in ein Fach ein, das der Empfänger öffnen kann. Um das Geld auszugeben, wiederholt der neue Empfänger den Vorgang.

In diesem Artikel werfen wir einen genaueren Blick auf Script, die Programmiersprache, die von den Nodes im Bitcoin-Netzwerk interpretiert wird. Script ist das, was den erwähnten Verriegelungs-/Entriegelungsmechanismus für die Tresore regelt.


Wie funktioniert Bitcoin?

In Anlehnung an unsere Analogie von vorhin könnte man sagen, dass jede Transaktion aus zwei Teilen besteht - einem Schlüssel (zum Entsperren Ihrer Kiste) und einem Schloss. Sie benutzen Ihren Schlüssel, um die Kiste zu öffnen, die den Scheck enthält, den Sie versenden möchten, und fügen dann einen neuen Schlüssel zu einer neuen Kiste mit einem anderen Schloss hinzu. Um Geld aus der neuen Kiste auszugeben, benötigen Sie einen weiteren Schlüssel.
Ganz einfach. Es kann auch unterschiedliche Arten von Schlössern im System geben. Vielleicht verlangen einige Tresore, dass Sie mehrere Schlüssel zur Verfügung stellen, und vielleicht müssen Sie bei anderen beweisen, dass Sie ein Geheimnis kennen. Es gibt eine Reihe von Bedingungen, die man stellen kann. 
Unser Schlüssel ist das, was wir ein scriptSig nennen. Das Schloss ist unser scriptPubKey. Wenn wir uns diese Komponenten etwas genauer ansehen, werden wir feststellen, dass sie tatsächlich aus Datenteilen und Codeblöcken bestehen. Wenn sie kombiniert werden, ergeben sie ein winziges Programm.

Wenn Sie eine Transaktion durchführen, senden Sie diese Kombination an das Netzwerk. Jeder Knoten (Node), der sie empfängt, überprüft das Programm, was ihm sagt, ob die Transaktion gültig ist. Wenn nicht, wird es einfach verworfen, und Sie können die gesperrten Mittel nicht ausgeben.

Die in Ihrem Besitz befindlichen Schecks (Coins) werden als nicht ausgegebene Transaktionsausgaben bzw. Unspent Transaction Outputs (UTXOs) bezeichnet. Die Gelder können von jedem verwendet werden, der den zum Schloss passenden Schlüssel zur Verfügung stellen kann. Dabei ist der Schlüssel das scriptSig und das Schloss das scriptPubKey.
Wenn sich die UTXOs in Ihrer Wallet befinden, haben diese wahrscheinlich eine Bedingung, die besagt, dass nur die Person, die den Besitz dieses öffentlichen Schlüssels nachweisen kann, diese Gelder entsperren kann. Um sie zu entsperren, stellen Sie ein scriptSig zur Verfügung, das eine digitale Signatur enthält, wobei Sie den privaten Schlüssel verwenden, der dem im scriptPubKey angegebenen öffentlichen Schlüssel zugeordnet ist. Dies alles wird in Kürze klarer werden.


Den Bitcoin-Stapel verstehen

Script ist eine so genannte stack-based also eine <0>Stapel-basierte Sprache. Das bedeutet, dass wir, wenn wir eine Reihe von Anweisungen lesen, diese in einer Art vertikaler Spalte platzieren, die man sich vorstellen kann. Die Liste A, B, C würde zum Beispiel zu einem Stapel mit A in unterster und C in oberster Position führen. Wenn die Anweisungen uns auffordern, etwas zu tun, operieren wir mit einem oder mehreren Elementen, beginnend am oberen Ende des Stapels.


Die Elemente A, B und C werden hinzugefügt und aus dem Stapel “herausgestoßen”.


Wir können zwischen den Daten (Dinge wie Signaturen, Hashes und öffentliche Schlüssel) und den Anweisungen (oder Opcodes) unterscheiden. Die Anweisungen entfernen Daten und machen etwas mit ihnen. Hier ist ein sehr einfaches Beispiel dafür, wie ein Script aussehen könnte:
<xyz> <md5 hasher> <d16fb36f0911f878998c136191af705e> <check if equal>
In Rot haben wir Daten, und in Blau haben wir die Opcodes. Wir lesen von links nach rechts, also legen wir zuerst die Zeichenfolge <xyz> auf den Stapel. Als nächstes kommt der Opcode <md5 hasher>. Diesen gibt es in Bitcoin nicht, aber nehmen wir an, er entfernt das oberste Element des Stapels (<xyz>) und hasht es mit dem MD5-Algorithmus. Dann wird die Ausgabe wieder auf dem Stack hinzugefügt. Die Ausgabe lautet hier zufällig d16fb36f0911f878998c136191af705e.
Welch ein Zufall! Unser nächstes hinzuzufügendes Element ist <d16fb36f0911f878998c136191af705e>, so dass unser Stapel nun zwei identische Elemente hat. Zuletzt holt <check if equal> zwei Elemente von oben heraus und prüft, ob sie gleich sind. Wenn dies der Fall ist, fügt es dem Stapel <1> hinzu. Wenn nicht, fügt es <0> hinzu. 
Damit sind wir am Ende unserer Anweisungsliste angelangt. Unser Skript hätte auf zwei Arten fehlschlagen können – wenn das verbleibende Element eine Null war oder wenn einer der Operatoren es fehlschlagen ließ, wenn einige Bedingungen nicht erfüllt waren. In diesem Beispiel hatten wir keine derartigen Operatoren, und am Ende hatten wir ein Nicht-Null-Element (<1>), so dass unser Skript gültig war. Diese Regeln gelten auch für echte Bitcoin-Transaktionen.

Das war nur ein erfundenes Programm. Schauen wir uns nun einige echte an.


Pay-to-Pubkey (P2PK)

Pay-to-Pubkey (P2PK) ist unglaublich unkompliziert. Es beinhaltet das Sperren von Geldern auf einen bestimmten öffentlichen Schlüssel. Wenn Sie auf diese Weise Gelder erhalten wollten, würden Sie in diesem Fall dem Absender Ihren öffentlichen Schlüssel zur Verfügung stellen, und nicht etwa eine Bitcoin-Adresse.

Die allererste Transaktion zwischen Satoshi Nakamoto und Hal Finney im Jahr 2009 war eine P2PK-Transaktion. Diese Struktur wurde in den frühen Tagen von Bitcoin sehr oft genutzt, aber heutzutage hat Pay-to-Pubkey-Hash (P2PKH) sie weitgehend ersetzt. 
Das Sperrskript für eine P2PK-Transaktion folgt dem Format <public key> OP_CHECKSIG. Einfach genug. Sie haben vielleicht schon vermutet, dass OP_CHECKSIG eine Signatur gegen den bereitgestellten öffentlichen Schlüssel prüft. Als solches wird unser SkriptSig eine einfache <signature> sein. Denken Sie daran, dass das scriptSig der Schlüssel zum Schloss ist.



Viel einfacher geht es nicht. Eine Signatur wird dem Stapel hinzugefügt, gefolgt von einem öffentlichen Schlüssel. OP_CHECKSIG nimmt sich beide und verifiziert die Signatur gegen den öffentlichen Schlüssel. Wenn sie übereinstimmen, fügt es dem Stapel eine <1> hinzu. Andernfalls fügt es eine <0> hinzu.

Aus Gründen, auf die wir im nächsten Abschnitt näher eingehen werden, wird P2PK nicht mehr wirklich verwendet.


Pay-to-Pubkey-Hash (P2PKH)

Pay-to-Pubkey-Hash (P2PKH) ist heute die gebräuchlichste Art der Transaktion. Nur bei veralteter Software ist dies nicht der Fall, Ihre aktuelle Wallet sollte P2PKH jedoch standardmäßig verwenden.

Der scriptPubKey in P2PKH lautet wie folgt:

OP_DUP OP_HASH160 <public key hash> OP_EQUALVERIFY OP_CHECKSIG

Bevor wir das scriptSig einführen, lassen Sie uns aufschlüsseln, was die neuen Opcodes bewirken werden:


OP_DUP

OP_DUP öffnet das erste Element und dupliziert es. Dann fügt es beide wieder dem Stapel hinzu. Normalerweise geschieht dies, damit wir eine Operation auf dem Duplikat durchführen können, ohne das Original zu beeinflussen.


OP_HASH160

Dadurch wird das erste Element ausgewählt und zweimal gehasht. Die erste Runde wird mit dem SHA-256-Algorithmus gehasht. Die SHA-256-Ausgabe wird dann mit dem RIPEMD-160-Algorithmus gehasht. Die resultierende Ausgabe wird wieder zu dem Stapel hinzugefügt.


OP_EQUALVERIFY

OP_EQUALVERIFY kombiniert zwei weitere Operatoren – OP_EQUAL und OP_VERIFY. OP_EQUAL nimmt zwei Elemente und prüft, ob sie identisch sind. Wenn sie identisch sind, fügt es dem Stapel eine 1 hinzu. Wenn nicht, fügt es eine 0 hinzu. OP_VERIFY nimmt das oberste Element und prüft, ob es wahr ist (d.h. ungleich Null). Ist dies nicht der Fall, schlägt die Transaktion fehl. In Kombination bewirkt OP_EQUALVERIFY, dass die Transaktion fehlschlägt, wenn die beiden obersten Elemente nicht übereinstimmen.

Diesmal sieht das scriptSig wie folgt aus:

<signature> <public key>

Sie müssen eine Signatur und den entsprechenden öffentlichen Schlüssel bereitstellen, um P2PKH-Ausgaben freizuschalten.



Sie können sehen, was im obigen GIF vor sich geht. Es unterscheidet sich nicht allzu sehr von einem P2PK-Skript. Wir fügen nur einen zusätzlichen Schritt hinzu, um zu überprüfen, ob der öffentliche Schlüssel mit dem Hash im Skript übereinstimmt.

Es gibt jedoch etwas zu beachten. In einem P2PKH-Sperr-Skript ist der öffentliche Schlüssel nicht sichtbar – wir können nur seinen Hash sehen. Wenn wir zu einem Blockchain-Explorer gehen und uns eine P2PKH-Ausgabe ansehen, die nicht ausgegeben wurde, können wir den öffentlichen Schlüssel nicht bestimmen. Er wird erst enthüllt, wenn der Empfänger beschließt, die Gelder zu transferieren.
Dies hat eine Reihe von Vorteilen. Der erste ist, dass der Hash des öffentlichen Schlüssels einfach leichter weitergegeben werden kann als ein vollständiger öffentlicher Schlüssel. Genau aus diesem Grund hat Satoshi ihn 2009 eingeführt. Der Hash des öffentlichen Schlüssels ist das, was wir heute als Bitcoin-Adresse kennen.
Der zweite Vorteil besteht darin, dass Hashes von öffentlichen Schlüsseln eine zusätzliche Sicherheitsebene gegen Quantencomputer bieten könnten. Da unser öffentlicher Schlüssel erst bekannt ist, wenn wir die Mittel ausgegeben haben, ist es für andere noch schwieriger, den privaten Schlüssel zu berechnen. Sie müssten die beiden Runden des Hashings (RIPEMD-160 und SHA-256) umkehren, um ihn zu erhalten.



Pay-to-Script-Hash (P2SH)

Pay-to-Script-Hash (P2SH) war eine sehr interessante Entwicklung für Bitcoin. Es ermöglicht es Absendern, Gelder an den Hash eines Skripts zu binden – sie müssen nicht wissen, was das Skript tatsächlich bewirkt. Nehmen Sie den folgenden SHA-256-Hash:

e145fe9ed5c23aa71fdb443de00c7d9b4a69f8a27a2e4fbb1fe1d0dbfb6583f1

Sie müssen den Input des Hashes nicht kennen, um Gelder für ihn zu sperren. Der das Geld ausgeben will, muss jedoch das Skript bereitstellen, das zum Hashing verwendet wurde, und muss die Bedingungen dieses Skripts erfüllen.

Der obige Hash wurde aus dem folgenden Skript erstellt:

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

Wenn Sie die an diesen scriptPubKey gebundenen Coins ausgeben wollen, stellen Sie nicht nur diese Befehle zur Verfügung. Sie benötigen auch ein scriptSig, das das abgeschlossene Skript als Wahr (True) auswerten lässt. In diesem Beispiel ist es das Element <multiply by 2>, mit dem Sie mit Zwei multiplizieren, und ein Ergebnis von <4> erhalten. Das bedeutet natürlich, dass unser scriptSig nur <2> ist.

Im wirklichen Leben ist der scriptPubKey für eine P2SH-Ausgabe:

OP_HASH160 <redeemScript hash> OP_EQUAL

Hier gibt es keine neuen Operators. Aber, wir haben <redeemScript hash> als ein neues Element. Wie der Name schon andeutet, handelt es sich dabei um einen Hash des Skripts, das wir zum Einlösen der Gelder bereitstellen müssen (das sogenannte redeemScript). Das ScriptSig ändert sich je nachdem, was im redeemScript steht. Im Allgemeinen werden Sie jedoch feststellen, dass es sich um eine Kombination aus Signaturen und den beigefügten öffentlichen Schlüsseln handelt, gefolgt vom (obligatorischen) redeemScript:

<signature> <public key> <redeemScript>

Unsere Bewertung unterscheidet sich ein wenig von der bisherigen Stapel-Ausführung, die wir bisher gesehen haben. Sie erfolgt in zwei Teilen. Der erste prüft einfach, ob Sie den richtigen Hash angegeben haben.



Sie werden feststellen, dass wir nichts mit den Elementen tun, die dem redeemScript vorausgehen. Sie werden an dieser Stelle nicht verwendet. Wir sind am Ende dieses Mini-Programms angelangt, und das oberste Element ist ungleich Null. Das bedeutet, dass es gültig ist.

Aber wir sind noch nicht ganz fertig. Die Netzwerk-Nodes erkennen diese Struktur als P2SH, so dass sie die Elemente des scriptSig tatsächlich in einem anderen Stapel bereitgestellt haben. Dort werden die Signatur und der öffentliche Schlüssel verwendet.
Bisher haben wir das redeemScript als ein Element behandelt. Aber jetzt wird es als eine Folge von Instruktionen interpretiert, die alles Mögliche bewirken können. Nehmen wir das Beispiel eines P2PKH-Sperr-Skripts, dem wir die <signature> und den <public key> übergeben müssen, die zu einem <public key hash> innerhalb des <redeemScript> passen.



Sobald Ihr redeemScript erweitert wurde, können Sie sehen, dass wir eine Situation haben, die genau wie eine normale P2PKH-Transaktion aussieht. Von dort aus führen Sie sie einfach wie eine normale Transaktion aus.

Wir haben hier ein so genanntes P2SH(P2PKH)-Skript demonstriert, aber es ist unwahrscheinlich, dass Sie so etwas in der freien Wildbahn finden werden. Nichts hindert Sie daran, eines zu machen, aber es bietet Ihnen keine zusätzlichen Vorteile und nimmt am Ende mehr Platz in einem Block ein (und kostet daher mehr).

P2SH ist im Allgemeinen nützlich für Dinge wie Multisignatur- oder SegWit-kompatible Transaktionen. Multisig-Transaktionen können sehr groß sein, da sie möglicherweise mehrere Schlüssel erfordern. Vor der Implementierung von Pay-to-Script-Hash müsste ein Absender alle möglichen öffentlichen Schlüssel in seinem Sperr-Skript auflisten. 

Bei P2SH spielt es jedoch keine Rolle, wie komplex die Ausgabebedingungen sind. Der Hash des redeemScript hat immer eine feste Größe. Die Kosten werden daher an den/die Benutzer weitergegeben, die das Sperr-Skript entsperren wollen.

Die SegWit-Kompatibilität ist ein weiterer Fall, in dem P2SH sich als nützlich erweist (auf die Einzelheiten, wie sich die Transaktionsstruktur unterscheidet, gehen wir im nächsten Abschnitt ein). SegWit war ein Soft Fork, welcher zu einer Änderung der Block-/Transaktionsformate führte. Da es sich um ein Opt-In-Upgrade handelt, erkennt nicht jede Wallet-Software diese Änderungen.

Das spielt keine Rolle, wenn Clients den SegWit-Skript-Hash in P2SH einpacken. Wie bei allen Transaktionen dieser Art müssen sie nicht wissen, wie das entsperrende redeemScript aussehen wird.


SegWit-Transaktionen (P2WPKH und P2WSH)

Eine umfassendere Einführung in SegWit finden Sie in dem Artikel Segregated Witness (SegWit) für Einsteiger.
Um das Transaktionsformat in SegWit zu verstehen, müssen Sie nur wissen, dass wir nicht mehr nur ein scriptSig und einen scriptPubKey haben. Jetzt haben wir auch ein neues Feld namens Witness. Die Daten, die wir im scriptSig aufbewahrt haben, werden zum Witness verschoben, so dass das scriptSig leer ist.

Sie haben eventuell bereits Adressen gesehen, die mit ‘bc1’ beginnen, diese nennen wir SegWit-native (im Gegensatz zu SegWit-kompatiblen Adressen, die mit einer ‘3’ beginnen, da es sich um P2SH-Adressen handelt).


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

Pay-to-Wit-Pubkey-Hash (P2WPKH) ist die SegWit-Version von P2PKH. Unser Witness sieht wie folgt aus:

<signature> <public key>

Sie werden feststellen, dass dies dasselbe ist wie das scriptSig von P2PKH. Hier ist das scriptSig leer. Währenddessen ähnelt das scriptPubKey dem folgenden:

<OP_0> <public key hash>

Das sieht ein bisschen merkwürdig aus, nicht wahr? Wo sind die Opcodes, mit denen wir die Signatur, den öffentlichen Schlüssel und seinen Hash vergleichen können?

Wir zeigen hier keine zusätzlichen Operatoren, weil die Nodes, die die Transaktion erhalten, wissen, was sie mit ihr zu tun haben, basierend auf der Länge des <public key hash>. Sie werden die Länge berechnen und verstehen, dass sie im gleichen Stil ausgeführt werden muss wie eine gute alte P2PKH-Transaktion.
Nodes ohne Upgrade wissen nicht, wie sie die Transaktion auf diese Weise interpretieren sollen, aber das spielt keine Rolle. Nach den alten Regeln gibt es keinen Witness, also lesen sie ein leeres scriptSig und einige Daten. Sie werten dies aus und kennzeichnen es als gültig – was sie betrifft, könnte jeder die Ausgabe ausgeben. Aus diesem Grund wird SegWit als rückwärtskompatibler Soft Fork betrachtet.


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

Pay-to-Witness-Script-Hash (P2WSH) ist das neue P2SH. Wenn Sie es bis hierher geschafft haben, können Sie sich wahrscheinlich denken, wie es aussehen wird, aber wir werden es trotzdem durchgehen. Unser Witness ist das, was wir normalerweise in das scriptSig eingeben würden. In einem P2WSH, das zum Beispiel eine P2PKH-Transaktion einbindet, könnte es etwa so aussehen:

<signature 1> <public key>

Hier ist unser scriptPubKey:

<OP_0> <script hash>

Es gelten die gleichen Regeln. SegWit-Nodes lesen die Länge des Script-Hashes und stellen fest, dass es sich um eine P2WSH-Ausgabe handelt, die ähnlich wie P2SH ausgewertet wird. In der Zwischenzeit sehen alte Nodes es einfach als eine Ausgabe an, die jeder ausgeben kann.


Fazit

In diesem Artikel haben wir ein wenig über die Bausteine von Bitcoin gelernt. Lassen Sie uns diese kurz zusammenfassen:


Script-TypBeschreibung

Pay-to-Pubkey (P2PK)

Sperrt Gelder für einen bestimmten öffentlichen Schlüssel

Pay-to-Pubkey-Hash (P2PKH)

Sperrt Gelder für den Hash eines bestimmten öffentlichen Schlüssels (d. h. eine Adresse)

Pay-to-Script-Hash (P2SH)

Sperrt Gelder für den Hash eines Scripts, das der Empfänger zur Verfügung stellen kann

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

Die SegWit-Version von P2PK

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

Die SegWit-Version von P2SH


Wenn man sich erst einmal tiefer in Bitcoin vertieft hat, beginnt man zu verstehen, warum es so viel Potenzial hat. Transaktionen können sich aus vielen verschiedenen Komponenten zusammensetzen. Durch die Manipulation dieser Bausteine haben die Nutzer ein hohes Maß an Flexibilität, wenn es darum geht, Bedingungen festzulegen, wie und wann Mittel ausgegeben werden können.