It is assumed that the reader is already familiar with the basics of Bitcoin, Bitcoin script, cryptography, and atomic swaps, and knows the difference between an image and a preimage. This article aims to give a precise but understandable description of how Lightning Network payments are performed under the hood, which may be useful for new Lightning Network developers.
Many thanks to Nazarii Shcherbak for his kind review.
I really am a big fan of Layer-2 solutions and their approaches. IMHO, Layer-2 solutions are state-of-the-art blockchain technology. Their ideas rely on the most novel cryptographic primitives, which contribute to a large amount of research in the field of computer science. Obviously, different approaches exist—optimistic rollups are the most cost-effective in terms of support and implementation, while pessimistic rollups are more complicated and expensive, but are also more interesting from an engineering perspective. In this post, I’d love to review another approach to Layer-2—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 open 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 a 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 the revocation public key. The same applies from Bob’s perspective: the $\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 immediate spending authorized by the revocation public key.
Note that the revocation private keys are different in Alice’s and Bob’s commitment transactions and are generated in a similar way to multisig. So, for example, Alice cannot spend the $\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 of new commitment transactions and the exchange of signatures for them. These transactions 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}$, which 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 for the corresponding revocation public keys in the 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, this approach is not used in the Lightning Network. Instead, its core ideas are used in another LN building block called an 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 the responder (Bob). Assume Alice has state $A_k$ and Bob has state $B_k$; then:
-
Alice submits a $\texttt{commitment_signed}$ message to Bob, sharing all required signatures for Bob’s new state $B_ {k+1}$;
-
Bob submits a $\texttt{commitment_signed}$ message to Alice, sharing all required signatures for Alice’s new state $A_ {k+1}$;
-
Bob sends a $\texttt{revoke_and_ack}$ message to Alice, assuming the final acceptance of state $k+1$ by sharing the revocation key for $B_k$;
-
Alice sends a $\texttt{revoke_and_ack}$ message to Bob, assuming the final acceptance of 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 HTLC payments. Similar to atomic swaps, an HTLC is an output that can be spent with knowledge of the preimage by X or after some time by Y. More precisely, imagine Alice wants to send some coins to Bob in the already existing channel:
- Both Alice and Bob have a pre-signed transaction for state $n$ (let’s denote them $A_n$ and $B_n$, respectively) with
the following structure:
commitment_tx: input: funding_output outputs: to_local to_remoteAt this point, they both can force-close the channel at state $n$.
-
Bob somehow shares with Alice the image of the expected payment (let’s discuss it later).
-
Then, Alice sends an $\texttt{update_add_htlc}$ message to Bob, initializing a payment process. Besides some technical information, this message contains the image, CLTV timeout, and amount.
- 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 - Alice sends a $\texttt{commitment_signed}$ message to Bob that contains a signature for 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 preimage branch or timeout branch OP_IF # To Bob via preimage + 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_ENDIFIn 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 preimage 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 preimage + Bob's signature OP_HASH160 <image> OP_EQUALVERIFY OP_CHECKSIG OP_ENDIF OP_ENDIFAdditionally, in this message, Alice shares two more signatures: (1) for the transaction that spends the HTLC output from Alice’s commitment transaction $A_{n+1}$ via the timeout path, and (2) for the transaction that spends the HTLC output from Bob’s commitment transaction $B_{n+1}$ via the preimage 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 knowledge of the preimage. The following table describes the opportunities of both Alice and Bob if Bob decides 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 preimage − + 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. This is because they both assume that the timeout spending transaction contains the $\texttt{nLockTime = cltv_expiry}$ field, which is also signed by Alice ( so can be verified by Bob).
-
Bob sends a $\texttt{commitment_signed}$ message to Alice, assuming the acceptance of state $n+1$. This message contains: (1) Bob’s signature for spending the HTLC in Alice’s commitment $A_{n+1}$ via the timeout path, and (2) Bob’s signature for Alice’s $A_{n+1}$ commitment transaction.
Note that at this step, both can spend the commitment transaction to force-close the channel. If the force-close is performed by either of them, Bob will be able to spend the HTLC output by preimage, 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 preimage − + Spend HTLC by timeout + − Punish HTLC spent by revocation key n/a − -
Bob sends a $\texttt{revoke_and_ack}$ message to Alice, assuming the final acceptance of state $n+1$ and revocation of the $n$ state. This message contains Bob’s revocation key to the $B_n$ state commitment.
-
Alice sends a $\texttt{revoke_and_ack}$ message to Bob, assuming the final acceptance of state $n+1$ and revocation 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 the HTLC, he cannot use it 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_remote}$ for both parties.
-
Bob sends an $\texttt{update_fulfill_htlc}$ message, sharing the preimage of the HTLC. It is safe for Bob because the preimage spending path additionally requires Bob’s signature.
-
Alice sends a $\texttt{commitment_signed}$ message to Bob for state $n+2$, 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$.
-
Bob sends a $\texttt{commitment_signed}$ message to Alice. This message contains Bob’s signature for Alice’s commitment transaction of state $n+2$.
-
Alice sends $\texttt{revoke_and_ack}$ to Bob, assuming the final acceptance of state $n+2$ and revocation of state $n+1$ (by sharing her revocation key for state $n+1$).
- Bob sends $\texttt{revoke_and_ack}$ to Alice, assuming the final acceptance of state $n+2$ and revocation of state $n+1$ (by sharing his revocation key for state $n+1$). Finally, $n+2$ represents the updated balances after the payment.
The careful reader may now wonder (1) how Alice receives the preimage from Bob, and (2) why Bob has to send the preimage to Alice to change the state. Basically, the answer lies in how the Lightning Network handles cross-channel payments (see paragraph below).
We also have not covered the process by which Alice and Bob exchange the HTLC and revocation keys, which you can find in BOLT 3. Briefly, during each $\texttt{revoke_and_ack}$ they both exchange a new $\texttt{per_commitment_point}$, which, coupled 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 send payments to 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, an 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 preimage $i$ and shares the invoice with Alice to receive some amount of Bitcoin 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 agree to perform a payment, each channel changes its state in accordance with steps 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 preimage $i$ to claim $\texttt{BTC}$ from Dave (Bob executes steps 9–13 with Dave).
- Dave now knows $i$ and can claim $A$ $\texttt{BTC}$ from Charlie (Dave executes steps 9–13 with Charlie).
- Charlie now knows $i$ and can claim $\texttt{BTC}$ from Alice (Charlie executes steps 9–13 with Alice).