<h2>Inner working of conditionals in Bitcoin Script</h2>
<p>The conditionals in Bitcoin Script are conceptually implemented using a stack of booleans, each boolean indicating whether to execute the current opcode when iterating through the Script for each depth of the conditional (nested IF / ELSE).</p>
<p>To grasp the functioning, let's first consider a single-boolean conditioned execution of opcodes. The interpreter will iterate through the Script by setting the boolean to <code>true</code> (do execute ops) at the beginning. When encountering an <code>IF</code> it will set the boolean to the value of the pushed data preceding the <code>IF</code>, casted to a boolean (<code>CastToBool</code> in the reference implementation).<br />
If this was <code>true</code> it will continue the execution of the following opcodes, effectively executing &quot;the <code>if {}</code> branch&quot;.<br />
If it was <code>false</code>, it will suspend execution until .... It encounters an <code>ELSE</code>! Encountering an <code>ELSE</code> will toggle the global boolean suspending execution. If it was previously <code>false</code>, it will become <code>true</code> and effectively execute &quot;the <code>else {}</code> branch&quot;.  To the contrary if it was <code>true</code>, it will become <code>false</code> and suspend execution of &quot;the <code>else {}</code> branch&quot;.</p>
<p>With a bit of ASCII art (<code>fExec</code> is the global boolean telling whether to actually execute the OPs):</p>
<pre><code>Value of fExec:  true    true      true         true  true    true         false      false            ???

Script        : |start| OP_BLABLA OP_DOSOMETHING &lt;1&gt; OP_IF OP_DOSOMESTUFF OP_ELSE OP_DOANOTHERSTUFF OP_ENDIF
</code></pre>
<pre><code>Value of fExec:  true    true      true         true  false    false       true      true             ???

Script        : |start| OP_BLABLA OP_DOSOMETHING &lt;0&gt; OP_IF OP_DOSOMESTUFF OP_ELSE OP_DOANOTHERSTUFF OP_ENDIF
</code></pre>
<p>Note how i marked the value of <code>fExec</code> as <code>???</code> when encountering <code>OP_ENDIF</code>. That's because the real implementation is slightly more complicated: in order to support nested conditionals, this is not a single boolean but a vector of booleans that are used to determine execution. That is:</p>
<ul>
<li><code>OP_IF</code> will push a new boolean to the vector</li>
<li><code>OP_ELSE</code> will toggle the last boolean of the vector</li>
<li><code>OP_ENDIF</code> will pop the last element of the vector</li>
</ul>
<h2>Going further</h2>
<h3>Multiple <code>ELSE</code> for a single <code>IF</code></h3>
<p>Note that the implementation of the <code>ELSE</code> being a single toggle it means that nothing prevents to toggle two times in a row. That is, you can have many following <code>ELSE</code> opcodes before the <code>ENDIF</code>. Two following <code>ELSE</code>s would effectively toggle the last boolean twice, hence executing the following opcodes as it would for &quot;the <code>if {}</code> branch&quot;.</p>
<p>Therefore in the example from your question:</p>
<pre><code>OP_IF &lt;foo&gt; OP_ELSE &lt;bar&gt; OP_ELSE &lt;baz&gt; OP_ENDIF
</code></pre>
<p>That's indeed <code>&lt;foo&gt;</code> and <code>&lt;baz&gt;</code> that will be executed.</p>
<h3>Quadratic behaviour when computing <code>fExec</code> from the vector of booleans</h3>
<p>The implementation of the conditional logic was <a href="https://github.com/bitcoin/bitcoin/pull/16902" rel="nofollow noreferrer">modified in 2020 by Pieter Wuille</a> to fix a <a href="https://bitslog.com/2017/04/17/new-quadratic-delays-in-bitcoin-scripts/" rel="nofollow noreferrer">quadratic behaviour found by Segio Demian Lerner</a>.<br />
Therefore the actual implementation does not actually use a stack for the booleans anymore, rather it stores the &quot;top boolean&quot; in a dedicated data structure imitating the previous implementation.</p>
<h3>Slightly related Tapscript rule</h3>
<p>The proposed new addition to the Script rules as part of the proposed Taproot soft fork <a href="https://github.com/bitcoin/bips/blob/master/bip-0342.mediawiki#cite_ref-10-0" rel="nofollow noreferrer">(Tapscript) lifts the limit of <code>201</code> OP codes</a>. This was made possible by the elimination of the aforementioned quadratic behaviour.</p>

