<p>At the present time the Script for a &quot;received HTLC output&quot;, that is for an HTLC that is paying us materialized as an output in our own commitment transaction, is (comments mine):</p>
<pre><code># Is it the hash of the revocation public key that we are presented?
OP_DUP OP_HASH160 &lt;RIPEMD160(SHA256(revocationpubkey))&gt; OP_EQUAL
OP_IF
    # If so, anyone that can provide a signature for it can spend this coin.
    OP_CHECKSIG
OP_ELSE
    # Otherwise, are we presented a 32-bytes long bytestring?
    &lt;remote_htlcpubkey&gt; OP_SWAP OP_SIZE 32 OP_EQUAL
    OP_IF
        # If so, we assume this is the payment hash preimage.
        # It must hash through ripemd160(sha256()) to the ripemd160() of the payment hash (because the payment hash is itself the sha256() of the payment preimage).
        OP_HASH160 &lt;RIPEMD160(payment_hash)&gt; OP_EQUALVERIFY
        # Now the payment preimage is valid verify we've got a signature from both the local and the remote node to spend this coin.
        2 OP_SWAP &lt;local_htlcpubkey&gt; 2 OP_CHECKMULTISIG
    OP_ELSE
        # Otherwise, we assume this is the timeout path.
        # We must not be able to spend through this path before `cltv_expiry` blocks.
        OP_DROP &lt;cltv_expiry&gt; OP_CHECKLOCKTIMEVERIFY OP_DROP
        # A signature against the remote HTLC pubkey is enough to spend after the timelock.
        OP_CHECKSIG
    OP_ENDIF
