Intro to Lightning Network (Pt.1)

 

It is assumed that the reader is already familiar with the basics of Bitcoin, Bitcoin script, cryptography, and atomic swaps, as well as knows the difference between an image and a pre-image. This article aims to give a precise but understandable description of how the Lightning Network payments are performed under the hood, which may be useful for newbie Lightning Network developers.

Many thanks to Nazarii Shcherbak for his kind review.

I really am a big fan of the Layer-2 solutions and their approaches. IMHO, Layer-2 solutions are a state-of-the-art of the overall blockchain technology. Their ideas lie on the most novel cryptographic primitives, which contribute to a large amount of research in the field of computer science. Obviously, there are different approaches exist - optimistic rollups stand for the most cost-effective in terms of support and implementation, while pessimistic rollups are more complicated and expensive, but also are more interesting from an engineering perspective. In this post i’d love to overview another approach for Layer-2 - the payment channels, the main representative of which is the Lightning Network.


It is known that Bitcoin has an average block time of 10 minutes, while the recommended number of blocks for finalization is 3 (6 is better). It basically means that each payment takes around 30 minutes to execute. Lightning Network (LN) provides people with the opportunity to perform cheap and fast payments in Bitcoin between each other. It leverages a bidirectional payment channel mechanism that also allows transfers between parties without a direct channel opened between them. The specification of Lightning Network protocols and messages is defined in BOLTs (Basis of Lightning Technology). This article is primarily based on BOLT 2 and BOLT 3.

What is a payment channel?

The default payment channel flow basically consists of three types of transactions:

  • The funding transaction,
  • The commitment transaction,
  • The closing transaction.

During the normal flow, only funding and closing transactions will be published on-chain. Participants keep commitment transactions off-chain and use them as the current channel state representation. Additionally, commitment transactions can be used to force-close the channel in case the opponent stops responding.

Let’s review the high-level definition of how payment channels work in LN. To establish a payment channel between two parties (say, Alice and Bob), both create the funding transaction with a simple 2-of-2 multisig spend requirement. The inputs to this transaction contain $A$ $\texttt{BTC}$ from Alice, and $B$ $\texttt{BTC}$ from Bob. More precisely, the funding output script is a P2WSH to:

2 <Alice's PubKey> <Bob's PubKey> 2 OP_CHECKMULTISIG

Then, before signing and submitting the funding transaction, Bob and Alice generate a commitment transaction that spends the funding transaction.

The commitment transaction contains two outputs: $\texttt{to_local}$ and $\texttt{to_remote}$. From Alice’s perspective, $\texttt{to_remote}$ output allows spending of $B$ $\texttt{BTC}$ authorized by Bob’s public key, and in turn $\texttt{to_local}$ output allows spending of $A$ $\texttt{BTC}$ after $T$ hours authorized by Alice’s public key or the immediate spending authorized by revocation public key. The same from Bob’s perspective: $\texttt{to_remote}$ output allows spending of $A$ $\texttt{BTC}$ authorized by Alice’s public key, while $\texttt{to_local}$ output allows spending of $B$ $\texttt{BTC}$ after $T$ hours authorized by Bob’s public key or the immediate spending authorized by revocation public key.

Note that the revocation private keys are different in Alice’s and Bob’s commitment transactions, and generated in a similar way to multisig. So, for example, Alice can not spend $\texttt{to_local}$ output from her commitment transaction just by signing it with the revocation key because it requires Bob’s part of this key. Each party holds its parts of the revocation keys in secret until the next state change. Below, we show how this mechanism is used to prevent each side from publishing old state commitments.

Let’s examine the $\texttt{to_local}$ output spending script:

OP_IF
# Penalty transaction
<revocationpubkey>
OP_ELSE
<to_self_delay (T hours)>
OP_CHECKSEQUENCEVERIFY
OP_DROP
<local_pubkey>
OP_ENDIF
OP_CHECKSIG

During the channel creation, Alice requests Bob’s signature for her commitment transaction, and in turn, Bob requests Alice’s signature for his commitment transaction. After they receive these signatures, they sign the funding transaction and submit it to the Bitcoin network.

Next, each transfer between Alice and Bob requires the creation and signature exchange for the new commitment transactions, which represent the new state (for example, after the transfer of $t$ $\texttt{BTC}$ from Alice to Bob, Alice’s state is $A-t$ $\texttt{BTC}$ and Bob’s state is $B+t$ $\texttt{BTC}$ that will be displayed accordingly in the commitment transactions’ outputs). Additionally, after each state transition (or creation of new commitment transactions), Alice and Bob exchange the private keys to the corresponding revocation public keys in previous commitment transactions. This mechanism prevents both sides from cheating by submitting the old commitment transaction to the network: during the $T$ hours, the second party can punish the cheater by taking all liquidity from the channel.

During the normal flow, if Alice and Bob decide to close the channel, they sign the closing transaction that allows spending of the funding transaction output according to the final channel state.

HTLC payments

