8000 Add high-level architecture diagrams by t-bast · Pull Request #1733 · ACINQ/eclair · GitHub
[go: up one dir, main page]
More Web Proxy on the site http://driver.im/
Skip to content

Add high-level architecture diagrams #1733

New issue

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

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

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Mar 24, 2021
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
234 changes: 234 additions & 0 deletions docs/Architecture.md
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 ar 10000 e 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 |
+---------+ +---------+ +------+
```
0