New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Terminology: commitment vs HTLC #553

Closed
s-tikhomirov opened this Issue Jan 18, 2019 · 13 comments

Comments

Projects
None yet
5 participants
@s-tikhomirov
Copy link

s-tikhomirov commented Jan 18, 2019

As far as I understood the Lightning design as per the original paper, there are three types of transactions on the life of a channel: the funding (opening) tx, many commitment txs, and the closing tx. Reading this spec, I'm confused about the terms "commitment" and "HTLC".

From the glossary:

Commitment transaction: A transaction that spends the funding transaction. <...>

So far so good.

HTLC: Hashed Time Locked Contract.
A conditional payment between two peers: the recipient can spend the payment by presenting its signature and a payment preimage, otherwise the payer can cancel the contract by spending it after a given time. These are implemented as outputs from the commitment transaction.
See container: commitment transaction
See parts: Payment hash, Payment preimage

What exactly is a payment? From the fact that a commitment transaction is a container of HTLC, I concluded that the HTLC is a Bitcoin script which defines the conditions under which UTXOs of the commitment transaction can be spent. But then in BOLT 2 I read:

dust_limit_satoshis is the threshold below which outputs should not be generated for this node's commitment or HTLC transactions

Another example:

feerate_per_kw indicates the initial fee rate <...> that this side will pay for commitment and HTLC transactions

The wording suggests that commitment transactions and HTLC transactions are different things. Are they?

@pm47

This comment has been minimized.

Copy link
Collaborator

pm47 commented Jan 18, 2019

The wording suggests that commitment transactions and HTLC transactions are different things. Are they?

Yes they are. Here is the current commitment scheme (it differs from the one originally proposed in the paper):

