-
Notifications
You must be signed in to change notification settings - Fork 265
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add high-level architecture diagrams (#1733)
It can be useful for newcomers to have a high-level view of the main components in eclair. This will help them quickly find where they should start digging into actual code to achieve what they want. We're leaving a lot of details out to ensure this document stays up-to-date and doesn't need to completely change every time we slightly rework internal details of our architecture.
- Loading branch information
Showing
1 changed file
with
234 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,234 @@ | ||
# Architecture of the eclair codebase | ||
|
||
Eclair is developed in [Scala](https://www.scala-lang.org/) and relies heavily on [Akka](https://akka.io/). | ||
Akka is an [actor programming](https://doc.akka.io/docs/akka/current/typed/guide/actors-intro.html?language=scala) framework similar to [Erlang](https://www.erlang.org/) for the JVM. | ||
|
||
The actor model provides a clean separation between components, allowing eclair to: | ||
|
||
1. Isolate faults and ensure high availability | ||
2. Scale across CPUs and machines efficiently | ||
3. Simplify development and testing | ||
|
||
At a high-level, almost every entity is a separate, sandboxed actor: | ||
|
||
- Every peer connection is an actor instance | ||
- Every lightning channel is an actor instance | ||
- Every payment attempt is an actor instance | ||
|
||
Some actors are long-lived (e.g. lightning channels) while others are very short-lived (e.g. payment attempts). | ||
|
||
## Top-level projects | ||
|
||
Eclair is split into four top-level projects: | ||
|
||
- `eclair-core`: core library implementing lightning | ||
- `eclair-node`: server daemon built upon `eclair-core` (exposes a Json RPC and WebSocket endpoint) | ||
- `eclair-front`: when using cluster mode, front-end server daemons handling peer connections | ||
- `eclair-node-gui` (deprecated): sample JavaFX user interface to demo eclair (should not be used in production) | ||
|
||
The entry point for `eclair-core` is in `Setup.scala`, where we start the actor system, connect to `bitcoind` and create top-level actors. | ||
|
||
## Actor system overview | ||
|
||
Here is a high-level view of the hierarchy of some of the main actors in the system: | ||
|
||
```ascii | ||
+---------+ | ||
+-------->| Channel | | ||
| +---------+ | ||
+------+ +---------+ | ||
+---------------->| Peer |----->| Channel | | ||
| +------+ +---------+ | ||
| | +---------+ | ||
| +-------->| Channel | | ||
| +---------+ | ||
+-------------+ | ||
| Switchboard | | ||
+-------------+ | ||
| +---------+ | ||
| +-------->| Channel | | ||
| | +---------+ | ||
| +------+ +---------+ | ||
+---------------->| Peer |----->| Channel | | ||
+------+ +---------+ | ||
| +---------+ | ||
+-------->| Channel | | ||
+---------+ | ||
+----------------+ | ||
+---------------->| ChannelRelayer | | ||
| +----------------+ | ||
+---------+ | ||
| Relayer | | ||
+---------+ | ||
| +-------------+ | ||
+---------------->| NodeRelayer | | ||
+-------------+ | ||
+------------------+ | ||
+----------->| PaymentLifecycle | | ||
| +------------------+ | ||
+---------------------------+ +------------------+ | ||
+---------------->| MultiPartPaymentLifecycle |----->| PaymentLifecycle | | ||
| +---------------------------+ +------------------+ | ||
| | +------------------+ | ||
| +----------->| PaymentLifecycle | | ||
+------------------+ +------------------+ | ||
| PaymentInitiator | | ||
+------------------+ +------------------+ | ||
| +----------->| PaymentLifecycle | | ||
| | +------------------+ | ||
| +---------------------------+ +------------------+ | ||
+---------------->| MultiPartPaymentLifecycle |----->| PaymentLifecycle | | ||
+---------------------------+ +------------------+ | ||
| +------------------+ | ||
+----------->| PaymentLifecycle | | ||
+------------------+ | ||
+---------------------+ | ||
+---------------->| MultiPartPaymentFSM | | ||
| +---------------------+ | ||
+----------------+ | ||
| PaymentHandler | | ||
+----------------+ | ||
| +---------------------+ | ||
+---------------->| MultiPartPaymentFSM | | ||
+---------------------+ | ||
+----------+ | ||
| Register | | ||
+----------+ | ||
+--------+ | ||
| Router | | ||
+--------+ | ||
``` | ||
|
||
And a short description of each actor's role: | ||
|
||
- Switchboard: creates and deletes peers | ||
- Peer: p2p connection to another lightning node (standard lightning messages described in [Bolt 1](https://github.com/lightningnetwork/lightning-rfc/blob/master/01-messaging.md)) | ||
- Channel: channel with another lightning node ([Bolt 2](https://github.com/lightningnetwork/lightning-rfc/blob/master/02-peer-protocol.md)) | ||
- Register: maps channel IDs to actors (provides a clean boundary between channel and payment components) | ||
- PaymentInitiator: entry point for sending payments | ||
- Relayer: entry point for relaying payments | ||
- PaymentHandler: entry point for receiving payments | ||
- Router: p2p gossip and the network graph ([Bolt 7](https://github.com/lightningnetwork/lightning-rfc/blob/master/07-routing-gossip.md)) | ||
|
||
Actors have two ways of communicating: | ||
|
||
- direct messages: when actors have a reference to other actors, they can exchange [direct messages](https://doc.akka.io/docs/akka/current/typed/interaction-patterns.html) | ||
- events: actors can emit events to a shared [event stream](https://doc.akka.io/docs/akka/current/event-bus.html), and other actors can register to these events | ||
|
||
## Payment scenarios | ||
|
||
Let's dive into a few payment scenarios to show which actors are involved. | ||
|
||
### Sending a payment | ||
|
||
When we send a payment: | ||
|
||
- we run a path-finding algorithm (`Router`) | ||
- we split the payment into smaller chunks if [MPP](https://github.com/lightningnetwork/lightning-rfc/blob/master/04-onion-routing.md#basic-multi-part-payments) is used (`MultiPartPaymentLifecycle`) | ||
- we retry with alternative routes in some failure cases and record failing channels/payments (`PaymentLifecycle`) | ||
- we add HTLCs to some of our channels | ||
|
||
```ascii | ||
+------------------+ +---------+ | ||
+----->| PaymentLifecycle |-----+ +----->| Channel | | ||
| +------------------+ | | +---------+ | ||
+------------------+ +---------------------------+ | +------------------+ | +----------+ | +---------+ | ||
| PaymentInitiator |-------->| MultiPartPaymentLifecycle |----+----->| PaymentLifecycle |-----+----->| Register |-----+----->| Channel | | ||
+------------------+ +---------------------------+ | +------------------+ | +----------+ | +---------+ | ||
| | +------------------+ | | +---------+ | ||
| +----->| PaymentLifecycle |-----+ +----->| Channel | | ||
| +------------------+ +---------+ | ||
| | | ||
| | | ||
| +--------+ | | ||
+----->| Router |<-----------+ | ||
+--------+ | ||
``` | ||
|
||
### Receiving a payment | ||
|
||
When we receive a payment: | ||
|
||
- htlcs are forwarded by channels to the relayer | ||
- a payment handler compares these htlcs to our payments database | ||
- and decides to fail or fulfill them | ||
|
||
```ascii | ||
+---------+ | ||
| Channel |-----+ | ||
+---------+ | | ||
+---------+ | +---------+ +----------------+ +----------+ | ||
| Channel |-----+----->| Relayer |----->| PaymentHandler |----->| Register | | ||
+---------+ | +---------+ +----------------+ +----------+ | ||
+---------+ | | ||
| Channel |-----+ | ||
+---------+ | ||
``` | ||
|
||
### Relaying a payment | ||
|
||
When we relay a payment: | ||
|
||
- htlcs are forwarded by channels to the relayer | ||
- the relayer identifies the type of relay requested and delegates work to a channel relayer or a node relayer | ||
- if a node relayer is used ([trampoline payments](https://github.com/lightningnetwork/lightning-rfc/pull/829)): | ||
- incoming htlcs are validated by a payment handler (similar to the flow to receive payments) | ||
- outgoing htlcs are sent out (similar to the flow to send payments) | ||
|
||
```ascii | ||
+----------------+ +----------+ +---------+ | ||
+--------->| ChannelRelayer |----->| Register |----->| Channel | | ||
| +----------------+ +----------+ +---------+ | ||
+---------+ +---------+ | ||
| Channel |----->| Relayer | | ||
+---------+ +---------+ | ||
| +-------------+ +---------------------------+ | ||
+--------->| NodeRelayer |----->| MultiPartPaymentLifecycle | | ||
+-------------+ +---------------------------+ | ||
^ | ||
| | ||
v | ||
+----------------+ | ||
| PaymentHandler | | ||
+----------------+ | ||
``` | ||
|
||
## Channel scenarios | ||
|
||
Let's describe some channel operations and see which actors are involved. | ||
|
||
### Opening a channel | ||
|
||
When we open a channel: | ||
|
||
- we exchange messages with our peer | ||
- we use funds from our on-chain bitcoin wallet | ||
- we start watching on-chain transactions to ensure our peer doesn't cheat us | ||
|
||
```ascii | ||
+------+ +---------+ +--------+ | ||
| Peer |----->| Channel |-----+----->| Wallet | | ||
+------+ +---------+ | +--------+ | ||
^ | | +---------+ | ||
| | +----->| Watcher | | ||
+--------------+ +---------+ | ||
``` | ||
|
||
### Closing a channel | ||
|
||
When our peer tries to cheat: | ||
|
||
- the blockchain watcher notices it and notifies the channel | ||
- the channel publishes on-chain transactions | ||
- and we notify our peer by sending an error message | ||
|
||
```ascii | ||
+---------+ +---------+ +------+ | ||
| Watcher |<----->| Channel |----->| Peer | | ||
+---------+ +---------+ +------+ | ||
``` |