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.
result
as program" (instead ofscriptPubKey
as program)? – Elliott Mar 26 '21 at 17:38result
) can contain whatever OP codes we want? – dassd Sep 01 '23 at 15:58scriptSig
is not exactly a direct push of the top element ofresult
, fail.". Does it mean that in this case any additional pushes are not allowed (opposite to P2SH)? So only the push of the redeem script and the redeem script is "OP_n (with n between 0 and 16, inclusive) followed by a direct push of exactly 2 to 40 bytes". 2) For P2WSH you wrote "Ifinput
is empty, or its top element's SHA256hash
does not equal hash, fail.", is it more accurate to saythe last item of witness data
since it's not stack? – dassd Sep 01 '23 at 23:35input
as script, with the other elements as input. If execution aborts, fail.". Are these other elements i.e. the other elements in the witness data, the initial stack? 4) Do these other items have to be push only, like in classic P2SH, or can some other OP codes as well? – dassd Sep 01 '23 at 23:35If 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
SegWit validation is started. For SegWit, you only wrote theif case
for version 0 (and let's assume for version 1). But what will happen if the version is, for example,2
or3
? Will it be recognized as a normal SegWit and then checked the scriptsig. If it is not empty, an error is thrown, and if it is, the script is immediately accepted without any additional checks of witness data sinceif case
for v2/v3 not exist? – dassd Sep 07 '23 at 10:40subject to things like empty scriptSig
. So, for example scriptPubKeyOP_2 <26-bytes>
will be recognized as segWit since it is, as you said:exactly equal to an OP_n (with n between 0 and 16, inclusive) followed by a direct push of exactly 2 to 40 bytes
. Since nothing has been defined for v2 yet, it will be anyone-can-spend and only check will be if the scriptSig is empty. Empty = accept, otherwise not. The content of witness is not important in this case (it will become important after the rules for v2 are introduced). Right? – dassd Sep 08 '23 at 13:09if the input is empty, fail
? – dassd Sep 14 '23 at 22:53OP_DUP OP_HASH160 ...
script will fail. – Pieter Wuille Sep 15 '23 at 00:30