OP_ENDIF - Closing a Conditional Block
4. OP_ENDIF — Closing a Conditional Block
Overview
OP_ENDIF marks the end of a conditional block opened by OP_IF or OP_NOTIF. It does not interact with the stack at all — its sole purpose is structural. Every OP_IF and OP_NOTIF must be matched with exactly one OP_ENDIF.
Opcode Reference
Opcode: OP_ENDIF
Hex: 0x68
Byte value: 104 (decimal)
Category: Flow Control
Role in Script Parsing
Before execution even begins, Bitcoin nodes parse the script to verify structural integrity. This pre-execution check ensures:
-
Every
OP_IF/OP_NOTIFhas a matchingOP_ENDIF. -
Every
OP_ELSEhas a precedingOP_IF/OP_NOTIF. -
No
OP_ENDIFappears without a preceding open conditional. -
Nesting depth does not exceed implementation limits.
; Pre-execution parse check (pseudocode):
depth = 0
for opcode in script:
if opcode in (OP_IF, OP_NOTIF):
depth += 1
elif opcode == OP_ENDIF:
depth -= 1
if depth < 0:
return SCRIPT_INVALID ; unmatched OP_ENDIF
if depth != 0:
return SCRIPT_INVALID ; unclosed OP_IF
OP_ENDIF Does Not Touch the Stack
This is one of the most important properties of OP_ENDIF: it is a no-op with respect to the stack. Its only effect is to close the interpreter's conditional tracking state.
Stack before OP_ENDIF: [ 0x01 0x02 ]
OP_ENDIF
Stack after OP_ENDIF: [ 0x01 0x02 ] ; unchanged
Maximum Nesting Depth
The Bitcoin Core reference implementation enforces a maximum conditional nesting depth (the MAX_OPS_PER_SCRIPT and related limits apply indirectly). In practice, deeply nested scripts become both difficult to audit and expensive in terms of witness data. Tapscript was designed to allow more expressive scripts through Taproot's MAST (Merkelized Abstract Syntax Tree) structure rather than deep nesting.
OP_ENDIF in Tapscript
In Tapscript (BIP 342), OP_ENDIF behaves identically to its legacy counterpart. The key difference is that in Tapscript, each spend reveals only one script leaf from a Merkle tree, so the need for deeply nested conditionals is reduced — different spending paths can live in different Taproot leaves.
; Tapscript leaf A (Alice's path):
<alice_pubkey> OP_CHECKSIG
; Tapscript leaf B (Bob's path with timelock):
<locktime> OP_CHECKSEQUENCEVERIFY OP_DROP
<bob_pubkey> OP_CHECKSIG
; No OP_IF needed — paths are separate leaves in the MAST
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: