The Stack-Based Execution Model
The Stack-Based Execution Model
Bitcoin Script is a stack-based language. To understand how any Bitcoin transaction is validated, you must understand what a stack is and how opcodes interact with it.
What is a Stack?
A stack is a data structure that operates on a last-in, first-out (LIFO) principle. Think of a physical stack of plates. You can only add a plate to the top (push) or remove the top plate (pop). You cannot reach into the middle of the stack.
In Bitcoin Script, data items are pushed onto the stack and opcodes operate on them. The result of each opcode either leaves new data on the stack or removes data. At the end of script execution, if the top item on the stack is non-zero (true), the script succeeds.
Stack Operations:
PUSH 5 Stack: [5]
PUSH 3 Stack: [5, 3]
OP_ADD Stack: [8] (pops 5 and 3, pushes 8)
PUSH 8 Stack: [8, 8]
OP_EQUAL Stack: [1] (pops both 8s, pushes 1 = TRUE)
Result: Stack top is 1 (TRUE) — script succeeds.
The Main Stack and the Alt Stack
Bitcoin Script actually maintains two stacks simultaneously:
-
The Main Stack: Where all normal operations happen. Opcodes push and pop from here by default.
-
The Alt Stack: An auxiliary stack used to temporarily store items. Only
OP_TOALTSTACKandOP_FROMALTSTACKinteract with it.
The alt stack allows scripts to save intermediate values without losing their position in a computation. It is an essential tool for complex script patterns like Hash Time Locked Contracts (HTLCs).
// Example using alt stack:
PUSH <value_A>
OP_TOALTSTACK // Move A to alt stack. Main: [], Alt: [A]
PUSH <value_B>
PUSH <value_C>
OP_ADD // Main: [B+C], Alt: [A]
OP_FROMALTSTACK // Main: [B+C, A], Alt: []
OP_ADD // Main: [A+B+C], Alt: []
How Opcodes Interact with the Stack
Every opcode in Bitcoin Script is one of three types:
1. Push opcodes: These place data onto the stack without performing any computation.
OP_1 // Pushes the integer 1
OP_16 // Pushes the integer 16
<20 bytes> // Pushes arbitrary byte data
2. Operation opcodes: These pop one or more items from the stack, perform a computation, and push the result.
OP_DUP // Pops top item, pushes it twice (duplicates)
OP_HASH160 // Pops top item, hashes it, pushes result
OP_CHECKSIG // Pops signature and pubkey, pushes 1 or 0
3. Flow control opcodes: These conditionally skip sections of script based on stack values.
OP_IF // Pops top item; if true, executes next branch
OP_ELSE // Switches to alternative branch
OP_ENDIF // Closes conditional block
Walking Through a Real P2PKH Script
The most common Bitcoin script type is Pay-to-Public-Key-Hash (P2PKH). Here is the full execution trace:
Initial stack: []
Unlocking script provides:
<sig> → Stack: [sig]
<pubKey> → Stack: [sig, pubKey]
Locking script executes:
OP_DUP → Stack: [sig, pubKey, pubKey] (duplicates top)
OP_HASH160 → Stack: [sig, pubKey, hash160(pubKey)] (hashes top)
<pubKeyHash>→ Stack: [sig, pubKey, hash160(pubKey), pubKeyHash]
OP_EQUALVERIFY → Stack: [sig, pubKey] (checks equality, fails if mismatch)
OP_CHECKSIG → Stack: [1] (verifies sig against pubKey)
Final stack: [1] → TRUE → Transaction valid.
Stack Overflow and Underflow
The Script interpreter enforces limits on stack operations:
-
Maximum stack depth: 1,000 items. If a script tries to push a 1,001st item, execution fails.
-
Stack underflow: If an opcode tries to pop more items than exist on the stack, execution fails immediately.
-
Item size limit: Each stack item can be at most 520 bytes.
These limits prevent resource exhaustion attacks where a script could fill up a node's memory.
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: