TeachMeBitcoin

OP_RETURN vs OP_VERIFY - Key Differences

From TeachMeBitcoin, the free encyclopedia Reading time: 3 min

11. OP_RETURN vs OP_VERIFY — Key Differences

Overview

Both OP_RETURN and OP_VERIFY can terminate script execution prematurely, but they serve entirely different purposes and have fundamentally different semantics. Confusing them is a common source of misunderstanding for Bitcoin developers.

Quick Reference

OP_VERIFY:  Hex 0x69  — Fail if top of stack is false. Unconditional termination on failure.
OP_RETURN:  Hex 0x6a  — Mark output as unspendable (provably prunable). Always "fails."

OP_RETURN — The Unspendable Marker

OP_RETURN was repurposed in Bitcoin Core 0.9.0 (March 2014) to allow embedding arbitrary data in transactions without creating unspendable UTXOs in the UTXO set. When a scriptPubKey begins with OP_RETURN, the output is:

  1. Provably unspendable — no valid scriptSig can ever satisfy it.

  2. Prunablenodes are not required to track it in the UTXO set.

  3. Data-bearing — up to 83 bytes (80 bytes of data + 3 bytes of overhead) can follow.

; OP_RETURN data embedding:
OP_RETURN <arbitrary_data>

; Example — embedding a document hash:
OP_RETURN 0x6f6d6e69 <sha256_document_hash>

; Common use cases:
; - Colored coins / token protocols (Omni, RGB)
; - Timestamping services (OpenTimestamps)
; - NFT metadata pointers
; - Cross-chain anchoring

OP_VERIFY — The Assertion Opcode

OP_VERIFY, as covered in sections 9 and 10, is used within spending scripts to assert conditions. It appears in scriptPubKey and scriptSig/witness contexts.

; OP_VERIFY in a spending context:
<computed_value>
<expected_value>
OP_EQUAL
OP_VERIFY          ; fail if computed != expected

Side-by-Side Comparison

Property OP_VERIFY OP_RETURN
Purpose Assert condition mid-script Mark output as unspendable / embed data
Location Inside scriptPubKey or scriptSig At start of scriptPubKey only
Stack interaction Pops top element None (terminates immediately)
Script continues? Yes (if condition true) Never
Use in witness Yes No
UTXO set N/A (appears in spending script) Output excluded from UTXO set
Data after opcode Not applicable Up to 80 bytes of arbitrary data

OP_RETURN in scriptPubKey

; OP_RETURN scriptPubKey format:
6a                  ; OP_RETURN (0x6a)
<pushdata>          ; optional data following

; Example with 20 bytes of data:
6a 14 <20_bytes_of_data>

; The UTXO is created but immediately prunable
; No scriptSig can ever satisfy OP_RETURN

Can OP_RETURN Appear Mid-Script?

Prior to the OP_RETURN standardization, some implementations treated OP_RETURN mid-script as simply failing at that point. However, in modern Bitcoin:

When Developers Confuse Them

; WRONG — developer tries to embed data in a spendable output using OP_RETURN:
<pubkey> OP_CHECKSIG OP_RETURN <data>
; This is non-standard and makes the output behave unexpectedly

; CORRECT — embed data in a separate OP_RETURN output:
; Output 0: P2PKH (spendable)
; Output 1: OP_RETURN <data> (data carrier, zero value)

; WRONG — developer tries to use OP_RETURN as an assertion:
<value> OP_1 OP_EQUAL OP_RETURN   ; does not work as intended
; CORRECT — use OP_VERIFY:
<value> OP_1 OP_EQUAL OP_VERIFY
☕ 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!