TeachMeBitcoin

How OP_VERIFY Terminates Scripts

From TeachMeBitcoin, the free encyclopedia Reading time: 3 min

10. How OP_VERIFY Terminates Scripts

Overview

When OP_VERIFY fails, it does not simply "take a false branch" or "clean up and exit" — it causes an immediate, unconditional, irrecoverable failure of the entire script execution. Understanding the termination mechanism is critical for script authors who need to reason about partial execution, opcode ordering, and security guarantees.

The Fail-Immediately Semantics

Bitcoin Script has no exception handling, no try-catch, no recovery mechanism. When OP_VERIFY encounters a false value:

; Script execution state at OP_VERIFY failure:
Opcode position:   anywhere in script
Stack state:       irrelevant — captured for logging only

Result: SCRIPT_ERR_VERIFY (error code 26 in Bitcoin Core)

Transaction:       marked invalid
Block containing it: if already in a block, node may reject the block

This is equivalent to the entire input being invalid — the UTXO is not spent, and if the transaction was submitted to the mempool, it is rejected without relay to peers.

Script Error Codes in Bitcoin Core

// From Bitcoin Core: src/script/script_error.h

enum class ScriptError {
  OK = 0,
  // ...
  VERIFY,                // OP_VERIFY failed
  EQUALVERIFY,           // OP_EQUALVERIFY failed
  CHECKMULTISIGVERIFY,   // OP_CHECKMULTISIGVERIFY failed
  CHECKSIGVERIFY,        // OP_CHECKSIGVERIFY failed
  NUMEQUALVERIFY,        // OP_NUMEQUALVERIFY failed
  // ...
};

Each VERIFY-family failure has its own error code for debugging purposes, even though they all result in the same outcome: transaction rejection.

Sequence of Events on OP_VERIFY Failure


1. Interpreter reaches OP_VERIFY

2. Pops top stack element

3. Evaluates: is it false?

4. YES → sets script_error = SCRIPT_ERR_VERIFY

5. Returns false from EvalScript()

6. CScriptCheck::operator()() returns false

7. Transaction validation fails

8. If in block: block validation fails

9. If in mempool: transaction discarded

OP_VERIFY Cannot Be Bypassed

Because OP_VERIFY causes immediate termination, there is no way to "work around" it within the script itself. Even if subsequent opcodes might have "fixed" the situation, they are never reached.

; Dangerous assumption — this does NOT work:
<false_value>
OP_VERIFY         ; FAILS HERE — execution stops
OP_DROP           ; NEVER REACHED
OP_1              ; NEVER REACHED
; Script is already dead — no recovery possible

OP_VERIFY Inside Conditional Blocks

OP_VERIFY inside an OP_IF block only executes if the interpreter is in an active execution state. If the OP_IF branch was not taken, OP_VERIFY is safely skipped:

OP_0        ; push false
OP_IF
  OP_VERIFY ; SKIPPED — we're in the false branch of OP_IF
OP_ENDIF
OP_1        ; push true — script succeeds

However, if you are in the true branch:

OP_1        ; push true
OP_IF
  OP_0
  OP_VERIFY ; EXECUTES — pops 0, FAILS immediately
OP_ENDIF

Comparing OP_VERIFY Failure with Normal Script Failure

Scripts can fail in multiple ways:

; Type 1: Final stack is false (empty or zero on top)
OP_0
; Script ends with 0 on stack → FAIL

; Type 2: OP_VERIFY explicit failure
OP_0 OP_VERIFY
; Explicit mid-script failure → FAIL (same end result, different error code)

; Type 3: Invalid opcode or disabled opcode
OP_2MUL  ; disabled since 2010
; Script fails immediately → FAIL

; Type 4: Stack underflow
OP_ADD   ; with only one item on stack
; Script fails → FAIL

All result in transaction invalidity, but OP_VERIFY failure is the most explicit and intentional form.

☕ Help support TeachMeBitcoin

TeachMeBitcoin is an ad-free, open-source educational repository curated by a passionate team of Bitcoin researchers and educators for public benefit. If you found our articles helpful, please consider supporting our hosting and ongoing content updates with a clean donation:

Ethereum: 0x578417C51783663D8A6A811B3544E1f779D39A85
Bitcoin: bc1q77k9e95rn669kpzyjr8ke9w95zhk7pa5s63qzz
Solana: 4ycT2ayqeMucixj3wS8Ay8Tq9NRDYRPKYbj3UGESyQ4J
Address copied to clipboard!