CC BY-SA 4.0
2021-04-19T17:08:35.837Z
IIUC, the behavior of multiple `OP_ELSE` for a single `OP_IF` is indeed the "redundant" one described in the question, correct? And there is no `OP_ELSEIF` equivalent?
orfeas
CC BY-SA 4.0
2021-04-19T17:34:04.133Z
Yes, i edited the answer to precisely answer your example :)
Antoine Poinsot
CC BY-SA 4.0
2021-04-18T15:12:17.657Z
2021-04-19T17:33:34.270Z
2021-04-19T17:33:34.270Z
Antoine Poinsot
<p>How does <code>OP_ELSE</code> work exactly? Is there an <code>else if</code> in Script?</p>
<hr />
<p>According to <a href="https://en.bitcoin.it/wiki/Script#Flow_control" rel="noreferrer">https://en.bitcoin.it/wiki/Script#Flow_control</a>, the statements after an <code>OP_ELSE</code> are executed in three cases. It says:</p>
<blockquote>
<p>If the preceding OP_IF or OP_NOTIF or OP_ELSE was not executed then these statements are.</p>
</blockquote>
<p>I'd like to understand how the 3rd case works, i.e. when there's a preceding <code>OP_ELSE</code> that is not followed. Consider this script and a <code>True</code> at the top of the stack:</p>
<pre><code>OP_IF
    &lt;foo&gt;
OP_ELSE
    &lt;bar&gt;
OP_ELSE
    &lt;baz&gt;
OP_ENDIF
</code></pre>
<p>If we follow the explanation of the quote to the letter, then that means that <code>&lt;foo&gt;</code> and <code>&lt;baz&gt;</code> are executed. This however is quite counter-intuitive. If this is the case, then the second <code>OP_ELSE</code> is redundant, as <code>&lt;baz&gt;</code> can simply go after <code>&lt;foo&gt;</code> to the same effect and with less opcodes.</p>
<p>Is there some other interpretation I'm missing?</p>
<p>I stumbled upon this detail while trying to write a script with 3 different branches, something like</p>
<pre><code>OP_IF top stack item is 0
    &lt;foo&gt;
OP_ELSEIF top stack item is 1
   &lt;bar&gt;
OP_ELSE
   &lt;baz&gt;
OP_ENDIF
</code></pre>
<p>I know the above isn't valid Script, but can something to this effect be achieved without resorting to the following?</p>
<pre><code>OP_IF
    &lt;foo&gt;
OP_ELSE
    OP_IF
        &lt;bar&gt;
    OP_ELSE
        &lt;baz&gt;
    OP_ENDIF
OP_ENDIF
</code></pre>
<p>Note that this is more expensive not only because it has more opcodes, but because two stack items are needed in the witness in order to execute <code>&lt;bar&gt;</code> or <code>&lt;baz&gt;</code>.</p>

<script><transaction-verification><opcodes>
Inner working of OP_IF and OP_ELSE
orfeas
# Inner working of OP_IF and OP_ELSE

(Asked by: username_0 on 2021-03-25)

How does `OP_ELSE` work exactly? Is there an `else if` in Script?

---

According to <https://en.bitcoin.it/wiki/Script#Flow_control>, the statements after an `OP_ELSE` are executed in three cases. It says:

> If the preceding OP\_IF or OP\_NOTIF or OP\_ELSE was not executed then these statements are.

I'd like to understand how the 3rd case works, i.e. when there's a preceding `OP_ELSE` that is not followed. Consider this script and a `True` at the top of the stack:

```
OP_IF
    <foo>
OP_ELSE
    <bar>
OP_ELSE
    <baz>
OP_ENDIF

```

If we follow the explanation of the quote to the letter, then that means that `<foo>` and `<baz>` are executed. This however is quite counter-intuitive. If this is the case, then the second `OP_ELSE` is redundant, as `<baz>` can simply go after `<foo>` to the same effect and with less opcodes.

Is there some other interpretation I'm missing?

I stumbled upon this detail while trying to write a script with 3 different branches, something like

```
OP_IF top stack item is 0
    <foo>
OP_ELSEIF top stack item is 1
   <bar>
OP_ELSE
   <baz>
OP_ENDIF

```

