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 and this 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.)