Bitcoin script types
Bitcoin doesn't make a distinction between Bitcoin script coming from
different sources, like scriptPubKey in transaction output or witness and
sigScript in transaction input. There are many other possible script
containers for Bitcoin script: redeem script, witness script, tapscript. In
fact, any "script" of [bitcoin::Script
] type can be used for inputs and
outputs. What is a valid script for one will be a valid script for the
other; the only req. is formatting of opcodes & pushes. That would mean that
in principle every input script can be used as an output script, but not
vice versa. But really what makes a "script" is just the fact that it's
formatted correctly.
While all Script
s represent the same type semantically, there is a
clear distinction at the logical level: Bitcoin script has the property
to be committed into some other Bitcoin script – in a nested structures like
in several layers, like redeemScript inside of sigScript used for P2SH,
or tapScript within witnessScript coming from witness field
for Taproot. These nested layers do distinguish on the information they
contain, since some of them only commit to the hashes of the nested scripts
([bitcoin::ScriptHash
], [WitnessProgram
]) or public keys
([bitcoin::PubkeyHash
], [bitcoin::WPubkeyHash
]), while other contain the
full source of the script.
The present type system represents a solution to the problem: it distinguish
different logical types by introducing Script
wrapper types. It defines
[LockScript
] as bottom layer of a script hierarchy, containing no other
script commitments (in form of their hashes). It also defines types above on
it: [PubkeyScript
] (for whatever is there in scriptPubkey
field of a
TxOut
), [SigScript
] (for whatever comes from sigScript
field of
[bitcoin::TxIn
]), [RedeemScript
] and [TapScript
]. Then, there are
conversion functions, which, for instance, can analyse [PubkeyScript
] and
if it is a custom script or P2PK return a [LockScript
] type - or otherwise
fail with error. So with this type system one is always sure which logical
information it does contain.
Type derivation
The following charts represent possible relations between script types:
LockScript
_________________________________
^ ^ ^ ^ ^
| | | | |
[txout.scriptPubKey] <===> PubkeyScript --?--/P2PK & custom/---+ | | | |
| | | |
[txin.sigScript] <===> SigScript --+--?!--/P2(W)PKH/--(#=PubkeyHash)--+ | | |
| | | |
| (#=ScriptHash) | |
| | | |
+--?!--> RedeemScript --+--?!------/P2SH/ | |
| | |
/P2WSH-in-P2SH/ /#=V0_WitnessProgram_P2WSH/ |
| | |
+--?!--> WitnessScript |
^^ | |
|| /#=V1_WitnessProgram/ |
|| | |
[?txin.witness] <=====================================================++ +--?---> TapScript
Legend:
[source] <===>
: data source[?source] <===>
: data source which may be absent--+--
: algorithmic branching (alternative computation options)--?-->
: a conversion exists, but it may fail (returns [Option
] or [Result
])--?!-->
: a conversion exists, but it may fail; however one of alternative branches must always succeed----->
: a conversion exists which can't fail--/format/--
: a format implied by scriptPubKey program--(#=type)--
: the hash of the value following->
must match to the value of the<type>
Type conversion
LockScript -+-> (PubkeyScript + RedeemScript) -+-> SigScript
| +-> WitnessScript
+-> PubkeyScript
|
+-> TapScript
PubkeyScript --?--> LockScript