As of September 2023, "high-level" script validation with all active consensus rules on the network is approximately this:
Top level evaluation
- Execute the
scriptSig
, and call the resulting stack stack
. If execution aborts, fail.
- Execute the
scriptPubKey
with stack
as input, and call the resulting stack result
. If execution aborts, fail.
- If
result
is empty, or its top element has numerical value 0, fail.
- [from BIP141] If
scriptPubKey
is exactly equal to an OP_n (with n
between 0 and 16, inclusive) followed by a direct push of exactly 2 to 40 bytes inclusive:
- If
scriptSig
not empty, fail.
- Run segwit validation with the 2-to-40 byte push in
scriptPubKey
as program, the n
value as version, and witness
as input (see further). If this execution aborts, fail.
- [From BIP16] If
scriptPubKey
is exactly equal to OP_HASH160 + a 20 byte push + OP_EQUAL, run P2SH validation:
- If
scriptSig
does not consists of only pushes, fail.
- If
result
is empty, fail.
- Interpret the top element of
result
as a script, and execute it, with the rest of result
as input. Call the resulting stack p2sh_result
. If this execution aborts, fail.
- If
p2sh_result
is empty, or its top element has numerical value 0, fail.
- [From BIP141] If the top element of
result
is exactly OP_n (with n
between 0 and 16 inclusive) followed by a direct push of 2 through 40 bytes inclusive:
- If
scriptSig
is not exactly a direct push of the top element of result
, fail.
- Run segwit validation with the 2-to-40 byte push in the top element of
result
as program, the n
value as version, and witness
as input (see further). If this execution aborts, fail.
- If segwit validation did not trigger, but a witness is provided in the transaction input, fail.
- If no failure occurred before this point, the input is valid.
Segwit validation
Segwit validation for version version
, with program program
, and input input
:
- [From BIP141] If the version is 0:
- If the program is not 20 or 32 bytes, fail.
- If the program is 20 bytes
hash
:
- If
input
is not exactly 2 elements, fail.
- Execute the script OP_DUP OP_HASH160
hash
OP_EQUALVERIFY OP_CHECKSIG, with initial stack input
. If execution aborts, fail.
- If the resulting stack is not exactly one element, or that element has numerical value 0, fail.
- If the program is 32 bytes
hash
:
- If
input
is empty, or its top element's SHA256 hash does not equal hash
, fail.
- Execute the top element of
input
as script, with the other elements as input. If execution aborts, fail.
- If the resulting stack is not exactly one element, or that element has numerical value 0, fail.
- [From BIP341] If the version is 1, the program length is 32, and this is not operating inside a P2SH wrapping:
- If the
input
consists of 0 elements, fail.
- If the last element of
input
starts with byte 0x50, call it the annex
and remove it from the input
.
- If the (remainder of)
input
consists of a single element, evaluate it as a Taproot key path spend:
- The element is interpreted as a single BIP340 (Schnorr) signature for the transaction, using a message hashing scheme described in BIP341. If the signature is invalid, fail.
- If the (remainder of)
input
consists of two or more elements, evaluate it as a Taproot script path spend:
- The last element of
input
is interpreted as a Taproot control block, encoding a leaf_version
, an internal x-only public key, and a Merkle path, and the penultimate element of input
is called the taproot_script
. The control block and taproot_script
are removed from input
.
- Recompute the Merkle root of the script tree, starting from the leaf (
leaf_version
and taproot_script
), and then tweak the internal x-only key with that Merkle root. If the result does not match the 32-byte witness program, fail.
- [From BIP342] If the
leaf_version
is 0xc0, taproot_script
is evaluated according to the Tapscript validation rules, with the remaining of input
as initial stack. See BIP342 for how this differs from normal script execution.
- If no failure occurred up to this point, return success.
Source: https://github.com/bitcoin/bitcoin/blob/v25.0/src/script/interpreter.cpp, functions VerifyScript
, VerifyWitnessProgram
, ExecuteWitnessScript
.
TL;DR: only the BIP16 P2SH pattern (OP_HASH160 <20 bytes> OP_EQUAL) and the BIP141 segwit pattern (OP_n <2 to 40 bytes>) are actual special cases that trigger additional rules. But the details are more complex.