Overview
Bitcoin Script is the programming language that powers all Bitcoin transactions. Every transaction output contains a locking script (scriptPubKey) that specifies the conditions under which the output can be spent. To spend that output, a subsequent transaction must provide an unlocking script (scriptSig) that satisfies those conditions. Script is intentionally limited in capability to prioritize security and predictability.
How Script Execution Works
Script uses a stack-based execution model where data and operators are processed left to right, pushing values onto and popping values from a stack:
Example: P2PKH (Pay-to-Public-Key-Hash) verification
Unlocking Script (scriptSig): <signature> <public_key>
Locking Script (scriptPubKey): OP_DUP OP_HASH160 <pubKeyHash> OP_EQUALVERIFY OP_CHECKSIG
Execution:
Stack: []
Push <signature> → [sig]
Push <public_key> → [sig, pubKey]
OP_DUP → [sig, pubKey, pubKey]
OP_HASH160 → [sig, pubKey, hash(pubKey)]
Push <pubKeyHash> → [sig, pubKey, hash(pubKey), pubKeyHash]
OP_EQUALVERIFY → [sig, pubKey] (hashes must match)
OP_CHECKSIG → [true] (signature valid)
Design Philosophy
Script is deliberately non-Turing-complete: it has no loops and always terminates. This design choice prevents denial-of-service attacks and ensures that every script's execution time can be bounded. While this limits Script's expressiveness compared to general-purpose smart contract languages, it makes Bitcoin's transaction validation highly predictable and secure.
Common Script Types
- P2PKH: Pay to a public key hash (legacy addresses starting with 1)
- P2SH: Pay to a script hash (addresses starting with 3), enabling complex scripts like multisig
- P2WPKH/P2WSH: SegWit versions with witness data separated from the transaction
- P2TR: Taproot outputs that can be spent via a key path or script path
Edge Cases
One notable edge case is the OP_RETURN opcode, which marks an output as provably unspendable. This is used to embed small amounts of arbitrary data on the blockchain without creating unspendable UTXOs that nodes must track indefinitely.