Visualizing potential paths for rebalancing channels in the Lightning Network
Tags: lightningnetwork, datavisualizations
Published: 2022-08-15 16:14:30

Once again, working with [LN Capital](https://twitter.com/LN_Capital) under [Summer of Bitcoin](https://twitter.com/summerofbitcoin) 2022 program, we were able to produce interesting visualizations for selecting potential paths for a payment in the Lightning Network (LN).

Recall that the LN is a payment channel network (PCN) built on top of Bitcoin. If you have a LN node, then you can send, receive, and forward payments through the network. Here, we are going to focus on sending payments. 

When you send a payment to another node, data gets back to you when the payment rather succeeds or fails. You are able to see the route of the payment, the fees in each channel, and in which channel, if any, the payment failed. 

You can also send a payment to yourself for rebalancing purposes. Rebalancing is needed when the inbound and outbound capacities of a channel become unbalanced. One way to rebalance your channels is creating a circular route, i.e. sending a payment from your node back to your node.

<img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/qpzdvhr4joamburn2c9s.png" alt="rebalancing example"/> <figcaption>Figure 1: Circular route rebalancing. Image taken from Matering the Lightning Network book, p. 139.</figcaption>

It would be great to have a tool that helps node owners visualize potential paths to rebalance their channels. With it, they could select which paths to probe by filtering and sorting the data of the different possible routes.

## Visualization tool

This time, we decided the best way to easily visualize this was with interactive tables, where you can filter, sort, and select data to display the full route you're interested in.  

The tool consists of 4 tables. The first one is for selecting a node you want to include in the rebalancing (central node), and the channel you want to send the payment from. The second table is for selecting a route that starts from the channel you selected before, and ends in the central node. Third one is for selecting the channel where you want to receive the payment. Finally, the fourth table is for selecting a route from the central node to your node, ending in the channel you selected right before.

For this task, the 3 main libraries used were `networkx`, `pandas`, and `dash`. `network` was used for computing the simple paths from one node to the rest in the network. `pandas` was used for creating the suitable dataframes, that later were converted into interactive tables using `dash`.

## First table
<img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/8f93xxrvgabb8n6j5zu6.png" alt="Table 1"/> <figcaption>Figure 2: Table 1 for selecting central node and outgoing channel.</figcaption>

This table has 3 columns: <br>
1. *source*: to choose your node
2. *central_node*: to choose a certain node you want to include in the rebalancing path
3. *Channel_out*: to choose the channel you want to send the payment from.

## Second table
<img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/fe2tctsatnbdqzd1seul.png" alt="Table 2"/> <figcaption>Figure 3: Table 2 for selecting a path to the central node.</figcaption>

This table is more interesting. All columns support filtering and sorting. It's an easy way to see which routes are cheaper, which take fewer hops, and which have a higher overall capacity.

Here is part of the code to build this table: <br>
```python
@app.callback(
    Output('secondtable-container', 'children'),
    Input('first-table', 'selected_row_ids'),
)
def make_second_table(selected_rows):
    if selected_rows is None:
        source_central, channel_out = [], []
    else:
        rows = [row.split(' -> ') for row in selected_rows]
        source_central = [row[0] for row in rows]
        channel_out = [row[1] for row in rows]

    masks = (grouped_routes.peers.isin(source_central) & grouped_routes.channel_out.isin(channel_out))
    second_dff = grouped_routes[masks]

    return html.Div([
        dash_table.DataTable(
            id='second-table',
            columns=[
                {'name': i, 'id': i, 'deletable': True} for i in second_dff.columns
                if i != 'id' and i != 'channel_out'
            ],
            data=second_dff.to_dict('records'),
            editable=False, # cells are not editable
            filter_action='native', # filter by entering text in the input box
            sort_action='native',
            sort_mode='multi',
            row_selectable='single',  
            page_action='native',
            page_current=0,
            page_size=10,
        ),
        html.Div(id='thirdtable-container'),  
    ])
```

## Third table
<img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/h1o6nn4nnbzqq5jnaqjq.png" alt="Table 3"/> <figcaption>Figure 4: Table 3 for selecting the channel where you want to receive the payment.</figcaption>

The third table is similar to the first one. It's only purpose is showing the channels you have, in order to select the one where you want to receive the payment, hence completing the circular path.

## Fourth table
<img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/bbjtdmoh62nhnbijuyda.png" alt="Table 4"/> <figcaption>Figure 5: Table 4 for selecting the route back to your node.</figcaption>

The final table is this one, similar to the second one but for selecting an appropriate route, based on your criteria, to complete the rebalancing path.

After selecting a row, a new container displays the whole information of the circular path, like this:
<img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/no0m5iww0fa03wb4taa2.png" alt="Final Container"/> <figcaption>Figure 6: The aggregated data of the whole path.</figcaption>

Here is a full demonstration of the tables functionality:


![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/vpylu37tqpitbxct0eg9.gif)
---

The value of having a tool like this is being tested. Feel free to leave in the comments whether this would help you in some way with your lightning node.