© Harris Brakmić 2019
H. BrakmićBitcoin and Lightning Network on Raspberry Pihttps://doi.org/10.1007/978-1-4842-5522-3_10

10. c-lightning

Harris Brakmić1 
(1)
Troisdorf, Germany
 

In this chapter we will learn how to set up a Lightning Node based on c-lightning , one of the three implementations of the BOLT specification. Using our previously configured Full Node, we will join the Lightning Network by opening and funding new channels to other nodes. We will also learn how to pay invoices and create own payment requests.

Compilation

Our first step will be to clone c-lightning project’s sources.
git clone https://github.com/ElementsProject/lightning.git
Then we will have to install certain libraries that are needed to successfully compile our c-lightning binaries.
sudo apt install -y autoconf automake asciidoc build-essential git libtool libgmp-dev libsqlite3-dev python python3 python3-mako python3-pip net-tools sqlite3 zlib1g-dev libsodium-dev

However, as we have already learned how to compile Bitcoin Core Wallet, a few of these libraries will be already available and mentioned during installation. In any case, we simply let the process finish.

Afterward, we will install the Python3 libraries from test and doc directories. For this we change the directory with cd lightning and execute the following commands.
sudo pip3 install -r tests/requirements.txt
sudo pip3 install -r doc/requirements.txt

Now we are ready to compile the c-lightning suite. In the cloned directory lightning we enter ./configure to start generation of Makefiles.

After the configuration process has completed successfully, we should get the command prompt back. We are now ready to enter the make command to kick off the compilation. If there were no errors, we would simply get the command prompt back as the final result. The last step is to install the binaries with sudo make install.

Configuration

Before we start the daemon lightningd, we have to provide a proper configuration that is by default located in .lightning/config. We first create the directory in our own $HOME and open the file config with an editor of our choice.
mkdir .lightning
touch .lightning/config
nano .lightning/config
The daemon reads the configuration entries when it starts up. They can be overridden by the flags given to the daemon on the console. If we prefer another location or configuration file, for example, we could change them by adding flags --lightning-dir and --conf. Our default configuration settings would contain following entries:
alias=LIGHTNING_NODE_NAME_HERE
rgb=CA1F7B
addr=:9735
network=testnet
bitcoin-cli=/usr/local/bin/bitcoin-cli
bitcoin-datadir=/home/pi/.bitcoin
bitcoin-rpcuser=raspiuser
bitcoin-rpcpassword=mypassword
bitcoin-rpcport=18332
bitcoin-rpcconnect=127.0.0.1
log-prefix=raspi-lightning
ignore-fee-limits=true
fee-base=10
daemon
Our configuration file contains settings for
  • The name of our node.

  • The color, which is an RGB value, that should be used to show our node in available Lightning Network explorers.

  • The IP address and port lightningd will listen on. Here we accept any IP address, and our port will be 9735, which is the default port according to BOLT specification. Unicode character 9735 is the symbol for lightning.

  • The network variant.

  • The connection settings for accessing our local Bitcoin RPC API.

  • The prefix for entries in lightning.log file.

  • Two additional settings regarding fee calculations, to make lightningd less strict (this should only be used in testnet).

  • The option daemon to run lightningd and other daemons in the background.

