Script Stack (Bitcoin)
Learn what the script stack is in Bitcoin and how this data structure executes spending conditions.
Key Takeaways
- The script stack is a last-in, first-out (LIFO) data structure that Bitcoin Script uses to evaluate spending conditions: every opcode reads inputs from, and writes results to, this stack.
- Bitcoin maintains two stacks during execution: the main stack, which holds operands and intermediate results, and the alt stack, which provides temporary storage via OP_TOALTSTACK and OP_FROMALTSTACK.
- Consensus rules cap each stack element at 520 bytes and limit the combined main and alt stack to 1,000 elements, constraints that shape what spending conditions are possible on Bitcoin.
What Is the Script Stack?
The script stack is the core data structure that powers Bitcoin Script execution. When a node validates a transaction, it runs the script associated with each input through a stack-based interpreter. Data elements (byte vectors) and opcodes interact on this stack to determine whether a spend is authorized. If the script completes without error and the top item on the stack is a nonzero value, the transaction is valid.
Stack-based languages differ from the register-based models used in most general-purpose programming. Instead of named variables and memory addresses, every operation pulls its inputs from the top of the stack and pushes its output back. This design makes Bitcoin Script simple to implement, easy to analyze for resource usage, and resistant to many classes of bugs that affect more expressive languages.
Bitcoin actually uses two stacks during script execution: the main stack and the alt stack. The main stack handles all regular computation, while the alt stack acts as a scratch pad for temporarily setting aside values.
How It Works
When the script interpreter processes a transaction input, it concatenates the witness data (or scriptSig) with the locking script (scriptPubKey) and evaluates them sequentially. Every element in the script is either a data push or an opcode, and each interacts with the stack in a specific way.
The Main Stack
The main stack is where all primary computation happens. Data pushes place byte vectors onto the top of the stack. Opcodes consume one or more items from the top, perform an operation, and push results back. Consider a simple example that checks whether two numbers sum to a specific value:
# ScriptPubKey: OP_ADD 5 OP_EQUAL
# ScriptSig: 2 3
# Execution trace:
# Step 1: Push 2 → Stack: [2]
# Step 2: Push 3 → Stack: [2, 3]
# Step 3: OP_ADD → Pops 2 and 3, pushes 5
# Stack: [5]
# Step 4: Push 5 → Stack: [5, 5]
# Step 5: OP_EQUAL → Pops both 5s, pushes 1 (true)
# Stack: [1]
# Result: top of stack is nonzero → validEvery standard Bitcoin transaction follows this pattern. A P2PKH spend pushes a signature and public key onto the stack, then runs opcodes like OP_DUP, OP_HASH160, and OP_CHECKSIG to verify ownership.
The Alt Stack
The alt stack is a secondary LIFO stack used for temporary value storage. Only two opcodes interact with it:
- OP_TOALTSTACK: moves the top item from the main stack onto the alt stack
- OP_FROMALTSTACK: moves the top item from the alt stack back onto the main stack
This is useful when a script needs to preserve a value while processing other data. For example, a script that must verify a signature and then reuse the public key for a second check can stash the key on the alt stack rather than duplicating it multiple times:
# Stash a value on the alt stack for later use
<pubkey>
OP_DUP
OP_TOALTSTACK # Save a copy to alt stack
<hash>
OP_EQUALVERIFY # Check hash of pubkey
OP_FROMALTSTACK # Retrieve pubkey from alt stack
<sig>
OP_CHECKSIG # Verify signature with pubkeyThe alt stack follows the same LIFO ordering as the main stack: the last item moved to the alt stack is the first one retrieved. Both stacks count toward the combined 1,000-element limit.
Stack Execution and Transaction Validity
After the entire script finishes executing, the interpreter checks the main stack to determine validity. A transaction input is considered valid when two conditions are met:
- No opcode triggered a failure during execution (for example, OP_VERIFY failing, or OP_CHECKSIG encountering an invalid signature with OP_CHECKSIGVERIFY)
- The top item remaining on the stack is a nonzero byte vector, which the interpreter treats as true
For SegWit and Tapscript spends, a "clean stack" rule additionally requires that exactly one item remains on the stack after execution. This prevents scripts from leaving extra unused data behind, which could otherwise be exploited for transaction malleability.
Stack Limits and Constraints
Bitcoin's consensus rules impose strict limits on the script stack to prevent denial-of-service attacks and ensure nodes can validate transactions with bounded resources.
| Limit | Legacy / SegWit v0 | Tapscript (BIP 342) |
|---|---|---|
| Stack element size | 520 bytes | 520 bytes (unchanged) |
| Combined stack + alt stack items | 1,000 elements | 1,000 elements (unchanged) |
| Non-push opcodes per script | 201 | Removed (sigops budget instead) |
| Script size | 10,000 bytes | Removed |
The 520-byte element size limit is a consensus rule enforced by Bitcoin Core's script interpreter. It constrains what can be pushed onto or produced on the stack, which in turn limits the complexity of redeem scripts and witness scripts. Standardness policy further restricts initial stack items (from the witness or scriptSig) to 80 bytes, though miners can include transactions exceeding the policy limit.
The 1,000-element limit applies to the combined count of items on the main stack and alt stack at any point during execution. This prevents scripts from consuming unbounded memory during validation.
While Tapscript (introduced by BIP 342) removed the opcode count and script size limits, it preserved the stack element size and stack depth constraints. BIP 342 does note that future soft forks could introduce new opcodes (via the OP_SUCCESS mechanism) that lift the 520-byte limit for specific use cases. For a deeper look at how these limits shape Bitcoin's programmability, see the research article on Bitcoin Script programmability.
Use Cases
The stack model underpins every Bitcoin transaction type. Different spending conditions produce different stack interaction patterns:
- Single-signature spends (P2WPKH): the witness pushes a signature and public key. OP_CHECKSIG pops both, verifies the signature, and pushes 1 (true) or 0 (false).
- Multisignature spends (OP_CHECKMULTISIG): multiple signatures and public keys are pushed onto the stack. The opcode consumes all of them and pushes a single boolean result.
- Hash-locked contracts (HTLCs): a preimage is pushed onto the stack. OP_SHA256 or OP_HASH160 hashes it, and OP_EQUAL checks against the expected hash. These patterns power Lightning channels and atomic swaps.
- Timelocked spends: OP_CHECKLOCKTIMEVERIFY and OP_CHECKSEQUENCEVERIFY read the top stack element and compare it against transaction-level timelock values without consuming it.
- Taproot script paths (script path spends): the witness includes the leaf script plus a control block. The script executes under Tapscript rules with the relaxed opcode budget, while the stack limits remain unchanged.
Stack Operations Reference
The Bitcoin Script opcode set includes several operations dedicated to stack manipulation:
| Opcode | Effect |
|---|---|
| OP_DUP | Duplicates the top stack item |
| OP_DROP | Removes the top stack item |
| OP_SWAP | Swaps the top two stack items |
| OP_ROT | Rotates the top three items (third becomes first) |
| OP_OVER | Copies the second item to the top |
| OP_PICK | Copies the nth item to the top (n is taken from the stack) |
| OP_ROLL | Moves the nth item to the top (n is taken from the stack) |
| OP_TOALTSTACK | Moves top item to the alt stack |
| OP_FROMALTSTACK | Moves top alt stack item to the main stack |
| OP_IFDUP | Duplicates the top item only if it is nonzero |
| OP_DEPTH | Pushes the current stack depth as a number |
These primitives, combined with arithmetic and cryptographic opcodes, give script authors the tools to express complex spending conditions within the stack model. For advanced applications, Miniscript compiles human-readable spending policies into stack-efficient Bitcoin Script that stays within resource limits.
Risks and Considerations
Resource Exhaustion
Without stack limits, a malicious script could push thousands of large elements onto the stack, forcing validators to allocate excessive memory. The 520-byte element cap and 1,000-item depth limit bound worst-case memory usage to roughly 520 KB per script execution, keeping validation feasible for all nodes.
Complexity Constraints
The 520-byte element size restricts what can be represented on the stack. This impacts protocols that need large data structures, such as BitVM verification circuits or advanced covenant schemes. Proposals like BIP 441 would raise the element limit to 4 MB under a new Tapscript version, but none have been activated.
Stack Overflow and Underflow
If a script attempts to pop from an empty stack, the interpreter immediately fails the transaction. Similarly, exceeding the 1,000-element depth at any point during execution causes the script to fail. Script authors must carefully reason about stack depth at every branch of conditional logic (using OP_IF and its variants) to avoid these failures.
Data Type Limitations
Stack elements are raw byte vectors with no enforced type system. Opcodes interpret them according to context: arithmetic opcodes treat elements as signed integers (limited to 4 bytes in legacy script), boolean opcodes check for zero or nonzero, and cryptographic opcodes expect specific formats. Misinterpreting an element's type can lead to unexpected script failures or unspendable outputs.
This glossary entry is for informational purposes only and does not constitute financial or investment advice. Always do your own research before using any protocol or technology.