<p>Almost all commits to the client prior to the commits that you have called out here were hard forks to due the inclusion of <code>OP_VER</code> and <code>OP_VERIF</code>, even if the change to the client wasn't otherwise an incompatible change. </p>

<pre><code>        case OP_VER:
        {
            CBigNum bn(VERSION);
            stack.push_back(bn.getvch());
        }
        break;
</code></pre>

<p>Quite simply, the opcode pushes <code>VERSION</code> onto the stack, which is the version number of the code being used to validate. This number was updated with every release, so no two versions prior to its removal are actually compatible with one another. </p>

<p>There's several others which you have not mentioned, such as that <code>nLockTime</code> was changed to an unsigned variable with a height based hard fork, some minor changes to the implementations of the opcodes, and the removal of double byte opcodes. It's very difficult to enumerate which of these versions are actually compatible with each other as a result of the huge number of changes, and the poor tooling we have which is compatible with these ancient versions. </p>

CC BY-SA 4.0
2020-05-18T20:40:45.807Z
2020-05-18T20:40:45.807Z
Claris
<p>My question is about the changes to bitcoin done by commit range <code>[a75560d8, 6ff5f718]</code>, and their effect on consensus.
Out of this range of four commits (all attributed to satoshi) during the dates July 30th-31st 2010, only the first and last commits are relevant to the question (the two in the middle seem like a build system change, not code).</p>

<p>The two commits (first and second from now on), <code>a75560d8</code> and <code>6ff5f718</code> are attributed to fixing quite a few vulnerabilities in bitcoin script semantics and execution.  For example, in the first commit :</p>

<ol>
<li>Constraints were applied to push and stack sizes</li>
<li>The so-called script versioning mechanism was removed, and the various <code>NOP#</code> opcodes were added in its place</li>
<li>Constraints were applied to bignum operations</li>
<li><code>OP_RETURN</code> was changed from merely terminating the script to returning <code>false</code> for the entire execution </li>
</ol>

<p>In the second commit :</p>

