You’re right that the signature wouldn’t truly be current in that hash because of the OP_CODESEPARATOR
used. Take into account that v0.1.0 was very unpolished code and had plenty of bugs and bizarre behaviour. Not the whole lot is sensible.
To clarify for those who need extra context, by the point we attain EvalScript()
, the script shall be of the shape:
txin.scriptSig + OP_CODESEPARATOR + txout.scriptPubKey
the place txin.scriptSig
is from the spending transaction enter, and can comprise the signature, and txout.scriptPubKey
is from the earlier transaction UTXO being spent and can comprise the general public key and OP_CHECKSIG
opcode. That is precisely what’s written within the query.
Ranging from the start, the signature shall be pushed onto the analysis stack, then we’ll hit the OP_CODESEPARATOR
so pbegincodehash
shall be up to date to that time within the script, then the general public key shall be pushed onto the analysis stack, and eventually the OP_CHECKSIG
is reached.
Precisely as you say, the signature and public key will then be taken off the stack in reverse order and saved in vchSig
and vchPubKey
respectively.
scriptCode
is then set to the subscript beginning at pbegincodehash
till the tip of the script. On this case, it begins on the OP_CHECKSIG
we encountered beforehand, so scriptCode
will merely comprise the general public key push and the OP_CHECKSIG
opcode.
Thus, when scriptCode.FindAndDelete(CScript(vchSig))
is known as, it does nothing on this case as a result of vchSig
is just not a part of scriptCode
.
Nevertheless, for the context of why deleting the signature from the script is necessary for verifying the signatures, let’s look a bit additional. CheckSig()
is known as with the signature (vchSig
), the general public key (vchPubKey
), and the scriptCode
:
CheckSig(vchSig, vchPubKey, scriptCode, txTo, nIn, nHashType)
which then calls
SignatureHash(scriptCode, txTo, nIn, nHashType)
to generate the hash of the message. The hash is generated by deleting all remaining OP_CODESEPARATOR
s from the script, setting the scriptSig of all the opposite inputs to the spending transaction to empty, units the scriptSig
of the present enter being signed to scriptCode
, after which (ignoring the opposite signing sorts) serialises the transaction and hashes it.
Recall that to confirm a signature we’d like the message (which is then hashed), the general public key, and the signature itself. The message must be in precisely the identical type as what was initially signed. That’s the reason we’ve got to delete the signature itself from the transaction being signed, as a result of it clearly could not have been current at signal time. Nevertheless, on this case, it does nothing, as a result of there are not any signatures after OP_CODESEPARATOR
anyway. The clearing of scriptSigs within the SignatureHash()
operate is extra necessary right here as a result of they’d all be empty at signing time.
To examine this, we will check out the SignSignature()
operate too, which truly generates the signatures. We will see that it passes scriptPrereq + txout.scriptPubKey
to the SignatureHash()
operate above because the scriptCode
. scriptPrereq
is at all times empty on this code. So mainly scriptCode
is at all times simply the scriptPubKey
. That matches precisely what we count on.