Since I am coding all these things without "translating" it from anywhere, I sometimes face some oddity in decisions that were made. Sometimes I am missing the rationale so here I am...
When looking at P2PKH scripts it all makes perfect sense:
<PushData-sig><PushData-pubkey>|<Dup><Hash160><PushData-20_byte_hash><EqualVerify><CheckSig>
Every "operation" does exactly what it says, they either push some data on top of stack or consume a number of items from the stack and interpret them specifically and give some result.
But then we have multisig/P2SH design the script stops making sense to me (a 2of3 example):
<0><PushData-sig1><PushData-sig2><PushData-redeem_script>|<Hash160><PushData-20_byte_hash><Equal>
Every operation is doing exactly what they are supposed to
except the final
PushData operation inside scriptsig! That one is not exactly pushing data, it is pushing a script which I also have to keep a copy of
without the script telling me to!!! Which means my script runner now has to have (what I will be calling from now on) a "hack" that copies this last
PushData first then runs the whole thing and then runs this last
PushData as a script!
Logically running this script (without the hack) should be like this:
<OP_0> => stack has 1 item (emptyBytes)
<PushData-sig1> => stack has 2 item (empty-sig1)
<PushData-sig2> => stack has 3 items (empty-sig1-sig2)
<PushData-redeem_script> => stack has 4 items (empty-sig1-sig2-redeemScr)
<Hash160> => pop top item, hash it, push => stack has 4 items (empty-sig1-sig2-hashresult)
<PushData-20_byte_hash> => stack has 5 items (empty-sig1-sig2-hashresult-givenHash)
<Equal> => pop 2 and compare => stack has 4 items (empty-sig1-sig2-true/false)
Without the hack we are left with a stack with 4 items in it and no more operations left to run!
Now here is another question. Why not simply do this instead:
<PushData-sigs><PushData-redeem_script>|<Dup><Hash160><PushData-20_byte_hash><EqualVerify><CheckMultiSig>
Now this would not only make sense but also stick to the already existing design. The script "tells me" to duplicate the redeem script with its
OP_DUP so I don't do it on my own, then perform the rest and finally the
OP_CHECKMULTISIG consumes 2 items (just like its CheckSig counterpart) and interprets the first as a redeem script and the second as the number of required signatures. It also requires less number of push operations so the transaction can be a little smaller the more signatures it has! That could have maybe solve the OP_0 bug(?)