What I am not getting is how the operation are done.
The address encodes the hash160 of the redeemScript. That address was given to the sender, who used it to construct an output scriptPubKey of the form OP_HASH160 <scripthash> OP_EQUAL
. The scripthash is really hash160(redeemScript), but the sender does not know that, as they aren't given the actual redeemScript, just its hash160. The <...>
notation here means "script opcode that pushes ... onto the stack".
The redeemscript is OP_2 <pubkey1> <pubkey2> <pubkey3> OP_3 OP_CHECKMULTISIG
. This script was created by the receiver, encoding their policy for spending, and then its hash160 was given in the form of a P2SH address (3...) to the sender.
The scriptSig is what is created by the receiver when they want to spend the coins. In this case it consists of OP_0 <sig1> <sig2> <redeemScript>
.
During validation, what happens is:
- First the scriptSig is executed, which pushes 4 items onto the stack (0, sig1, sig2, and redeemScript).
- Then the scriptPubKey is executed, starting with the previous execution's final stack as initial state. It contains 3 opcodes, each modifying that stack:
OP_HASH160
: takes the final element of the stack (the redeemScript) and replaces it with hash160(redeemScript).
<scripthash>
: pushes the scripthash onto the stack, so now the stack is (0, sig1, sig2, hash160(redeemScript), scripthash).
OP_EQUALVERIFY
: removes the top two items on the stack and compares them. If they are equal, a 1 is pushed onto the stack, otherwise a zero. In our case, the scripthash is equal to hash160(redeemScript) (because the spender revealed the correct redeemScript) and thus a 1 is pushed. The stack is now (0, sig1, sig2, 1).
- The final stack is examined: validity rules require that the stack is not empty, and that its top element is nonzero. That is the case here: the top element is 1. If that wasn't the case, the spend would be marked invalid and execution would stop here.
That's it for the ordinary execution. However, because the scriptSig is exactly of the form OP_HASH160 <20-byte scripthash> OP_EQUAL
, the BIP16 P2SH validation rules trigger for a secondary round of processing. This time:
- It is verified that the scriptSig contains only push opcodes, and no other opcodes. If this is not true, the P2SH validation marks the transaction as invalid.
- The stack we had just after executing the scriptSig is restored (0, sig1, sig2, redeemScript).
- Its top element (the redeemScript) is removed from the stack, and reinterpreted as a script, and executed, with all the other stack elements as input. It consists of 5 opcodes:
OP_2
: pushes a 2 onto the stack, which now becomes (0, sig1, sig2, 2).
<pubkey1>
: pushes pubkey1 onto the stack, which becomes (0, sig1, sig2, 2, pubkey1).
<pubkey2>
: pushes pubkey2 onto the stack, which becomes (0, sig1, sig2, 2, pubkey1, pubkey2).
<pubkey3>
: pushes pubkey3 onto the stack, which becomes (0, sig1, sig2, 2, pubkey1, pubkey2, pubkey3).
OP_3
: pushes a 2 onto the stack, which now becomes (0, sig1, sig2, 2, pubkey1, pubkey2, pubkey3, 3).
OP_CHECKMULTISIG
inspects the stack, sees a 3 on top, removes it, as well as the 3 pubkeys that precede it. Then it encounters a 2 on top, removes, as well as the 2 signatures that precede it. Then it removes one more element (a historical bug that is very hard to fix). Then it checks those signatures against every subset of 2 of those 3 pubkeys. If matches are found, it puts a 1 on the stack, otherwise a 0. In this case, the signatures are valid for some subset of the public keys, and the stack becomes (1).
- The final stack is inspected, requiring that it is not empty, and its top element is nonzero. As it is a 1 here, that is the case.