用語集 / 開発者向けリファレンス
OP_VERIFY
- OP_VERIFYとは?
- OP_VERIFYはスタックの最上位の項目を取り出し、その項目が真でない限りスクリプト全体を中断します。これにより、Bitcoin Script内のあらゆる検査が厳格な要件になります。
バイト0x69は、この言語の汎用のアサーションです。ScriptはOP_IFで分岐できますが、エラーを発生させる方法も、スタック上に残ったもの以外の戻り値も持ちません。そのため、コントラクトは答えを計算し、それをこの命令に渡すことで条件を強制します。これまでに行われたほぼすべての支払いは、通常は融合されたオペコードの中に隠れた形で、この命令を通ってきました。
仕組み
OP_VERIFYはスタックから1つの項目を取り出し、1つの問いを投げかけます。それは真ですか?
ここでの真は、数値的なものではなくバイトレベルの概念です。空の項目は偽です。ゼロバイトの並びも偽であり、負のゼロ、つまり0x80で終わるゼロの並びも偽です。それ以外はすべて真とみなされ、20バイトのハッシュや33バイトの公開鍵も含まれます。項目が偽であれば、スクリプトはその場で終了し、それを保持するインプットは無効となり、それを取り囲むトランザクションも無効になります。項目が真であれば、スタックには何も戻されず、評価は次のオペコードへ進みます。
この動作により、スクリプトは複数の事柄を順に検査できます。スクリプトは最後に真の値がちょうど1つ残った場合にのみ成功するため、アサーションがなければ、すべての条件を最後の単一のブール値に畳み込まなければなりません。アサーションがあれば、コントラクトはタイムロックを要求し、次にハッシュのプリイメージを要求し、次に署名を要求することができ、最初に満たされない時点で失敗します。
4つのオペコードはアサーションを内蔵しており、1バイトを節約するためだけに存在します。OP_EQUALVERIFY、OP_CHECKSIGVERIFY、OP_CHECKMULTISIGVERIFY、OP_NUMEQUALVERIFYです。これらが一般的なケースをカバーするため、単独の0x69はメインネット上ではまれです。
2つのオペコードは名前にVERIFYを含みながら、このようには動作しません。BIP65のOP_CHECKLOCKTIMEVERIFYとBIP112のOP_CHECKSEQUENCEVERIFYは、以前は意味を持たなかったno-opコードにソフトフォークで追加されたため、古いノードを満足させるには、スタックを見つけたときとまったく同じ状態に保つ必要がありました。どちらも最上位の項目を検査し、条件が満たされない場合は失敗しますが、どちらもそれを消費しません。そのため実際のスクリプトでは、必ずその後にOP_DROPが続きます。
使われる場面
アサーションは、スクリプトが証明すべき事柄を複数持つ場所に集中します。
単純なタイムロック付きのボールトは、公開鍵、OP_CHECKSIGVERIFY、144ブロック(およそ1日)といった遅延、そしてOP_CHECKSEQUENCEVERIFYという形で記述されます。LightningのコミットメントスクリプトとHTLCスクリプトも同じように構築され、プリイメージの検査と署名の検査を連鎖させ、どちらか一方だけでは資金を動かすのに十分でないようにしています。Taprootのスクリプトパスによる支払いはこのパターンに大きく依存しています。tapscriptがOP_CHECKMULTISIGをOP_CHECKSIGADDに置き換え、複数鍵のポリシーをコンパクトに保つためにVERIFY形式を使うからです。
Miniscriptは、いくつかのデスクトップウォレットが支出条件を読みやすい形式で記述するために現在使用しているポリシーコンパイラであり、これらのオペコードを代わりに出力します。生のスクリプトを手書きせずにアサーションが生成される様子を見る最も簡単な方法です。
OP_VERIFY vs OP_RETURN
OP_VERIFYとOP_RETURNはどちらもスクリプトを悪い形で終了させますが、最初に問いを投げかけるのは一方だけです。OP_VERIFYは渡された値が偽のときに失敗するため、正しい支払いは何の痕跡も残さずにそのまま通過します。OP_RETURNは、バイト0x6aであり、実行されるたびに条件を一切伴わずに失敗します。まさにそのため、決して支払いに使えないアウトプットを構築したり、トランザクションにデータを添付したりするのに使われます。前者で終了するスクリプトには、何か誤ったものが渡されています。後者で終了するスクリプトは、そもそも支払いに使えるようには意図されていません。