用語集 / 開発者向けリファレンス
OP_EQUALVERIFY
- OP_EQUALVERIFYとは?
- OP_EQUALVERIFYはスタックの最上位2項目を比較し、両者が異なればスクリプトを即座に停止させます。レガシーな支出が正しい公開鍵を提示したことを証明する仕組みは、まさにこの動作によります。
バイト0x88は、ビットコインで最も古いスクリプトテンプレートの中央に位置するチェックポイントです。成功しても何も残さず、失敗すれば実行をその場で止めるため、誤った鍵を渡すインプットは支払いの失敗ではなく、どのノードもリレーしない無効なトランザクションを生みます。ウォレットがそもそも正しい鍵で署名したかどうかは、通常ここで決まります。
仕組み
OP_EQUALVERIFYはスタックから2つの項目を取り出し、バイト単位で比較して、そのまま静かに処理を続けるか、スクリプトを終了させるかのいずれかを行います。
レガシーな支出でこれが実行される時点で、スタックには20バイトの文字列が2つあります。一方は、コインが到着したとき、場合によっては数年も前にアウトプットがコミットした指紋です。もう一方は、支出者がたった今提示した公開鍵の指紋です。この20バイトのうち1ビットでも異なれば評価は終了し、そこから回復する道はありません。Bitcoin Scriptには例外処理も再試行もないためです。
成功しても何もプッシュされません。融合形式が存在する理由はまさにこれであり、25バイトのpay-to-public-key-hashスクリプトが、誰も望まない真偽値の残りではなく署名検証で終われる理由でもあります。Bitcoin Coreのインタプリタはこの融合をそのまま実装しており、比較のケースを実行した後にそのまま一般のアサーションのケースへ進むため、両者は似て非なる2つの経路ではなく1つのコード経路です。
このパターンは言語全体に繰り返し現れます。融合された検証用オペコードは、いずれも対応する単純なオペコードのちょうど1バイト上に位置します。等価比較なら0x87と0x88、署名検証なら0xacと0xad、旧式のマルチシグオペコードなら0xaeと0xafです。他の何かが起こる前に条件が成立していなければならない場面では、スクリプトの作者はより大きいほうのバイトを選びます。
どこで見られるか
OP_EQUALVERIFYに最も明快に出会う場所は、ブロックエクスプローラーではなく拒否メッセージです。
アドレスと一致しない鍵で署名したトランザクションをブロードキャストすると、Bitcoin Coreはmandatory-script-verify-flag-failedと応答し、続く括弧の中で失敗したOP_EQUALVERIFYオペレーションを名指しします。実際には、このエラーはほぼ常に1つのことを意味します。署名デバイスが、コインを所有するパスまたはシードとは異なるパスまたはシードから鍵を導出したということです。誤った導出パスでウォレットを復元してから支出しようとすると、まさにこの状態になります。
デコードされたスクリプトにも明瞭に現れます。1で始まるアドレスへの支払いを行うアウトプットは、このオペコードを4番目に置く5トークンのスクリプトとして表示され、bitcoin-cliのdecodescriptも、貼り付けたredeem scriptに対して同じアセンブリを出力します。
OP_EQUALVERIFY vs OP_VERIFY
OP_EQUALVERIFYは特定の比較にアサーションを溶接したものであり、OP_VERIFYはアサーションそのものです。一般形式であるバイト0x69は、検査する値が何から生じたかを一切知りません。1つの項目をポップし、それが真であることを要求するだけです。OP_EQUALVERIFYは比較と要求を1バイトの中で同時に行うため、両者が別々に書かれることはほとんどありません。条件が算術、タイムロックの検査、あるいは単純な等価比較ではないプリイメージの検査から生じる場合は一般形式を選びます。問いが本当に2つのバイト列が一致するかどうかである場合は、融合形式を選びます。単一鍵の支出では、それは常にそうです。