OP_ENDIF
</code></pre>
<p><em>(I omitted <code>option_anchor_outputs</code> for simplicity and since it doesn't matter for this question.)</em></p>
<p>If this output ends up onchain and we know the <code>sha256()</code> preimage of <code>payment_hash</code>, we can spend it using the corresponding HTLC-success transaction. We also cannot spend it another way, to make sure the revocation delay is enforced (see <a href="https://bitcoin.stackexchange.com/a/97225/101498">this</a> and <a href="https://bitcoin.stackexchange.com/a/95543/101498">this</a> answers for more about 2-stage HTLCs).</p>
<p>Here is the detailed script execution when spending using the HTLC-success transaction:</p>
<ul>
<li>Initial stack: <code>0 &lt;remotehtlcsig&gt; &lt;localhtlcsig&gt;  &lt;payment_preimage&gt;</code></li>
<li>Executing <code>OP_DUP</code>. Resulting stack: <code>0 &lt;remotehtlcsig&gt; &lt;localhtlcsig&gt;  &lt;payment_preimage&gt; &lt;payment_preimage&gt;</code>.</li>
<li>Executing <code>OP_HASH160 &lt;RIPEMD160(SHA256(revocationpubkey))&gt; OP_EQUAL</code>. Resulting stack: <code>0 &lt;remotehtlcsig&gt; &lt;localhtlcsig&gt; &lt;payment_preimage&gt; 0</code>.</li>
<li>Executing <code>OP_HASH160 &lt;RIPEMD160(SHA256(revocationpubkey))&gt; OP_EQUAL</code>. Resulting stack: <code>0 &lt;remotehtlcsig&gt; &lt;localhtlcsig&gt; &lt;payment_preimage&gt; 0</code>.</li>
<li>Executing <code>OP_IF</code>, we &quot;jump&quot; in the <code>ELSE</code> branch of the conditional. Resulting stack: <code>0 &lt;remotehtlcsig&gt; &lt;localhtlcsig&gt; &lt;payment_preimage&gt;</code>.</li>
<li>Executing <code>&lt;remote_htlcpubkey&gt; OP_SWAP</code>. Resulting stack: <code>0 &lt;remotehtlcsig&gt; &lt;localhtlcsig&gt; &lt;remote_htlcpubkey&gt; &lt;payment_preimage&gt;</code>.</li>
<li>Executing <code>OP_SIZE 32 OP_EQUAL</code>. Resulting stack (since <code>payment_preimage</code> is 32 bytes long): <code>0 &lt;remotehtlcsig&gt; &lt;localhtlcsig&gt; &lt;remote_htlcpubkey&gt; &lt;payment_preimage&gt; 1</code>.</li>
<li>Executing <code>OP_IF</code>, we &quot;jump&quot; in the first branch of the conditional. Resulting stack: <code>0 &lt;remotehtlcsig&gt; &lt;localhtlcsig&gt; &lt;remote_htlcpubkey&gt; &lt;payment_preimage&gt;</code>.</li>
<li>Executing <code>OP_HASH160 &lt;RIPEMD160(payment_hash)&gt; OP_EQUALVERIFY</code>. Resulting stack: <code>0 &lt;remotehtlcsig&gt; &lt;localhtlcsig&gt; &lt;remote_htlcpubkey&gt;</code>.</li>
<li>Executing <code>2 OP_SWAP &lt;local_htlcpubkey&gt; 2</code>. Resulting stack: <code>0 &lt;remotehtlcsig&gt; &lt;localhtlcsig&gt; 2 &lt;remote_htlcpubkey&gt; &lt;local_htlcpubkey&gt; 2</code>.</li>
<li>Executing <code>OP_CHECKMULTISIG</code>. Resulting stack: <code>1</code>. (Do keep in mind the <code>CHECKMULTISIG</code> bug that makes it consume one-too-many elements on the stack.)</li>
</ul>

CC BY-SA 4.0
2023-02-27T14:53:01.250Z
Thank you! I see. I had overlooked the fact that the second-stage HTLC success transactions are for "received HTLC outputs" while the second-stage HTLC timeout transactions are for "offered HTLC outputs".
matthias
CC BY-SA 4.0
2023-02-27T14:55:32.197Z
You're welcome. I've added comments to the Script as well to (hopefully!) give more clarity about what it's doing.
Antoine Poinsot
CC BY-SA 4.0
2023-02-27T14:47:54.510Z
2023-02-27T15:21:27.533Z
2023-02-27T15:21:27.533Z
Antoine Poinsot
<p>BOLT #3 <a href="https://github.com/lightning/bolts/blob/master/03-transactions.md#htlc-timeout-and-htlc-success-transactions" rel="nofollow noreferrer">specifies</a> that an HTLC success transaction (the second-stage transaction that spends an HTLC by providing the preimage) has the witness script <code>0 &lt;remotehtlcsig&gt; &lt;localhtlcsig&gt;  &lt;payment_preimage&gt;</code>.
<a href="https://bitcoin.stackexchange.com/questions/92087/can-someone-explain-how-an-htlc-is-redeemed">This question</a> and the respective answers assume that the input script of the HTLC success transaction is <code>&lt;remotehtlcsig&gt; &lt;payment_preimage&gt;</code>. The answers explain in detail how the scripts are executed.</p>
<p>As <a href="https://github.com/ElementsProject/lightning/blob/master/bitcoin/script.c#L805" rel="nofollow noreferrer">implementations seem</a> to implement the script according to the specification, I wonder how the script is actually executed. How does the script execution work if there is the additional <code>localhtlcsig</code>? Is the <code>localhtlcsig</code> dropped from the stack at some point during the execution?</p>

<lightning-network><script><hash-time-locked-contract>
Script for Success of HTLC in the Lightning Network
matthias
# Script for Success of HTLC in the Lightning Network

(Asked by: username_0 on 2023-02-24)

BOLT #3 [specifies](https://github.com/lightning/bolts/blob/master/03-transactions.md#htlc-timeout-and-htlc-success-transactions) that an HTLC success transaction (the second-stage transaction that spends an HTLC by providing the preimage) has the witness script `0 <remotehtlcsig> <localhtlcsig> <payment_preimage>`.
[This question](https://bitcoin.stackexchange.com/questions/92087/can-someone-explain-how-an-htlc-is-redeemed) and the respective answers assume that the input script of the HTLC success transaction is `<remotehtlcsig> <payment_preimage>`. The answers explain in detail how the scripts are executed.

As [implementations seem](https://github.com/ElementsProject/lightning/blob/master/bitcoin/script.c#L805) to implement the script according to the specification, I wonder how the script is actually executed. How does the script execution work if there is the additional `localhtlcsig`? Is the `localhtlcsig` dropped from the stack at some point during the execution?

**Tags:** lightning-network, script, hash-time-locked-contract


---

## 1 answers

### Answer by username_1 on 2023-02-27. Score: 2 | Accepted answer

At the present time the Script for a "received HTLC output", that is for an HTLC that is paying us materialized as an output in our own commitment transaction, is (comments mine):

```
# Is it the hash of the revocation public key that we are presented?
OP_DUP OP_HASH160 <RIPEMD160(SHA256(revocationpubkey))> OP_EQUAL
OP_IF
    # If so, anyone that can provide a signature for it can spend this coin.
    OP_CHECKSIG
OP_ELSE
    # Otherwise, are we presented a 32-bytes long bytestring?
    <remote_htlcpubkey> OP_SWAP OP_SIZE 32 OP_EQUAL
    OP_IF
        # If so, we assume this is the payment hash preimage.
        # It must hash through ripemd160(sha256()) to the ripemd160() of the payment hash (because the payment hash is itself the sha256() of the payment preimage).
        OP_HASH160 <RIPEMD160(payment_hash)> OP_EQUALVERIFY
        # Now the payment preimage is valid verify we've got a signature from both the local and the remote node to spend this coin.
        2 OP_SWAP <local_htlcpubkey> 2 OP_CHECKMULTISIG
    OP_ELSE
        # Otherwise, we assume this is the timeout path.
        # We must not be able to spend through this path before `cltv_expiry` blocks.
        OP_DROP <cltv_expiry> OP_CHECKLOCKTIMEVERIFY OP_DROP
        # A signature against the remote HTLC pubkey is enough to spend after the timelock.
        OP_CHECKSIG
    OP_ENDIF
OP_ENDIF

```

*(I omitted `option_anchor_outputs` for simplicity and since it doesn't matter for this question.)*

If this output ends up onchain and we know the `sha256()` preimage of `payment_hash`, we can spend it using the corresponding HTLC-success transaction. We also cannot spend it another way, to make sure the revocation delay is enforced (see [this](https://bitcoin.stackexchange.com/a/97225/101498) and [this](https://bitcoin.stackexchange.com/a/95543/101498) answers for more about 2-stage HTLCs).

Here is the detailed script execution when spending using the HTLC-success transaction:

* Initial stack: `0 <remotehtlcsig> <localhtlcsig> <payment_preimage>`
* Executing `OP_DUP`. Resulting stack: `0 <remotehtlcsig> <localhtlcsig> <payment_preimage> <payment_preimage>`.
* Executing `OP_HASH160 <RIPEMD160(SHA256(revocationpubkey))> OP_EQUAL`. Resulting stack: `0 <remotehtlcsig> <localhtlcsig> <payment_preimage> 0`.
* Executing `OP_HASH160 <RIPEMD160(SHA256(revocationpubkey))> OP_EQUAL`. Resulting stack: `0 <remotehtlcsig> <localhtlcsig> <payment_preimage> 0`.
* Executing `OP_IF`, we "jump" in the `ELSE` branch of the conditional. Resulting stack: `0 <remotehtlcsig> <localhtlcsig> <payment_preimage>`.
* Executing `<remote_htlcpubkey> OP_SWAP`. Resulting stack: `0 <remotehtlcsig> <localhtlcsig> <remote_htlcpubkey> <payment_preimage>`.
* Executing `OP_SIZE 32 OP_EQUAL`. Resulting stack (since `payment_preimage` is 32 bytes long): `0 <remotehtlcsig> <localhtlcsig> <remote_htlcpubkey> <payment_preimage> 1`.
* Executing `OP_IF`, we "jump" in the first branch of the conditional. Resulting stack: `0 <remotehtlcsig> <localhtlcsig> <remote_htlcpubkey> <payment_preimage>`.
* Executing `OP_HASH160 <RIPEMD160(payment_hash)> OP_EQUALVERIFY`. Resulting stack: `0 <remotehtlcsig> <localhtlcsig> <remote_htlcpubkey>`.
* Executing `2 OP_SWAP <local_htlcpubkey> 2`. Resulting stack: `0 <remotehtlcsig> <localhtlcsig> 2 <remote_htlcpubkey> <local_htlcpubkey> 2`.
* Executing `OP_CHECKMULTISIG`. Resulting stack: `1`. (Do keep in mind the `CHECKMULTISIG` bug that makes it consume one-too-many elements on the stack.)

> **Comments:**
> **username_0**: Thank you! I see. I had overlooked the fact that the second-stage HTLC success transactions are for "received HTLC outputs" while the second-stage HTLC timeout transactions are for "offered HTLC outputs".  
> **username_1**: You're welcome. I've added comments to the Script as well to (hopefully!) give more clarity about what it's doing.  

---