Above, we described the simplest way for two parties to exchange liquidity with each other. Nevertheless, such an approach is not used in Lightning Network. Instead, its core ideas are used in another LN building block called HTLC.

Let’s first examine the high-level overview of how parties can change their state in the Lightning Network channel. Each state change $k \rightarrow k+1$ basically assumes the following message exchange between the initiator (Alice) and responder (Bob). Assume Alice has state $A_k$ and Bob has state $B_k$, then:

  • Alice submits $\texttt{commitment_signed}$ message to Bob, sharing all required signatures to Bob’s new state $B_ {k+1}$;

  • Bob submits $\texttt{commitment_signed}$ message to Alice, sharing all required signatures to Alice’s new state $A_ {k+1}$;

  • Bob sends $\texttt{revoke_and_ack}$ message to Alice, assuming the final acceptance of the state $k+1$ by sharing the revocation key for $B_k$;

  • Alice sends $\texttt{revoke_and_ack}$ message to Bob, assuming the final acceptance of the state $k+1$ by sharing the revocation key for $A_k$.

One can note that this flow does not cover the underlying logic of why the state has to be changed and how to verify the correctness of the proposed state.

Let’s now continue with the HTLC payments. Similar to the atomic swaps, the HTLC is an output that can be spent with the knowledge of the pre-image by X or after some time by Y. More precisely, imagine Alice wants to send some coins to Bob in the already existing channel:

  1. Both Alice and Bob have a pre-signed transaction of state $n$ (let’s denote them $A_n$ and $B_n$ accordingly) with the following structure:
     commitment_tx:
         input:
             funding_output
         outputs:
             to_local
             to_remote
    

    At this point, they both can force-close the channel at state $n$.

  2. Bob somehow shares with Alice the image of the expected payment (let’s discuss it later).

  3. Then, Alice sends $\texttt{update_add_htlc}$ message to Bob, initializing a payment process. Besides some technical information, this message contains the image, CLTV timeout, and amount.

  4. Next, both Alice and Bob update their commitments (moving to the state $n+1$) to have the following structure:
     commitment_tx:
         input:
             funding_output
         outputs:
             to_local
             to_remote
             htlc
    
  5. Alice sends $\texttt{commitment_signed}$ message to Bob, that contains a signature to his $B_{n+1}$ state commitment, assuming Bob has added the corresponding HTLC output and has deducted the corresponding amount from Alice’s $\texttt{to_remote}$ output. This HTLC output for Bob looks as follows:
    OP_DUP OP_HASH160 <Bob_revocationkey_addr> OP_EQUAL # Penalty branch with revocation key knowledge
    OP_IF
    OP_CHECKSIG
    OP_ELSE
    <Alice_htlc_pubkey> OP_SWAP OP_SIZE 32 OP_EQUAL # Decide if we go into pre-image branch or timeout branch
    OP_IF
    # To Bob via pre-image + Alice's and Bob's signatures
    OP_HASH160 <image> OP_EQUALVERIFY
    2 OP_SWAP <Bob_htlc_pubkey> 2 OP_CHECKMULTISIG
    OP_ELSE
    # To Alice after timeout + Alice signature
    OP_DROP <cltv_expiry> OP_CHECKLOCKTIMEVERIFY OP_DROP
    OP_CHECKSIG
    OP_ENDIF
    OP_ENDIF
    

    In turn, the HTLC output in Alice’s commitment $A_{n+1}$ is as follows:

    OP_DUP OP_HASH160 <Alice_revocationkey_addr> OP_EQUAL # Penalty branch with revocation key knowledge
    OP_IF
    OP_CHECKSIG
    OP_ELSE
    <Bob_htlc_pubkey> OP_SWAP OP_SIZE 32 OP_EQUAL # Decide if we go into pre-image branch or timeout branch
    OP_NOTIF
    # To Alice after timeout + Bob's and Alice's signatures
    OP_DROP 2 OP_SWAP <Alice_htlc_pubkey> 2 OP_CHECKMULTISIG
    OP_ELSE
    # To Bob via pre-image + Bob signature
    OP_HASH160 <image> OP_EQUALVERIFY
    OP_CHECKSIG
    OP_ENDIF
    OP_ENDIF
    

    Additionally, in this message, Alice shares two more signatures: (1) to the transaction that spends the HTLC output from Alice’s commitment transaction $A_{n+1}$ via timeout path, and (2) to the transaction that spends the HTLC output from Bob’s commitment transaction $B_{n+1}$ via pre-image path. It is required to convince Bob that even if Alice decides to force-close the channel by submitting her commitment transaction $A_{n+1}$, Bob will be able to spend the HTLC output with the knowledge of the pre-image. The following table describes the opportunities of both Alice and Bob if Bob decided now to force close:

      Alice Bob
    Punish old state spent ($n$) by revocation key n/a
    Spend to_local (after timeout) +
    Spend to_remote +
    Spend HTLC by pre-image +
    Spend HTLC by timeout +
    Punish HTLC spent by revocation key n/a

    Also, one can note that Alice’s HTLC script does not verify the timeout explicitly. It is because both assume that the timeout spending transaction contains $\texttt{nLockTime = cltv_expiry}$ field, which is also signed by Alice ( so can be verified by Bob).

  6. Bob sends $\texttt{commitment_signed}$ message to Alice assuming the acceptance of $n+1$ state. This message contains: (1) Bob’s signature to the timeout path spend of HTLC in Alice’s commitment $A_{n+1}$, and (2) Bob’s signature to Alice’s $A_{n+1}$ commitment transaction.

    Note that on this step, both can spend the commitment transaction to perform channel force-close. If the force-close is performed by any of them, Bob will be able to spend the HTLC output by pre-image, and Alice will be able to spend the HTLC by timeout. The following table describes the opportunities of both Alice and Bob if Alice decides to force-close

      Alice Bob
    Punish old state spent ($n$) by revocation key n/a
    Spend to_local (after timeout) +
    Spend to_remote +
    Spend HTLC by pre-image +
    Spend HTLC by timeout +
    Punish HTLC spent by revocation key n/a
  7. Bob sends $\texttt{revoke_and_ack}$ message to Alice assuming the final acceptance of $n+1$ state and revoking of the $n$ state. This message contains Bob’s revocation key to the $B_n$ state commitment.

  8. Alice sends $\texttt{revoke_and_ack}$ message to Bob assuming the final acceptance of $n+1$ state and revoking of the $n$ state. This message contains Alice’s revocation key to the $A_n$ state commitment. At this point, we finally have a new $n+1$ state that is safe for both Alice and Bob.

    Unfortunately, the current form of state commitments is inconvenient for Bob, because while he owns the $\texttt{BTC}$ in HTLC, he can not use them in transfers. So, Alice and Bob have to update commitment transactions by removing the HTLCs and changing the corresponding balances in $\texttt{to_local}$ and $\texttt{to_remove}$ of both parties.

  9. Bob sends $\texttt{update_fulfill_htlc}$ message, sharing the pre-image of HTLC. It is safe for Bob because the pre-image spending path additionally requires Bob’s signature.

  10. Alice sends $\texttt{commitment_signed}$ message to Bob for the $n+2$ state, where the HTLC is deleted while the balances are updated accordingly. As before, this message contains Alice’s signature for Bob’s commitment transaction of state $n+2$.

  11. Bob sends $\texttt{commitment_signed}$ message to Alice. This message contains Bob’s signature for Alice’s commitment transaction of state $n+2$.

  12. Alice sends $\texttt{revoke_and_ack}$ to Bob assuming the final acceptance of the $n+2$ and revoking the $n+1$ state (by sharing her revocation key for $n+1$ state).

  13. Bob sends $\texttt{revoke_and_ack}$ to Alice assuming the final acceptance of the $n+2$ and revoking the $n+1$ state (by sharing his revocation key for $n+1$ state). Finally, the $n+2$ represents the updated balances after the payment.