After we have saved this file, we can start the daemon on the console with
lightningd –-testnet
The output returned by lightningd would look like this:
2019-09-21T18:48:11.751Z INFO raspi-lightning
2019-09-21T18:48:11.751Z INFO raspi-lightning Server started with public key 0370e894fa6e8ff735dc3278543ea2718c632ce380aaf30ce35fa261e8c0c7611e, alias BTC-TEST-RASPI-LIGHTNING-NODE (color #ca1f7b) and lightningd v0.7.2.1-56-g49496ab-modded
We have successfully configured and started our c-lightning daemon. Now it is time to learn how to control it with lightning-cli, its command line interface. Our first step will be to get basic information about our own node by issuing this command:
 lightning-cli getinfo.
It will give us a picture about our network connection, blockchain type, and the current state of our wallet.
{
   "id": "0370e894fa6e8ff735dc3278543ea2718c632ce380aaf30ce35fa261e8c0c7611e",
   "alias": "BTC-TEST-RASPI-LIGHTNING-NODE",
   "color": "ca1f7b",
   "num_peers": 35,
   "num_pending_channels": 0,
   "num_active_channels": 35,
   "num_inactive_channels": 0,
   "address": [
      {
         "type": "ipv4",
         "address": "37.201.115.117",
         "port": 9735
      }
   ],
   "binding": [
      {
         "type": "ipv4",
         "address": "0.0.0.0",
         "port": 9735
      }
   ],
   "version": "v0.7.2.1-56-g49496ab-modded",
   "blockheight": 1579246,
   "network": "testnet",
   "msatoshi_fees_collected": 5582,
   "fees_collected_msat": "5582msat"
}

As we can see, my node is already connected to several other lightning nodes. In the Lightning Network, nodes remember their channels and can easily reopen them as long as their peers are online as well. A channel can also be declared pending, which is always the case when a new channel opens, because the initial funding will take some time to settle on the blockchain. The same applies to closing a channel as we have learned in the previous chapter. A node can issue a close command, but the finalization will always take a certain number of blocks both of the nodes agreed upon when they created the channel in the first place.

Setting Up a Lightning Node

When a completely new node is started, the first step we’d have to take care of is to properly fund its wallet, because in Lightning Network channels can only be opened by nodes who have money at their disposal. Of course, it could be possible that some other node would connect ours, but as nobody “out there” knows about it, the chances are extremely low.

The first command we execute is creating a new address for our node, where we will send our tBTC to:
 lightning-cli newaddr
If you don’t have any, you can visit web-based “testnet faucets” listed below. There are many faucets on the net, but some of them are full of ads and sometimes even spyware. In general, one should be careful when visiting faucets, especially those who promise “real bitcoins”. In our case, however, we are only searching for monetary useless but technologically very useful tBTC coins.
../images/486570_1_En_10_Chapter/486570_1_En_10_Fig1_HTML.jpg
Figure 10-1

A website of a testnet faucet showing the tBTC that got sent to our node

The address we got is in Bech32 format, because this is the default address format in the Lightning Network. It looks like this:
{
   "address": "tb1qg085r8xmfs2yxapsykjmnprvv4lqx9fnql7nnh",
   "bech32": "tb1qg085r8xmfs2yxapsykjmnprvv4lqx9fnql7nnh"
}
Our lightning node maintains its own, separate wallet, that is not visible to our Bitcoin node and vice-versa. If you happen to be using a faucet that doesn’t support Bech32 addresses, you can create a P2SH formatted address with:
 lightning-cli newaddr p2sh-segwit

However, the bitcoins we’re sending to our lightning node aren’t “lost forever” and can be later taken out and sent back to our Bitcoin node’s wallet. But to properly function, our lightning node must have direct access to its own bitcoins, because lightning nodes are “hot wallets” that must always be online for their payment channels to work. A lightning node that’s offline isn’t capable of receiving and sending anything, which is contrary to what we have learned about Bitcoin.

In Bitcoin, you can send funds to any address, regardless if the node’s owner is running it right now or not, because the blockchain is copied over many other nodes that will take care of this particular transaction to settle. In the Lightning Network, nobody cares about your transactions and channels. Therefore, a node that wants to receive money must also be there to take it.

After we have received some tBTC from one of the faucets, we are ready to fund our node. For proper funding we don’t need full tBTC coins, because even small amounts like 0.0001 tBTC would be perfectly sufficient. We will now check the current balance of our node by executing:
lightning-cli listfunds
The data returned would vary from node to node, but they’d all contain two areas: channels and outputs. Those represent funds that have been locked in channels and unspent outputs that could be later used for funding new channels. Here I am showing only a few entries from the complete list.
   "outputs": [
      {
         "txid": "08271bd9ad24dbef72b224882210f51aefa49c5578ff1f56a1efc71c17d769a7",
         "output": 0,
         "value": 999501,
         "amount_msat": "999501000msat",
   ],
   "channels": [
      {
         "peer_id": "02d6c7db1df781d53b1b9a96eb269d4316353dc4a939f0d7363fa50439c1ba0a9c",
         "short_channel_id": "1576603x120x0",
         "channel_sat": 500000,
         "our_amount_msat": "500000000msat",

As Lightning Network’s primary use is for micropayments, the units we know from Bitcoin are simply too large. One bitcoin contains 100,000,000 satoshis, and in Lightning Network we count in milli-satoshis, which are 1000 times smaller than a single satoshi.

Our next step is to open a payment channel. Currently, we have no peers at all. The next command would return only an empty list:
lightning-cli listpeers
The easiest way to find peers on testnet is by using one of the publicly available lightning explorers. However, take care of not accidentally using mainnet explorers. If you try to open a channel with one of their nodes, you will get weird blockchain errors, indicating that your node is trying to send funds from a chain they don’t recognize. A good testnet explorer with search functionality is located at https://1ml.com/testnet (Figure 10-2).
../images/486570_1_En_10_Chapter/486570_1_En_10_Fig2_HTML.jpg
Figure 10-2

A Lightning Network testnet explorer

To connect with another node, we need its ID, IP-address, and port (if not using the default one). Some of the nodes you might find show no IP addresses and ports, which means that they’re running as private nodes that nobody can connect to. This is nothing unusual as there is no rule that a Lightning Node must be available to anyone in the wider network. It always depends on the use-case if a node should be public or not. Merchants might surely want to operate public nodes, because customers should be able to send payments to stores anytime. Someone paying monthly bills only would rather prefer to remain private.

Port Forwarding with upnpc

If your node is running within a private network, where the only routable IP address is located on the router configured by your provider, chances are that you will either have to configure port forwarding or activate it via UPnP (Universal Plug and Play). With UPnP one can let the node automatically configure and update port forwarding. The package MiniUPnPc is available in Raspbian’s apt package repository.
sudo apt install miniupnpc
Our next step will be to create a small script in our home directory that will execute upnpc. Later we will insert them into crontab’s list.
nano ~/update_port_fwd.sh
Then enter this script:
#!/bin/sh
upnpc -e "lightning network" -a 192.168.0.87 9735 9735 TCP

The script will be executed by the shell to call the upnpc binary, which will establish the port forwarding for port 9735 for the given IP address. The IP address shown in the previous picture should be changed to your machine’s address that you can get by executing ifconfig on your node’s terminal.

After having saved the script, we change its flags by making it executable.
chmod + x ~/update_port_fwd.sh
You should also check that your router supports and has currently activated UPnP. As there are many different router-types, the location will vary greatly. Usually, it’s a single option that can be activated and deactivated. Here’s one example of such an option in a router (Figure 10-3).
../images/486570_1_En_10_Chapter/486570_1_En_10_Fig3_HTML.jpg
Figure 10-3

Activating UPnP on router

We can execute our script once to test its functionality. Afterward, we will insert it into crontab to avoid manual typing in future.
./update_port_fwd.sh
If we get an answer containing the port 9735 and the external IP address from which the incoming packets will be forwarded to our node, we are ready to set up two entries in our crontab‘s list. We open crontab in edit mode:
crontab -e
We then add these two lines:
@reboot   /home/pi/update_port_fwd.sh
*/10 * * * * /home/pi/update_port_fwd.sh

The first entry will execute our script at each reboot, while the second would do it every 10 minutes. This way we keep our port forwarding intact without having to manually take care of script execution and port checking.

Creating Payment Channels

When searching for nodes in the test explorer, we should prefer the newest ones, because the older the entry, the greater the chance that a node isn’t online anymore. Also, we should look for the capacity they offer. If the capacity, that is, the number of coins, is too low, we might later have problems with routing our payments. The bigger the payments we want to send, the greater the capacity of our “neighborhood” should be. Also, we too should provide enough liquidity for other nodes to consider us as worthy of connecting and opening new payment channels. The more liquidity we offer, the greater the chance to become a routing node for others, who would then pay for our payment forwarding services.

After we have selected a node with good characteristics, we will issue two commands, one for creating the channel and the other for funding it. The command
lightning-cli connect NodeID@IP:Port

expects a node ID, IP, and port which we get from the explorer. The format I am using here is NodeID@IP:Port, but they can also be given as separate arguments.

If the connection was successful, the result we get will be a new ID that points at the new payment channel. Our next step is to properly fund it. However, this task can sometimes be very tricky, for example, when the counterparty expects an initial payment that’s higher as we would like to pay for it. In such cases we can either accept the parameters given by the node or close the connection and search for a more suitable counterparty. To close a connection, we need to use:
lightning-cli disconnect ChannelID

In our case, however, the other node’s expectations were acceptable to us so that we agreed upon investing 500,000,000msat, that is, 500,000 satoshis.

The command for funding a new payment channel is
 lightning-cli fundchannel ChannelID amount_of_satoshis
Immediately, we would get back the raw transaction and its ID, which will be published on the blockchain. We will now have to wait for three confirmations before we can use the channel. In the meantime, we can explore it by issuing the command:
lightning-cli listpeers

Previously, it showed us only an empty list as no other node was connected with us. Now we get a large JSON object containing many details about our peer node, the channel, the funding amounts, and various other rules both nodes agreed upon.

The information about the current state of the channel is also there.
"status": [
"CHANNELD_AWAITING_LOCKING: Funding needs 3 more confirmations to lockin."
]

The more peers we get, the larger the output of listpeers will become.

Also, our wallet balance has changed as we can see it by executing
lightning-cli listfunds
Previously, the channels property of the returned JSON object was empty. This time it contains information about funds that were used to fund our payment channel. We also can use our private Bitcoin testnet explorer to search for our funding transaction. But as the Bitcoin testnet is globally available, any other testnet explorer could be used as well.
../images/486570_1_En_10_Chapter/486570_1_En_10_Fig4_HTML.jpg
Figure 10-4

Searching for funding transaction in testnet explorer

One must take into account that block generation in Bitcoin’s testnet is not as predictable as in mainnet. Therefore, it could take a considerable amount of time until the three blocks get generated.

Ultimately, the funding transaction will get confirmed which will be indicated by a changed entry in peer information JSON.
"status": [
"CHANNELD_NORMAL: Funding transaction locked."
]
The output of getinfo has changed as well.
"num_peers": 1,
"num_pending_channels": 0,
"num_active_channels": 1,
"num_inactive_channels": 0,

We have successfully funded our first payment channel. Both nodes can now send payments and generate invoices. However, to increase our networking capability, we should connect more nodes. For example, the node that belongs to operators of the search engine we used can be found here (Figure 10-5).

To create a payment channel with it, we repeat the commands and only replace the NodeID and IP:
lightning-cli connect 02312627fdf07fbdd7e5ddb136611bdde9b00d26821d14d94891395452f67af248@23.237.77.12:9735
After the connection got established, we fund the new channel with
lightning-cli fundchannel 02312627fdf07fbdd7e5ddb136611bdde9b00d26821d14d94891395452f67af248 100000

Here I have funded the channel with 100,000 satoshis.

Similarly, we will have to wait for three blocks for our funding transaction to get confirmed. After a while, we will be able to find our node by entering its ID in the search engine.
../images/486570_1_En_10_Chapter/486570_1_En_10_Fig6_HTML.jpg
Figure 10-6

Searching for own Lightning Node

There is also an option to claim ownership of a node. A user would be asked to open a channel to search engine’s public node with a certain amount of satoshis defined by the search engine, which will only be shown to the user. For this, obviously, one has to register there first.

Running c-lightning on Regtest

An alternative way of learning how to use c-lightning would be to run our Bitcoin Core node in regtest mode and with multiple lightningd processes. They would access the same regtest datadir of the Bitcoin daemon. In our case the default datadir is $HOME/.bitcoin. We’d also need a separate regtest lightning directories for each lightningd, because the current one we use was created under testnet, and its sqlite3 database wouldn’t be compatible with the regtest network.

As c-lightning uses the sqlite31 database internally, each network needs a separate one. One can’t switch from one network to another without having created a new sqlite3 database for it. Therefore, we create two separate directories, .lightningd_regtest1 and .lightningd_regtest2, and initialize two separate lightningd processes with following parameters:
lightningd --network regtest --lightning-dir $HOME/.lightning_regtest1 --bitcoin-datadir $HOME/.bitcoin   --addr 127.0.0.1:20000 --daemon
lightningd --network regtest --lightning-dir $HOME/.lightning_regtest2 --bitcoin-datadir $HOME/.bitcoin --addr 127.0.0.1:20001 --daemon

Then we can generate a few bitcoins by using the RPC calls generate or generatetoaddress from the console with the bitcoin-cli tool. And just like with testnet nodes, we would have to fund our two regtest variants by using the same set of commands as already done in testnet. The last step will be to connect those nodes with each other by using their lightning IDs, which we can get with the command lightning-cli getinfo. Of course, our single Bitcoin node must already be running in regtest mode, which we declare by activating the option regtest=1 in bitcoin.conf. However, this setup wouldn’t be as “realistic” as the one with testnet.

Using c-lightning

With our configured testnet node, we should now try to use our payment channels for buying something. One good opportunity to test the machinery is the website https://starblocks.acinq.co where we can buy cappuccino from a demo coffee shop (Figure 10-7).
../images/486570_1_En_10_Chapter/486570_1_En_10_Fig7_HTML.jpg
Figure 10-7

A Lightning coffee shop

After we have selected our favorite coffee variant, we click “checkout” and copy the given payment request. A payment request is a long alphanumeric string that always begins with ln and the network prefix, which in our case is tb1 (Figure 10-8).
../images/486570_1_En_10_Chapter/486570_1_En_10_Fig8_HTML.jpg
Figure 10-8

A Lightning payment request with QR code

Alternatively, we could have paid our coffee with an application that supports QR codes. And in the following chapters, we will install such an application. Our next console command is lightning-cli pay, which we use to pay the invoice. We simply copy the given bolt11 string from the payment request when executing this command.

The returned result contains information about the payment status, its destination, and the amount paid in milli-satoshis. Simultaneously, the coffee shop will inform us about the successful payment as well (Figure 10-9). This is the power of the Lightning Network. Instant payments without trusted intermediaries and waiting times like block confirmations.
../images/486570_1_En_10_Chapter/486570_1_En_10_Fig9_HTML.jpg
Figure 10-9

Payment successful

We can also decode the payment request with
 lightning-cli decodepay BOLT11
Replace BOLT11 with the bolt11 string from your payment. You should get a JSON object containing data like this:
{
   "currency": "tb",
   "created_at": 1567804722,
   "expiry": 3600,
   "payee": "03933884aaf1d6b108397e5efe5c86bcf2d8ca8d2f700eda99db9214fc2712b134",
   "msatoshi": 1900000,
   "amount_msat": "1900000msat",
   "description": "1 Scala Chip Frappuccino",
   "min_final_cltv_expiry": 20,
   "payment_hash": "0085fac18d88cc622ba9fdbd8567ff47f0083efd94e254a2c9684f09ea0f616b",
   "signature": "30440220020e2bcc88f69967140565571644676407318e3b15578ff9076cc68779a6638e02204afe1dd6eabddac6bfd3fa5c010c13e834dfc9e058a1e4003f0a267b57abe8a1"
}

Indeed, it is always a good idea to check the contents of payment requests before paying them, especially when dealing with unknown services. The same functionality is also available in various mobile applications that can read QR codes. To list all previous payments the command listpayments can be used.

Currently, there is only one payment, so the list in this node is rather short. To issue a payment request on our own, we have the command invoice that needs a few parameters:
  • Requested amount in milli-satoshis

  • Payment name

  • Payment description

There are another parameters, like expiry time and fallback addresses, which we don’t need right now.
lightning-cli invoice 100 "PaymentRequest1"
"my fist payment request"

The resulting JSON object contains the payment hashes, the default expiration time and the most important entry: the bolt11 string. This is our own payment request similar to the one we just paid. The warning in the last line is informing us that our node isn’t well-connected, which is currently the case as we only have one payment channel open. Therefore, we should open more and especially open more channels with nodes that offer sufficient liquidity. We could also decode our payment request with decodepay.

We would now have to forward this request to the paying side. This can be done via any other transport medium, as long as the original bolt11 string remains unchanged and paid within the given expiry time, which is 1 week by default. And of course, there is a command to list them all:
lightning-cli listinvoices

Activating Experimental Features

The functionalities we used so far are part of every c-lightning distribution. However, there is a way to activate special features, which are useful for people who want to try out different scenarios, especially when working on c-lightning’s source code. It is needless to say that such features could be very dangerous and provoke various problems ranging from “normal” ones like daemon crashes up to losing assets. But as long as the binaries are being executed in testnet or regtest mode, the risks are acceptable. To activate them, the following flags must be added when executing the configure script.
  • --enable-developer

  • --enable-experimental-features

  • --disable-valgrind

  • --enable-static

The first two options activate the compilation of developer and experimental features, while the other two remove extra checks and activate static builds, which create single binary bundles that don’t load external libraries. After having recompiled the binaries, we get a new group of commands.
../images/486570_1_En_10_Chapter/486570_1_En_10_Fig10_HTML.jpg
Figure 10-10

New commands for lightning-cli

Using Plugins

c-lightning is very modular and capable of loading of plugins, which can be written in any programming language that can process streams from stdin (standard input) and stdout (standard output). A plugin is a separate piece software that lightningd will load at start. A plugin can be as simple as a logger or very complex with several commands, which can be activated with lightning-cli. The capability of introducing new commands, which can then be used via the standard interface, lightning-cli, is a powerful feature of c-lightning. A new command would basically become part of the standard interface with its own help information and error handling.

To load a plugin, one must provide its full path by using the --plugin flag. There exists a GitHub repository with many interesting community-provided plugins. https://github.com/lightningd/plugins. We will clone it to our device by using the standard git clone command. A good start into c-lightning’s plugin system will be the summary plugin from this repository. The plugin itself is written in Python, which we have already installed during our previous compilation tasks. Our first step will be to install the needed requirements for this plugin. For this we use the standard package manager pip3. We go into the subdirectory with cd summary and execute the following command from there:
sudo pip3 install -r requirements.txt

The pylightning package that got installed by pip3 is the client library for lightningd. It implements the mechanics needed for communication with the Unix socket offered by lightningd. Every lightningd plugin must communicate over this socket. However, as dealing with Unix sockets is not very intuitive and error prone, libraries like pylightning are here to take away a lot of burden regarding “ceremonial code” so that plugin developers can concentrate on more important tasks.

To load test the plugin, we will have to stop our current lightningd instance with:
lightning-cli stop.
Then we will start it again, but this time with the plugin flag added to it:
lightningd --plugin=/home/pi/ln-plugins/summary/summary.py
The daemon will start, and it would look like nothing else happened. However, the plugin is there and running. It even got integrated into lightning-cli. If we execute lightning-cli help, the following entry would be shown among the usual commands.
summary
         Gets summary information about this node.
And it also provides its own help information when we execute this:
lightning-cli help summary

To use the plugin, we won’t have to deal with new binaries or interfaces as all communication would still go over the standard lightning-cli interface.

To execute the plugin, one has to type in this command:
lightning-cli -H summary

How the Plugin System Works

Essentially, for a plugin to be considered valid by lightnignd, it has to understand at least these two methods: init and getmanifest2. The init method must be available in the plugin so that lightningd can establish a communication channel with it. After the init method has been called by lightningd, the plugin must respond. The response itself can be any data as the current version of lightningd is simply discarding them. The important part is the signal given by the plugin that it’s ready to process commands which will be sent to it later.

The second method, getmanifest, is more complex and is being used to describe the plugin so that lightningd knows what the plugin can do. The information in getmanifest is organized as a JSON object and comprises of following parts:
  • options

  • rpcmethods

  • subscriptions

  • hooks

  • dynamic

Except dynamic, all others are data arrays. A plugin can declare itself “dynamic”, which means that it can be managed later, while lightningd is running. For plugins that should never be stopped, this entry must be set to “false”. Plugins can provide their own methods, which then will be shown among the standard commands in lightning-cli. The summary plugin we used is providing such a command that is declared by its getmanifest entry. In such cases, a plugin is acting as an extension to the standard machinery provided by the c-lightning suite.

But a plugin doesn’t have to provide a command to be accepted. It can also be just a passive consumer of events generated by lightnignd. For this the subscription part in the getmanifest definition should be used to define, which events the plugin is interested in. The following is an example with two event subscriptions.
"subscriptions": [
              "connect",
              "disconnect"
       ],

Although being rather small, plugins are powerful entities that can be combined with other environments running outside c-lightning. For example, a plugin could take data from lightningd and forward it to a web-API, which then would be used by a web server to generate reports on the current state of lightningd. c-lightning and other BOLT implementations provide backend services that take care of connecting and managing the Lightning Network without dictating what else should be done with them. It’s up to users and application developers to provide meaningful and user-friendly applications that run on top of the raw machinery.

Writing a Plugin

We will create a JavaScript plugin that listens to events3 from lightningd and writes them to a logfile in /tmp directory. In particular, we are interested in these events which we define in config.json file:
{
    "subscriptions": [
        "connect",
        "disconnect",
        "channel_opened",
        "invoice_payment",
        "warning",
        "forward_event",
        "sendpay_success",
        "sendpay_failure"
    ]
}
The configuration file gets loaded by plugin.js script source, where the whole logic of the plugin resides. To start the plugin script, we have to activate the daemon with the --plugin flag that gives the full path of the plugin source file.
lightningd --plugin=$HOME/ln-plugin-js/plugin.js
The output in the console would contain basic information about your lightnind instance.
2019-09-28T11:51:32.795Z INFO raspi-lightning -----------------
2019-09-28T11:51:32.795Z INFO raspi-lightning Server started with public key 0370e894fa6e8ff735dc3278543ea2718c632ce380aaf30ce35fa261e8c0c7611e, alias BTC-TEST-RASPI-LIGHTNING-NODE (color #ca1f7b) and lightningd v0.7.2.1-307-g12da10c
But before trying to start the plugin, we must take care of marking it executable so that lightningd can start it. This is done with
chmod +x plugin.js
When we open plugin.js in an editor, we see that it begins with the usual header, or shebang,4 that declares its loader mechanism. Then come a few lines of require imports, because our plugin relies on several external packages that we have previously installed by executing npm install from within plugin’s directory.
#!/usr/bin/env node
const fs = require('fs');
const split = require('split');
const config = require('./config.json');
const logfile = '/tmp/clightning.log';
const logger = require('tracer').console({
  transport : (data) => {
      fs.createWriteStream(logfile, {
          flags: 'a',
          encoding: 'utf8',
          mode: 0666
      }).write(`${data.rawoutput} `);
  }
});
let inputLine = '';
const manifestJson = {
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "options": [],
    "rpcmethods": [],
    "subscriptions": config.subscriptions
  }
};
function log(severity, message) {
  logger.info(`${severity} | ${message}`);
}
function processLine (line) {
  inputLine += line;
  try
  {
    const json = JSON.parse(inputLine);
    inputLine = "";
    if (json["method"] == 'init') {
      process.stdout.write(JSON.parse('{}'));
      log('info', 'init call answered');
    } else if (json["method"] == 'getmanifest') {
      manifestJson.id = json.id;
      process.stdout.write(JSON.stringify(manifestJson));
      log('info', JSON.stringify(manifestJson));
    } else {
      log('info', JSON.stringify(json));
    }
  }
  catch(e){
  }
}
function initPlugin() {
  log('info', 'starting plugin');
  process.stdin.pipe(split()).on('data', processLine);
};
module.exports = initPlugin();

The logging mechanism of our plugin is based on an external npm package called tracer.5 After having declared the transport logic that should be used by tracer, we define the expected manifestJson variable. This structure describes our plugin. In our case, we’re only interested in listening to events so that rpcmethods and options property in manifestJson will remain empty. If we were instead declaring own functions and options, we would be using them. The third property, subscriptions, is where we use the data gathered from config.json to declare all the events our plugin wants to hear about. This way we can simply change the contents of config.json without touching the script itself. All it needs is a restart of the plugin.

The most important function is processLine, where the communication between plugin and lightningd happens. More precisely, lightningd is sending chunks of data via stdin (standard input). It then expects the plugin to combine and parse those chunks into meaningful JSON objects and eventually answer with new JSON objects by using stdout (standard output). Therefore, our plugin is not allowed to use stdin/stdout for anything else, like console outputs for example. If we want to output something on our console, we can use stderr instead. An example of an entry in /tmp/clightning.log that informs about a successful payment would look like this:
2019-09-28T13:44:43+0200 <info> plugin.js:40 (log) info | {"jsonrpc":"2.0","method":"sendpay_success","params":{"sendpay_success":{"id":7,"payment_hash":"3c4e92dad907428653cb6b9e4cf79557912625d843180237f5892b4889b27c6e","destination":"03933884aaf1d6b108397e5efe5c86bcf2d8ca8d2f700eda99db9214fc2712b134","msatoshi":1900000,"amount_msat":"1900000msat","msatoshi_sent":1900002,"amount_sent_msat":"1900002msat","created_at":1569671081,"status":"complete","payment_preimage":"3f78998a26f96305a44e891a4c52122f4d685be76da9c7c267d7a3a82c187561","bolt11":"lntb19u1pwc73uepp5838f9kkeqapgv57tdw0yeau427gjvfwcgvvqydl43y453zdj03hqdp8xys9xcmpd3sjqsmgd9czq3njv9c8qatrvd5kumccqp5lvqz4au3vpge8lx709483ecxfkwvnzrvgmzh7x54xw0l3jfts558xh7p3jxm6sk7eulm4c5gg00w8rkk508tvacwh4mtf2my6ezprwcqnx4muq"}}}

Here we have bought some coffee from our shop, and the corresponding event sendpay_success was generated by lightningd.

The plugin.js code itself is being executed at the end of the source file by using the module.exports statement that maps to initPlugin() function call. As we aren’t interested in “exporting” any function to lightningd, which wouldn’t be able to understand it anyway, we instead call the function initPlugin() and forward its results to lightningd. In this case the result is a working plugin that immediately starts reading data from stdin and registers itself by replying to init and getmanifest methods sent by lightningd. From this point on, the whole communication is basically a continuous exchange of JSON data.

Running c-lightning with systemd

Being a daemon itself, it is obvious that the best way to run lightningd is by writing a separate systemd script which would start it at each boot. We will create a new file called clightning.service in the standard systemd directory under /etc/systemd/system.
[Unit]
Description=c-lightning network daemon
Requires=bitcoin.service
After=bitcoin.service
[Service]
ExecStart=/usr/local/bin/lightningd --daemon --testnet
         --lightning-dir=/home/pi/.lightning
         --conf=/home/pi/.lightning/config
         --log-file=/home/pi/.lightning/lightning.log
PIDFile=/home/pi/.lightning/lightningd-testnet.pid
User=pi
Group=pi
Type=forking
Restart=always
RestartSec=10
PrivateTmp=true
ProtectSystem=full
NoNewPrivileges=true
PrivateDevices=true
MemoryDenyWriteExecute=true

To make sure that it will start only after bitcoin.service has started, we add a starting requirement in the [Unit] part of its configuration. The [Service] part describes the execution of lightningd and the configuration options it needs to select the correct network. The PIDFile entry is important, because for every network type we use, its pidfile should reflect the name of the network. The hardening measures at the end are for protecting the operating system from attacks, for example, in cases when the service got compromised.

To activate it, we use the standard systemctl command enable.
sudo systemctl enable clightning
Now we can either reboot our device and wait for Bitcoin and c-lightning services to boot or start it immediately with
sudo systemctl start clightning.
To trace its execution, we can use the journalctl with
journalctl -f -u clightning

Summary

In this chapter we have learned to build, use, and extend the c-lightning implementation of the BOLT protocol. We have learned how to find other nodes and open payment channels with them. Also, we have learned how to buy coffee by using the Lightning Network and experience fast payments without any intermediaries and long block generation times. We have learned about the extensibility of c-lightning and how to use its plugin system. And to make our Lightning Node as automatic as possible, we have written a systemd script that starts the Lightning Network machinery at boot.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.144.237.77