Glossar / Entwicklerreferenz
OP_VERIFY
- Was ist OP_VERIFY?
- OP_VERIFY nimmt das oberste Element vom Stack und bricht das gesamte Skript ab, sofern dieses Element nicht wahr ist, wodurch jede Prüfung im Bitcoin-Skript zu einer harten Anforderung wird.
Byte 0x69 ist die Allzweck-Zusicherung der Sprache. Script kann mit OP_IF verzweigen, aber es hat keine Möglichkeit, einen Fehler auszulösen, und keinen Rückgabewert außer dem, was auf dem Stack übrig bleibt, daher besteht ein Vertrag auf einer Bedingung, indem er die Antwort berechnet und sie dieser Anweisung übergibt. Nahezu jede jemals geleistete Zahlung lief durch eine solche, meist verborgen in einem zusammengefassten Opcode.
Wie es funktioniert
OP_VERIFY entfernt ein Element vom Stack und stellt eine einzige Frage: Ist dies wahr?
Wahrheit ist hier ein Begriff auf Byte-Ebene und nicht auf Zahlenebene. Ein leeres Element ist falsch. Das gilt auch für eine Folge von Nullbytes und für negative Null, eine Folge von Nullen, die mit 0x80 endet. Alles andere gilt als wahr, einschließlich eines Hashes von 20 Bytes oder eines öffentlichen Schlüssels von 33 Bytes. Ist das Element falsch, endet das Skript auf der Stelle und der Input, der es enthält, ist ungültig, was die Transaktion um ihn herum ungültig macht. Ist das Element wahr, geht nichts zurück auf den Stack und die Auswertung fährt mit dem nächsten Opcode fort.
Dieses Verhalten ermöglicht es einem Skript, mehrere Dinge nacheinander zu prüfen. Ein Skript ist nur erfolgreich, wenn am Ende genau ein wahrer Wert übrig bleibt, daher müsste ohne Zusicherungen jede Bedingung in einen einzigen abschließenden booleschen Wert gefaltet werden. Mit ihnen kann ein Vertrag eine Zeitsperre verlangen, dann eine Hash-Preimage verlangen und dann eine Signatur verlangen, wobei er beim ersten Fehlschlag scheitert.
Vier Opcodes haben die Zusicherung eingebaut und existieren allein, um ein Byte zu sparen: OP_EQUALVERIFY, OP_CHECKSIGVERIFY, OP_CHECKMULTISIGVERIFY und OP_NUMEQUALVERIFY. Da diese die gängigen Fälle abdecken, ist ein einzelner 0x69 im Mainnet selten.
Zwei Opcodes tragen VERIFY im Namen und verhalten sich überhaupt nicht so. OP_CHECKLOCKTIMEVERIFY aus BIP65 und OP_CHECKSEQUENCEVERIFY aus BIP112 wurden per Soft Fork auf zuvor bedeutungslose No-Op-Codes gesetzt, daher mussten sie, um ältere Nodes zufriedenzustellen, den Stack genau so hinterlassen, wie sie ihn vorgefunden hatten. Beide prüfen das oberste Element und scheitern, wenn die Bedingung nicht erfüllt ist, aber keiner von beiden verbraucht es, weshalb echte Skripte ihnen immer OP_DROP folgen lassen.
Wo Sie es sehen
Zusicherungen treten überall dort gehäuft auf, wo ein Skript mehr als eine Sache nachweisen muss.
Ein einfacher zeitgesperrter Tresor liest sich als öffentlicher Schlüssel, OP_CHECKSIGVERIFY, eine Verzögerung wie etwa 144 Blöcke (ungefähr ein Tag), dann OP_CHECKSEQUENCEVERIFY. Die Commitment- und HTLC-Skripte von Lightning sind genauso aufgebaut und verketten eine Preimage-Prüfung und eine Signaturprüfung, sodass keine von beiden allein ausreicht, um Geld zu bewegen. Ausgaben über Skriptpfade bei Taproot stützen sich stark auf dieses Muster, da tapscript OP_CHECKMULTISIG durch OP_CHECKSIGADD ersetzt hat und Verify-Formen verwendet, um Richtlinien mit mehreren Schlüsseln kompakt zu halten.
Miniscript, der Richtlinien-Compiler, den mehrere Desktop-Wallets inzwischen verwenden, um Ausgabebedingungen in lesbarer Form zu beschreiben, erzeugt diese Opcodes für Sie. Es ist der einfachste Weg zu beobachten, wie Zusicherungen erzeugt werden, ohne rohes Skript von Hand zu schreiben.
OP_VERIFY vs. OP_RETURN
OP_VERIFY und OP_RETURN beenden beide ein Skript auf schlechte Weise, aber nur einer von beiden stellt vorher eine Frage. OP_VERIFY scheitert, wenn der ihm übergebene Wert falsch ist, daher läuft eine korrekte Ausgabe ohne eine Spur an ihm vorbei. OP_RETURN, Byte 0x6a, scheitert immer, wenn es ausgeführt wird, ohne jede Bedingung, und genau deshalb wird es verwendet, um Ausgaben zu erstellen, die niemals ausgegeben werden können, und um Daten an eine Transaktion anzuhängen. Ein Skript, das am ersten scheitert, erhielt etwas Falsches. Ein Skript, das am zweiten scheitert, war von vornherein nie zur Ausgabe bestimmt.