+------------+
| funding tx |
+------------+
      |
      |        +-------------+
      \--------| commit tx B |
               +-------------+
                  |  |  |  |  
                  |  |  |  | A's main output
                  |  |  |  \------------------ to A
                  |  |  |
                  |  |  |
                  |  |  |                  ,-- to B (& delay)
                  |  |  | B's main output /
                  |  |  \----------------<
                  |  |                    \ 
                  |  |                     `-- to A (& revocation key)
                  |  |
                  |  |                                                ,-- to B (& delay)
                  |  |                        +-----------------+    /
                  |  |                     ,--| HTLC-timeout tx |---<
                  |  | HTLC offered by B  /   +-----------------+    \
                  |  \-------------------<     (after timeout)        `-- to A (& revocation key)
                  |                       \
                  |                        `-- to A (& payment preimage)
                  |                        \
                  |                         `- to A (& revocation key)
                  |                   
                  |                                                   ,-- to B (& delay)
                  |                           +-----------------+    /
                  |                        ,--| HTLC-success tx |---<
                  | HTLC received by B    /   +-----------------+    \
                  \----------------------<     (w/ payment preimage)  `-- to A (& revocation key)
                                          \
                                           `-- to A (after timeout)
                                           \
                                            `- to A (& revocation key)
@s-tikhomirov

This comment has been minimized.

Copy link
Author

s-tikhomirov commented Jan 18, 2019

@pm47 Thanks a lot! This scheme would be really helpful somewhere early in the spec, wouldn't it? Especially for people coming from the original paper and not realizing yet that the implementation is substantially different.

So would it be correct to define a HTLC as a Bitcoin script which determines the rules for spending some of the UTXOs of a commitment transaction? (While others -- the top two in the scheme -- are using different kind of scripts)

UPD So how many outputs does a commitment transaction have? I supposed it had two ("main outputs"), with the sum equal to the channel capacity. Then what do arrows to HTLCs ("HTLC offered by B", "HTLC received by B") represent?

@pm47

This comment has been minimized.

Copy link
Collaborator

pm47 commented Jan 19, 2019

So would it be correct to define a HTLC as a Bitcoin script which determines the rules for spending some of the UTXOs of a commitment transaction?

I guess you could say that, but that's not a definition IMO, more a description of how it is currently implemented. I think BOLT 0 does a pretty good job at defining HTLCs.

How many outputs does a commitment transaction have? I supposed it had two ("main outputs"), with the sum equal to the channel capacity.

You are right, if both parties have a non-dust balance and there are no pending payments, indeed there will be two outputs.

When an A->B payment is initiated, a corresponding output will be added in the commitment, with the amount being subtracted from the sender's main output. Then if the payment succeeds, B will present a payment_preimage to A, thus proving that it could pull the funds from the output, and parties will agree to make a new commitment were the HTLC output is removed and its amount added to B's main output. This "dance" is covered in BOLT 2 Normal Operations.

Then what do arrows to HTLCs ("HTLC offered by B", "HTLC received by B") represent?

Those are payments currently being sent or received by B. Each of them will have an output (provided the amount is above dust).

I think what you may be missing is that, at all time, there are two "symmetrical" commitments, one for each side of the channel. In my above example, when the payment was pending, A's commitment had one "offered HTLC output", and B's commitment has one "received HTLC output".

@s-tikhomirov

This comment has been minimized.

Copy link
Author

s-tikhomirov commented Jan 20, 2019

The symmetrical nature of the channel is clear to me, what is not so clear is the semantics of the word "payment" and how it maps to actual scripts, UTXOs, and transactions.

a corresponding output will be added in the commitment, with the amount being subtracted from the sender's main output

I don't quite understand the meaning of "added" here.

Consider a newly established channel between Alice and Bob. Say, Alice funded the channel with 1 BTC, and 0.1 BTC goes to Bob initially. Each of them has their own version of the initial commitment transaction, each with two outputs: 0.9 to Alice, 0.1 to Bob (modulo delays / revocations, that part is clear).

Imagine Alice wants to send 0.2 BTC to Bob. Is the following the correct description of what happens?

"A new pair of commitment transactions is created, each of them now with three outputs: 0.7 to Alice [was: 0.9], 0.1 to Bob [as before], and 0.2 in an HTLC."

What confuses me is the lack of clear separation of the two processes:

  1. payments between Alice and Bob in an isolated channel;
  2. somebody else's payments being routed through the channel between Alice and Bob.

Are HTLCs used in both of these processes, or only the second one?

@pm47

This comment has been minimized.

Copy link
Collaborator

pm47 commented Jan 20, 2019

Imagine Alice wants to send 0.2 BTC to Bob. Is the following the correct description of what happens?

"A new pair of commitment transactions is created, each of them now with three outputs: 0.7 to Alice [was: 0.9], 0.1 to Bob [as before], and 0.2 in an HTLC."

Yes that's correct

What confuses me is the lack of clear separation of the two processes:

  1. payments between Alice and Bob in an isolated channel;
  2. somebody else's payments being routed through the channel between Alice and Bob.

Are HTLCs used in both of these processes, or only the second one?

HTLCs are used in both, and you won't find a separation because there is none. As far as the channel Alice-Bob is concerned, there is really no difference between those two payments. The only difference is that in case 1. Bob will fetch the payment_preimage from some kind of local database, and in case 2. Bob will eventually get the payment_preimage from a downstream channel. But this happens outside the scope of the channel.

@s-tikhomirov

This comment has been minimized.

Copy link
Author

s-tikhomirov commented Jan 20, 2019

HTLCs are used in both, and you won't find a separation because there is none

The whole picture is much clearer for me now!

But Alice and Bob could just re-negotiate 2-output commitment transactions with new balances between each other, if the payment only concerns them, right? Does BOLT-Lightning do all payments using the same HTLC construction for the sake of uniformity?

Bob will fetch the payment_preimage from some kind of local database

So to receive a payment Bob must tell Alice the hash value that he knows a preimage of? Is this what invoices are about?

(I realize that this discussion has transitioned into some kind of general Q&A. Feel free to close the issue if you feel it's off topic. I greatly appreciate your answers and hope that clarifying the questions I have may reveal not-so-clear parts of the spec and help improve it for easier understanding by the future readers.)

@pm47 pm47 added the question label Jan 21, 2019

@pm47

This comment has been minimized.

Copy link
Collaborator

pm47 commented Jan 21, 2019

But Alice and Bob could just re-negotiate 2-output commitment transactions with new balances between each other, if the payment only concerns them, right?

How do you suggest we do that? (that's a trick question ;-)

Does BOLT-Lightning do all payments using the same HTLC construction for the sake of uniformity?

Why would we want to make things more complicated? And consider the privacy implications: with this construct, intermediate nodes don't know if the next node in the route is the last one.

I realize that this discussion has transitioned into some kind of general Q&A.

Yes, let's close this, I'll keep answering if you have more questions on the topic. Also feel free to submit a PR to BOLT 3 with the commitment scheme.

@pm47 pm47 closed this Jan 21, 2019

@s-tikhomirov

This comment has been minimized.

Copy link
Author

s-tikhomirov commented Jan 25, 2019

@pm47, I have a couple more question regarding the actual scripts. From a high level, an HTLC from Alice to Bob may be spent in one of three ways: by Bob (with preimage), by Bob (with revocation key), or by Alice (after a timeout). But in the actual scripts (and in the scheme above) I see two similar revocation conditions: in the output of the commitment transaction and the output of the HTLC transaction. Why do we need to repeat the same logic twice?

Is my assumption correct that the parties have to create a pair of HTLCs first, and only then sign the commitment transaction which references the HTLC pubkey? Even so, wasn't there a way to express 3 spending conditions in 3 conditions, not 4?

Also, why is the revocation condition expressed as OP_DUP OP_HASH160 h(revocationpubkey) OP_EQUAL (followed by OP_CHECKSIG in the corresponding branch) in the commitment output but just as revocationpubkey in the HTLC output?

@pm47

This comment has been minimized.

Copy link
Collaborator

pm47 commented Jan 26, 2019

From a high level, an HTLC from Alice to Bob may be spent in one of three ways: by Bob (with preimage), by Bob (with revocation key), or by Alice (after a timeout).

This is only true if you are considering Alice's commitment tx. The same HTLC, in Bob's commitment tx, would be spendable by Bob (with preimage), by Alice (with revocation key), or by Alice (after a timeout).

I see two similar revocation conditions: in the output of the commitment transaction and the output of the HTLC transaction. Why do we need to repeat the same logic twice?

Suppose that this payment succeeds (Bob has the preimage), and later on Bob decides to publish the now-revoked commitment that contained this HTLC. If Bob was able to spend the HTLC output right away using the preimage, then he could prevent Alice from using her revocation key by being quicker than her. That's why we have a 2nd stage HTLC-Success, which includes an additional relative delay, giving time for Alice to take all the funds before Bob can spend them.

Is my assumption correct that the parties have to create a pair of HTLCs first, and only then sign the commitment transaction which references the HTLC pubkey?

No, the flow goes like this (sender signs first):

        +-------+                               +-------+
        |       |--(1)---- update_add_htlc ---->|       |
        |       |                               |       |
        |       |--(2)--- commitment_signed --->|       |
        |   A   |<-(3)---- revoke_and_ack ------|   B   |
        |       |                               |       |
        |       |<-(4)--- commitment_signed ----|       |
        |       |--(5)---- revoke_and_ack ----->|       |
        +-------+                               +-------+

Commitment and HTLC signatures are sent together (see message commitment_signed in BOLT 2).

Even so, wasn't there a way to express 3 spending conditions in 3 conditions, not 4?

We could, but we found it less optimal. Rationale is here: #88.

Also, why is the revocation condition expressed as OP_DUP OP_HASH160 h(revocationpubkey) OP_EQUAL (followed by OP_CHECKSIG in the corresponding branch) in the commitment output but just as revocationpubkey in the HTLC output?

Hmm, you got me with that one. I don't have a definite answer right off the bat, but pretty sure this is an optimization; I'll look into it.

@joaojoyce

This comment has been minimized.

Copy link

joaojoyce commented Feb 6, 2019

Just adding that I'm finding this exchange incredibly useful to the general understanding of the current implementation of LN HTLCs!

For instance, although there are some references to the "second-stage HTLC" in Bolt 3 and also references to "HTLC-success" and "HTLC-timeout" I'm finding them hard to grasp from the original text. Also they can't be linked to the LN white paper since they don't appear in it and, understandably, result from discussion and improvements that happened after the LN paper.

I'm just wondering if this is a sign that there might be a need for some more references or small changes in the text itself in order to help newcomers (like myself and I'm sure many others) understand all the HTLC flow and script conditions.

This is in no way a criticism to the work put together in this rfc! I actually wish I already had the level of understanding and clear vision to contribute with some improvement.

Meanwhile this discussion helps a lot. Thank you!

@nadahalli

This comment has been minimized.

Copy link

nadahalli commented Feb 6, 2019

Just adding that I'm finding this exchange incredibly useful to the general understanding of the current implementation of LN HTLCs!>
Meanwhile this discussion helps a lot. Thank you!

I agree. I have subscribed to this particular issue just to be able to read updates, and come back again and again to understand the nuances better.

@joaojoyce

This comment has been minimized.

Copy link

joaojoyce commented Feb 6, 2019

For anyone who is trying to consolidate some understanding of this the "Reaching The Ground With Lightning" paper by Rusty Russel might give an idea of some diferences between the original LN paper and the current implementation.

https://github.com/ElementsProject/lightning/blob/master/doc/deployable-lightning.pdf

Might be useful, @nadahalli.

@rustyrussell

This comment has been minimized.

Copy link
Collaborator

rustyrussell commented Feb 8, 2019

Also, why is the revocation condition expressed as OP_DUP OP_HASH160 h(revocationpubkey) OP_EQUAL (followed by OP_CHECKSIG in the corresponding branch) in the commitment output but just as revocationpubkey in the HTLC output?

This is a good catch! We could have further optimized the to-local and htlc txs using the same technique (on the assumption that this branch is approximately never used).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment