Stack Overflow and Depth Limits
19. Stack Overflow and Depth Limits
Overview
Bitcoin Script enforces strict limits on stack depth and script complexity to prevent denial-of-service attacks and ensure deterministic execution across all network nodes. Understanding these limits is essential for script developers, especially those working with complex multi-input scripts, Lightning Network constructs, and Tapscript.
The 1000-Item Stack Limit
Bitcoin Core enforces a maximum stack depth of 1000 items across all active stacks (main stack + alt stack):
// From Bitcoin Core src/script/interpreter.cpp
static const size_t MAX_STACK_SIZE = 1000;
This limit applies to:
-
The main stack (primary operand stack)
-
The alt stack (used by OP_TOALTSTACK / OP_FROMALTSTACK)
-
The combined total of both stacks must not exceed 1000
Main Stack: [ x1, x2, ..., xM ] (M items)
Alt Stack: [ y1, y2, ..., yA ] (A items)
Constraint: M + A <= 1000
The 201-Opcode Limit
In legacy script, no script may contain more than 201 opcodes (non-pushdata opcodes):
MAX_OPS_PER_SCRIPT = 201
Note: Pushdata opcodes (OP_0 through OP_16, OP_PUSHDATA1, etc.) are not counted toward this limit. Only opcodes that perform operations are counted:
Counted: OP_DUP, OP_HASH160, OP_CHECKSIG, OP_ADD, etc.
Not Counted: OP_0, OP_1, OP_PUSHDATA1, etc. (pure data push)
In Tapscript (BIP 342), this 201-opcode limit is removed, but the stack size limit of 1000 remains.
The 520-Byte Element Size Limit
Each individual stack element is limited to 520 bytes:
MAX_SCRIPT_ELEMENT_SIZE = 520 bytes
This prevents large data blobs from being placed on the stack and ensures that operations like OP_HASH160 operate on bounded inputs.
Valid push: <data up to 520 bytes>
Invalid push: <data 521+ bytes> → script FAILS
The 10,000-Byte Script Size Limit
The total serialized size of a locking or unlocking script must not exceed 10,000 bytes:
MAX_SCRIPT_SIZE = 10,000 bytes
In Tapscript, leaf scripts can be larger (up to the transaction weight limit), but practical script size is still bounded by block size limits.
Stack Manipulation Opcodes and Depth Growth
The following opcodes increase stack depth:
OP_DUP → +1
OP_2DUP → +2
OP_3DUP → +3
OP_OVER → +1
OP_2OVER → +2
OP_DEPTH → +1
OP_PICK → net 0 (n consumed, copy added)
OP_TUCK → +1
The following opcodes decrease stack depth:
OP_DROP → -1
OP_2DROP → -2
OP_NIP → -1
OP_ROLL → net 0 (n consumed, item moved)
OP_SWAP → net 0
OP_ROT → net 0
Neutral opcodes (same depth):
OP_SWAP, OP_ROT, OP_2SWAP, OP_2ROT, OP_ROLL, OP_PICK
Stack Overflow in Practice
A script that naively pushes items in a loop can exhaust the 1000-item limit:
Hypothetical script (NOT valid — for illustration):
OP_1 (repeated 1001 times)
→ Fails at the 1001st push
In practice, this is constrained by the script size limit (10,000 bytes), which also limits how many items can be pushed. At 1 byte per OP_N push (for small values), a maximum of 10,000 items could theoretically be pushed before the byte limit is hit — but the 1000-item stack limit will trigger first.
Stack Underflow
Attempting to consume more items than exist causes a stack underflow failure:
Empty stack:
OP_DROP → FAIL (stack underflow)
OP_DUP → FAIL (stack underflow)
OP_SWAP → FAIL (requires 2 items)
The interpreter checks stack depth before executing any opcode that consumes stack items.
Tapscript Changes (BIP 342)
Under Tapscript:
Change 1: 201 opcode limit REMOVED (unlimited opcodes per script leaf)
Change 2: Stack size limit of 1000 MAINTAINED
Change 3: MAX_SCRIPT_ELEMENT_SIZE of 520 bytes MAINTAINED for most ops
Change 4: Disabled opcodes (OP_CAT, etc.) behave as OP_SUCCESS in some contexts
Practical Design Rules
When designing scripts with multiple stack manipulation opcodes:
Rule 1: Track the stack depth at every step
Rule 2: Ensure no path exceeds 1000 items
Rule 3: Always clean up temporary values with OP_DROP or OP_2DROP
Rule 4: Prefer fixed-depth opcodes (OP_OVER, OP_ROT) over OP_PICK/OP_ROLL with large n
Rule 5: Test all code paths — conditional branches may have different stack depths
Summary
Stack depth limits, opcode limits, and element size limits together define the execution envelope for Bitcoin Script. Developers must understand these constraints when composing complex scripts to avoid runtime failures and ensure consistent evaluation across all Bitcoin nodes.
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: