TeachMeBitcoin

Stack Overflow and Depth Limits

From TeachMeBitcoin, the free encyclopedia Reading time: 4 min

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:

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.

☕ 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!