The careful reader may now wonder (1) how Alice receives the pre-image from Bob, and (2) why Bob has to send the pre-image to Alice to change the state? Basically, the answer is in how the Lightning Network handles the cross-channel payments (see paragraph below).

We also have not covered the process of exchanging the HTLC and revocation keys by both Alice and Bob, which you can find in BOLT 3. Briefly, during each $\texttt{revoke_and_ack}$ they both exchange a new $\texttt{per_commitment_point}$ which, in a couple with some other fixed parameters, determines a public key for the next HTLC as well as the revocation key for the next state.

Cross-channel payments

Even if Alice and Bob do not have a direct payment channel, they can still receive payments from each other. Leveraging the HTLC payment protocol above, Bob can create an invoice, which describes all the required information for Alice to perform a payment. More precisely, invoice defines the way to encode the amount, image, payment path across channels (optionally), and some other technical information. Then, this invoice can be shared with the payer to perform a payment. This payment flow (Alice pays Bob) looks as follows:

  • Bob generates a secret pre-image $i$ and shares with Alice the invoice to receive some amount of Bitcoins using the image $I$.
  • Alice finds a route that leverages existing payment channels, for example: Alice $\rightarrow$ Charlie $\rightarrow$ Dave $\rightarrow$ Bob.
  • If all of them accept to perform a payment, each channel changes its state in accordance with 3-8 of the above payment flow. Basically, it assumes that:

    • Charlie will get paid only if he can produce $i$ before the deadline.
    • Dave will get paid only if he can produce $i$ before the deadline.
    • Bob already knows $i$.
  • Bob reveals the pre-image $i$ to claim $\texttt{BTC}$ from Dave (Bob executes 9-13 with Dave).
  • Dave now knows $i$ and can claim $A$ $\texttt{BTC}$ from Charlie (Dave executes 9-13 with Charlie).
  • Charlie now knows $i$ and can claim $\texttt{BTC}$ from Alice (Charlie executes 9-13 with Alice).