I know the above isn't valid Script, but can something to this effect be achieved without resorting to the following?

```
OP_IF
    <foo>
OP_ELSE
    OP_IF
        <bar>
    OP_ELSE
        <baz>
    OP_ENDIF
OP_ENDIF

```

Note that this is more expensive not only because it has more opcodes, but because two stack items are needed in the witness in order to execute `<bar>` or `<baz>`.

**Tags:** script, transaction-verification, opcodes


---

## 1 answers

### Answer by username_1 on 2021-04-18. Score: 5 | Accepted answer

## Inner working of conditionals in Bitcoin Script

The conditionals in Bitcoin Script are conceptually implemented using a stack of booleans, each boolean indicating whether to execute the current opcode when iterating through the Script for each depth of the conditional (nested IF / ELSE).

To grasp the functioning, let's first consider a single-boolean conditioned execution of opcodes. The interpreter will iterate through the Script by setting the boolean to `true` (do execute ops) at the beginning. When encountering an `IF` it will set the boolean to the value of the pushed data preceding the `IF`, casted to a boolean (`CastToBool` in the reference implementation).  
If this was `true` it will continue the execution of the following opcodes, effectively executing "the `if {}` branch".  
If it was `false`, it will suspend execution until .... It encounters an `ELSE`! Encountering an `ELSE` will toggle the global boolean suspending execution. If it was previously `false`, it will become `true` and effectively execute "the `else {}` branch". To the contrary if it was `true`, it will become `false` and suspend execution of "the `else {}` branch".

With a bit of ASCII art (`fExec` is the global boolean telling whether to actually execute the OPs):

```
Value of fExec:  true    true      true         true  true    true         false      false            ???

Script        : |start| OP_BLABLA OP_DOSOMETHING <1> OP_IF OP_DOSOMESTUFF OP_ELSE OP_DOANOTHERSTUFF OP_ENDIF

```

```
Value of fExec:  true    true      true         true  false    false       true      true             ???

Script        : |start| OP_BLABLA OP_DOSOMETHING <0> OP_IF OP_DOSOMESTUFF OP_ELSE OP_DOANOTHERSTUFF OP_ENDIF

```

Note how i marked the value of `fExec` as `???` when encountering `OP_ENDIF`. That's because the real implementation is slightly more complicated: in order to support nested conditionals, this is not a single boolean but a vector of booleans that are used to determine execution. That is:

* `OP_IF` will push a new boolean to the vector
* `OP_ELSE` will toggle the last boolean of the vector
* `OP_ENDIF` will pop the last element of the vector

## Going further

### Multiple `ELSE` for a single `IF`

Note that the implementation of the `ELSE` being a single toggle it means that nothing prevents to toggle two times in a row. That is, you can have many following `ELSE` opcodes before the `ENDIF`. Two following `ELSE`s would effectively toggle the last boolean twice, hence executing the following opcodes as it would for "the `if {}` branch".

Therefore in the example from your question:

```
OP_IF <foo> OP_ELSE <bar> OP_ELSE <baz> OP_ENDIF

```

That's indeed `<foo>` and `<baz>` that will be executed.

### Quadratic behaviour when computing `fExec` from the vector of booleans

The implementation of the conditional logic was [modified in 2020 by Pieter Wuille](https://github.com/bitcoin/bitcoin/pull/16902) to fix a [quadratic behaviour found by Segio Demian Lerner](https://bitslog.com/2017/04/17/new-quadratic-delays-in-bitcoin-scripts/).  
Therefore the actual implementation does not actually use a stack for the booleans anymore, rather it stores the "top boolean" in a dedicated data structure imitating the previous implementation.

### Slightly related Tapscript rule

The proposed new addition to the Script rules as part of the proposed Taproot soft fork [(Tapscript) lifts the limit of `201` OP codes](https://github.com/bitcoin/bips/blob/master/bip-0342.mediawiki#cite_ref-10-0). This was made possible by the elimination of the aforementioned quadratic behaviour.

> **Comments:**
> **username_0**: IIUC, the behavior of multiple `OP_ELSE` for a single `OP_IF` is indeed the "redundant" one described in the question, correct? And there is no `OP_ELSEIF` equivalent?  
> **username_1**: Yes, i edited the answer to precisely answer your example :)  

---

