Merge branch 'develop'
@ -60,7 +60,7 @@ Now that you're familiar with these basic terms, let's move to a concept you are
|
|||||||
|
|
||||||
You will often hear people calling Bitcoin and the Lightning Network "trustless". At first glance this is confusing. After all, isn't trust a good thing? Banks even use it in their names! Isn't a "trustless" system, a system devoid of trust, a bad thing?
|
You will often hear people calling Bitcoin and the Lightning Network "trustless". At first glance this is confusing. After all, isn't trust a good thing? Banks even use it in their names! Isn't a "trustless" system, a system devoid of trust, a bad thing?
|
||||||
|
|
||||||
The use of the the word "trustless" is intended to convey the ability to operate without _needing_ trust in the other participants in the system. In a decentralized system like Bitcoin, you can always choose to transact with someone you trust. However, the system ensures you can't be cheated even if you can't trust the other party in a transaction. Trust is a nice-to-have instead of a must-have property of the system.
|
The use of the word "trustless" is intended to convey the ability to operate without _needing_ trust in the other participants in the system. In a decentralized system like Bitcoin, you can always choose to transact with someone you trust. However, the system ensures you can't be cheated even if you can't trust the other party in a transaction. Trust is a nice-to-have instead of a must-have property of the system.
|
||||||
|
|
||||||
Contrast that to traditional systems like banking where you _must_ place your trust in a third party, since it controls your money. If the bank violates your trust, you may be able to find some recourse from a regulator or court, but at an enormous cost of time, money, and effort.
|
Contrast that to traditional systems like banking where you _must_ place your trust in a third party, since it controls your money. If the bank violates your trust, you may be able to find some recourse from a regulator or court, but at an enormous cost of time, money, and effort.
|
||||||
|
|
||||||
@ -89,7 +89,7 @@ Cryptographic systems like Bitcoin and the Lightning Network are systems that al
|
|||||||
|
|
||||||
The big distinction between a cryptographic system like this and a traditional financial system is that in traditional finance you have a _trusted third party_, for example a bank, to ensure that outcomes are fair. A significant problem with such systems is that they give too much power to the third party, and they are also vulnerable to a _single point of failure_. If the trusted third party itself violates trust or attempts to cheat, the basis of trust breaks.
|
The big distinction between a cryptographic system like this and a traditional financial system is that in traditional finance you have a _trusted third party_, for example a bank, to ensure that outcomes are fair. A significant problem with such systems is that they give too much power to the third party, and they are also vulnerable to a _single point of failure_. If the trusted third party itself violates trust or attempts to cheat, the basis of trust breaks.
|
||||||
|
|
||||||
As you study cryptographic systems, you will notice a certain pattern: instead of relying on a trusted third party, these systems attempt to prevent unfair outcomes by using a system of incentives and disincentives. In cryptographic systems you place trust in the _protocol_, which is effectively a system with a set of rules that, if properly designed, will correctly apply the desired incentives and disincentives. The advantage of this approach is two-fold. Not only do you avoid trusting a third party, you also reduce the need to enforce fair outcomes. So long as the participants follow the agreed protocol and stay within the system, the incentive mechanism in that protocol achieves fair outcomes without enforcement.
|
As you study cryptographic systems, you will notice a certain pattern: instead of relying on a trusted third party, these systems attempt to prevent unfair outcomes by using a system of incentives and disincentives. In cryptographic systems you place trust in the _protocol_, which is effectively a system with a set of rules that, if properly designed, will correctly apply the desired incentives and disincentives. The advantage of this approach is two-fold: Not only do you avoid trusting a third party, you also reduce the need to enforce fair outcomes. So long as the participants follow the agreed protocol and stay within the system, the incentive mechanism in that protocol achieves fair outcomes without enforcement.
|
||||||
|
|
||||||
The use of incentives and disincentives to achieve fair outcomes is one aspect of a branch of mathematics called _game theory_, which studies "models of strategic interaction among rational decision makers" footnote:[Wikipedia "Game Theory": https://en.wikipedia.org/wiki/Game_theory]. Cryptographic systems that control financial interactions between participants, such as Bitcoin and the Lightning Network, rely heavily on game theory to prevent participants from cheating and allow participants who don't trust each other to achieve fair outcomes.
|
The use of incentives and disincentives to achieve fair outcomes is one aspect of a branch of mathematics called _game theory_, which studies "models of strategic interaction among rational decision makers" footnote:[Wikipedia "Game Theory": https://en.wikipedia.org/wiki/Game_theory]. Cryptographic systems that control financial interactions between participants, such as Bitcoin and the Lightning Network, rely heavily on game theory to prevent participants from cheating and allow participants who don't trust each other to achieve fair outcomes.
|
||||||
|
|
||||||
|
@ -28,7 +28,7 @@ If you need a refresher on the fundamentals of Bitcoin, you can find a summary r
|
|||||||
* Transaction inputs and outputs
|
* Transaction inputs and outputs
|
||||||
* Transaction chaining
|
* Transaction chaining
|
||||||
* Bitcoin script
|
* Bitcoin script
|
||||||
* Multsignature addresses and scripts
|
* Multisignature addresses and scripts
|
||||||
* Timelocks
|
* Timelocks
|
||||||
* Complex scripts
|
* Complex scripts
|
||||||
|
|
||||||
|
27
06_lightning_architecture.asciidoc
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
== Lightning Network Architecture
|
||||||
|
|
||||||
|
In the first part of this book we introduced the main concepts of the Lightning Network, worked through a comprehensive example of routing a payment and set up the tools we can use to explore further. In the second part of the book we will explore the Lightning Network in a lot more technical detail, dissecting each of the building blocks.
|
||||||
|
|
||||||
|
In this section we will outline the components of the Lightning Network in more detail and provide a "big picture" perspective to guide you through the following chapters.
|
||||||
|
|
||||||
|
=== The Lightning Network Protocol Suite
|
||||||
|
|
||||||
|
The Lightning Network is composed of a complex collection of protocols that run on top of the internet. We can broadly classify these protocols into five distinct layers that make up a _protocol stack_, where each layer build upon and uses the protocols in the layer below. Also, each protocol layer abstracts the underlying layers and "hides" some of the complexity.
|
||||||
|
|
||||||
|
The architecture diagram shown in <<lightning_network_protocol_suite>> provides an overview of these layers and their component protocols:
|
||||||
|
|
||||||
|
[[lightning_network_protocol_suite]]
|
||||||
|
.The Lightning Network Protocol Suite
|
||||||
|
image::images/lightning-network-protocol-suite.png[]
|
||||||
|
|
||||||
|
The five layers of the Lightning Network, from the bottom up, are:
|
||||||
|
|
||||||
|
Network Connection Layer:: This contains the protocols that interact directly with the internet core protocols (TCP/IP), overlay protocols (Tor v2/v3), and internet services (DNS). This layer also contains the cryptographic transport protocols that protect Lightning messages.
|
||||||
|
|
||||||
|
Messaging Layer:: This layer contains the protocols that nodes use to negotiate features, format messages, and encode message fields.
|
||||||
|
|
||||||
|
Peer-2-Peer (P2P) Layer:: This layer is primary protocol layer for communication between Lightning nodes and contains all the different messages exchanged between nodes.
|
||||||
|
|
||||||
|
Routing Layer:: This layer contains the protocols used to route payments between nodes, end-to-end and atomically. This layer contains the "core" functionality of the Lightning Network: routed payments.
|
||||||
|
|
||||||
|
Payment Layer:: The highest layer of the network, which presents a reliable payment interface to applications.
|
634
07_routing_htlcs.asciidoc
Normal file
@ -0,0 +1,634 @@
|
|||||||
|
[[routing_on_a_network_of_payment_channels]]
|
||||||
|
== Routing on a Network of Payment channels
|
||||||
|
|
||||||
|
In this section we will finally unpack how payment channels can be connected to form a _network of payment channels_ via a process called _routing_. Specifically, we will look at the first part of the routing layer, the Atomic & Trustless Multihop Payment protocol. This is highlighted by a double outline in the protocol suite diagram:
|
||||||
|
|
||||||
|
[[LN_protocol_routing_highlight]]
|
||||||
|
.The Lightning Network Protocol Suite
|
||||||
|
image::images/LN-protocol-routing-highlight.png[]
|
||||||
|
|
||||||
|
=== Routing a payment
|
||||||
|
|
||||||
|
In this section we will examine routing from the perspective of Dina, a gamer who receives donations from her fans while she streams her game sessions.
|
||||||
|
|
||||||
|
The innovation of routed payment channels allows Dina to receive tips without maintaining a separate channel with every one of her fans who want to tip her.
|
||||||
|
As long as there exists a path of well-funded channels from that viewer to Dina, she will be able to receive payment from that fan.
|
||||||
|
The nodes along the path from the fan to Dina are intermediaries and called "routing nodes" in the context of routing a payment.
|
||||||
|
|
||||||
|
There is no functional difference between the "routing nodes" and the nodes operated by Dina's fans. Any Lightning node is capable of routing payments across its payment channels.
|
||||||
|
|
||||||
|
[[dina-routing-diagram]]
|
||||||
|
.Any one of Dina's fans in the diagram can pay her by routing via the nodes in between them and Dina
|
||||||
|
image:images/dina-routing-diagram.png["Any one of Dina's fans in the diagram can pay her by routing via the nodes in between them and Dina"]
|
||||||
|
|
||||||
|
Importantly, the routing nodes are unable to steal the funds while routing a payment from a fan to Dina.
|
||||||
|
Furthermore, routing nodes cannot lose money while participating in the routing process.
|
||||||
|
Routing nodes can charge a routing fee for acting as an intermediary, although they don't have to and may choose to route payments for free.
|
||||||
|
|
||||||
|
Another important detail is that due to the use of onion routing, intermediary nodes are only explicitly aware of the one node preceding them and the one node following them in the route.
|
||||||
|
They will not necessarily know who is the sender and recipient of the payment.
|
||||||
|
This enables fans to use intermediary nodes to pay Dina, without leaking private information and without risking theft.
|
||||||
|
|
||||||
|
This process of connecting a series of payment channels with end-to-end security, and the incentive structure for nodes to _forward_ payments, is one of the key innovations of the Lightning Network.
|
||||||
|
|
||||||
|
In this chapter, we'll dive into the mechanism of routing in the Lightning Network, detailing the precise manner in-which payments flow through the network.
|
||||||
|
|
||||||
|
First, we will clarify the concept of "routing" and compare it to that of "path finding", as these are often confused and used interchangeably.
|
||||||
|
|
||||||
|
Next, we will construct the fairness protocol: A Conditional Chained End-to-End Secure Payment (CCESP) used to route payments. To demonstrate how this fairness protocol works, we will be using a physical equivalent of transferring gold coins between 4 people.
|
||||||
|
|
||||||
|
Finally, we will look at the CCESP implementation currently used in the Lightning Network, which is called a Hash Time-Locked Contract (HTLC).
|
||||||
|
|
||||||
|
=== Routing vs. Path Finding
|
||||||
|
|
||||||
|
It's important to note that we separate the concept of _routing_ from the concept of _path finding_. These two concepts are often confused and the term "routing" is often used to describe both concepts. Let's remove the ambiguity, before we proceed any further.
|
||||||
|
|
||||||
|
Path Finding, which is covered in <<path_finding>> is the process of finding and choosing a contiguous path made of payment channels which connects the sender A to the recipient B. The sender of a payment does the path finding, by examining the _channel graph_ which they have assembled from channel announcements gossiped by other nodes.
|
||||||
|
|
||||||
|
Routing refers to the series of interactions across the network that allow a payment to _flow_ from A to B, across the path previously selected by path finding. Routing is the _active_ process of sending a payment on a path, which involves the cooperation of all the intermediary nodes along that path.
|
||||||
|
|
||||||
|
An important rule of thumb is that it's possible for a _path_ to exist between Alice and Bob, yet there may not be an active _route_ on which to send the payment.
|
||||||
|
|
||||||
|
One example is the scenario where all the nodes connecting Alice and Bob are currently off-line.
|
||||||
|
|
||||||
|
In theory, one can examine the _channel graph_ and connect a series of payment channels from Alice to Bob, hence a _path_ exists. However, as the intermediary nodes are offline, the payment cannot be sent and so no _route_ exists.
|
||||||
|
|
||||||
|
=== Creating a network of payment channels
|
||||||
|
|
||||||
|
Before we dive into the concept of a conditional chained end-to-end secure payment, let's work through an example.
|
||||||
|
Let us to return to Alice who, in previous chapters, purchased a coffee from Bob with whom she has an open channel.
|
||||||
|
Alice now watches a live stream from Dina the gamer, and wants to send her a tip via the Lightning Network.
|
||||||
|
However, Alice has no direct channel with Dina.
|
||||||
|
Alice could open a direct channel, however that would require liquidity and on-chain fees which could be more than the value of the tip itself.
|
||||||
|
|
||||||
|
Instead, Alice can use her existing open channels to send a tip to Dina _without_ the need to open a channel directly with Dina.
|
||||||
|
|
||||||
|
This is possible, as long as there exists some path of channels from Alice to Dina with sufficient capacity to route the tip.
|
||||||
|
|
||||||
|
From previous chapters, we know Alice has an open channel with Bob, the coffee shop owner.
|
||||||
|
Bob, in turn, has an open channel with the software developer Chan who helps him with the point of sale system he uses in his coffee shop.
|
||||||
|
Chan is also the owner of a large software company which develops the game that Dina plays, and they already have an open channel which Dina uses to pay for the game's license and in-game items.
|
||||||
|
|
||||||
|
If we draw out this series of payment channels, it's possible to manually trace a _path_ from Alice to Dina that uses Bob and Chan as intermediary routing nodes.
|
||||||
|
Alice can then craft a _route_ from this outlined path, and use it to send a tip of a few thousand satoshis to Dina, with the payment being _forwarded_ by Bob and Chan.
|
||||||
|
Essentially, Alice will pay Bob, who will pay Chan, who will pay Dina.
|
||||||
|
And no direct channel from Alice to Dina is required.
|
||||||
|
|
||||||
|
[[routing-network]]
|
||||||
|
.A network of payment channels
|
||||||
|
image:images/routing-network.png[]
|
||||||
|
|
||||||
|
The main challenge is to do this in a way that prevents Bob and Chan from stealing the money that Alice wants delivered to Dina.
|
||||||
|
|
||||||
|
==== A physical example of "routing"
|
||||||
|
|
||||||
|
To understand how the Lightning Network protects the payment while being routed, we can compare to an example of routing physical payments with gold coins in the real world.
|
||||||
|
|
||||||
|
Assume Alice wants to give 10 gold coins to Dina, but does not have direct access to Dina.
|
||||||
|
However, Alice knows Bob, who knows Chan, who knows Dina and so she decides to ask Bob and Chan for help.
|
||||||
|
|
||||||
|
[[alice-dina-routing-1]]
|
||||||
|
.Alice wants to pay Dina 10 gold coins
|
||||||
|
image:images/gold-coins-network1.png[]
|
||||||
|
|
||||||
|
She can pay Bob to pay Chan to pay Dina, but how does she make sure that Bob or Chan don't run off with the coins after receiving them?
|
||||||
|
In the physical world contracts could be used for safely carrying out a series of payments.
|
||||||
|
|
||||||
|
Alice could negotiate a contract with Bob which reads:
|
||||||
|
|
||||||
|
[[alice-bob-contract-1]]
|
||||||
|
====
|
||||||
|
_I (Alice) will give you (Bob) 10 gold coins if you pass them on to Chan_
|
||||||
|
====
|
||||||
|
|
||||||
|
While this contract is nice in the abstract, in the real world, Alice runs the risk that Bob might breach the contract and hope to not get caught by law enforcement.
|
||||||
|
Even if Bob gets caught by law enforcement, Alice faces the risk that he might be bankrupt and be unable to return her 10 gold coins.
|
||||||
|
Assuming these issues are magically solved, it's still unclear how to leverage such a contract to achieve our desired outcome: the coins ultimately being delivered to Dina.
|
||||||
|
|
||||||
|
We thus improve our contract:
|
||||||
|
|
||||||
|
[alice-dina-routing-2]
|
||||||
|
====
|
||||||
|
_I (Alice) will reimburse you (Bob) with 10 gold coins if you can prove to me (for example via a receipt) that you already have delivered 10 gold coins to Chan_
|
||||||
|
====
|
||||||
|
|
||||||
|
You might ask yourself why should Bob sign such a contract.
|
||||||
|
He has to pay Chan but ultimately gets nothing out of the exchange, and he runs the risk that Alice might not reimburse him.
|
||||||
|
Bob could offer Chan a similar contract to pay Dina, but similarly Chan has no reason to accept it either.
|
||||||
|
Even putting aside the risk, Bob and Chan must _already_ have 10 gold coins to send, otherwise they wouldn't be able to participate in the contract.
|
||||||
|
Thus Bob and Chan face both risk and opportunity cost for agreeing to this contract, and they would need to be compensated in order for them to accept it.
|
||||||
|
|
||||||
|
Alice can this make this attractive to both Bob and Chan, by offering them fees of 1 gold coin each, if they transmit her payment to Dina.
|
||||||
|
The final contract would instead read:
|
||||||
|
|
||||||
|
[alice-dina-routing-3]
|
||||||
|
====
|
||||||
|
_I (Alice) will reimburse you (Bob) with 12 gold coins if you can prove to me (for example via a receipt) that you already have delivered 11 golden coins to Chan_
|
||||||
|
====
|
||||||
|
|
||||||
|
Alice now promises Bob 12 gold coins.
|
||||||
|
There are 10 to be delivered to Dina and 2 for the fees.
|
||||||
|
She promises 12 to Bob if he can prove that he has forwarded 11 to Chan.
|
||||||
|
The difference of 1 gold coin is the fee that Bob will earn for helping out with this particular payment.
|
||||||
|
|
||||||
|
[[alice-dina-routing-2]]
|
||||||
|
.Alice pays Bob, Bob pays Chan, Chan pays Dina
|
||||||
|
image:images/gold-coins-network2.png[]
|
||||||
|
|
||||||
|
As there is still the issue of trust and the risk that either Alice or Bob don't honor the contract, all parties decide to use an escrow service.
|
||||||
|
At the start of the exchange, Alice could "lock up" these 12 golden coins in escrow that will only be paid to Bob once he proves that he's paid 11 golden coins to Chan.
|
||||||
|
|
||||||
|
This escrow service is an "ideal functionality", which will later be replaced by a more trust-minimized mechanism.
|
||||||
|
Let's assume for now that everyone trusts this escrow.
|
||||||
|
|
||||||
|
In the Lightning Network, the receipt (proof of payment) could take the form of a secret that only Dina knows.
|
||||||
|
In practice, this secret would be a large random number that is large enough to prevent others from guessing it (typically _very, very_ large number, encoded using 256 bits!).
|
||||||
|
|
||||||
|
Dina generates this secret value +R+ from a random number generator.
|
||||||
|
|
||||||
|
The secret could then be committed to the contract by including the SHA256 hash of the secret in the contract itself, as follows:
|
||||||
|
|
||||||
|
latexmath:[\(H = SHA256(R)\)]
|
||||||
|
|
||||||
|
We call this hash of the payment's secret the payment hash.
|
||||||
|
The secret which "unlocks" the payment is called the payment secret.
|
||||||
|
|
||||||
|
For now, we keep things simple and assume that Dina's secret is simply the text line: `+Dinas secret+`.
|
||||||
|
In order to "commit" to this secret, she computes the SHA256 hash which when encoded in hex, can be displayed as: `+0575965b3b44be51e8057d551c4016d83cb1fba9ea8d6e986447ba33fe69f6b3+`.
|
||||||
|
footnote:[You can verify this by typing `echo -n "Dinas secret" | sha256sum` to your Linux command line shell.]
|
||||||
|
|
||||||
|
To facilitate Alice's payment, Dina will create the secret and the payment hash and send the payment hash to Alice.
|
||||||
|
|
||||||
|
[[alice-dina-routing-3]]
|
||||||
|
.Dina sends the hashed secret to Alice
|
||||||
|
image:images/gold-coins-network3.png[]
|
||||||
|
|
||||||
|
Alice doesn't know the secret but she can rewrite her contract to use the hash of the secret as a proof of payment:
|
||||||
|
|
||||||
|
[alice-dina-routing-4]
|
||||||
|
====
|
||||||
|
_I (Alice) will reimburse you (Bob) with 12 gold coins if you can show me a valid message that hashes to:`+057596...+`.
|
||||||
|
You can acquire this message by setting up a similar Contract with Chan who has to set up a similar contract with Dina.
|
||||||
|
In order to assure you that you will get reimbursed I will provide the 12 gold coins to an trusted escrow before you set up your next contract._
|
||||||
|
====
|
||||||
|
|
||||||
|
This new contract now protects Alice from Bob not forwarding to Chan, protects Bob from not being reimbursed by Alice, and ensures that there will be proof that Dina was ultimately paid via the hash of Dina's secret.
|
||||||
|
This secret message that hashes to the +057596...+ is called a _pre-image_.
|
||||||
|
|
||||||
|
After Bob and Alice agree to the contract, and Bob receives the message from the escrow that Alice has deposited the 12 gold coins, Bob can now negotiate a similar contract with Chan.
|
||||||
|
|
||||||
|
Note that since Bob is taking a service fee of 1 coin, he will only forward 11 gold coins to Chan once Chan shows proof that he has paid Dina.
|
||||||
|
Similarly, Chan will also demand a fee and will expect to receive 11 gold coins once he has proved that he has paid Dina the promised 10 gold coins.
|
||||||
|
|
||||||
|
Bob's contract with Chan will read:
|
||||||
|
|
||||||
|
[alice-dina-routing-5]
|
||||||
|
====
|
||||||
|
_I (Bob) will reimburse you (Chan) with 11 gold coins if you can show me a valid message that hashes to:`+057596...+`.
|
||||||
|
You can acquire this message by setting up a similar contract with Dina.
|
||||||
|
In order to assure you that you will get reimbursed I will provide the 11 gold coins to an trusted escrow before you set up your next contract._
|
||||||
|
====
|
||||||
|
|
||||||
|
Once Chan gets the message from the escrow that Bob has deposited the 11 gold coins, Chan sets up a similar contract with Dina:
|
||||||
|
|
||||||
|
[alice-dina-routing-6]
|
||||||
|
====
|
||||||
|
_I (Chan) will reimburse you (Dina) with 10 golden coins if you can show me a valid message that hashes to:`+057596...+`.
|
||||||
|
In order to assure you that you will get reimbursed after revealing the secret I will provide the 10 gold coins to an trusted escrow._
|
||||||
|
====
|
||||||
|
|
||||||
|
Everything is now in place.
|
||||||
|
Alice has a contract with Bob and has placed 12 gold coins in escrow.
|
||||||
|
Bob has a contract with Chan and has placed 11 gold coins in escrow
|
||||||
|
Chan has a contract with Dina and has placed 10 gold coins in escrow.
|
||||||
|
It is now up to Dina to reveal the secret, which is the pre-image to the hash she has established as proof of payment.
|
||||||
|
|
||||||
|
Dina now sends +"Dinas secret"+ to Chan.
|
||||||
|
|
||||||
|
He checks that +"Dinas secret" hashes to +057596...+. Chan now has proof of payment and so instructs the escrow service to release the 10 golden coins to Dina.
|
||||||
|
|
||||||
|
Chan now provides the secret to Bob. Bob checks it and instructs the escrow service to release the 11 gold coins to Chan.
|
||||||
|
|
||||||
|
Bob now provides the secret to Alice.
|
||||||
|
Alice checks it and instructs the escrow to release 12 gold coins to Bob.
|
||||||
|
|
||||||
|
All the contracts are now settled.
|
||||||
|
Alice has paid a total of 12 gold coins, 1 of which was received by Bob, 1 of which was received by Chan, and 10 of which were received by Dina.
|
||||||
|
With a chain of contracts like this in place, Bob and Chan could not run away with the money because they deposited it in escrow first.
|
||||||
|
|
||||||
|
However, one issue still remains.
|
||||||
|
If Dina refused to release her secret pre-image, then Chan, Bob, and Alice would all have their coins stuck in escrow but wouldn't be reimbursed.
|
||||||
|
And similarly if anyone else along the chain failed to pass on the secret, the same thing would happen.
|
||||||
|
So while no one can steal money from Alice everyone can still lose money.
|
||||||
|
|
||||||
|
Luckily, this can be resolved by adding a deadline to the contract.
|
||||||
|
|
||||||
|
We could amend the contract so that if it is not fulfilled by a certain deadline, then the contract expires and the escrow service returns the money to the person who made the original deposit.
|
||||||
|
We call this deadline a "time lock".
|
||||||
|
|
||||||
|
The deposit is locked with the escrow service for a certain amount of time, and is eventually released even if no proof of payment was provided.
|
||||||
|
|
||||||
|
In order to factor this in, the contract between Alice and Bob is once again amended with a new clause:
|
||||||
|
|
||||||
|
[alice-dina-routing-7]
|
||||||
|
====
|
||||||
|
_Bob has 24 hours to show the secret after the contract was signed.
|
||||||
|
If Bob does not provide the secret by this time, Alice's deposit will be refunded by the escrow service and the contract becomes invalid._
|
||||||
|
====
|
||||||
|
|
||||||
|
Bob, of course, now has to make sure he receives the proof of payment within 24 hours.
|
||||||
|
Even if he successfully pays Chan, if he receives the proof of payment later than 24 hours he will not be reimbursed. To remove that risk, Bob must give Chan and even shorter deadline.
|
||||||
|
|
||||||
|
In turn, Bob will alter his contract with Chan in the following way:
|
||||||
|
|
||||||
|
[alice-dina-routing-8]
|
||||||
|
====
|
||||||
|
_Chan has 22 hours to show the secret after the contract was signed.
|
||||||
|
If he does not provide the secret by this time, Bob's deposit will be refunded by the escrow service and the contract becomes invalid._
|
||||||
|
====
|
||||||
|
|
||||||
|
As you might have guessed, Chan is now incentivized to also alter his contract with Dina:
|
||||||
|
|
||||||
|
[alice-dina-routing-9]
|
||||||
|
====
|
||||||
|
_Dina has 20 hours to show the secret after the contract was signed.
|
||||||
|
If he does not provide the secret by this time, Bob's deposit will be refunded by the escrow service and the contract becomes invalid._
|
||||||
|
====
|
||||||
|
|
||||||
|
With such a chain of contracts we can ensure that, after 24 hours, the payment will successfully deliver from Alice to Bob to Chan to Dina, or it will fail and everyone will be refunded.
|
||||||
|
Either the contract fails or succeeds, there's no middle ground.
|
||||||
|
|
||||||
|
In the context of the Lightning Network, we call this "all or nothing" property _atomicity_.
|
||||||
|
|
||||||
|
As long as the escrow is trustworthy and faithfully performs its duty, then no party will have their coins stolen in the process.
|
||||||
|
|
||||||
|
The pre-condition to this _route_ working at all, is that all parties in the path have enough money to satisfy the required series of deposits.
|
||||||
|
|
||||||
|
While this seems like a minor detail we will see in later this chapter that this requirement is actually one of the more difficult issues for Lightning Network nodes.
|
||||||
|
It becomes progressively more difficult as the size of the payment increases.
|
||||||
|
Furthermore, the parties cannot use their money while it is locked in escrow.
|
||||||
|
|
||||||
|
Thus users forwarding payments face an opportunity cost for locking the money, which is ultimately reimbursed through routing fees, as we saw in the example above.
|
||||||
|
|
||||||
|
Now that we've seen a physical payment routing example, we will see how this can be implemented on the Bitcoin blockchain, without any need for third-party escrow. To do this we will be setting up the contracts between the participants using Bitcoin Script. We replace the third-party escrow with _smart contracts_ that implement a fairness protocol. Let's break that concept down and implement it!
|
||||||
|
|
||||||
|
=== Fairness Protocol
|
||||||
|
|
||||||
|
As we saw in the first chapter of this book, the innovation of Bitcoin is the ability to use cryptographic primitives to implement a fairness protocol that substitutes trust in third parties (intermediaries), with a trusted protocol.
|
||||||
|
|
||||||
|
In our gold coin example, we needed an "escrow" service in order to prevent any one of the parties from reneging on their obligations. The innovation of cryptographic fairness protocols allows us to replace the escrow service with a protocol.
|
||||||
|
|
||||||
|
The properties of the fairness protocol we want to create are:
|
||||||
|
|
||||||
|
Trsutless Operation:: The participants in a routed payment do not need to trust each other, or any intermediary or third party. Instead, they trust the protocol to protect them from cheating.
|
||||||
|
|
||||||
|
Atomicity:: The payment is fully executed, or it fails and everyone is refunded. There is no possibility of an intermediary collecting a routed payment and not forwarding it to the next hop. Thus, the intermediaries can't cheat or steal.
|
||||||
|
|
||||||
|
Multihop:: The security of the system extends end-to-end for payments routed through multiple payment channels, just as it is for a payment between the two ends of a single payment channel.
|
||||||
|
|
||||||
|
An optional, additional property, is the ability to split payments into multiple parts while maintaining atomicity for the entire payment. These are called _Multi-Part Payments (MPP)_ and are explored further in <<multipart_payments>>.
|
||||||
|
|
||||||
|
==== Implementing Atomic Trustless Multihop Payments
|
||||||
|
|
||||||
|
Bitcoin Script is flexible enough that there are dozens of ways to implement a fairness protocol that has the properties of atomicity, trustless operation and multihop security. Choosing a specific implementation is dependent on certain tradeoffs between privacy, efficiency and complexity.
|
||||||
|
|
||||||
|
The fairness protocol for routing used in the Lightning Network today is called a Hash Time-Locked Contract (HTLC). HTLCs use a hash pre-image as the secret that unlocks a payment, as we saw in the gold coin example in this chapter. The recipient of a payment generates a random secret number and calculates its hash. The hash becomes the condition of payment and once the secret is revealed, all the participants can redeem their incoming payments. HTLCs offer atomicity, trustless operation and multihop security. While HTLCs are efficient and very simple, they involve a small compromise of privacy (see <<htlc_privacy_compromise>>).
|
||||||
|
|
||||||
|
Another proposed mechanism for implementing routing is a _Point Time-Locked Contract (PTLC)_. PTLCs also achieve atomicity, trustless operation and multihop security, but do so with increased efficincy and better privacy. Efficient implementation of PTLCs depends on a new digital signature algorithm called _Schnorr signatures_, which is expected to active in Bitcoin in 2021.
|
||||||
|
|
||||||
|
=== Revisiting our example
|
||||||
|
|
||||||
|
Let's revisit our example from the first part of this chapter. Alice wants to "tip" Dina, with a Lightning payment. Let's say Alice wants to send Dina 50,000 satoshis as a tip.
|
||||||
|
|
||||||
|
For Alice to pay Dina, Alice will need Dina's node to generate a Lightning invoice. We will discuss this in more detail in <<bolt11_invoices>>. For now, let's assume that Dina has a website that can produce a Lightning invoice for tips.
|
||||||
|
|
||||||
|
[TIP]
|
||||||
|
====
|
||||||
|
Lightning payments can be sent without an invoice, using a feature called _keysend_, which we will discuss in more detail in <<keysend>>. For now, we will explain the simpler payment flow using an invoice.
|
||||||
|
====
|
||||||
|
|
||||||
|
Alice visits Dina's site, enter the amount of 50,000 satoshis in a form and in response, Dina's Lightning node generate a payment request for 50,000 satoshis in the form of a Lightning invoice.
|
||||||
|
|
||||||
|
[[alice-dina-invoice-1]]
|
||||||
|
.Alice requests an invoice from Dina's website
|
||||||
|
image:images/alice-dina-invoice-1.png["Alice requests an invoice from Dina's website"]
|
||||||
|
|
||||||
|
As we saw in previous examples, we assume that Alice does not have a direct payment channel to Dina. Instead, Alice has a channel to Bob, Bob has a channel to Chan and Chan has a channel to Dina. To pay Dina, Alice must find a path that connects her to Dina. We will discuss that step in more detail in <<path_finding>>. For now, let's assume that Alice is able to gather information about available channels and sees that there is a path from her to Dina, via Bob and Chan.
|
||||||
|
|
||||||
|
[NOTE]
|
||||||
|
====
|
||||||
|
Remember how Bob and Chan might expect a small compensation for routing the payment through their nodes? Alice wants to pay Dina 50,000 satoshis, but as you will see in the following sections she will send Bob 50,200 satoshis. The extra 200 satoshis will pay Bob and Chan 100 satohis each, as a routing fee.
|
||||||
|
====
|
||||||
|
|
||||||
|
Now, Alice's node can construct a Lightning payment. In the next few sections we will see how Alice's node constructs a Hash Time-Locked Contract (HTLCs) to pay Dina and how that HTLC is forwarded along the path from Alice to Dina.
|
||||||
|
|
||||||
|
|
||||||
|
==== On-chain vs Off-chain settlement of HTLCs
|
||||||
|
|
||||||
|
The purpose of the Lightning Network is to enable _off-chain_ transactions that are trusted just the same as on-chain transactions, because no one can cheat. The reason no one can cheat is because at any time, any of the participants can take their off-chain transactions on-chain. Each off-chain transaction is ready to be submitted to the Bitcoin blockchain at any time. Thus, the Bitcoin blockchain acts as a dispute-resolution and final settlement mechanism if necessary.
|
||||||
|
|
||||||
|
The mere fact that any transaction can be taken on-chain at any time is precisely the reason that all those transactions can be kept off-chain. If you know you have recourse, you can continue to cooperate with the other participants and avoid the need for on-chain settlement and extra fees.
|
||||||
|
|
||||||
|
In all the examples that follow, we will assume that any of these transactions can be made on-chain at any time. The participants will choose to keep them off-chain, but there is no difference in the functionality of the system other than the higher fees and delay imposed by on-chain mining of the transactions. The example works the same if all the transactions are on-chain or off-chain.
|
||||||
|
|
||||||
|
=== Hash Time Locked Contracts (HTLCs)
|
||||||
|
|
||||||
|
In this section we explain how Hash Time Locked Contracts (HTLCs) work.
|
||||||
|
|
||||||
|
The first part of a Hash Time-Locked Contract is the "Hash". This refers to the use of a cryptographic hash algorithm to commit to a randomly generated secret. Knowledge of the secret allows redemption of the payment. The cryptographic hash function, guarantees that while it's infeasible for anyone to guess the secret pre-image, it's easy for anyone to verify the hash, and there's only one possible pre-image that resolves the payment condition.
|
||||||
|
|
||||||
|
Alice has a Lightning invoice from Dina. Inside that invoice Dina has encoded a _payment hash_, which is the cryptographic hash of a secret that Dina's node produced. Dina's secret is called the _payment pre-image_. The payment hash acts as an identifier that can be used to route the payment to Dina. The payment pre-image acts as a receipt and proof of payment once the payment is complete.
|
||||||
|
|
||||||
|
[[alice-dina-invoice-2]]
|
||||||
|
.Alice gets a payment hash from Dina
|
||||||
|
image:images/alice-dina-invoice-2.png["Alice gets a payment hash from Dina"]
|
||||||
|
|
||||||
|
In the Lightning Network, Dina's payment pre-image won't be a phrase like "Dina's secret", but a random number generated by Dina's node. Let's call that random number +R+.
|
||||||
|
|
||||||
|
Dina's node will calculate a cryptographic hash of +R+, such that:
|
||||||
|
|
||||||
|
[[payment_hash_and_preimage]]
|
||||||
|
.Calculating the payment hash
|
||||||
|
----
|
||||||
|
H = SHA256(R)
|
||||||
|
----
|
||||||
|
|
||||||
|
In <<payment_hash_and_preimage>> +H+ is the hash, or _payment hash_ and +R+ is the secret or _payment pre-image_.
|
||||||
|
|
||||||
|
The use of a cryptographic hash function is one element that guarantees _trustless operation_. The payment intermediaries do not need to trust each other because they know that no one can guess the secret or fake it.
|
||||||
|
|
||||||
|
==== HTLCs in Bitcoin Script
|
||||||
|
|
||||||
|
In our gold coin example, Alice had a contract enforced by escrow like this:
|
||||||
|
|
||||||
|
[[alice_bob_contract]]
|
||||||
|
====
|
||||||
|
_Alice will reimburse Bob with 12 gold coins if you can show a valid message that hashes to:_ +0575...f6b3+. _Bob has 24 hours to show the secret after the contract was signed. If Bob does not provide the secret by this time, Alice's deposit will be refunded by the escrow service and the contract becomes invalid._
|
||||||
|
====
|
||||||
|
|
||||||
|
Let's see how we would implement this as an HTLC in Bitcoin Script. In <<received_htlc>> we see an HTLC Bitcoin Script as currently used in the Lightning Network. You can find this definition in https://github.com/lightningnetwork/lightning-rfc/blob/master/03-transactions.md#offered-htlc-outputs[BOLT3 - Transactions]:
|
||||||
|
|
||||||
|
[[received_htlc]]
|
||||||
|
.HTLC implemented in Bitcoin Script (BOLT3)
|
||||||
|
[source,linenum]
|
||||||
|
----
|
||||||
|
# To remote node with revocation key
|
||||||
|
OP_DUP OP_HASH160 <RIPEMD160(SHA256(revocationpubkey))> OP_EQUAL
|
||||||
|
OP_IF
|
||||||
|
OP_CHECKSIG
|
||||||
|
OP_ELSE
|
||||||
|
<remote_htlcpubkey> OP_SWAP OP_SIZE 32 OP_EQUAL
|
||||||
|
OP_IF
|
||||||
|
# To local node via HTLC-success transaction.
|
||||||
|
OP_HASH160 <RIPEMD160(payment_hash)> OP_EQUALVERIFY
|
||||||
|
2 OP_SWAP <local_htlcpubkey> 2 OP_CHECKMULTISIG
|
||||||
|
OP_ELSE
|
||||||
|
# To remote node after timeout.
|
||||||
|
OP_DROP <cltv_expiry> OP_CHECKLOCKTIMEVERIFY OP_DROP
|
||||||
|
OP_CHECKSIG
|
||||||
|
OP_ENDIF
|
||||||
|
OP_ENDIF
|
||||||
|
----
|
||||||
|
|
||||||
|
Wow that looks complicated! Don't worry though, we will take it one step at a time and simplfy it.
|
||||||
|
|
||||||
|
The Bitcoin Script currently used in the Lightning Network is quite complex because it is optimized for on-chain space efficiency, which makes very compact but difficult to read.
|
||||||
|
|
||||||
|
In the following sections, we will focus on the main elements of the script and present simplified scripts that are slightly different from what is actually used in Lightning.
|
||||||
|
|
||||||
|
The main part of the HTLC is in line 10 of <<received_htlc>>. Let's build it up from scratch!
|
||||||
|
|
||||||
|
==== Payment pre-image and hash verification
|
||||||
|
|
||||||
|
The core of an HTLC is the "hash", where payment can be made if the recipient knows the payment pre-image. Alice locks the payment to a specific payment hash and Bob has to present a payment pre-image to claim the funds. The Bitcoin system can verify that Bob's payment pre-image is correct by hashing it and comparing the result to the payment hash that Alice used to lock the funds.
|
||||||
|
|
||||||
|
This part of an HTLC can be implemented in Bitcoin Script as follows:
|
||||||
|
|
||||||
|
----
|
||||||
|
OP_SHA256 <H> OP_EQUAL
|
||||||
|
----
|
||||||
|
|
||||||
|
Alice can create a transaction output that pays, 50,200 satoshi with a locking script above, replacing <H> with the hash value +0575...f6b3+ provided by Dina. Then, Alice can sign this transaction and offer it to Bob:
|
||||||
|
|
||||||
|
.Alice's offers a 50,200 satoshi HTLC to Bob
|
||||||
|
----
|
||||||
|
OP_SHA256 0575...f6b3 OP_EQUAL
|
||||||
|
----
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Bob can't spend this HTLC until he knows Dina's secret, so spending the HTLC is conditional on Bob's fullfilment of the payment all the way to Dina.
|
||||||
|
|
||||||
|
Once Bob has Dina's secret, Bob can spend this output with an unlocking script containing the secrect pre-image value +R+
|
||||||
|
|
||||||
|
The unlocking script and locking script would combined to produce:
|
||||||
|
|
||||||
|
----
|
||||||
|
<R> OP_SHA256 <H> OP_EQUAL
|
||||||
|
----
|
||||||
|
|
||||||
|
The Bitcoin Script engine would evaluate this script as follows:
|
||||||
|
|
||||||
|
1. +R+ is pushed to the stack
|
||||||
|
1. The OP_SHA256 operator takes the value +R+ off the stack and hashes it, pushing the result H~R~ to the stack
|
||||||
|
1. +H+ is pushed to the stack
|
||||||
|
1. The OP_EQUAL operator compares +H+ and H~R~. If they are equal, the result is +TRUE+, the script is complete and the payment is verified.
|
||||||
|
|
||||||
|
==== Extending HTLCs from Alice to Dina
|
||||||
|
|
||||||
|
Alice will now extend the HTLC across the network so that it reaches Dina.
|
||||||
|
|
||||||
|
[[alice-dina-htlc-1]]
|
||||||
|
.Propagating the HTLC across the network
|
||||||
|
image:images/alice-dina-htlc-1.png["Propagating the HTLC across the network"]
|
||||||
|
|
||||||
|
Alice has given Bob an HTLC for 50,200 satoshi. Bob can now create an HTLC for 50,100 satoshi and give it to Chan.
|
||||||
|
|
||||||
|
Bob knows that Chan can't redeem Bob's HTLC without broadcasting the secret, at which point Bob can also use the secret to redeem Alice's HTLC. This is a really important point, because it ensures end-to-end _atomicity_ of the HTLC. To spend the HTLC, one needs to reveal the secret, which then makes it possible for others to spend their HTLC also. Either all the HTLCs are spendable, or none of the HTLCs are spendable: atomicity!
|
||||||
|
|
||||||
|
Since Alice's HTLC is 100 satoshi more that the HTLC Bob gave to Chan, Bob will earn 100 satoshi as a routing fee if this payment completes.
|
||||||
|
|
||||||
|
Bob isn't taking a risk and isn't trusting Alice or Chan. Instead, Bob is trusting that a signed transaction together with the secret will be redeemable on the Bitcoin blockchain.
|
||||||
|
|
||||||
|
Similarly, Chan can extend a 50,000 HTLC to Dina. He isn't risking anything or trusting Bob or Dina. To redeem the HTLC, Dina would have to broadcast the secret, which Chan could use to redeem Bob's HTLC. Chan would also earn 100 satoshis as a routing fee.
|
||||||
|
|
||||||
|
==== Back-propagating the secret
|
||||||
|
|
||||||
|
Once Dina receives a 50,000 HTLC from Chan, she can now get paid. Dina could simply commit this HTLC on-chain and spend it by revealing the secret in the spending transaction. Or, instead, Dina can update the channel balance with Chan by giving him the secret. There's no reason to incur a transaction fee and go on-chain. So, instead, Dina sends the secret to Chan and they agree to update their channel balances to reflect a 50,000 satoshi Lightning payment to Dina.
|
||||||
|
|
||||||
|
Notice Dina's channel balance goes from 50,000 satoshi to 100,000 satoshi. Chan's channel balance is reduced from 200,000 satoshi to 150,000 satoshi. The channel capacity hasn't changed, but 50,000 has moved from Chan's side of the channel to Dina's side of the channel.
|
||||||
|
|
||||||
|
[[alice-dina-htlc-redeem-1]]
|
||||||
|
.Dina settles Chan's HTLC off-chain
|
||||||
|
image:images/alice-dina-htlc-redeem-1.png["Dina settles Chan's HTLC off-chain"]
|
||||||
|
|
||||||
|
Chan now has the secret and has paid Dina 50,000 satoshi. He can do this without any risk, because the secret allows Chan to redeem the 50,100 HTLC from Bob. Chan has the option to commit that HTLC on chain and spend it by revealing the secret on the Bitcoin blockchain. But, like Dina, he'd rather avoid transaction fees. So instead, he sends the secret to Bob so they can update their channel balances to reflect a 50,100 satoshi Lightning payment from Bob to Chan. Chan has paid Dina 50,000 satoshi, and received 50,100 satoshi from Bob. So Chan has 100 satoshi more in his channel balances, which he earned as a routing fee.
|
||||||
|
|
||||||
|
[[alice-dina-htlc-redeem-2]]
|
||||||
|
.Chan settles Bob's HTLC off-chain
|
||||||
|
image:images/alice-dina-htlc-redeem-2.png["Chan settles Bob's HTLC off-chain"]
|
||||||
|
|
||||||
|
Bob now has the secret too. He can use it to spend Alice's HTLC on-chain. Or, he can avoid transaction fees by settling the HTLC in the channel with Alice. Bob sends the secret to Alice and they update the channel balance to reflect a 50,200 satoshi Lightning payment from Alice to Bob. Bob has recieved 50,200 satoshi from Alice and paid 50,100 satoshi to Chan, so he has an extra 100 satoshi in his channel balances from routing fees.
|
||||||
|
|
||||||
|
[[alice-dina-htlc-redeem-3]]
|
||||||
|
.Bob settles Alice's HTLC off-chain
|
||||||
|
image:images/alice-dina-htlc-redeem-3.png["Bob settles Alice's HTLC off-chain"]
|
||||||
|
|
||||||
|
Alice receives the secret and has settled the 50,200 satoshi HTLC. The secret can be used as a _receipt_ to prove that Dina got paid for that specific payment hash.
|
||||||
|
|
||||||
|
The final channel balances reflect Alice's payment to Dina and the routing fees paid at each hop
|
||||||
|
|
||||||
|
[[alice-dina-htlc-redeem-4]]
|
||||||
|
.Channel balances after the payment
|
||||||
|
image:images/alice-dina-htlc-redeem-4.png["Channel balances after the payment"]
|
||||||
|
|
||||||
|
[[preventing_theft]]
|
||||||
|
==== Signature binding - preventing theft of HTLCs
|
||||||
|
|
||||||
|
There's a catch. Did you notice it?
|
||||||
|
|
||||||
|
If Alice, Bob and Chan create the HTLCs as shown above, they face a small but not insignificant risk of loss. Any of those HTLCs can be redeemed (spent) by anyone who knows the secret. At first only Dina knows the secret. Dina is supposed to only spend the HTLC from Chan. But Dina could spend all three HTLCs at the same time, or even in a single spending transaction! After all Dina knows the secret before anyone else. Similarly, once Chan knows the secret he is only supposed to spend the HTLC offered by Bob. But what if Chan also spends Alice's offered HTLC too?
|
||||||
|
|
||||||
|
This is not _trustless_! It fails the most important security feature. We need to fix this.
|
||||||
|
|
||||||
|
The HTLC script must have an additional condition that binds each HTLC to a specific recipient. We do this by requiring a digital signature that matches the public key of each recipient, thereby preventing anyone else from spending that HTLC. Since only the designated recipient has the ability to produce a digital signature matching that public key, only the designated recipient can spend that HTLC.
|
||||||
|
|
||||||
|
Let's look at the scripts again with this modification in mind. Alice's HTLC for Bob is modified to include Bob's Public Key and the +OP_CHECKSIG+ operator.
|
||||||
|
|
||||||
|
Here's the modified HTLC script:
|
||||||
|
|
||||||
|
----
|
||||||
|
OP_SHA256 <H> OP_EQUALVERIFY <Bob's Pub> OP_CHECKSIG
|
||||||
|
----
|
||||||
|
|
||||||
|
[TIP]
|
||||||
|
====
|
||||||
|
Notice that we also changed +OP_EQUAL+ to +OP_EQUALVERIFY+. When an operator has the suffix +VERIFY+ it does not return +TRUE+ or +FALSE+ on the stack. Instead it *halts* execution and fails the script if the result is false and continues without any stack output if it is true.
|
||||||
|
====
|
||||||
|
|
||||||
|
To redeem this HTLC, Bob has to present an unlocking script that includes a signature from Bob's private key as well as the secret payment pre-image, like this:
|
||||||
|
|
||||||
|
----
|
||||||
|
<Bob's Signature> <R>
|
||||||
|
----
|
||||||
|
|
||||||
|
The unlocking and locking script are combined and evaluated by the scripting engine, as follows:
|
||||||
|
|
||||||
|
----
|
||||||
|
<Bob's Sig> <R> OP_SHA256 <H> OP_EQUALVERIFY <Bob's Pub> OP_CHECKSIG
|
||||||
|
----
|
||||||
|
|
||||||
|
1. +<Bob's Sig>+ is pushed on to the stack
|
||||||
|
1. +R+ is pushed on to the stack
|
||||||
|
1. OP_SHA256 pops and hashes +R+ from the top of the stack and pushes H~R~ on to the stack
|
||||||
|
1. +H+ is pushed on to the stack
|
||||||
|
1. OP_EQUALVERIFY pops H and H~R~ and compares them. If they are not the same, execution halts. Otherwise, we continue without output to the stack
|
||||||
|
1. +<Bob's Pub> key is pushed to the stack
|
||||||
|
1. OP_CHECKSIG pops +<Bob's Sig>+ and +<Bob's Pub>+ and verifies the signature. The result (TRUE/FALSE) is pushed to the stack.
|
||||||
|
|
||||||
|
As you can see, this is slightly more complicated, but now we have fixed the HTLC and made sure only the intended recipient can spend it.
|
||||||
|
|
||||||
|
==== Hash Optimization
|
||||||
|
|
||||||
|
Let's look at the first part of the HTLC script so far:
|
||||||
|
|
||||||
|
----
|
||||||
|
OP_SHA256 <H> OP_EQUALVERIFY
|
||||||
|
----
|
||||||
|
|
||||||
|
If we look at this in a symbolic representation above, it looks like the +OP_+ operators take up the most space. But that's not the case. Bitcoin Script is encoded in binary, with each operator representing one byte. Meanwhile, the +<H>+ value we use as a placeholder for the payment hash is a 32-byte (256-bit) value. You can find a listing of all the Bitcoin Script operators and their binary and hex encoding in https://en.bitcoin.it/wiki/Script[Bitcoin Wiki: Script], or in https://github.com/bitcoinbook/bitcoinbook/blob/develop/appdx-scriptops.asciidoc[Mastering Bitcoin Appendix: Transaction Script Language Operators, Constants, and Symbols].
|
||||||
|
|
||||||
|
Represented in hexadecimal, our HTLC script would look like this:
|
||||||
|
|
||||||
|
----
|
||||||
|
a8 0575965b3b44be51e8057d551c4016d83cb1fba9ea8d6e986447ba33fe69f6b3 88
|
||||||
|
----
|
||||||
|
|
||||||
|
In hexadecimal encoding, +OP_SHA256+ is +a8+ and +OP_EQUALVERIFY+ is +88+. The total length of this script is 34 bytes, of which 32 bytes are the hash.
|
||||||
|
|
||||||
|
As we've mentioned previously, any participant in the Lightning network should be able to take an off-chain transaction they hold and put it on-chain if they need to enforce their claim to funds. To take a transaction on-chain, they'd have to pay transaction fees to the miners and these fees are proportional to the *size in bytes* of the transaction.
|
||||||
|
|
||||||
|
Therefore, we want to find ways to minimize the on-chain "weight" of transactions by optimizing the script as much as possible. One way to do that is to add another hash function on top of the SHA256 algorithm, one that produces smaller hashes. The Bitcoin Script language provides the +OP_HASH160+ operator that "double hashes" a pre-image: first the pre-image is hashed with SHA256 and then the resulting hash is hashed again with the RIPEMD160 hash algorithm. The hash resulting from RIPEMD160 is 160 bits or 20 bytes, much more compact. In Bitcoin Script this is a very common optimization that is used in many of the common address formats.
|
||||||
|
|
||||||
|
So, let's use that optimization instead. Our SHA256 hash is +057596...69f6b3+. Putting that through another round of hasing with RIPEMD160 gives us the result:
|
||||||
|
|
||||||
|
----
|
||||||
|
R = "Dinas secret"
|
||||||
|
H256 = SHA256(R)
|
||||||
|
H256 = 0575965b3b44be51e8057d551c4016d83cb1fba9ea8d6e986447ba33fe69f6b3
|
||||||
|
H160 = RIPEMD160(H)
|
||||||
|
H160 = 9e017f6767971ed7cea17f98528d5f5c0ccb2c71
|
||||||
|
----
|
||||||
|
|
||||||
|
Alice can calculate the RIPEMD160 hash of the payment hash that Dina provides and use the shorter hash in her HTLC, as can Bob and Chan!
|
||||||
|
|
||||||
|
The "optimized" HTLC script would look like this:
|
||||||
|
|
||||||
|
----
|
||||||
|
OP_HASH160 <H160> OP_EQUALVERIFY
|
||||||
|
----
|
||||||
|
|
||||||
|
Encoded in hex this is:
|
||||||
|
|
||||||
|
----
|
||||||
|
a9 9e017f6767971ed7cea17f98528d5f5c0ccb2c71 88
|
||||||
|
----
|
||||||
|
|
||||||
|
Where OP_HASH160 is +a9+ and OP_EQUALVERIFY is +88+. This script is only 22 bytes long! We've saved 12 bytes from every transaction that redeems an HTLC on-chain.
|
||||||
|
|
||||||
|
With that optimization, you now see how we arrive at the HTLC script shown in line 10 of <<received_htlc>>:
|
||||||
|
|
||||||
|
----
|
||||||
|
...
|
||||||
|
# To local node via HTLC-success transaction.
|
||||||
|
OP_HASH160 <RIPEMD160(payment_hash)> OP_EQUALVERIFY...
|
||||||
|
----
|
||||||
|
|
||||||
|
==== HTLC cooperative and timeout failure
|
||||||
|
|
||||||
|
So far we looked at the "Hash" part of HTLC, and how it would work if everyone cooperated and was online at the time of payment.
|
||||||
|
|
||||||
|
What happens if someone goes offline or fails to cooperate? What happens if the payment cannot succeed?
|
||||||
|
|
||||||
|
We need to ensure a way to "fail gracefully", because occasional routing failures are inevitable. There are two ways to fail: cooperatively and with a time-locked refund.
|
||||||
|
|
||||||
|
Cooperative failure is relatively simple: the HTLC is unwound by every participant in the route removing the HTLC output from their commitment transactions without changing the balance. We'll look at how that works in detail in <<channel_operation>>.
|
||||||
|
|
||||||
|
Let's look at how we can reverse an HTLC without the cooperation of one or more participants. We need to make sure that if one of the participants does not cooperate, the funds are not simply locked in the HTLC _forever_. This would give someone the opportunity to ransom the funds of another participant: "I'll leave your funds tied up forever if you don't pay me ransom."
|
||||||
|
|
||||||
|
To prevent this, every HTLC script includes a refund clause that is connected to a time-lock. Remember our original escrow contract? "Bob has 24 hours to show the secret after the contract is signed. If Bob does not provide the secret by this time, Alice's deposit will be refunded"
|
||||||
|
|
||||||
|
The time-locked refund is an important part of the script that ensures _atomicity_, so that the entire end-to-end payment either succeeds or fails gracefully. There is not "half paid" state to worry about. If there is a failure, every participant can either unwind the HTLC cooperatively with their channel partner, or put the time-locked refund transaction on-chain unilaterally to get their money back.
|
||||||
|
|
||||||
|
To implement this refund in Bitcoin Script, we use a special operator +OP_CHECKLOCKTIMEVERIFY+ also known +OP_CLTV+ for short. Here's the script, as seen previously in line 13 of <<received_htlc>>:
|
||||||
|
|
||||||
|
----
|
||||||
|
...
|
||||||
|
OP_DROP <cltv_expiry> OP_CHECKLOCKTIMEVERIFY OP_DROP
|
||||||
|
OP_CHECKSIG
|
||||||
|
...
|
||||||
|
----
|
||||||
|
|
||||||
|
The +OP_CLTV+ operator takes an expiry time defined as the block height after which this transaction is valid. If the tranaction timelock is not set the same as +<cltv_expiry>+, the evaluation of the script fails and the transaction is invalid. Otherwise, the script continues without any output to the stack. Remember, the +VERIFY+ suffix means this operator does not output +TRUE+ or +FALSE+, but instead either halts/fails, or continus without stack output.
|
||||||
|
|
||||||
|
Essentially, the +OP_CLTV+ acts as a "gatekeeper" preventing the script from proceeding any further if the <cltv_expiry> block height has not been reached on the Bitcoin blockchain.
|
||||||
|
|
||||||
|
The +OP_DROP+ operator simply drops the topmost item on the script stack. This is necessary in the beginning, because there is a "leftover" item from the previous script lines. It is necessary *after* +OP_CLTV+ in order to remove the +<cltv_expiry>+ item from the top of the stack as it is no longer necessary.
|
||||||
|
|
||||||
|
Finally, once the stack has been cleaned up, there should be a public key and signature left behind, that +OP_CHECKSIG+ can verify. As we saw in <<preventing_theft>>, this is necessary to ensure that only the rightful owner of the funds can claim them, by binding this output to their public key and requiring a signature.
|
||||||
|
|
||||||
|
==== Decrementing time-locks
|
||||||
|
|
||||||
|
As the HTLCs are extended from Alice to Dina, the time-lock refund clause in each HTLC has a _different_ cltv_expiry value. We will see this in more detail as we talk about <<onion_routing>>. But suffice it to say that to ensure an orderly unwinding of a payment that fails, each hop needs to wait a bit less for their refund. The different between time-locks for each hop is called the cltv_expiry_delta and is set by each node and advertized to the network as we will see in <<gossip>>.
|
||||||
|
|
||||||
|
For example, Alice sets the refund time-lock on the first HTLC to a block height of current+500 blocks ("current" being the current block height). Bob would then set the time-lock cltv_expiry on the HTLC to Chan to current+450 blocks. Chan would set the time-lock to current+400 blocks from the current block height. This way, Chan can get a refund on the HTLC he offered to Dina _before_ Bob gets a refund on the HTLC he offered to Chan. Bob can get a refund of the HTLC he offered to Chan before Alice can get a refund for the HTLC she offered to Bob. The decrementing time-lock prevents race conditions and ensures the HTLC chain is unwound backwards, from the destination towards the origin.
|
||||||
|
|
||||||
|
=== Conclusion
|
||||||
|
|
||||||
|
In this chapter we saw how Alice can pay Dina even though she doesn't have a direct payment channel. Alice can find a path that connects her to Dina and route a payment across several payment channels so that it reaches Dina.
|
||||||
|
|
||||||
|
To ensure that the payment is _atomic_ and _trustless_ across _multiple hops_, Alice needs to implement a fairness protocol in cooperation with all the intermediary nodes in the path. The fairness protocol is currently implemented as a _Hash Time-Locked Contract (HTLC)_, which commits funds to a payment hash derived from a secret payment pre-image.
|
||||||
|
|
||||||
|
Each of the participants in the payment route can extend an HTLC to the next participant, without worrying about theft or stuck funds. The HTLC can be redeemed by revealing the secret payment pre-image. Once an HTLC reaches Dina, she reveals the pre-image which flows backwards resolving all the HTLCs offered.
|
||||||
|
|
||||||
|
Finally, we saw how a time-locked refund clause completes the HTLC, ensuring that every participant can get a refund if the payment fails but for whatever reason one of the participants doesn't cooperate in unwinding the HTLCs. By always having the option to go on-chain for a refund, the HTLC achieves the fairness goal of atomicity and trustless operation.
|
@ -35,10 +35,12 @@ The current status of the book is "IN PROGRESS". See below for status of specifi
|
|||||||
| [Nodes (LN Clients)](04_node_client.asciidoc) | #################### | :heavy_check_mark: |
|
| [Nodes (LN Clients)](04_node_client.asciidoc) | #################### | :heavy_check_mark: |
|
||||||
| [Operating a Node](05_node_operations.asciidoc) | ############################# | :heavy_check_mark: |
|
| [Operating a Node](05_node_operations.asciidoc) | ############################# | :heavy_check_mark: |
|
||||||
| PART 2 | PART 2 | PART2 |
|
| PART 2 | PART 2 | PART2 |
|
||||||
| [Intro to LN Routing (HTLCs)](routing.asciidoc) | #################### | :lock_with_ink_pen: |
|
| [Lightning Architecture](06_lightning_architecture.asciidoc) | # | :mag: |
|
||||||
|
| [Routing (HTLCs)](07_routing_htlcs.asciidoc) | ############### | :mag: |
|
||||||
| [Channel Construction in Detail](channel-construction.asciidoc) | ########### | :lock_with_ink_pen: |
|
| [Channel Construction in Detail](channel-construction.asciidoc) | ########### | :lock_with_ink_pen: |
|
||||||
| [Channel operation with HTLCs and Statemachine](channel-operation.asciidoc) | ###### | :lock_with_ink_pen: |
|
| [Channel operation with HTLCs and Statemachine](channel-operation.asciidoc) | ###### | :lock_with_ink_pen: |
|
||||||
| [Payment Path Finding](path-finding.asciidoc) | ############### | :lock_with_ink_pen: |
|
| [Payment Path Finding](path-finding.asciidoc) | ############### | :lock_with_ink_pen: |
|
||||||
|
| [Onion Construction and Routing](onions.asciidoc) | # | :lock_with_ink_pen: |
|
||||||
| [P2P Communication](p2p.asciidoc) | ### | :bookmark_tabs: |
|
| [P2P Communication](p2p.asciidoc) | ### | :bookmark_tabs: |
|
||||||
| [Channel Graph and Gossip Layer](channel-graph.asciidoc) | ### | :bookmark_tabs: |
|
| [Channel Graph and Gossip Layer](channel-graph.asciidoc) | ### | :bookmark_tabs: |
|
||||||
| [End-to-End Payment Presentation Layer](e2e-presentation-layer.asciidoc) | ### | :bookmark_tabs: |
|
| [End-to-End Payment Presentation Layer](e2e-presentation-layer.asciidoc) | ### | :bookmark_tabs: |
|
||||||
@ -50,7 +52,7 @@ The current status of the book is "IN PROGRESS". See below for status of specifi
|
|||||||
| [An - License Notices](appendix_license_notices.asciidoc) | # | :heavy_check_mark: |
|
| [An - License Notices](appendix_license_notices.asciidoc) | # | :heavy_check_mark: |
|
||||||
|
|
||||||
|
|
||||||
Total Word Count: 97452
|
Total Word Count: 101126
|
||||||
|
|
||||||
Target Word Count: 100,000-120,000
|
Target Word Count: 100,000-120,000
|
||||||
|
|
||||||
|
@ -79,7 +79,7 @@ While it takes longer than a single sentence, the SHA256 function processes the
|
|||||||
|
|
||||||
Now at this point you might be wondering how it is possible for a function that digests data of unlimited size to produce a unique fingerprint that is a fixed-size number?
|
Now at this point you might be wondering how it is possible for a function that digests data of unlimited size to produce a unique fingerprint that is a fixed-size number?
|
||||||
|
|
||||||
In theory, since there an infinite number of possible pre-images (inputs) and only a finite number of fingerprints, there must be many pre-images that produce the same 256-bit fingerprint. when two pre-images produce the same hash, this is known as a _collision_.
|
In theory, since there is an infinite number of possible pre-images (inputs) and only a finite number of fingerprints, there must be many pre-images that produce the same 256-bit fingerprint. When two pre-images produce the same hash, this is known as a _collision_.
|
||||||
|
|
||||||
In practice, a 256-bit number is so large that you will never find a collision on purpose. Cryptographic hash functions work on the basis that a search for a collision is a brute-force effort that takes so much energy and time that it is not practically possible.
|
In practice, a 256-bit number is so large that you will never find a collision on purpose. Cryptographic hash functions work on the basis that a search for a collision is a brute-force effort that takes so much energy and time that it is not practically possible.
|
||||||
|
|
||||||
@ -89,17 +89,17 @@ Deterministic:: The same input always produces the same hash.
|
|||||||
|
|
||||||
Irreversible:: It is not possible to compute the pre-image of a hash.
|
Irreversible:: It is not possible to compute the pre-image of a hash.
|
||||||
|
|
||||||
Collission-Proof:: It is computationally infeasible to find two messages that have the same hash.
|
Collision-Proof:: It is computationally infeasible to find two messages that have the same hash.
|
||||||
|
|
||||||
Uncorrelated:: A small change in the input produces such a big change in the output that the output seems uncorrelated to the input.
|
Uncorrelated:: A small change in the input produces such a big change in the output that the output seems uncorrelated to the input.
|
||||||
|
|
||||||
Uniform/Random:: A cryptographic hash function produces hashes that are uniformly distributed across the entire 256-bit space of possible outputs. The output of a hash appears to be random, though it is not truly random.
|
Uniform/Random:: A cryptographic hash function produces hashes that are uniformly distributed across the entire 256-bit space of possible outputs. The output of a hash appears to be random, though it is not truly random.
|
||||||
|
|
||||||
Using these features of cryptographic hashes, we can do build some interesting applications:
|
Using these features of cryptographic hashes, we can build some interesting applications:
|
||||||
|
|
||||||
Fingerprints:: A hash can be used to fingerprint a file or message so that it can be uniquely identified. Hashes can be used as universal identifiers of any data set.
|
Fingerprints:: A hash can be used to fingerprint a file or message so that it can be uniquely identified. Hashes can be used as universal identifiers of any data set.
|
||||||
|
|
||||||
Integrity Proof:: A fingerprint of a file or message demonstrates its integrity, as the file or message cannot be tampered with or modified in any way without changing the fingerprint. This is often use to ensure software has not been tampered with before installing it on your computer.
|
Integrity Proof:: A fingerprint of a file or message demonstrates its integrity, as the file or message cannot be tampered with or modified in any way without changing the fingerprint. This is often used to ensure software has not been tampered with before installing it on your computer.
|
||||||
|
|
||||||
Commitment/Non-repudiation:: You can commit to a specific pre-image (e.g. a number or message) without revealing it, by publishing its hash. Later, you can reveal the secret and everyone can verify that it is the same thing you committed to earlier because it produces the published hash.
|
Commitment/Non-repudiation:: You can commit to a specific pre-image (e.g. a number or message) without revealing it, by publishing its hash. Later, you can reveal the secret and everyone can verify that it is the same thing you committed to earlier because it produces the published hash.
|
||||||
|
|
||||||
|
@ -55,7 +55,7 @@ While your funds on the Lightning Network are called to be "off-chain" they are
|
|||||||
|
|
||||||
One thing about the Lightning Network is however messing with this understanding of ownership.
|
One thing about the Lightning Network is however messing with this understanding of ownership.
|
||||||
On the Lightning Network there exist several presigned Transactions which allocate some of the bitcoin to you and some to your channel partner.
|
On the Lightning Network there exist several presigned Transactions which allocate some of the bitcoin to you and some to your channel partner.
|
||||||
Without the the ability to sequence transaction and invalidate old ones via the penalty based revocation mechanism (or other techniques) we could not define clear ownership as the funds would be distributed among its two owners according to which ever transaction would first be broadcasted and successfully mined.
|
Without the ability to sequence transaction and invalidate old ones via the penalty based revocation mechanism (or other techniques) we could not define clear ownership as the funds would be distributed among its two owners according to which ever transaction would first be broadcasted and successfully mined.
|
||||||
|
|
||||||
If the last paragraph of this summary was confusing: No worries! We are getting there now!
|
If the last paragraph of this summary was confusing: No worries! We are getting there now!
|
||||||
****
|
****
|
||||||
@ -162,7 +162,7 @@ While this seems like an impossible problem, Alice has an idea:
|
|||||||
|
|
||||||
Before broadcasting her funding transaction she already prepared and finishes it so that she knows the transaction id.
|
Before broadcasting her funding transaction she already prepared and finishes it so that she knows the transaction id.
|
||||||
She can now create the commitment transaction that spends the output of the funding transaction and ask Bob to provide a signature.
|
She can now create the commitment transaction that spends the output of the funding transaction and ask Bob to provide a signature.
|
||||||
At that time Bob has nothing to loose by signing the commitment transaction.
|
At that time Bob has nothing to lose by signing the commitment transaction.
|
||||||
He did not have Coins at the multisig address anyway.
|
He did not have Coins at the multisig address anyway.
|
||||||
Even if he did Alice intends to spend from an output which Bob never was involved in.
|
Even if he did Alice intends to spend from an output which Bob never was involved in.
|
||||||
Thus at that point for Bob it is perfectly reasonable to sign the commitment transaction that spends the funding transaction.
|
Thus at that point for Bob it is perfectly reasonable to sign the commitment transaction that spends the funding transaction.
|
||||||
|
@ -129,7 +129,7 @@ The `revoke_and_ack` Lightning message contains three data fields.
|
|||||||
* [`point`:`next_per_commitment_point`]
|
* [`point`:`next_per_commitment_point`]
|
||||||
|
|
||||||
While it is really simple and straight forward it is very crucial.
|
While it is really simple and straight forward it is very crucial.
|
||||||
Bob shares the the `per_commitment_secret` of the old commitment transaction which serves as the revocation key and would allow Alice in future to penalize Bob if he publishes the old commitment transaction without the HTLC output.
|
Bob shares the `per_commitment_secret` of the old commitment transaction which serves as the revocation key and would allow Alice in future to penalize Bob if he publishes the old commitment transaction without the HTLC output.
|
||||||
As in a future Alice and Bob might want to negotiate additional commitment transactions he already shares back the `next_per_commitment_point` that he will use in his next commitment transaction.
|
As in a future Alice and Bob might want to negotiate additional commitment transactions he already shares back the `next_per_commitment_point` that he will use in his next commitment transaction.
|
||||||
|
|
||||||
Alice checks that the `per_commitment_secret` produces the last `per_commitment_point` and constructs her new commitment transaction with the HTLC output.
|
Alice checks that the `per_commitment_secret` produces the last `per_commitment_point` and constructs her new commitment transaction with the HTLC output.
|
||||||
|
@ -17,7 +17,7 @@ A key requirement for a second layer protocol such as Lightning (which will be d
|
|||||||
The `nSequence` field was intended to allow users to transmit updated versions of a transaction to the network, changing the outputs of a transaction, effectively creating a payment channel.
|
The `nSequence` field was intended to allow users to transmit updated versions of a transaction to the network, changing the outputs of a transaction, effectively creating a payment channel.
|
||||||
Such a payment channel would then be valid as long as the transaction was not mined.
|
Such a payment channel would then be valid as long as the transaction was not mined.
|
||||||
|
|
||||||
According to a mailing list post in 2013, by early Bitcoin developer Mike Hearn, Satoshi Nakamoto envisioned this construct for high frequency trading.footnote:HearnBitcoinDev[Mike Hearn on Bitcoin-dev - April 16th 2013 - Anti DoS for tx replacement http://web.archive.org/web/20190501234813/https://lists.linuxfoundation.org/pipermail/bitcoin-dev/2013-April/002417.html.]
|
According to a mailing list post in 2013 by early Bitcoin developer Mike Hearn, Satoshi Nakamoto envisioned this construct for high frequency trading.footnote:HearnBitcoinDev[Mike Hearn on Bitcoin-dev - April 16th 2013 - Anti DoS for tx replacement http://web.archive.org/web/20190501234813/https://lists.linuxfoundation.org/pipermail/bitcoin-dev/2013-April/002417.html.]
|
||||||
|
|
||||||
However, there were some weaknesses in this initial formulation that limited its potential. Firstly, the payment channel would only be open until the transaction was mined in a block, either limiting the duration of the payment channel or handing control of the payment channel to the miners. Secondly, there was no economic incentive for miners to respect the `nSequence` number (to replace the state of the channel in the mempool), reducing the utility of this mechanism.
|
However, there were some weaknesses in this initial formulation that limited its potential. Firstly, the payment channel would only be open until the transaction was mined in a block, either limiting the duration of the payment channel or handing control of the payment channel to the miners. Secondly, there was no economic incentive for miners to respect the `nSequence` number (to replace the state of the channel in the mempool), reducing the utility of this mechanism.
|
||||||
|
|
||||||
@ -25,9 +25,9 @@ The Revocable Sequence Maturity Contracts (RSMC), which formed payment channels
|
|||||||
|
|
||||||
Using this new feature of the `nSequence` number, the RSMC was able to enforce a novel penalty mechanism: each time a party goes to claim a state on chain (which may or may not be the latest), the other party is given a period of time to challenge that claim (enforced by the `nSequence` number of `OP_CHECKSEQUENCEVERIFY`).
|
Using this new feature of the `nSequence` number, the RSMC was able to enforce a novel penalty mechanism: each time a party goes to claim a state on chain (which may or may not be the latest), the other party is given a period of time to challenge that claim (enforced by the `nSequence` number of `OP_CHECKSEQUENCEVERIFY`).
|
||||||
|
|
||||||
If a participant of the channel is able to present evidence to the blockchain of an intent to claim a revoked state, then the honest party s rewarded with all the funds of the cheating party.
|
If a participant of the channel is able to present evidence to the blockchain of an intent to claim a revoked state, then the honest party is rewarded with all the funds of the cheating party.
|
||||||
|
|
||||||
This enforcement of prior revoked states (only the latest channel state is valid) created a very strong economic incentive via the penalty mechanism: if a party attempts to renegade a signed contract, they lose all their funds!
|
This enforcement of prior revoked states (only the latest channel state is valid) created a very strong economic incentive via the penalty mechanism: if a party attempts to renege a signed contract, they lose all their funds!
|
||||||
|
|
||||||
This "challenge period" enforced by the `nSequence` was one of the novel contributions of the RSMC to the payment channel design space: the blockchain was used as a court wherein disputes could be handled objectively.
|
This "challenge period" enforced by the `nSequence` was one of the novel contributions of the RSMC to the payment channel design space: the blockchain was used as a court wherein disputes could be handled objectively.
|
||||||
|
|
||||||
@ -50,13 +50,13 @@ Alice cannot effectively broadcast the refund transaction to be mined in a block
|
|||||||
Therefore, Bob can securely receive more updates to the channel balance as long as it remains `open`.
|
Therefore, Bob can securely receive more updates to the channel balance as long as it remains `open`.
|
||||||
|
|
||||||
This mechanism would allow two users to engage in several smaller transactions which all happened outside of the Bitcoin network.
|
This mechanism would allow two users to engage in several smaller transactions which all happened outside of the Bitcoin network.
|
||||||
While this construction of the unidirectional payment channel would have solved the custody problem of exchanges it has never been widely implemented.
|
While this construction of the unidirectional payment channel would have solved the custody problem of exchanges, it has never been widely implemented.
|
||||||
|
|
||||||
A fundamental blocker to deploying payment channels in production was the issue of transaction malleability.
|
A fundamental blocker to deploying payment channels in production was the issue of transaction malleability.
|
||||||
|
|
||||||
In the worst case, this could be exploited by an attacker to prevent a party from closing the channel on-chain as their settlement transaction had a chance to become invalidated if the funding transaction has it's transaction ID inadvertently changed.
|
In the worst case, this could be exploited by an attacker to prevent a party from closing the channel on-chain as their settlement transaction had a chance to become invalidated if the funding transaction has it's transaction ID inadvertently changed.
|
||||||
|
|
||||||
Also as a payment channel this system was not too useful as the channel could only at total send the total amount of provided bitcoin in the funding transaction.
|
Also, as a payment channel this system was not too useful because the channel could only at total send the total amount of provided bitcoin in the funding transaction.
|
||||||
Once the timelock was over or all bitcoin were sent to B the channel would have to be closed.
|
Once the timelock was over or all bitcoin were sent to B the channel would have to be closed.
|
||||||
The obvious idea of opening two channels one from A to B and one from B to A would not have helped as each of those channels would have to be closed and reestablished once it ran dry.
|
The obvious idea of opening two channels one from A to B and one from B to A would not have helped as each of those channels would have to be closed and reestablished once it ran dry.
|
||||||
The core breakthrough for the Lightning Network to become a reality was the ability to create payment channels which technically can live forever and can send money back and forth as often as the peers wish to in combination with routing payments among several channels.
|
The core breakthrough for the Lightning Network to become a reality was the ability to create payment channels which technically can live forever and can send money back and forth as often as the peers wish to in combination with routing payments among several channels.
|
||||||
@ -66,8 +66,8 @@ The core breakthrough for the Lightning Network to become a reality was the abil
|
|||||||
You can watch a video explaining the construction and operation of unidirectional payment channels online at: https://youtu.be/AcP3czefanM
|
You can watch a video explaining the construction and operation of unidirectional payment channels online at: https://youtu.be/AcP3czefanM
|
||||||
====
|
====
|
||||||
|
|
||||||
Surprisingly both properties took quite some while until the community figured them out.
|
Surprisingly, both properties took quite some while until the community figured them out.
|
||||||
Technically speaking the unidirectional payment channel has all the important ingredients (funding transaction to a 2-2 multisignature wallet, a transaction spending from the wallet encoding the balance, a timelock to allow refunding if the other side becomes unresponsive, off chain communication and the fact that no additional trust other than the one in the bitcoin network) of modern payment channels which are used in the Lightning Network.
|
Technically speaking, the unidirectional payment channel has all the important ingredients (funding transaction to a 2-2 multisignature wallet, a transaction spending from the wallet encoding the balance, a timelock to allow refunding if the other side becomes unresponsive, off chain communication and the fact that no additional trust, other than trust in the bitcoin network, is required) of modern payment channels which are used in the Lightning Network.
|
||||||
Despite being widely used in today's world, we will study the unidirectional payment channel in more depth in this book as it is an easy to understand educational example to approach the construction of today's payment channels.
|
Despite being widely used in today's world, we will study the unidirectional payment channel in more depth in this book as it is an easy to understand educational example to approach the construction of today's payment channels.
|
||||||
This setup has one safety issue as transactions have been malleable without the segwit upgrade.
|
This setup has one safety issue as transactions have been malleable without the segwit upgrade.
|
||||||
A problem that needed to be solved for any payment channel construction that we know up till today and which has been fixed in August 2017.
|
A problem that needed to be solved for any payment channel construction that we know up till today and which has been fixed in August 2017.
|
||||||
@ -85,13 +85,13 @@ The key difference was that a trusted party would have co-signed the spend of th
|
|||||||
The Ultra Server was not able to steal bitcoin.
|
The Ultra Server was not able to steal bitcoin.
|
||||||
|
|
||||||
The next day, probably in response to Gavin's blogpost, Meni Rosenfeld started a discussion related to how these ideas could be combined.footnote:[Meni Rosenfeld on Bitcointalk - July 5th 2012 - Trustless, instant, off-the-chain Bitcoin payments http://web.archive.org/web/20190419103457/https://bitcointalk.org/index.php?topic=91732.0]
|
The next day, probably in response to Gavin's blogpost, Meni Rosenfeld started a discussion related to how these ideas could be combined.footnote:[Meni Rosenfeld on Bitcointalk - July 5th 2012 - Trustless, instant, off-the-chain Bitcoin payments http://web.archive.org/web/20190419103457/https://bitcointalk.org/index.php?topic=91732.0]
|
||||||
As Hashed Timelocked Contracts have neither been invented nor seen to solve the issue of trustless routing, Rosenfeld imagined trusted routing nodes.
|
As Hashed Timelocked Contracts had neither been invented nor seen to solve the issue of trustless routing, Rosenfeld imagined trusted routing nodes.
|
||||||
Without mentioning the term network or routing of payments the idea of connecting payment channels and being able to send funds from anyone to anyone else even if there was no direct channel was born.
|
Without mentioning the term network or routing of payments, the idea of connecting payment channels and being able to send funds from anyone to anyone else, even if there was no direct channel between them, was born.
|
||||||
In Rosenfelds solution payment providers would be the ultraservers and they would settle the transactions among themselves based on trust.
|
In Rosenfeld's solution, payment providers would be the ultraservers and they would settle the transactions among themselves based on trust.
|
||||||
It took us another 3 years until the Lightning Network whitepaper emerged which had solved all the bits and bolts necessary to get rid of the trust in Rosenfelds solution.
|
It took us another 3 years until the Lightning Network whitepaper emerged which had solved all the bits and bolts necessary to get rid of the trust in Rosenfeld's solution.
|
||||||
|
|
||||||
It was 2013 that Bitcoin developer Mike Hearn referred to Meni Rosenfelds proposal and suggesting to reactivate the `nSequence` field which Satoshi previously had deactivated.footnote:HearnBitcoinDev[]
|
It was 2013 that Bitcoin developer Mike Hearn referred to Meni Rosenfeld's proposal and suggesting to reactivate the `nSequence` field which Satoshi previously had deactivated.footnote:HearnBitcoinDev[]
|
||||||
Also Hearn referred to a section on the contracts article talking about the case of micropayment channels with the help of `nSequence`.
|
Also, Hearn referred to a section on the contracts article talking about the case of micropayment channels with the help of `nSequence`.
|
||||||
|
|
||||||
Links:
|
Links:
|
||||||
* https://en.bitcoin.it/w/index.php?title=Contract&oldid=36712#Example_7:_Rapidly-adjusted_.28micro.29payments_to_a_pre-determined_party
|
* https://en.bitcoin.it/w/index.php?title=Contract&oldid=36712#Example_7:_Rapidly-adjusted_.28micro.29payments_to_a_pre-determined_party
|
||||||
|
@ -129,10 +129,10 @@ Commitment Transaction::
|
|||||||
Submitting an older (outdated) commitment transaction is considered "cheating" (i.e. protocol breach) in the Lightning network and can be penalized by the other party claiming all the funds in the channel for themselves.
|
Submitting an older (outdated) commitment transaction is considered "cheating" (i.e. protocol breach) in the Lightning network and can be penalized by the other party claiming all the funds in the channel for themselves.
|
||||||
|
|
||||||
computationally easy::
|
computationally easy::
|
||||||
A problem is considered to be computationally easy if there exists an algorithm that is able to compute the solution to the problem rather quickly.
|
A problem is considered to be computationally easy if there exists an algorithm that is able to compute the solution to the problem rather quickly (in polynomial time complexity).
|
||||||
|
|
||||||
computationally hard::
|
computationally hard::
|
||||||
A problem is considered to be computationally hard if no algorithm exists or is known that is able to compute the solution to the problem rather quickly.
|
A problem is considered to be computationally hard if no algorithm exists or is known that is able to compute the solution to the problem rather quickly (in polynomial time complexity).
|
||||||
|
|
||||||
confirmations::
|
confirmations::
|
||||||
Once a transaction is included in a block, it has one confirmation. As soon as _another_ block is mined on the same blockchain, the transaction has two confirmations, and so on. Six or more confirmations are considered sufficient proof that a transaction cannot be reversed.
|
Once a transaction is included in a block, it has one confirmation. As soon as _another_ block is mined on the same blockchain, the transaction has two confirmations, and so on. Six or more confirmations are considered sufficient proof that a transaction cannot be reversed.
|
||||||
@ -146,7 +146,7 @@ Diffie Hellman Key Exchange::
|
|||||||
It is an anonymous key agreement protocol that allows two parties, each having an elliptic-curve public-private key pair, to establish a shared secret over an insecure communication channel.
|
It is an anonymous key agreement protocol that allows two parties, each having an elliptic-curve public-private key pair, to establish a shared secret over an insecure communication channel.
|
||||||
This shared secret may be directly used as a key, or to derive another key.
|
This shared secret may be directly used as a key, or to derive another key.
|
||||||
The key, or the derived key, can then be used to encrypt subsequent communications using a symmetric-key cipher.
|
The key, or the derived key, can then be used to encrypt subsequent communications using a symmetric-key cipher.
|
||||||
An example of the derived key would be the shared secrete between the ephemeral session key of a sender of an onion with the nodes public key of a hop of the onion as described and used by the SPHINX Mix Format.
|
An example of the derived key would be the shared secret between the ephemeral session key of a sender of an onion with the nodes public key of a hop of the onion as described and used by the SPHINX Mix Format.
|
||||||
Via https://en.wikipedia.org/w/index.php?title=Elliptic-curve_Diffie%E2%80%93Hellman&oldid=836070673
|
Via https://en.wikipedia.org/w/index.php?title=Elliptic-curve_Diffie%E2%80%93Hellman&oldid=836070673
|
||||||
|
|
||||||
digital signature::
|
digital signature::
|
||||||
@ -157,7 +157,7 @@ digital signature::
|
|||||||
|
|
||||||
double-spending::
|
double-spending::
|
||||||
Double-spending is the result of successfully spending some money more than once.
|
Double-spending is the result of successfully spending some money more than once.
|
||||||
Bitcoin protects against double-spending by verifying each transaction added to the blockchain plays by the rules that the inputs for the transaction have not previously already been spent.
|
Bitcoin protects against double-spending by verifying that each transaction added to the blockchain plays by the rules; this means checking that the inputs for the transaction have not previously already been spent.
|
||||||
The Revocable Sequence Maturity Contracts used to construct payment channels heavily attempt to double-spend bitcoin.
|
The Revocable Sequence Maturity Contracts used to construct payment channels heavily attempt to double-spend bitcoin.
|
||||||
|
|
||||||
downstream payment::
|
downstream payment::
|
||||||
|
@ -8,11 +8,11 @@ Thus the sender has to be aware of the Channel Graph.
|
|||||||
The channel graph is the interconnected set of publicly advertised channels (more on that later), and the nodes that these channels interlink.
|
The channel graph is the interconnected set of publicly advertised channels (more on that later), and the nodes that these channels interlink.
|
||||||
As channels are backed by a funding transaction that is happening on chain one might falsely believe that Lightning Nodes could just extract the existing channels from the Bitcoin Blockchain.
|
As channels are backed by a funding transaction that is happening on chain one might falsely believe that Lightning Nodes could just extract the existing channels from the Bitcoin Blockchain.
|
||||||
However this only possible to a certain extend.
|
However this only possible to a certain extend.
|
||||||
The Funding transactions are Pay to Whitness Script addresses and the nature of the script will only be revealed once the funding transaction output is spent.
|
The Funding transactions are Pay to Witness Script addresses and the nature of the script will only be revealed once the funding transaction output is spent.
|
||||||
Even if the nature of the script was known we emphasize that not all 2 - of - 2 multisignature scripts correspond to payment channels.
|
Even if the nature of the script was known we emphasize that not all 2 - of - 2 multisignature scripts correspond to payment channels.
|
||||||
Since not even every Pay to Whitness Script address that we see in the Bitcoin Blockchain corresponds to a payment channel this approach is not helpful.
|
Since not even every Pay to Witness Script address that we see in the Bitcoin Blockchain corresponds to a payment channel this approach is not helpful.
|
||||||
There are actually more reasons why looking at the Bitcoin Blockchain might not be helpful.
|
There are actually more reasons why looking at the Bitcoin Blockchain might not be helpful.
|
||||||
For example on the Lightnign Network the Bitcoin keys that are used for signing are rotated by the nodes for every channel and update.
|
For example on the Lightning Network the Bitcoin keys that are used for signing are rotated by the nodes for every channel and update.
|
||||||
Thus even if we could reliably detect funding transactions on the Bitcoin Blockchain we would not know which two nodes on the Lightning Network own that particular channel.
|
Thus even if we could reliably detect funding transactions on the Bitcoin Blockchain we would not know which two nodes on the Lightning Network own that particular channel.
|
||||||
Thus we could node create the Channel Graph that would be used to create candidate paths during the payment delivery via onion routing.
|
Thus we could node create the Channel Graph that would be used to create candidate paths during the payment delivery via onion routing.
|
||||||
|
|
||||||
@ -20,11 +20,11 @@ The Lightning Network solves the afore mentioned problem by implementing a gossi
|
|||||||
Gossip protocols are typical for peer 2 peer networks and are being used so that nodes can share information with other nodes without talking to those other nodes directly.
|
Gossip protocols are typical for peer 2 peer networks and are being used so that nodes can share information with other nodes without talking to those other nodes directly.
|
||||||
For that Lightning Nodes open encrypted peer 2 peer connections to each other and share novel information that they have received from other peers.
|
For that Lightning Nodes open encrypted peer 2 peer connections to each other and share novel information that they have received from other peers.
|
||||||
As soon as a node wants to share some information - for example about a newly created channel - it sends a message to all its peers.
|
As soon as a node wants to share some information - for example about a newly created channel - it sends a message to all its peers.
|
||||||
Uppon receiving a message a node decides if the received message was novel and if so it will forward the information to its peers.
|
Upon receiving a message a node decides if the received message was novel and if so it will forward the information to its peers.
|
||||||
In this way if the peer 2 peer network is connected all new information that is necessary for the operation of the network will eventually be propagated to all other peers.
|
In this way if the peer 2 peer network is connected all new information that is necessary for the operation of the network will eventually be propagated to all other peers.
|
||||||
|
|
||||||
Obviously if a new peer initially wants to join the network it needs to know some other peers on the Network initially.
|
Obviously if a new peer initially wants to join the network it needs to know some other peers on the Network initially.
|
||||||
Only then the new peer could connect to them in order to learn about the existance of other peers.
|
Only then the new peer could connect to them in order to learn about the existence of other peers.
|
||||||
In this chapter, we'll explore exactly _how_ Lightning nodes discover each
|
In this chapter, we'll explore exactly _how_ Lightning nodes discover each
|
||||||
other, and also the channel graph itself.
|
other, and also the channel graph itself.
|
||||||
When most refer to the _network_ part
|
When most refer to the _network_ part
|
||||||
@ -84,7 +84,7 @@ node that wishes to join the network as he sets out on his journey to which cons
|
|||||||
|
|
||||||
. discovery a set of bootstrap peers.
|
. discovery a set of bootstrap peers.
|
||||||
. download and validate the channel graph.
|
. download and validate the channel graph.
|
||||||
. begin the process of ongoing maintainance of the channel graph itself.
|
. begin the process of ongoing maintenance of the channel graph itself.
|
||||||
|
|
||||||
|
|
||||||
### P2P Boostrapping
|
### P2P Boostrapping
|
||||||
@ -269,7 +269,7 @@ In the above command, we've queried the server so we can obtain an `IPv4`
|
|||||||
address for our target node. Now that we have both the raw public key _and_ IP
|
address for our target node. Now that we have both the raw public key _and_ IP
|
||||||
address, we can connect to the node using the `brontide` transport protocol at:
|
address, we can connect to the node using the `brontide` transport protocol at:
|
||||||
`026c64f5a7f24c6f7f0e1d6ec877f23b2f672fb48967c2545f227d70636395eaf3@X.X.X.X`.
|
`026c64f5a7f24c6f7f0e1d6ec877f23b2f672fb48967c2545f227d70636395eaf3@X.X.X.X`.
|
||||||
Querying for the curent `A` record for a given node can also be used to look up
|
Querying for the current `A` record for a given node can also be used to look up
|
||||||
the _latest_ set of addresses for a given node. Such queries can be used to
|
the _latest_ set of addresses for a given node. Such queries can be used to
|
||||||
more quickly (compared to waiting on gossip as we'll cover later) sync the
|
more quickly (compared to waiting on gossip as we'll cover later) sync the
|
||||||
latest addressing information for a node.
|
latest addressing information for a node.
|
||||||
|
BIN
images/LN-protocol-routing-highlight.png
Normal file
After Width: | Height: | Size: 269 KiB |
BIN
images/alice-dina-htlc-1.png
Normal file
After Width: | Height: | Size: 147 KiB |
BIN
images/alice-dina-htlc-redeem-1.png
Normal file
After Width: | Height: | Size: 146 KiB |
BIN
images/alice-dina-htlc-redeem-2.png
Normal file
After Width: | Height: | Size: 132 KiB |
BIN
images/alice-dina-htlc-redeem-3.png
Normal file
After Width: | Height: | Size: 119 KiB |
BIN
images/alice-dina-htlc-redeem-4.png
Normal file
After Width: | Height: | Size: 88 KiB |
BIN
images/alice-dina-htlc.png
Normal file
After Width: | Height: | Size: 120 KiB |
BIN
images/alice-dina-invoice-1.png
Normal file
After Width: | Height: | Size: 109 KiB |
BIN
images/alice-dina-invoice-2.png
Normal file
After Width: | Height: | Size: 148 KiB |
BIN
images/dina-routing-diagram.png
Normal file
After Width: | Height: | Size: 124 KiB |
Before Width: | Height: | Size: 20 KiB |
BIN
images/gold-coins-network1.png
Normal file
After Width: | Height: | Size: 73 KiB |
BIN
images/gold-coins-network2.png
Normal file
After Width: | Height: | Size: 91 KiB |
BIN
images/gold-coins-network3.png
Normal file
After Width: | Height: | Size: 112 KiB |
BIN
images/lightning-network-protocol-suite.png
Normal file
After Width: | Height: | Size: 1.5 MiB |
@ -1,334 +1,3 @@
|
|||||||
[[routing_on_a_network_of_payment_channels]]
|
|
||||||
== Routing on a Network of Payment channels
|
|
||||||
|
|
||||||
In this section we will finally unpack how payment channels can be connected to a network of other payment channels via a process called _routing_.
|
|
||||||
|
|
||||||
=== Routing vs. Path Finding
|
|
||||||
|
|
||||||
It's important to note that we separate the concept of _routing_ from the concept of _path finding_. These two concepts are often confused and the term "routing" is often used to describe both concepts. Let's remove the ambiguity, before we proceed any further.
|
|
||||||
|
|
||||||
Path Finding, which is covered in <<path_finding>> is the process of finding and choosing a contiguous path made of payment channels which connects the sender A to the recipient B. The sender of a payment does the path finding, by examining the _channel graph_ which they have assembled from channel announcements gossiped by other nodes.
|
|
||||||
|
|
||||||
Routing refers to the series of interactions across the network that allow a payment to _flow_ from A to B, across the path previously selected by path finding. Routing is the _active_ process of sending a payment on a path, which involves the cooperation of all the intermediary nodes along that path.
|
|
||||||
|
|
||||||
An important rule of thumb is that it's possible for a _path_ to exist between Alice and Bob, yet there may not be an active _route_ on which to send the payment.
|
|
||||||
|
|
||||||
One example is the scenario where all the nodes connecting Alice and Bob are currently off-line.
|
|
||||||
|
|
||||||
In theory, one can examine the _channel graph_ and connect a series of payment channels from Alice to Bob, hence a _path_ exists. However, as the intermediary nodes are offline, the payment cannot be sent and so no _route_ exists.
|
|
||||||
|
|
||||||
=== Routing a payment
|
|
||||||
|
|
||||||
In this section we will examine routing from the perspective of Dina, a gamer who receives donations from her fans while she livestreams her game sessions.
|
|
||||||
|
|
||||||
The innovation of routed payment channels allows Dina to receive tips without maintaining a separate channel with every one of her fans who want to tip her.
|
|
||||||
As long as there exists a path of well-funded channels from that viewer to Glori, she will be able to receive payment from that fan.
|
|
||||||
The nodes along the path from the fan to Dina are intermediaries and called "routing nodes" in the context of routing a payment.
|
|
||||||
|
|
||||||
[[dina-routing-diagram]]
|
|
||||||
.Any one of Dina's fans in the diagram can pay her by routing via the nodes in between them and Dina
|
|
||||||
image:images/dina-routing-diagram.PNG["Any one of Dina's fans in the diagram can pay her by routing via the nodes in between them and Dina"]
|
|
||||||
|
|
||||||
Importantly, the routing nodes are unable to steal the funds while routing a payment from a fan to Dina.
|
|
||||||
Furthermore, routing nodes cannot lose money while participating in the routing process.
|
|
||||||
Routing nodes can charge a routing fee for acting as an intermediary, although they don't have to and may choose to route payments for free.
|
|
||||||
|
|
||||||
Another important detail is that due to the use of onion routing, intermediary nodes are only explicitly aware of the one node preceding them and the one node following them in the route.
|
|
||||||
They will not necessarily know who is the sender and recipient of the payment.
|
|
||||||
This enables fans to use intermediary nodes to pay Dina, without leaking private information and without risking theft.
|
|
||||||
|
|
||||||
This process of connecting a series of payment channels with end-to-end security, and the incentive structure for nodes to _forward_ payments, is one of the key innovations of the Lightning Network.
|
|
||||||
|
|
||||||
In this chapter, we'll dive into the mechanism of routing in the Lightning Network, detailing the precise manner in-which payments flow through the network.
|
|
||||||
First, we will cover the concept of a conditional chained end-to-end secure payment, most commonly referred to as a Hash Time Locked Transaction (HTLC).
|
|
||||||
Having learned how payments can be transmitted through the network, we will then discuss the concept of source-based routing and contrast it to the privacy preserving onion routing used in the network today.
|
|
||||||
Finally, we will explore the exact mechanism of payment forwarding.
|
|
||||||
We will discuss how the _structure_ (edges, fees, time-locks, etc) of the route is determined by the sender, and is then transmitted to each individual node along the route.
|
|
||||||
|
|
||||||
|
|
||||||
=== Creating a Network of payment channels
|
|
||||||
|
|
||||||
Before we dive into the concept of a conditional chained end-to-end secure payment, let's work through an example.
|
|
||||||
Let us to return to Alice who, in previous chapters, purchased a coffee from Bob with whom she has an open channel.
|
|
||||||
Alice now watches a live stream from Dina the gamer, and wants to send her a tip via the Lightning Network.
|
|
||||||
However, Alice has no direct channel with Dina.
|
|
||||||
Alice could open a direct channel, however that would require liquidity and on-chain fees which could be more than the value of the tip itself.
|
|
||||||
|
|
||||||
Instead, Alice can use her existing open channels to send a tip to Dina _without_ the need to open a channel directly with Dina.
|
|
||||||
|
|
||||||
This is possible, as long as there exists some path of channels from Alice to Dina with sufficient capacity to route the tip.
|
|
||||||
|
|
||||||
From previous chapters, we know Alice has an open channel with Bob, the coffee shop owner.
|
|
||||||
Bob, in turn, has an open channel with the software developer Chan who helps him with the point of sale system he uses in his coffee shop.
|
|
||||||
Chan is also the owner of a large software company which develops the game that Dina plays, and they already have an open channel which Dina uses to pay for the game's license and in-game items.
|
|
||||||
|
|
||||||
If we draw out this series of payment channels, it's possible to manually trace a _path_ from Alice to Dina that uses Bob and Chan as intermediary routing nodes.
|
|
||||||
Alice can then craft a _route_ from this outlined path, and use it to send a tip of a few thousand satoshis to Dina, with the payment being _forwarded_ by Bob and Chan.
|
|
||||||
Essentially, Alice will pay Bob, who will pay Chan, who will pay Dina.
|
|
||||||
And no direct channel from Alice to Dina is required.
|
|
||||||
|
|
||||||
[[routing-network]]
|
|
||||||
.The network of payment channels of our friends can be seen here:
|
|
||||||
image:images/routing-network.png[]
|
|
||||||
|
|
||||||
The main challenge is to do this in a way that prevents Bob and Chan from stealing the money that Alice wants delivered to Dina.
|
|
||||||
To understand how the Lightning Network protects the payment while being routed, we can compare to an example of routing physical payments with golden coins in the real world.
|
|
||||||
|
|
||||||
Assume Alice wants to give 10 gold coins to Dina, but does not have direct access to Dina.
|
|
||||||
However, Alice knows Bob, who knows Chan, who knows Dina and so she decides to ask Bob and Chan for help.
|
|
||||||
She can pay Bob to pay Chan to pay Dina, but how does she make sure that Bob or Chan don't run off with the coins after receiving them?
|
|
||||||
In the physical world contracts could be used for safely carrying out a series of payments.
|
|
||||||
|
|
||||||
Alice could negotiate a contract with Bob which reads:
|
|
||||||
|
|
||||||
[alice-dina-routing-1]
|
|
||||||
====
|
|
||||||
_I (Alice) will give you (Bob) 10 gold coins if you pass them on to Chan_
|
|
||||||
====
|
|
||||||
|
|
||||||
While this contract is nice in the abstract, in the real world, Alice runs the risk that Bob might breach the contract and hope to not get caught by law enforcement.
|
|
||||||
Even if Bob gets caught by law enforcement, Alice faces the risk that he might be bankrupt and be unable to return her 10 gold coins.
|
|
||||||
Assuming these issues are magically solved, it's still unclear how to leverage such a contract to achieve our desired outcome: the coins ultimately being delivered to Dina.
|
|
||||||
|
|
||||||
We thus improve our contract:
|
|
||||||
|
|
||||||
[alice-dina-routing-2]
|
|
||||||
====
|
|
||||||
_I (Alice) will reimburse you (Bob) with 10 gold coins if you can prove to me (for example via a receipt) that you already have delivered 10 gold coins to Chan_
|
|
||||||
====
|
|
||||||
|
|
||||||
You might ask yourself why should Bob sign such a contract.
|
|
||||||
He has to pay Chan but ultimately gets nothing out of the exchange, and he runs the risk that Alice might not reimburse him.
|
|
||||||
Bob could offer Chan a similar contract to pay Dina, but similarly Chan has no reason to accept it either.
|
|
||||||
Even putting aside the risk, Bob and Chan must _already_ have 10 gold coins to send, otherwise they wouldn't be able to participate in the contract.
|
|
||||||
Thus Bob and Chan face both risk and opportunity cost for agreeing to this contract, and they would need to be compensated in order for them to accept it.
|
|
||||||
|
|
||||||
Alice can this make this attractive to both Bob and Chan, by offering them fees of 1 gold coin each, if they transmit her payment to Dina.
|
|
||||||
The final contract would instead read:
|
|
||||||
|
|
||||||
[alice-dina-routing-3]
|
|
||||||
====
|
|
||||||
_I (Alice) will reimburse you (Bob) with 12 gold coins if you can prove to me (for example via a receipt) that you already have delivered 11 golden coins to Chan_
|
|
||||||
====
|
|
||||||
|
|
||||||
Alice now promises Bob 12 gold coins.
|
|
||||||
There are 10 to be delivered to Dina and 2 for the fees.
|
|
||||||
She promises 12 to Bob if he can prove that he has forwarded 11 to Chan.
|
|
||||||
The difference of 1 gold coin is the fee that Bob will earn for helping out with this particular payment.
|
|
||||||
|
|
||||||
As there is still the issue of trust and the risk that either Alice or Bob don't honor the contract, all parties decide to use an escrow service.
|
|
||||||
At the start of the exchange, Alice could "lock up" these 12 golden coins in escrow that will only be paid to Bob once he proves that he's paid 11 golden coins to Chan.
|
|
||||||
|
|
||||||
This escrow service is an "ideal functionality", which will later be replaced by a more trust-minimized mechanism.
|
|
||||||
Let's assume for now that everyone trusts this escrow.
|
|
||||||
|
|
||||||
In the Lightning Network, the receipt (proof of payment) could take the form of a secret that only Dina knows.
|
|
||||||
In practice, this secret would be a large random number that is large enough to prevent others from guessing it (typically _very, very_ large number, encoded using 256 bits!).
|
|
||||||
The secret could then be committed to the contract by including the SHA256 hash of the secret in the contract itself.
|
|
||||||
We call this hash of the payment's secret the payment hash.
|
|
||||||
The secret which "unlocks" the payment is called the payment secret.
|
|
||||||
|
|
||||||
For now, we keep things simple and assume that Dina's secret is simply the text line: `+Dinas secret+`.
|
|
||||||
In order to "commit" to this secret, she computes the SHA256 hash which when encoded in hex, can be displayed as: `+f23c83babfb0e5f001c5030cf2a06626f8a940af939c1c35bd4526e90f9759f5+`.
|
|
||||||
footnote:[You can verify this by typing `echo -n "Dinas secret" | sha256sum` to your Linux command line shell.]
|
|
||||||
|
|
||||||
To facilitate Alice's payment, Dina will create the secret and the payment hash and send the payment hash to Alice. Alice doesn't know the secret but she can rewrite her contract to use the hash of the secret as a proof of payment:
|
|
||||||
|
|
||||||
[alice-dina-routing-4]
|
|
||||||
====
|
|
||||||
_I (Alice) will reimburse you (Bob) with 12 gold coins if you can show me a valid message that hashes to:`+f23c83...+`.
|
|
||||||
You can acquire this message by setting up a similar Contract with Chan who has to set up a similar contract with Dina.
|
|
||||||
In order to assure you that you will get reimbursed I will provide the 12 gold coins to an trusted escrow before you set up your next contract._
|
|
||||||
====
|
|
||||||
|
|
||||||
This new contract now protects Alice from Bob not forwarding to Chan, protects Bob from not being reimbursed by Alice, and ensures that there will be proof that Dina was ultimately paid via the hash of Dina's secret.
|
|
||||||
This secret message that hashes to the +f23c83...+ is called a _pre-image_.
|
|
||||||
|
|
||||||
After Bob and Alice agree to the contract, and Bob receives the message from the escrow that Alice has deposited the 12 gold coins, Bob can now negotiate a similar contract with Chan.
|
|
||||||
|
|
||||||
Note that since Bob is taking a service fee of 1 coin, he will only forward 11 gold coins to Chan once Chan shows proof that he has paid Dina.
|
|
||||||
Similarly, Chan will also demand a fee and will expect to receive 11 gold coins once he has proved that he has paid Dina the promised 10 gold coins.
|
|
||||||
|
|
||||||
Bob's contract with Chan will read:
|
|
||||||
|
|
||||||
[alice-dina-routing-5]
|
|
||||||
====
|
|
||||||
_I (Bob) will reimburse you (Chan) with 11 gold coins if you can show me a valid message that hashes to:`+f23c83...+`.
|
|
||||||
You can acquire this message by setting up a similar contract with Dina.
|
|
||||||
In order to assure you that you will get reimbursed I will provide the 11 gold coins to an trusted escrow before you set up your next contract._
|
|
||||||
====
|
|
||||||
|
|
||||||
Once Chan gets the message from the escrow that Bob has deposited the 11 gold coins, Chan sets up a similar contract with Dina:
|
|
||||||
|
|
||||||
[alice-dina-routing-6]
|
|
||||||
====
|
|
||||||
_I (Chan) will reimburse you (Dina) with 10 golden coins if you can show me a valid message that hashes to:`+f23c83...+`.
|
|
||||||
In order to assure you that you will get reimbursed after revealing the secret I will provide the 10 gold coins to an trusted escrow._
|
|
||||||
====
|
|
||||||
|
|
||||||
Everything is now in place.
|
|
||||||
Alice has a contract with Bob and has placed 12 gold coins in escrow.
|
|
||||||
Bob has a contract with Chan and has placed 11 gold coins in escrow
|
|
||||||
Chan has a contract with Dina and has placed 10 gold coins in escrow.
|
|
||||||
It is now up to Dina to reveal the secret, which is the pre-image to the hash she has established as proof of payment.
|
|
||||||
|
|
||||||
Dina now sends +"Dinas secret"+ to Chan.
|
|
||||||
|
|
||||||
He checks that +"Dinas secret" hashes to +f23c83...+. Chan now has proof of payment and so instructs the escrow service to release the 10 golden coins to Dina.
|
|
||||||
|
|
||||||
Chan now provides the secret to Bob. Bob checks it and instructs the escrow service to release the 11 gold coins to Chan.
|
|
||||||
|
|
||||||
Bob now provides the secret to Alice.
|
|
||||||
Alice checks it and instructs the escrow to release 12 gold coins to Bob.
|
|
||||||
|
|
||||||
All the contracts are now settled.
|
|
||||||
Alice has paid a total of 12 gold coins, 1 of which was received by Bob, 1 of which was received by Chan, and 10 of which were received by Dina.
|
|
||||||
With a chain of contracts like this in place, Bob and Chan could not run away with the money because they deposited it in escrow first.
|
|
||||||
|
|
||||||
However, one issue still remains.
|
|
||||||
If Dina refused to release her secret pre-image, then Chan, Bob, and Alice would all have their coins stuck in escrow but wouldn't be reimbursed.
|
|
||||||
And similarly if anyone else along the chain failed to pass on the secret, the same thing would happen.
|
|
||||||
So while no one can steal money from Alice everyone can still lose money.
|
|
||||||
|
|
||||||
Luckily, this can be resolved by adding a deadline to the contract.
|
|
||||||
|
|
||||||
We could amend the contract so that if it is not fulfilled by a certain deadline, then the contract expires and the escrow service returns the money to the person who made the original deposit.
|
|
||||||
We call this deadline a "time lock".
|
|
||||||
|
|
||||||
The deposit is locked with the escrow service for a certain amount of time, and is eventually released even if no proof of payment was provided.
|
|
||||||
|
|
||||||
In order to factor this in, the contract between Alice and Bob is once again amended with a new clause:
|
|
||||||
|
|
||||||
[alice-dina-routing-7]
|
|
||||||
====
|
|
||||||
_Bob has 24 hours to show the secret after the contract was signed.
|
|
||||||
If Bob does not provide the secret by this time, Alice's deposit will be refunded by the escrow service and the contract becomes invalid._
|
|
||||||
====
|
|
||||||
|
|
||||||
Bob, of course, now has to make sure he receives the proof of payment within 24 hours.
|
|
||||||
Even if he successfully pays Chan, if he receives the proof of payment later than 24 hours he will not be reimbursed. To remove that risk, Bob must give Chan and even shorter deadline.
|
|
||||||
|
|
||||||
In turn, Bob will alter his contract with Chan in the following way:
|
|
||||||
|
|
||||||
[alice-dina-routing-8]
|
|
||||||
====
|
|
||||||
_Chan has 22 hours to show the secret after the contract was signed.
|
|
||||||
If he does not provide the secret by this time, Bob's deposit will be refunded by the escrow service and the contract becomes invalid._
|
|
||||||
====
|
|
||||||
|
|
||||||
As you might have guessed, Chan is now incentivized to also alter his contract with Dina:
|
|
||||||
|
|
||||||
[alice-dina-routing-9]
|
|
||||||
====
|
|
||||||
_Dina has 20 hours to show the secret after the contract was signed.
|
|
||||||
If he does not provide the secret by this time, Bob's deposit will be refunded by the escrow service and the contract becomes invalid._
|
|
||||||
====
|
|
||||||
|
|
||||||
With such a chain of contracts we can ensure that, after 24 hours, the payment will successfully deliver from Alice to Bob to Chan to Dina, or it will fail and everyone will be refunded.
|
|
||||||
Either the contract fails or succeeds, there's no middle ground.
|
|
||||||
|
|
||||||
In the context of the Lightning Network, we call this "all or nothing" property _atomicity_.
|
|
||||||
|
|
||||||
As long as the escrow is trustworthy and faithfully performs its duty, then no party will have their coins stolen in the process.
|
|
||||||
|
|
||||||
The pre-condition to this _route_ working at all, is that all parties in the path have enough money to satisfy the required series of deposits.
|
|
||||||
|
|
||||||
While this seems like a minor detail we will see in later this chapter that this requirement is actually one of the more difficult issues for Lightning Network nodes.
|
|
||||||
It becomes progressively more difficult as the size of the payment increases.
|
|
||||||
Furthermore, the parties cannot use their money while it is locked in escrow.
|
|
||||||
Thus users forwarding payments face an opportunity cost for locking the money, which is ultimately reimbursed through routing fees, as we saw in the example above.
|
|
||||||
|
|
||||||
In the following two sections we will discuss how the Bitcoin scripting language can be used to set up conditional chained end-to-end secure payment contracts _without_ third party escrows, similar to the gold coin contracts described above.
|
|
||||||
These are called Hash Time Locked Contracts (HTLCs).
|
|
||||||
For HTLCs, there are no trusted third parties who act as an escrow; the Bitcoin Network itself becomes the "escrow" service.
|
|
||||||
|
|
||||||
Then, we will discuss how users are able to use an HTLC to securely "route" a payment through the Lightning Network.
|
|
||||||
|
|
||||||
Currently (in 2020), the Lightning Network uses a routing protocol called source-based onion routing, although it is possible to route payments with other routing protocols.
|
|
||||||
|
|
||||||
Finally we will discuss the precise details of forwarding, settling, and canceling HTLCs in the network.
|
|
||||||
|
|
||||||
=== Hash Time Locked Contracts as a Conditional Chained End to End Secure Payment
|
|
||||||
|
|
||||||
Our example in the prior section using "golden coins", was intended to lay same base intuition which we'll leverage in this section to explain how HTLCs work in practice.
|
|
||||||
HTLC is actually an acronym that stands for "Hash Time-Locked Contracts".
|
|
||||||
A HTLC is a _specific_ instantiation of a Conditional Chained End to End Secure Payment (CCESP, don't use this acronym?).
|
|
||||||
As we'll see in the later chapters, given a set of adequate cryptographic constructs, many other instantiations are possible as well.
|
|
||||||
|
|
||||||
Before we dive into the specifics of HTLCs, it may be helpful to first build intuition on an abstraction over this concrete concept.
|
|
||||||
First, let's unpack what it means for something to be a conditional chained end to end secure payment:
|
|
||||||
|
|
||||||
==== Conditional End to End Secure Payments by Construction
|
|
||||||
|
|
||||||
===== Conditional Payments
|
|
||||||
|
|
||||||
A payment can be said to be conditional, if the completion of the payment relies on the completion of a certain event.
|
|
||||||
In the golden coins example, this "condition" was the reveal of a hash pre-image.
|
|
||||||
We could feasibly substitute this hash pre-image reveal for any other construct with "hardness" properties. Namely: it should be infeasible for a party that doesn't know the proper "solution" of the condition to satisfy it, the "description" of the condition shouldn't give away any information about the true "solution", and once a solution has been chosen and a description created from it, it shouldn't be possible to "alter" that solution and have it still be a valid condition for the description.
|
|
||||||
|
|
||||||
The payment should _only_ be able to be redeemed if a valid solution is revealed. Critical, all conditions need to be timed in order to allow the construct to return the funds back to the sender if a solution to this condition isn't revealed.
|
|
||||||
The combination of the condition, and a timeout on the condition gives the payment a trait we commonly refer to as atomicity: either the payment happens, or the receiver if refunded the funds.
|
|
||||||
|
|
||||||
===== Conditional Chained Payment
|
|
||||||
|
|
||||||
Building upon our conditional payment, it may be possible to *chain* this payment, allowing it to involve the payer, the payee, and possibly several intermediaries.
|
|
||||||
Each intermediary, is able to present a _slightly_ modified version of the condition (without invalidating it all together), and so on in an iterated manner until the conditional payment reaches the payee.
|
|
||||||
Once it reaches the payee, then the payment should be able to be _iteratively_ resolved, starting at the payee all the way back to the payer.
|
|
||||||
|
|
||||||
Each chaining creates an "incoming" and "outgoing" conditional payment.
|
|
||||||
A node receives a conditional payment from a party (incoming condition), and then extends the conditional payment to the next party in the chain (outgoing condition).
|
|
||||||
The payment is extended in from payer to payee, but settled from payee to payer, as each of the intermediaries gain the solution to the outgoing condition, and use that (possibly augmenting it) to satisfy the incoming solution.
|
|
||||||
|
|
||||||
Typically the payer rewards the intermediaries by sending slightly more than the payment amount, in order to allow the intermediaries to send out less with their outgoing payment than what they received from the incoming payment.
|
|
||||||
The difference between these two payment values makes up the "forwarding fee" collected by the intermediary.
|
|
||||||
|
|
||||||
=== Conditional Chained End to End Secure Payment ===
|
|
||||||
|
|
||||||
With our final addition, we'll achieve "end to end security".
|
|
||||||
By this we mean that: no intermediaries are able to "claim" the payment without first obtaining the solution from someone further down from them in the chain.
|
|
||||||
Additionally, we also require that the amount the payer intended to send is fully received by the payee.
|
|
||||||
Finally, we require that non of the intermediaries are able to "contaminate" the payment beyond giving incorrect directions to the party that directly follows them.
|
|
||||||
In other words, the intermediary shouldn't be able to materially affect the propagation of the payment several hops away from it.
|
|
||||||
|
|
||||||
== Hash Time Locked Contracts ==
|
|
||||||
|
|
||||||
In this section, we'll construct a conditional chained end to end payment known as the HTLC.
|
|
||||||
At each step we'll add a new component, then examine it in light of our original definition to ensure all requirements and security properties are reached.
|
|
||||||
|
|
||||||
First, the "condition". For an HTLC, the condition is typically the reveal of a hash pre-image that matches a particular hash.
|
|
||||||
This hash is typically referred to as the "payment hash", with the pre-image being called the "payment pre-image".
|
|
||||||
If the name didn't give too much away, for an HTLC, we'll use a _cryptographically secure_ hash function as one part of our condition.
|
|
||||||
By using a cryptographic hash function, we ensure that it's infeasible for another party to "guess" the solution of our condition, it's easy for anyone to verify the solution, and there's only one "solution" to the condition.
|
|
||||||
|
|
||||||
In order to implement the "refund" functionality, we rely on the "absolute time lock" functionality of Bitcoin script.
|
|
||||||
|
|
||||||
With all that said, a basic Bitcoin script implementing a hash time-locked contract would look something like the following:
|
|
||||||
```
|
|
||||||
OP_SIZE 32 OP_EQUAL
|
|
||||||
|
|
||||||
OP_IF
|
|
||||||
OP_HASH160 <ripemd(payHash)> OP_EQUALVERIFY
|
|
||||||
<receiver key>
|
|
||||||
OP_ELSE
|
|
||||||
OP_CHECKLOCKTIMEVERIFY <timeout>
|
|
||||||
OP_DROP
|
|
||||||
<sender key>
|
|
||||||
|
|
||||||
OP_CHECKSIGVERIFY
|
|
||||||
```
|
|
||||||
|
|
||||||
Alice can present this script to Bob in order to kick off the conditional payment.
|
|
||||||
For the chained aspect, Alice needs to be able to communicate the proper payment details to each hop in the route.
|
|
||||||
Recall that each hop will specify a forwarding fee rate, as well as other parameters that express their forwarding policy.
|
|
||||||
In addition to this forwarding rate, Alice also needs to be conceded about what time locks to use.
|
|
||||||
Each node in the hop needs some time to be able to settle the outgoing, then incoming payment on-chain in the worst case.
|
|
||||||
As a result, when constructing the final route, we need to give each node some buffer time, we call this before time, the "time lock delta".
|
|
||||||
Factoring in this time-lock delta, the time-lock of the outgoing HTLC will decrease as the route progresses, as the outgoing HTLC will expire before the incoming HTLC.
|
|
||||||
This set of decrementing time-locks is critical to the operation of the system, as it ensure out atomicity property for each hop, assuming they're able to get into the chain in time.
|
|
||||||
|
|
||||||
In the next section, we'll go into the exact mechanism of how Alice is able to deliver forwarding details to each hop in the route.
|
|
||||||
In addition, we'll dive further into proper time-lock construction, as incorrect time-lock set up can violate our atomicity property and lead to a loss of funds.
|
|
||||||
|
|
||||||
=== HTLC Packet Forwarding: Source Based Onion Routing
|
=== HTLC Packet Forwarding: Source Based Onion Routing
|
||||||
|
|
||||||
So far you have learnt that payment channels can be connected to a network which can be utilized to send payment from one participant to another one through a path of payment channels.
|
So far you have learnt that payment channels can be connected to a network which can be utilized to send payment from one participant to another one through a path of payment channels.
|
||||||
@ -563,6 +232,7 @@ Since we use the network itself for transport of these onion packets, Alice is a
|
|||||||
She only needs a public key from each participant which is the public `node_id` of the Lightning node and known to Alice.
|
She only needs a public key from each participant which is the public `node_id` of the Lightning node and known to Alice.
|
||||||
In the network today, Alice learns about the public key via the gossip network, which is described in Chapter N.
|
In the network today, Alice learns about the public key via the gossip network, which is described in Chapter N.
|
||||||
|
|
||||||
|
|
||||||
===== CLTV expiry and deltas
|
===== CLTV expiry and deltas
|
||||||
|
|
||||||
==== Pitfalls with source based Routing and HTLCs
|
==== Pitfalls with source based Routing and HTLCs
|
||||||
@ -573,7 +243,6 @@ In the second part you have seen how the necessary information for setting up HT
|
|||||||
However, in the above scenarios, we only discussed flows where everything goes as expected (the optimistic path).
|
However, in the above scenarios, we only discussed flows where everything goes as expected (the optimistic path).
|
||||||
In this section, we'll now turn out attention into the various scenarios where the payment flow across the route breaks down.
|
In this section, we'll now turn out attention into the various scenarios where the payment flow across the route breaks down.
|
||||||
|
|
||||||
|
|
||||||
First, it's important to know that once a node sends a fully valid onion packet out to the first hop, they cannot directly influence the course of the route.
|
First, it's important to know that once a node sends a fully valid onion packet out to the first hop, they cannot directly influence the course of the route.
|
||||||
In other words:
|
In other words:
|
||||||
|
|
||||||
@ -665,15 +334,12 @@ Thus the HTLCs which are below the dust limit can be understood to be additional
|
|||||||
Most Lightning Nodes support the configuration of minimum accepted HTLC values.
|
Most Lightning Nodes support the configuration of minimum accepted HTLC values.
|
||||||
Operators have to consider if they want to risk overpaying fees or losing funds in the forced channel closure cases because the commitment transactions have been added to the fees.
|
Operators have to consider if they want to risk overpaying fees or losing funds in the forced channel closure cases because the commitment transactions have been added to the fees.
|
||||||
|
|
||||||
|
|
||||||
Explain fee and time-lock considerations
|
Explain fee and time-lock considerations
|
||||||
The “HTLC Switch” analogy compared to regular network switch
|
The “HTLC Switch” analogy compared to regular network switch
|
||||||
Circuit map concept, how to handle forwarding
|
Circuit map concept, how to handle forwarding
|
||||||
Pipeline styles for HTLCs
|
Pipeline styles for HTLCs
|
||||||
Error handling and encryption for HTLCs
|
Error handling and encryption for HTLCs
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Explain “one little trick” of DH re-randomization
|
Explain “one little trick” of DH re-randomization
|
||||||
Explain how we keep the packet size fixed, what’s MAC’d, etc
|
Explain how we keep the packet size fixed, what’s MAC’d, etc
|
||||||
Introduce the new modern payload format which uses TLV
|
Introduce the new modern payload format which uses TLV
|
@ -184,6 +184,7 @@ Following is an alphabetically sorted list of all the GitHub contributors, inclu
|
|||||||
* Eduardo Lima III (@elima-iii)
|
* Eduardo Lima III (@elima-iii)
|
||||||
* Emilio Norrmann (@enorrmann)
|
* Emilio Norrmann (@enorrmann)
|
||||||
* Francisco Calderón (@grunch)
|
* Francisco Calderón (@grunch)
|
||||||
|
* Giovanni Zotta (@GiovanniZotta)
|
||||||
* Gustavo Silva (@GustavoRSSilva)
|
* Gustavo Silva (@GustavoRSSilva)
|
||||||
* Haoyu Lin (@HAOYUatHZ)
|
* Haoyu Lin (@HAOYUatHZ)
|
||||||
* Hatim Boufnichel (@boufni95)
|
* Hatim Boufnichel (@boufni95)
|
||||||
@ -197,8 +198,10 @@ Following is an alphabetically sorted list of all the GitHub contributors, inclu
|
|||||||
* Paul Wackerow (@wackerow)
|
* Paul Wackerow (@wackerow)
|
||||||
* René Köhnke (@rene78)
|
* René Köhnke (@rene78)
|
||||||
* Ricardo Marques (@RicardoM17)
|
* Ricardo Marques (@RicardoM17)
|
||||||
|
* Sebastian Falbesoner (@theStack)
|
||||||
* Sergei Tikhomirov (@s-tikhomirov)
|
* Sergei Tikhomirov (@s-tikhomirov)
|
||||||
* Simone Bovi (@SimoneBovi)
|
* Simone Bovi (@SimoneBovi)
|
||||||
|
* Taylor Masterson (@tjmasterson)
|
||||||
* Umar Bolatov (@bolatovumar)
|
* Umar Bolatov (@bolatovumar)
|
||||||
|
|
||||||
Without the help offered by everyone listed above, this book would not have been possible. Your contributions demonstrate the power of open source and open culture, and we are eternally grateful for your help.
|
Without the help offered by everyone listed above, this book would not have been possible. Your contributions demonstrate the power of open source and open culture, and we are eternally grateful for your help.
|
||||||
|