<ol>
<li>Constraints were applied on the maximum number of opcodes in the script</li>
<li>Execution of unknown opcodes was set to return <code>false</code> for the execution</li>
<li>The maximum size of the script was reduced by half to 10kb </li>
<li>A change to <code>*SHIFT</code> opcodes was done (I don't really uderstand it though)</li>
<li>A function called <code>VerifyScript</code> was introduced into bitcoin which changed the behavior of script execution</li>
</ol>

<p>This question is about this list of changes, and whether any of them might be non backwards compatible.  Specifically, I will focus on change (5) from the second commit : <a href="https://github.com/bitcoin/bitcoin/commit/6ff5f718#diff-8458adcedc17d046942185cb709ff5c3" rel="noreferrer">6ff5f718:script.cpp</a></p>

<p><em>Before</em> this change, at the point of txout redemption, a redeeming transaction's input's <code>scriptSig</code> and the prevout's <code>scriptPubKey</code> were joined to form a single script by placing an <code>OP_CODESEPARATOR</code> between them, and passing the result to <code>EvalScript</code> which would execute the script.</p>

<p>Inside <code>EvalScript</code>, an empty stack was created and results from the various operations done in the script are pushed onto it.  When script execution completes without errors, a boolean is returned; if the stack is not empty then the top element is passed to a <code>CastToBool</code> function and and returned (<code>true</code> or <code>false</code>), and if the stack is empty then <code>false</code> is returned.</p>

<p><em>After</em> the change, the <code>VerifyScript</code> function wraps around two separate calls to <code>EvalScript</code>, executing <code>scriptSig</code> and <code>scriptPubKey</code> separately one after the other.  The empty stack which was previously created within <code>EvalScript</code> is instead created in <code>VerifyScript</code> before any script execution begins, and the final check of the stack's contents (or lack thereof) and <code>CastToBool</code> was also moved to <code>VerifyScript</code>, to the point after both <code>scriptSig</code> and <code>scriptPubKey</code> completed their execution.</p>

<p>In <code>VerifyScript</code>, first the <code>scriptSig</code> from the redeeming transaction is passed to <code>EvalScript</code> along with the empty stack.  The machine executes the script and results from the operations are pushed to the stack that was passed in with it.  If no errors occurred during execution, <code>true</code> is returned to <code>VerifyScript</code>.
Secondly, if indeed <code>true</code> was returned, the <code>scriptPubKey</code> from the funding transaction is passed to <code>EvalScript</code> along with the stack, which at that point holds the contents left over from <code>scriptSig</code>'s execution.
The <code>scriptPubKey</code> is executed, which further manipulates the stack's contents and if no errors occured, returns <code>true</code> back to <code>VerifyScript</code>.
Lastly, if <code>true</code> was returned, then the check for empty stack and <code>CastToBool</code> are done, which determines the final result of script verification.</p>

<p>The reason for this change was cited as being a fix to a possible vulnerability in Script : <a href="https://bitcoin.stackexchange.com/a/83561/64730">SE answer</a>, <a href="https://bitcointalk.org/index.php?topic=5095376.msg49150302#msg49150302" rel="noreferrer">BCTalk thread</a>.
Although it's orthogonal to this question, it's why I included the list of changes from commit <code>a75560d8</code>.</p>

<p>It's not too hard to see that considering simple (lacking a checksig) scripts, this change is indeed backwards compatible.  At worst, some scripts might become unspendable, but there doesn't seem to be a case where a previously unspendable script might become spendable as a result of this change.</p>

<p>Even for scripts with a checksig like <code>p2pk</code>, <code>p2pkh</code> and multisig, the <code>CHECKSIG</code> opcode is always taking place in <code>scriptPubKey</code>, which was separated from the elements of <code>scriptSig</code> by an <code>OP_CODESEPARATOR</code> prior to this change.  <em>Seemingly</em>, the semantics remained the same - until about two years later.</p>

<p>Looking at the wiki page for <code>OP_CHECKSIG</code> <a href="https://en.bitcoin.it/wiki/OP_CHECKSIG#How_it_works" rel="noreferrer">wiki-checksig</a>, steps (2) to (4) explain how to go from <code>scriptCode</code> to <code>subScript</code>, and specifically what happens when an <code>OP_CODESEPARATOR</code> exists in <code>scriptCode</code> :</p>

<blockquote>
  <ol start="2">
  <li>A new subScript is created from the <code>scriptCode</code> (the <code>scriptCode</code> is the actually executed script - either the <code>scriptPubKey</code> for non-segwit,
  non-P2SH scripts, or the <code>redeemscript</code> in non-segwit P2SH scripts). The
  script from the immediately after the most recently parsed
  <code>OP_CODESEPARATOR</code> to the end of the script is the <code>subScript</code>. If there
  is no <code>OP_CODESEPARATOR</code> the entire script becomes the <code>subScript</code></li>
  <li>Any occurrences of <code>sig</code> are deleted from subScript, if present (it is not standard to have a signature in an input script of a
  transaction)</li>
  <li>Any remaining <code>OP_CODESEPARATORS</code> are removed from <code>subScript</code></li>
  </ol>
</blockquote>

<p>Now, <em>prior</em> to commit <code>6ff5f718</code>, when <code>scriptSig</code> and <code>scriptPubKey</code> were joined to form a single script, the <code>scriptCode</code> would look like :</p>

<pre><code>&lt;scriptSig&gt; CODESEPARATOR &lt;scriptPubKey&gt;
</code></pre>

<p>With checksig operations taking place in <code>scriptPubKey</code>, making <code>subScript</code> be everything to the right of <code>CODESEPARATOR</code> - basically <code>&lt;scriptPubKey&gt;</code> itself (unless more codeseparators or if signatures consumed by a checksig also exist in <code>scriptPubKey</code>).</p>

<p><em>After</em> the commit, there would actually be two separate executions with <code>scriptSig</code> first and <code>scriptPubKey</code> second, where each execution would have its own <code>scriptCode</code> and subsequently its own <code>subScript</code>.
Now, Because checksig operations are still only being done in <code>scriptPubKey</code>, it appears that <code>subScript</code> would remain the same, but what would happen if a <code>CHECK(MULTI)SIG</code> opcode gets executed in <code>scriptSig</code>?</p>

<p>In January 24th 2012, block 163685 was mined which contained transaction <code>eb3b82c0884e3efa6d8b0be55b4915eb20be124c9766245bcc7f34fdac32bccb</code>.
This transaction, the two immediately after it, and its funding at <code>b8fd633e7713a43d5ac87266adc78444669b987a56b3a65fb92d58c2c4b0e84d</code> which were also mined in the same block are all mentioned in <a href="https://github.com/bitcoin/bips/blob/master/bip-0017.mediawiki#specification" rel="noreferrer">BIP-17</a>, which is an alternative implementation of <code>p2sh</code> semantics :</p>

<blockquote>
  <ul>
  <li><p><code>OP_CHECKHASHVERIFY</code> will re-define the existing <code>OP_NOP2</code> opcode, and will function as follows when executed:</p></li>
  <li><p>First, hash the end of the prior script (in the general case, <code>scriptSig</code>; if no prior script, a null string is hashed) beginning
  from the last evaluated <code>OP_CODESEPARATOR</code> onward (or from the
  beginning of the script, if no <code>OP_CODESEPARATOR</code> was present)</p></li>
  <li>Then, compare this with the item on the top of the stack (if there is none, the script fails immediately)</li>
  <li>If the hashes match, do nothing, proceed as if an <code>OP_NOP</code>; if they do not match, the script fails immediately. Note that in the case of a
  matched hash, the top stack item (the hash being compared with) is not
  popped off the stack. This is for backward compatibility.</li>
  </ul>
</blockquote>

<p>Notice how in bip17 the <code>redeemScript</code> is given as an actual executable script in <code>scriptSig</code>, rather than a single data push of a blob as is the case with bip16.  Even though older nodes will not enforce the <code>hash160</code> of <code>scriptSig</code> to be equal to the 20 bytes value from prevout's <code>scriptPubKey</code>, they would still have to execute it and validate any <code>CHECK(MULTI)SIG</code> operations within.</p>

<p>I'm assuming here that these bip17 example transactions were mined and validated by nodes running software that was recent in Jan. 2012, but suppose there were still nodes on the network running older software, and specifically ones running versions <code>v0.3.6</code> and lower.  Would these older nodes be able to come to consensus with the newer nodes about the validity of block 163685?</p>

<p>Going over the funding transaction <code>b8fd633e7713a43d5ac87266adc78444669b987a56b3a65fb92d58c2c4b0e84d</code>, and looking at the output at index 1, we see the <code>scriptPubKey</code> (<code>NOP2</code> is actually a non active <code>OP_CHECKHASHVERIFY</code>)</p>

<pre><code>0x14 0x2a9bc5447d664c1d0141392a842d23dba45c4f13 NOP2 DROP
</code></pre>

<p>And in the spending transaction <code>eb3b82c0884e3efa6d8b0be55b4915eb20be124c9766245bcc7f34fdac32bccb</code>, from the input at index 1, we have the <code>scriptSig</code></p>

<pre><code>0 0x47 0x30440220276d6dad3defa37b5f81add3992d510d2f44a317fd85e04f93a1e2daea64660202200f862a0da684249322ceb8ed842fb8c859c0cb94c81e1c5308b4868157a428ee01 CODESEPARATOR 1 0x21 0x0232abdc893e7f0631364d7fd01cb33d24da45329a00357b3a7886211ab414d55a 1 CHECKMULTISIG
</code></pre>

<p>Consider first how software from <code>v0.3.7</code> and above would construct the <code>subScript</code> for the <code>CHECKMULTISIG</code> in <code>scriptSig</code>.  We begin with a <code>scriptCode</code> which is exactly <code>scriptSig</code>, and since a <code>CODESEPARATOR</code> is executed, <code>subScript</code> becomes :</p>

<pre><code>1 0x21 0x0232abdc893e7f0631364d7fd01cb33d24da45329a00357b3a7886211ab414d55a 1 CHECKMULTISIG
</code></pre>

<p>Now consider how software from <code>v0.3.6</code> and below would construct the <code>subScript</code> for the same <code>CHECKMULTISIG</code>.  Our <code>scriptCode</code> is no longer made from only <code>scriptSig</code>, but from a joining of it and <code>scriptPubKey</code> by a <code>CODESEPARATOR</code>.  The <code>scriptCode</code> would look like :</p>

<pre><code>0 0x47 0x30440220276d6dad3defa37b5f81add3992d510d2f44a317fd85e04f93a1e2daea64660202200f862a0da684249322ceb8ed842fb8c859c0cb94c81e1c5308b4868157a428ee01 CODESEPARATOR 1 0x21 0x0232abdc893e7f0631364d7fd01cb33d24da45329a00357b3a7886211ab414d55a 1 CHECKMULTISIG CODESEPARATOR 0x14 0x2a9bc5447d664c1d0141392a842d23dba45c4f13 NOP2 DROP
</code></pre>

<p>Recall the rules from the wiki.  At the point when <code>CHECKMULTISIG</code> is executed, <code>subScript</code> is everything from the point after the last executed <code>CODESEPARATOR</code> and until the end of the script, with all <code>CODESEPARATOR</code>s on the right hand side of the checksig operator removed :</p>

<pre><code>1 0x21 0x0232abdc893e7f0631364d7fd01cb33d24da45329a00357b3a7886211ab414d55a 1 CHECKMULTISIG 0x14 0x2a9bc5447d664c1d0141392a842d23dba45c4f13 NOP2 DROP
</code></pre>

<p>If this is correct, then it appears that old nodes with versions <code>v0.3.6</code> and below cannot agree on which is the correct <code>sighash</code> for this spending transaction, but since I can't realistically run any such old version software, I can't be absolutely sure.  I did patch a recent bitcoin core version with some changes that enabled me to simulate validation of tx <code>eb3b82c0884e3efa6d8b0be55b4915eb20be124c9766245bcc7f34fdac32bccb</code>, and as expected it did not pass validation.  I will add the two sighashes below along with the public key and signature for comparison.</p>

<p><strong>So my question is</strong>, is there something I'm misunderstanding or perhaps missed that would allow pre-<code>v0.3.7</code> and post-<code>v0.3.7</code> nodes to come to consensus about the validity of block 163685?</p>

<p>(also relevant : <a href="https://bitcoin.stackexchange.com/q/79797/64730">this SE question</a>)</p>

<hr>

<pre><code>Pubkey : 0232abdc893e7f0631364d7fd01cb33d24da45329a00357b3a7886211ab414d55a
Signature (DER) : 30440220276d6dad3defa37b5f81add3992d510d2f44a317fd85e04f93a1e2daea64660202200f862a0da684249322ceb8ed842fb8c859c0cb94c81e1c5308b4868157a428ee
Signature (r,s) : (276D6DAD3DEFA37B5F81ADD3992D510D2F44A317FD85E04F93A1E2DAEA646602, F862A0DA684249322CEB8ED842FB8C859C0CB94C81E1C5308B4868157A428EE)
</code></pre>

<p>Pre-<code>v0.3.7</code> sighash (does not validate) :</p>

<pre><code>01000000
02
4de8b0c4c2582db95fa6b3567a989b664484c7ad6672c85a3da413773e63fdb8 00000000
00
FFFFFFFF
4de8b0c4c2582db95fa6b3567a989b664484c7ad6672c85a3da413773e63fdb8 01000000
3C 51210232abdc893e7f0631364d7fd01cb33d24da45329a00357b3a7886211ab414d55a51ae142a9bc5447d664c1d0141392a842d23dba45c4f13b175
FFFFFFFF
02
E0FD1C0000000000 19 76a914380cb3c594de4e7e9b8e18db182987bebb5a4f7088ac
C0C62D0000000000 17 142a9bc5447d664c1d0141392a842d23dba45c4f13b175
00000000
01000000

sha256  : 1EB276326D72CB358F6C275D6542F76EED4E36364727CB82D40A116244EBDDB5
sha256d : 11491E74778E1FA8C40CC8E07E1F835677CF1AC81F54255EC1C7125C1894939A
</code></pre>

<p>Post-<code>v0.3.7</code> sighash (does validate) :</p>

<pre><code>01000000
02
4de8b0c4c2582db95fa6b3567a989b664484c7ad6672c85a3da413773e63fdb8 00000000
00
FFFFFFFF
4de8b0c4c2582db95fa6b3567a989b664484c7ad6672c85a3da413773e63fdb8 01000000
25 51210232abdc893e7f0631364d7fd01cb33d24da45329a00357b3a7886211ab414d55a51ae
FFFFFFFF
02
E0FD1C0000000000 19 76a914380cb3c594de4e7e9b8e18db182987bebb5a4f7088ac
C0C62D0000000000 17 142a9bc5447d664c1d0141392a842d23dba45c4f13b175
00000000
01000000

sha256  : 3858A592C15A47F3058010689883DECCD4AF41F5367B9776429613DFB3339883
sha256d : 8D7AD159644D312664472F90E7B823071B1361725CAC78531569FD836EA90350
</code></pre>

CC BY-SA 4.0
2019-01-21T05:17:01.787Z
I believe you are correct. This is a good example of why changes to anything related to consensus need to be examined very carefully in order to not introduce any consensus incompatible changes.
Ava Chow
CC BY-SA 4.0
2019-01-21T17:31:02.947Z
Thanks for reading through it.  It's very much appreciated.
arubi
CC BY-SA 4.0
2019-09-02T07:45:27.073Z
Very good exploration! Good job!
behkod
<script><consensus><validation><opcodes>
Did the introduction of VerifyScript cause a backwards incompatible change to consensus?
arubi
# Did the introduction of VerifyScript cause a backwards incompatible change to consensus?

(Asked by: username_0 on 2019-01-19)

My question is about the changes to bitcoin done by commit range `[a75560d8, 6ff5f718]`, and their effect on consensus.
Out of this range of four commits (all attributed to satoshi) during the dates July 30th-31st 2010, only the first and last commits are relevant to the question (the two in the middle seem like a build system change, not code).

The two commits (first and second from now on), `a75560d8` and `6ff5f718` are attributed to fixing quite a few vulnerabilities in bitcoin script semantics and execution. For example, in the first commit :

1. Constraints were applied to push and stack sizes
2. The so-called script versioning mechanism was removed, and the various `NOP#` opcodes were added in its place
3. Constraints were applied to bignum operations
4. `OP_RETURN` was changed from merely terminating the script to returning `false` for the entire execution

In the second commit :

1. Constraints were applied on the maximum number of opcodes in the script
2. Execution of unknown opcodes was set to return `false` for the execution
3. The maximum size of the script was reduced by half to 10kb
4. A change to `*SHIFT` opcodes was done (I don't really uderstand it though)
5. A function called `VerifyScript` was introduced into bitcoin which changed the behavior of script execution

This question is about this list of changes, and whether any of them might be non backwards compatible. Specifically, I will focus on change (5) from the second commit : [6ff5f718:script.cpp](https://github.com/bitcoin/bitcoin/commit/6ff5f718#diff-8458adcedc17d046942185cb709ff5c3)

*Before* this change, at the point of txout redemption, a redeeming transaction's input's `scriptSig` and the prevout's `scriptPubKey` were joined to form a single script by placing an `OP_CODESEPARATOR` between them, and passing the result to `EvalScript` which would execute the script.

Inside `EvalScript`, an empty stack was created and results from the various operations done in the script are pushed onto it. When script execution completes without errors, a boolean is returned; if the stack is not empty then the top element is passed to a `CastToBool` function and and returned (`true` or `false`), and if the stack is empty then `false` is returned.

*After* the change, the `VerifyScript` function wraps around two separate calls to `EvalScript`, executing `scriptSig` and `scriptPubKey` separately one after the other. The empty stack which was previously created within `EvalScript` is instead created in `VerifyScript` before any script execution begins, and the final check of the stack's contents (or lack thereof) and `CastToBool` was also moved to `VerifyScript`, to the point after both `scriptSig` and `scriptPubKey` completed their execution.

In `VerifyScript`, first the `scriptSig` from the redeeming transaction is passed to `EvalScript` along with the empty stack. The machine executes the script and results from the operations are pushed to the stack that was passed in with it. If no errors occurred during execution, `true` is returned to `VerifyScript`.
Secondly, if indeed `true` was returned, the `scriptPubKey` from the funding transaction is passed to `EvalScript` along with the stack, which at that point holds the contents left over from `scriptSig`'s execution.
The `scriptPubKey` is executed, which further manipulates the stack's contents and if no errors occured, returns `true` back to `VerifyScript`.
Lastly, if `true` was returned, then the check for empty stack and `CastToBool` are done, which determines the final result of script verification.

The reason for this change was cited as being a fix to a possible vulnerability in Script : [SE answer](https://bitcoin.stackexchange.com/a/83561/64730), [BCTalk thread](https://bitcointalk.org/index.php?topic=5095376.msg49150302#msg49150302).
Although it's orthogonal to this question, it's why I included the list of changes from commit `a75560d8`.

It's not too hard to see that considering simple (lacking a checksig) scripts, this change is indeed backwards compatible. At worst, some scripts might become unspendable, but there doesn't seem to be a case where a previously unspendable script might become spendable as a result of this change.

Even for scripts with a checksig like `p2pk`, `p2pkh` and multisig, the `CHECKSIG` opcode is always taking place in `scriptPubKey`, which was separated from the elements of `scriptSig` by an `OP_CODESEPARATOR` prior to this change. *Seemingly*, the semantics remained the same - until about two years later.

Looking at the wiki page for `OP_CHECKSIG` [wiki-checksig](https://en.bitcoin.it/wiki/OP_CHECKSIG#How_it_works), steps (2) to (4) explain how to go from `scriptCode` to `subScript`, and specifically what happens when an `OP_CODESEPARATOR` exists in `scriptCode` :

> 2. A new subScript is created from the `scriptCode` (the `scriptCode` is the actually executed script - either the `scriptPubKey` for non-segwit,
>    non-P2SH scripts, or the `redeemscript` in non-segwit P2SH scripts). The
>    script from the immediately after the most recently parsed
>    `OP_CODESEPARATOR` to the end of the script is the `subScript`. If there
>    is no `OP_CODESEPARATOR` the entire script becomes the `subScript`
> 3. Any occurrences of `sig` are deleted from subScript, if present (it is not standard to have a signature in an input script of a
>    transaction)
> 4. Any remaining `OP_CODESEPARATORS` are removed from `subScript`

Now, *prior* to commit `6ff5f718`, when `scriptSig` and `scriptPubKey` were joined to form a single script, the `scriptCode` would look like :

```
<scriptSig> CODESEPARATOR <scriptPubKey>

```

With checksig operations taking place in `scriptPubKey`, making `subScript` be everything to the right of `CODESEPARATOR` - basically `<scriptPubKey>` itself (unless more codeseparators or if signatures consumed by a checksig also exist in `scriptPubKey`).

*After* the commit, there would actually be two separate executions with `scriptSig` first and `scriptPubKey` second, where each execution would have its own `scriptCode` and subsequently its own `subScript`.
Now, Because checksig operations are still only being done in `scriptPubKey`, it appears that `subScript` would remain the same, but what would happen if a `CHECK(MULTI)SIG` opcode gets executed in `scriptSig`?

In January 24th 2012, block 163685 was mined which contained transaction `eb3b82c0884e3efa6d8b0be55b4915eb20be124c9766245bcc7f34fdac32bccb`.
This transaction, the two immediately after it, and its funding at `b8fd633e7713a43d5ac87266adc78444669b987a56b3a65fb92d58c2c4b0e84d` which were also mined in the same block are all mentioned in [BIP-17](https://github.com/bitcoin/bips/blob/master/bip-0017.mediawiki#specification), which is an alternative implementation of `p2sh` semantics :

> * `OP_CHECKHASHVERIFY` will re-define the existing `OP_NOP2` opcode, and will function as follows when executed:
> * First, hash the end of the prior script (in the general case, `scriptSig`; if no prior script, a null string is hashed) beginning
>   from the last evaluated `OP_CODESEPARATOR` onward (or from the
>   beginning of the script, if no `OP_CODESEPARATOR` was present)
> * Then, compare this with the item on the top of the stack (if there is none, the script fails immediately)
> * If the hashes match, do nothing, proceed as if an `OP_NOP`; if they do not match, the script fails immediately. Note that in the case of a
>   matched hash, the top stack item (the hash being compared with) is not
>   popped off the stack. This is for backward compatibility.

Notice how in bip17 the `redeemScript` is given as an actual executable script in `scriptSig`, rather than a single data push of a blob as is the case with bip16. Even though older nodes will not enforce the `hash160` of `scriptSig` to be equal to the 20 bytes value from prevout's `scriptPubKey`, they would still have to execute it and validate any `CHECK(MULTI)SIG` operations within.

I'm assuming here that these bip17 example transactions were mined and validated by nodes running software that was recent in Jan. 2012, but suppose there were still nodes on the network running older software, and specifically ones running versions `v0.3.6` and lower. Would these older nodes be able to come to consensus with the newer nodes about the validity of block 163685?

Going over the funding transaction `b8fd633e7713a43d5ac87266adc78444669b987a56b3a65fb92d58c2c4b0e84d`, and looking at the output at index 1, we see the `scriptPubKey` (`NOP2` is actually a non active `OP_CHECKHASHVERIFY`)

```
0x14 0x2a9bc5447d664c1d0141392a842d23dba45c4f13 NOP2 DROP

```

And in the spending transaction `eb3b82c0884e3efa6d8b0be55b4915eb20be124c9766245bcc7f34fdac32bccb`, from the input at index 1, we have the `scriptSig`

```
0 0x47 0x30440220276d6dad3defa37b5f81add3992d510d2f44a317fd85e04f93a1e2daea64660202200f862a0da684249322ceb8ed842fb8c859c0cb94c81e1c5308b4868157a428ee01 CODESEPARATOR 1 0x21 0x0232abdc893e7f0631364d7fd01cb33d24da45329a00357b3a7886211ab414d55a 1 CHECKMULTISIG

```

Consider first how software from `v0.3.7` and above would construct the `subScript` for the `CHECKMULTISIG` in `scriptSig`. We begin with a `scriptCode` which is exactly `scriptSig`, and since a `CODESEPARATOR` is executed, `subScript` becomes :

```
1 0x21 0x0232abdc893e7f0631364d7fd01cb33d24da45329a00357b3a7886211ab414d55a 1 CHECKMULTISIG

```

Now consider how software from `v0.3.6` and below would construct the `subScript` for the same `CHECKMULTISIG`. Our `scriptCode` is no longer made from only `scriptSig`, but from a joining of it and `scriptPubKey` by a `CODESEPARATOR`. The `scriptCode` would look like :

```
0 0x47 0x30440220276d6dad3defa37b5f81add3992d510d2f44a317fd85e04f93a1e2daea64660202200f862a0da684249322ceb8ed842fb8c859c0cb94c81e1c5308b4868157a428ee01 CODESEPARATOR 1 0x21 0x0232abdc893e7f0631364d7fd01cb33d24da45329a00357b3a7886211ab414d55a 1 CHECKMULTISIG CODESEPARATOR 0x14 0x2a9bc5447d664c1d0141392a842d23dba45c4f13 NOP2 DROP

```

Recall the rules from the wiki. At the point when `CHECKMULTISIG` is executed, `subScript` is everything from the point after the last executed `CODESEPARATOR` and until the end of the script, with all `CODESEPARATOR`s on the right hand side of the checksig operator removed :

```
1 0x21 0x0232abdc893e7f0631364d7fd01cb33d24da45329a00357b3a7886211ab414d55a 1 CHECKMULTISIG 0x14 0x2a9bc5447d664c1d0141392a842d23dba45c4f13 NOP2 DROP

```

If this is correct, then it appears that old nodes with versions `v0.3.6` and below cannot agree on which is the correct `sighash` for this spending transaction, but since I can't realistically run any such old version software, I can't be absolutely sure. I did patch a recent bitcoin core version with some changes that enabled me to simulate validation of tx `eb3b82c0884e3efa6d8b0be55b4915eb20be124c9766245bcc7f34fdac32bccb`, and as expected it did not pass validation. I will add the two sighashes below along with the public key and signature for comparison.

**So my question is**, is there something I'm misunderstanding or perhaps missed that would allow pre-`v0.3.7` and post-`v0.3.7` nodes to come to consensus about the validity of block 163685?

(also relevant : [this SE question](https://bitcoin.stackexchange.com/q/79797/64730))

---

```
Pubkey : 0232abdc893e7f0631364d7fd01cb33d24da45329a00357b3a7886211ab414d55a
Signature (DER) : 30440220276d6dad3defa37b5f81add3992d510d2f44a317fd85e04f93a1e2daea64660202200f862a0da684249322ceb8ed842fb8c859c0cb94c81e1c5308b4868157a428ee
Signature (r,s) : (276D6DAD3DEFA37B5F81ADD3992D510D2F44A317FD85E04F93A1E2DAEA646602, F862A0DA684249322CEB8ED842FB8C859C0CB94C81E1C5308B4868157A428EE)

```

Pre-`v0.3.7` sighash (does not validate) :

```
01000000
02
4de8b0c4c2582db95fa6b3567a989b664484c7ad6672c85a3da413773e63fdb8 00000000
00
FFFFFFFF
4de8b0c4c2582db95fa6b3567a989b664484c7ad6672c85a3da413773e63fdb8 01000000
3C 51210232abdc893e7f0631364d7fd01cb33d24da45329a00357b3a7886211ab414d55a51ae142a9bc5447d664c1d0141392a842d23dba45c4f13b175
FFFFFFFF
02
E0FD1C0000000000 19 76a914380cb3c594de4e7e9b8e18db182987bebb5a4f7088ac
C0C62D0000000000 17 142a9bc5447d664c1d0141392a842d23dba45c4f13b175
00000000
01000000

sha256  : 1EB276326D72CB358F6C275D6542F76EED4E36364727CB82D40A116244EBDDB5
sha256d : 11491E74778E1FA8C40CC8E07E1F835677CF1AC81F54255EC1C7125C1894939A

```

Post-`v0.3.7` sighash (does validate) :

```
01000000
02
4de8b0c4c2582db95fa6b3567a989b664484c7ad6672c85a3da413773e63fdb8 00000000
00
FFFFFFFF
4de8b0c4c2582db95fa6b3567a989b664484c7ad6672c85a3da413773e63fdb8 01000000
25 51210232abdc893e7f0631364d7fd01cb33d24da45329a00357b3a7886211ab414d55a51ae
FFFFFFFF
02
E0FD1C0000000000 19 76a914380cb3c594de4e7e9b8e18db182987bebb5a4f7088ac
C0C62D0000000000 17 142a9bc5447d664c1d0141392a842d23dba45c4f13b175
00000000
01000000

sha256  : 3858A592C15A47F3058010689883DECCD4AF41F5367B9776429613DFB3339883
sha256d : 8D7AD159644D312664472F90E7B823071B1361725CAC78531569FD836EA90350

```

**Tags:** script, consensus, validation, opcodes

> **Comments:**
> **username_1**: I believe you are correct. This is a good example of why changes to anything related to consensus need to be examined very carefully in order to not introduce any consensus incompatible changes.  
> **username_0**: Thanks for reading through it.  It's very much appreciated.  
> **username_2**: Very good exploration! Good job!  

---

## 1 answers

### Answer by username_3 on 2020-05-18. Score: 3

Almost all commits to the client prior to the commits that you have called out here were hard forks to due the inclusion of `OP_VER` and `OP_VERIF`, even if the change to the client wasn't otherwise an incompatible change.

```
        case OP_VER:
        {
            CBigNum bn(VERSION);
            stack.push_back(bn.getvch());
        }
        break;

```

Quite simply, the opcode pushes `VERSION` onto the stack, which is the version number of the code being used to validate. This number was updated with every release, so no two versions prior to its removal are actually compatible with one another.

There's several others which you have not mentioned, such as that `nLockTime` was changed to an unsigned variable with a height based hard fork, some minor changes to the implementations of the opcodes, and the removal of double byte opcodes. It's very difficult to enumerate which of these versions are actually compatible with each other as a result of the huge number of changes, and the poor tooling we have which is compatible with these ancient versions.


---

