Getting started with CLNRest plugin
In this live we see how to start and use the new builtin plugin CLNRest that transforms RPC calls into a REST service. We learn how to use the Swagger interface to generate/send http requests. Then we connect to the websocket offered by CLNRest that sends lightningd notification. Finally, we take a look at CLNRest implementation to show how plugin developers can take advantage of the new JSON RPC method checkrune
.
CLNRest changes from v23.08.1 to v23.11
This live was recorded the day after v23.08.1 point release. Since then, Core Lightning v23.11 has been released with some changes. Some parts of the video if reproduced as is with v23.11 won't work. We list here what they are and what should be done instead if you are running Core Lightning v23.11 and maybe also things that I forgot to mentioned during the live.
CLNRest Python dependencies
The clnrest
Python plugin depends on the following packages that can
be installed like this on Ubuntu:
$ sudo apt-get install python3-json5 python3-flask python3-gunicorn
$ pip3 install --user flask-cors flask_restx pyln-client flask-socketio gevent gevent-websocket
See lightning:doc/getting-started/getting-started/installation.md.
CLNRest config options prefixed by cln
The config options rest-port
, rest-protocol
, rest-host
and rest-certs
have been renamed respectively to clnrest-port
, clnrest-protocol
,
clnrest-host
and clnrest-certs
by adding cln
prefix.
So for instance, if we want clnrest
web server to listen to on the port
3010
, we must run the following command:
lightningd --clnrest-port=3010
Self-signed certificates
During the live we used curl
flag --insecure
to skip the TLS
verification.
Starting with 23.11, the certificate authority file is also provided, so we can
also use --cacert
flag with the certificate authority file to issue
the curl
request like this (instead of --insecure
):
$ curl --cacert /tmp/l2-regtest/regtest/ca.pem \
► -X 'POST' \
► 'https://localhost:3010/v1/getinfo' \
► -H 'accept: application/json' \
► -H 'Rune: FPD_6O81E8UdSkmpy2qtjPcuPVbxVi0lIQ-OMtVic_U9MA==' \
► -H 'Content-Type: application/json' \
► -d '{}'
We assume the same setup as in the live session (the lightning
directory of l2
node is /tmp/l2-regtest/
).
Websocket requires a readonly rune
Starting with Core Lightning version v23.11, connecting to clnrest
websocket requires a readonly
rune.
Let's look at an example where we create a NodeJS websocket client
that connects to clnrest
plugin of a node l1
running on regtest using
a readonly
rune. Then we create an invoice with that node and observe
an invoice_creation
notification being forwarded to that websocket
client.
Assuming the lightning
repository is cloned and that we are at the top
of it, we start 2 nodes running on regtest using start_ln
command from
contrib/startup_regtest.sh
script and restart l1
with clnrest
enabled
by setting clnrest-port
option to 3010
:
◉ tony@tony:~/clnlive/lightning:[git»(HEAD detached at v23.11)]
$ source contrib/startup_regtest.sh
...
◉ tony@tony:~/clnlive/lightning:[git»(HEAD detached at v23.11)]
$ start_ln
...
◉ tony@tony:~/clnlive/lightning:[git»(HEAD detached at v23.11)]
$ alias l1-cli
alias l1-cli='lightning-cli --lightning-dir=/tmp/l1-regtest'
◉ tony@tony:~/clnlive/lightning:[git»(HEAD detached at v23.11)]
$ l1-cli stop
"Shutdown complete"
◉ tony@tony:~/clnlive/lightning:[git»(HEAD detached at v23.11)]
$ lightningd --lightning-dir=/tmp/l1-regtest --clnrest-port=3010 --daemon
clnrest
web server is now running at https://127.0.0.1:3010
with
/tmp/l1-regtest/regtest/ca.pem
certificate authority.
Thus, we can connect to its websocket available at
https://127.0.0.1:3010
.
To connect to that websocket we must provide a readonly
rune that we
create like this:
◉ tony@tony:~/clnlive/lightning:[git»(HEAD detached at v23.11)]
$ l1-cli createrune null readonly
{
"rune": "kYjRUZvgkKOFO3angTlIovd6TGPO5zSnKM90WZQDszc9MCZtZXRob2RebGlzdHxtZXRob2ReZ2V0fG1ldGhvZD1zdW1tYXJ5Jm1ldGhvZC9saXN0ZGF0YXN0b3Jl",
"unique_id": "0"
}
Now in a file named clnrest-websocket.js
we implement the following
Node JS websocket client that will be able to connect to our websocket
server running at https://127.0.0.1:3010
:
const https = require("https");
const os = require("os")
const rootCas = require("ssl-root-cas").create();
rootCas.addFile("/tmp/l1-regtest/regtest/ca.pem");
const io = require("socket.io-client");
const socket = io.connect("https://127.0.0.1:3010", {
extraHeaders: {
Rune:
"kYjRUZvgkKOFO3angTlIovd6TGPO5zSnKM90WZQDszc9MCZtZXRob2RebGlzdHxtZXRob2ReZ2V0fG1ldGhvZD1zdW1tYXJ5Jm1ldGhvZC9saXN0ZGF0YXN0b3Jl",
},
agent: https.globalAgent,
});
socket.on("connect", function () {
console.log("Websocket connection established at https://127.0.0.1:3010");
});
socket.on("message", function (data) {
console.log("Notification: ", data);
});
In another terminal, we install clnrest-websocket.js
dependencies and
run it which establishes a connection with clnrest
websocket with the
terminal hanging waiting for incoming messages (forwarded Core
Lightning notifications) from clnrest
:
# TERMINAL 2
◉ tony@tony:~/clnlive/lightning:[git»(HEAD detached at v23.11)]
$ npm install ssl-root-cas socket.io-client
◉ tony@tony:~/clnlive/lightning:[git»(HEAD detached at v23.11)]
$ node clnrest-websocket.js
Websocket connection established at https://127.0.0.1:3010
Back in the first terminal, we create an invoice like this:
◉ tony@tony:~/clnlive/lightning:[git»(HEAD detached at v23.11)]
$ l1-cli invoice 10000 label description
{
"payment_hash": "fe3874d285a20521f2a4d41ab1329c2d3cd16801263c3969447c9a848a4430ca",
"expires_at": 1702224390,
"bolt11": "lnbcrt100n1pjkefuxsp5rpa4kweh4aykywqfgzmw56ct0dd40ldmmak5qv2l0mfkpmsqpu3spp5lcu8f5595gzjru4y6sdtzv5u957dz6qpyc7rj62y0jdgfzjyxr9qdqjv3jhxcmjd9c8g6t0dcxqyjw5qcqp2fp4p3x3kug5mt0aqdpryf9n58ddn339lgt24rkcgc78uq6n3kv8aarqq9qx3qysgq8ps05vdfetc8w5x3xzud7fckklvyxnw5n3jzq9asys7ee7e4y0g3sjjjvhvvmsc4xj6e0qg9f9qt7aat9jltvptxvk8dkmyvxdwcmdcp6xlhjp",
"payment_secret": "187b5b3b37af4962380940b6ea6b0b7b5b57fdbbdf6d40315f7ed360ee000f23",
"created_index": 1,
"warning_capacity": "Insufficient incoming channel capacity to pay invoice"
}
This triggered an invoice_creation
notification that has been
forwarded to clnrest
plugin which queued it up for a second and then
broadcasted it to our Node JS listener. We can see in the second
terminal running clnrest-websocket.js
script that the invoice_creation
message has been received:
# TERMINAL 2
◉ tony@tony:~/clnlive/lightning:[git»(HEAD detached at v23.11)]
$ node clnrest-websocket.js
Websocket connection established at https://127.0.0.1:3010
Notification: {
invoice_creation: {
msat: 10000,
preimage: 'b173d0ccc614cc81e65c478e77ecfde420ca74936eee9e4ac1be85e7653d66b7',
label: 'label'
}
}
^C
Transcript with corrections and improvements
Hi everybody, let's jump in into that session. I'm happy to see you
and spend some time talking with you about about clnrest
new builtin
plugin in v23.08 implemented by Shahana.
This plugin lets us do HTTP requests to our node and run JSON RPC command in our node and also offer a websocket connection to receive Core Lightning notifications.
We are going to see how to get this working.
Note that I'm running Core Lightning 23.08.1.
Start 2 Lightning nodes running on regtest
Let's start two Lightning nodes running on the Bitcoin regtest
chain
by sourcing the script lightning/contrib/startup_regtest.sh
provided
by CLN repository and running the command start_ln
:
◉ tony@tony:~/clnlive:
$ source lightning/contrib/startup_regtest.sh
lightning-cli is /usr/local/bin/lightning-cli
lightningd is /usr/local/bin/lightningd
Useful commands:
start_ln 3: start three nodes, l1, l2, l3
connect 1 2: connect l1 and l2
fund_nodes: connect all nodes with channels, in a row
stop_ln: shutdown
destroy_ln: remove ln directories
◉ tony@tony:~/clnlive:
$ start_ln
Bitcoin Core starting
awaiting bitcoind...
Making "default" bitcoind wallet.
error code: -35
error message:
Wallet "default" is already loaded.
[1] 1646572
[2] 1646618
WARNING: eatmydata not found: install it for faster testing
Commands:
l1-cli, l1-log,
l2-cli, l2-log,
bt-cli, stop_ln, fund_nodes
We can check that l2-cli
is just an alias for lightning-cli
with the
base directory being /tmp/l2-regtest
:
◉ tony@tony:~/clnlive:
$ alias l2-cli
alias l2-cli='lightning-cli --lightning-dir=/tmp/l2-regtest'
To be sure that we have at least a lightning node running on regtest,
we can call the subcommand getinfo
like this:
◉ tony@tony:~/clnlive:
$ l2-cli getinfo | jq .id
"03fd22c90bc2aaa17e5a1928eeef20944783d57de7c36a712fd733b63b8149a00e"
/tmp/l2-regtest/log
I want in that session to show where we can get information and play with the node.
So, let's jump into /tmp/l2-regtest/log
log file of l2
node.
We can see that just after creating the configuration directory and
openning the log file, the plugin manager started the builtin plugins
including clnrest
:
2023-09-14T14:10:07.019Z INFO lightningd: Creating configuration directory /tmp/l2-regtest/regtest
2023-09-14T14:10:07.019Z DEBUG lightningd: Opened log file /tmp/l2-regtest/log
2023-09-14T14:10:07.023Z DEBUG plugin-manager: started(1646626) /usr/local/libexec/c-lightning/plugins/autoclean
2023-09-14T14:10:07.034Z DEBUG plugin-manager: started(1646627) /usr/local/libexec/c-lightning/plugins/chanbackup
2023-09-14T14:10:07.038Z DEBUG plugin-manager: started(1646628) /usr/local/libexec/c-lightning/plugins/bcli
2023-09-14T14:10:07.045Z DEBUG plugin-manager: started(1646629) /usr/local/libexec/c-lightning/plugins/commando
2023-09-14T14:10:07.049Z DEBUG plugin-manager: started(1646630) /usr/local/libexec/c-lightning/plugins/fetchinvoice
2023-09-14T14:10:07.052Z DEBUG plugin-manager: started(1646631) /usr/local/libexec/c-lightning/plugins/funder
2023-09-14T14:10:07.056Z DEBUG plugin-manager: started(1646632) /usr/local/libexec/c-lightning/plugins/topology
2023-09-14T14:10:07.059Z DEBUG plugin-manager: started(1646633) /usr/local/libexec/c-lightning/plugins/keysend
2023-09-14T14:10:07.062Z DEBUG plugin-manager: started(1646634) /usr/local/libexec/c-lightning/plugins/offers
2023-09-14T14:10:07.066Z DEBUG plugin-manager: started(1646635) /usr/local/libexec/c-lightning/plugins/pay
2023-09-14T14:10:07.069Z DEBUG plugin-manager: started(1646636) /usr/local/libexec/c-lightning/plugins/txprepare
2023-09-14T14:10:07.072Z DEBUG plugin-manager: started(1646637) /usr/local/libexec/c-lightning/plugins/cln-renepay
2023-09-14T14:10:07.075Z DEBUG plugin-manager: started(1646638) /usr/local/libexec/c-lightning/plugins/spenderp
2023-09-14T14:10:07.078Z DEBUG plugin-manager: started(1646639) /usr/local/libexec/c-lightning/plugins/sql
2023-09-14T14:10:07.081Z DEBUG plugin-manager: started(1646640) /usr/local/libexec/c-lightning/plugins/bookkeeper
2023-09-14T14:10:07.087Z DEBUG plugin-manager: started(1646641) /usr/local/libexec/c-lightning/plugins/clnrest/clnrest.py
To get the plugin started we must specify a port to rest-port
config
option. And by default the start_ln
command that we use to start l2
node on regest doesn't specify it. So we see in the log that after
the plugin manager tried to start clnrest
it disabled it:
2023-09-14T14:10:08.292Z DEBUG plugin-clnrest.py: Killing plugin: disabled itself at init: `rest-port` option is not configured
Note that starting with v23.11 rest-port
option has been replaced by
clnrest-port
option (see CLNRest changes from v23.08.1 to v23.11).
We'll start that plugin in the next section.
If you've never tried to debug or to check the log, this is a good place to look at for information and also to report issues if you encounter some.
Start clnrest
Let's restart l2
node with clnrest
plugin enabled.
First we stop it:
◉ tony@tony:~/clnlive:
$ l2-cli stop
"Shutdown complete"
Then we restart lightningd
setting --rest-port
config option to 3010
:
◉ tony@tony:~/clnlive:
$ lightningd --lightning-dir=/tmp/l2-regtest --rest-port=3010 --daemon
Note that starting with v23.11 --rest-port
must be replaced by --clnrest-port
(see CLNRest changes from v23.08.1 to v23.11).
We can check using nc
utility that clnrest
is now listening on port
3010 at localhost:
◉ tony@tony:~/clnlive:
$ nc -z -v localhost 3010
Connection to localhost (127.0.0.1) 3010 port [tcp/*] succeeded!
Note that:
127.0.0.1
is the default value for--rest-host
(which is from v23.11--clnrest-host
) andHTTPS
is the default value for--rest-protocol
(which is from v23.11--clnrest-protocol
).
GET /v1/list-methods
Let's jump into our browser and visit https://localhost:3010
address
which serves the Swagger interface we can use to query our node
and do a GET /v1/list-methods
request, which lists all the methods we
can run on l2
node using clnrest
plugin, like this:
This also gives use the curl
command to run to do the exact same
request to which we add --insecure
flag to skip the TLS verification.
the self-signed certificates:
◉ tony@tony:~/clnlive:
$ curl --insecure -X 'GET' \
► 'https://localhost:3010/v1/list-methods' \
► -H 'accept: application/json'
Command: addgossip message
Category: utility
Description: Inject gossip {message} into gossipd
Verbose: HELP! Please contribute a description for this json_command!
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Command: autoclean-once subsystem age
Category: plugin
Description: Perform a single run of autocleaning on one subsystem
Verbose: Requires {subsystem} and {age}
...
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Command: waitsendpay payment_hash [timeout] [partid] [groupid]
Category: payment
Description: Wait for payment attempt on {payment_hash} to succeed or fail, but only up to {timeout} seconds.
Verbose: HELP! Please contribute a description for this json_command!
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Command: withdraw destination satoshi [feerate] [minconf] [utxos]
Category: plugin
Description: Send funds to {destination} address
Verbose: Send to {destination} {satoshi} (or 'all') at optional {feerate} using utxos from {minconf} or {utxos}.
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Note that for that request /v1/list-methods
we don't need to provide
a rune in the header of the request.
The other endpoints need a rune and this is what we are going to see in the next section.
POST /v1/getinfo
Let's do a HTTP request that runs the getinfo
command in l2
node.
To that we need to provide in the header of POST request a rune
(authorization token) that let us run the getinfo
command.
If you don't know about Core Lightning runes you can check Introduction to commando and commando-rune.
We can generate an unrestricted rune on l2
node using createrune
command like this:
◉ tony@tony:~/clnlive:
$ l2-cli createrune
{
"rune": "FPD_6O81E8UdSkmpy2qtjPcuPVbxVi0lIQ-OMtVic_U9MA==",
"unique_id": "0",
"warning_unrestricted_rune": "WARNING: This rune has no restrictions! Anyone who has access to this rune could drain funds from your node. Be careful when giving this to apps that you don't trust. Consider using the restrictions parameter to only allow access to specific rpc methods."
}
We use that rune in the Swagger interface
and do a POST /v1/getinfo
request, which runs getinfo
on l2
node and
gives us back the response using clnrest
plugin, like this:
We get the same JSON object as if we run the following command:
◉ tony@tony:~/clnlive:
$ l2-cli getinfo
{
"id": "03fd22c90bc2aaa17e5a1928eeef20944783d57de7c36a712fd733b63b8149a00e",
"alias": "LOUDPHOTO",
"color": "03fd22",
"num_peers": 0,
"num_pending_channels": 0,
"num_active_channels": 0,
"num_inactive_channels": 0,
"address": [],
"binding": [
{
"type": "ipv4",
"address": "127.0.0.1",
"port": 7272
}
],
"version": "v23.08.1",
"blockheight": 1,
"network": "regtest",
"fees_collected_msat": 0,
"lightning-dir": "/tmp/l2-regtest/regtest",
"our_features": {
"init": "08a0000a0269a2",
"node": "88a0000a0269a2",
"channel": "",
"invoice": "02000002024100"
}
}
The Swagger interface also gives use the curl
command to run to do the
exact same request to which we add --insecure
flag to skip the TLS
verification:
◉ tony@tony:~/clnlive:
$ curl --insecure -X 'POST' \
► 'https://localhost:3010/v1/getinfo' \
► -H 'accept: application/json' \
► -H 'Rune: FPD_6O81E8UdSkmpy2qtjPcuPVbxVi0lIQ-OMtVic_U9MA==' \
► -H 'Content-Type: application/json' \
► -d '{}'
{"id": "03fd22c90bc2aaa17e5a1928eeef20944783d57de7c36a712fd733b63b8149a00e", "alias": "LOUDPHOTO", "color": "03fd22", "num_peers": 0, "num_pending_channels": 0, "num_active_channels": 0, "num_inactive_channels": 0, "address": [], "binding": [{"type": "ipv4", "address": "127.0.0.1", "port": 7272}], "version": "v23.08.1", "blockheight": 1, "network": "regtest", "fees_collected_msat": "0msat", "lightning-dir": "/tmp/l2-regtest/regtest", "our_features": {"init": "08a0000a0269a2", "node": "88a0000a0269a2", "channel": "", "invoice": "02000002024100"}}
Note that in Core Lightning v23.08.1, it is no longer needed to pass the node id in the header of the requests.
POST requests with a rune restricted to the invoice command
Let's create a rune that authorizes to run only the invoice
command:
◉ tony@tony:~/clnlive:
$ l2-cli createrune null '[["method=invoice"]]'
{
"rune": "SfE5g35cmd6pDQEb7PbVUHyz2e9Q_QOcjd1t2ZgxmW09MSZtZXRob2Q9aW52b2ljZQ==",
"unique_id": "1"
}
Now in the Swagger interface we use that new rune instead of the
previous unrestricted one and we try to do a POST /v1/getinfo
request
as we did before. As this rune no longer authorizes to call methods
different for invoice
on l2
node we get the following error:
Now let's generate an invoice by doing a POST /v1/invoice
request with
the data part being
{
"amount_msat": "10000",
"label": "inv",
"description": "pizza"
}
like this
To complete that example, we are going to pay that invoice with l1
node.
First we fund the nodes and create a channel from l1
node to l2
node
using fund_nodes
command provided by
lightning/contrib/startup_regtest.sh
script
◉ tony@tony:~/clnlive:
$ fund_nodes
Mining into address bcrt1qcqm8vdlk7xpgd69fp5994gextw3qtvf8zaqxj5... done.
bitcoind balance: 50.00000000
Waiting for lightning node funds... found.
Funding channel from node 1 to node 2. Waiting for confirmation... done.
and we check that l2
has its previously generated invoice unpaid:
◉ tony@tony:~/clnlive:
$ l2-cli listinvoices
{
"invoices": [
{
"label": "inv",
"bolt11": "lnbcrt100n1pjsxx36sp57zyg0h5s3s0knz2626p9vkm9vdavddavelq03rmxw633e50e6fkqpp5smt5dp0sfyxre7sux0qy28srpq5heajnfrewd4jz4qdxmcr8y8dsdqgwp5h57npxqyjw5qcqp29qxpqysgqaeqhg5t3s754954hg56xucza2rp0u674gk5rp5nt6wsvsut59lnrq5zwkd55lhe9j25ptyrngj3ftcrgps52e5epu0lfnnjf6mqxsqcphcw9la",
"payment_hash": "86d74685f0490c3cfa1c33c0451e0308297cf65348f2e6d642a81a6de06721db",
"amount_msat": 10000,
"status": "unpaid",
"description": "pizza",
"expires_at": 1695306938,
"created_index": 1
}
]
}
And finally we pay that invoice:
◉ tony@tony:~/clnlive:
$ l1-cli pay lnbcrt100n1pjsxx36sp57zyg0h5s3s0knz2626p9vkm9vdavddavelq03rmxw633e50e6fkqpp5smt5dp0sfyxre7sux0qy28srpq5heajnfrewd4jz4qdxmcr8y8dsdqgwp5h57npxqyjw5qcqp29qxpqysgqaeqhg5t3s754954hg56xucza2rp0u674gk5rp5nt6wsvsut59lnrq5zwkd55lhe9j25ptyrngj3ftcrgps52e5epu0lfnnjf6mqxsqcphcw9la
{
"destination": "03fd22c90bc2aaa17e5a1928eeef20944783d57de7c36a712fd733b63b8149a00e",
"payment_hash": "86d74685f0490c3cfa1c33c0451e0308297cf65348f2e6d642a81a6de06721db",
"created_at": 1694702327.026,
"parts": 1,
"amount_msat": 10000,
"amount_sent_msat": 10000,
"payment_preimage": "15dec389fb7135f807ff9fe0915f08d00e81d959fc7f54c8dc06e647ed01d2be",
"status": "complete"
}
CLNRest websocket and CLN notifications
The clnrest
plugin once started exposes a websocket endpoint that
forward Core Lightning notifications.
Note that starting with Core Lightning v23.11, we need to provide a readonly
rune to the websocket client to connect to clnrest
plugin (see CLNRest
changes from v23.08.1 to v23.11).
Let's consider clnrest-websocket.js
websocket client which connect
clnrest
plugin on l2
node:
const io = require('socket.io-client');
const socket = io.connect('https://127.0.0.1:3010', {rejectUnauthorized: false});
socket.on('connect', function() {
console.log("I'm connected!");
});
socket.on('message', function(data) {
console.log('I received a message: ', data);
});
socket.on('disconnect', function() {
console.log("I'm disconnected!");
});
In another terminal we install socket.io-client
dependency and connect
to the websocket:
TERMINAL #2
◉ tony@tony:~/clnlive:
$ npm i socket.io-client
added 9 packages in 1s
◉ tony@tony:~/clnlive:
$ node clnrest-websocket.js
I'm connected!
Then we generate an invoice in l2
node using the Swagger interface in
we see in the terminal 2 almost at the same time an invoice_creation
notification being forwarded to the websocket client
clnrest-websocket.js
:
◉ tony@tony:~/clnlive:
$ node clnrest-websocket.js
I'm connected!
I received a message: {'invoice_creation': {'msat': '10000msat', 'preimage': '3bee0d00e7ea124111e4ad1649e0878eed26826b20b93eb04e5d8fb949d31670', 'label': 'inv-1'}}
Finally we pay that invoice we l1
node
◉ tony@tony:~/clnlive:
$ l1-cli pay lnbcrt100n1pjsx8gpsp5ynak3sff5dme03qhn5waccxw47q964fua4r9ufv64eunydfnrqvspp5ynp2fdkh48wywwpy65kesepulppatky9t865vhqlky8gtnkkahfsdqgwp5h57npxqyjw5qcqp29qxpqysgqqa380yun5a7g6npmvnmyh37xszezv8raqhtyp7uernv0eztcpch4755d4y2yjptmwa5mnsfum4g38cdsj56xyt4fpckcpkhh582k2xsqr0t3jz
{
"destination": "03fd22c90bc2aaa17e5a1928eeef20944783d57de7c36a712fd733b63b8149a00e",
"payment_hash": "24c2a4b6d7a9dc473824d52d98643cf843d5d88559f5465c1fb10e85ced6edd3",
"created_at": 1694702917.711,
"parts": 1,
"amount_msat": 10000,
"amount_sent_msat": 10000,
"payment_preimage": "3bee0d00e7ea124111e4ad1649e0878eed26826b20b93eb04e5d8fb949d31670",
"status": "complete"
}
which led to two notifications invoice_payment and coin_movement to
be forwarded to clnrest-websocket.js
websocket client:
◉ tony@tony:~/clnlive:
$ node clnrest-websocket.js
I'm connected!
I received a message: {'invoice_creation': {'msat': '10000msat', 'preimage': '3bee0d00e7ea124111e4ad1649e0878eed26826b20b93eb04e5d8fb949d31670', 'label': 'inv-1'}}
I received a message: {'invoice_payment': {'msat': '10000msat', 'preimage': '3bee0d00e7ea124111e4ad1649e0878eed26826b20b93eb04e5d8fb949d31670', 'label': 'inv-1'}}
I received a message: {'coin_movement': {'version': 2, 'node_id': '03fd22c90bc2aaa17e5a1928eeef20944783d57de7c36a712fd733b63b8149a00e', 'type': 'channel_mvt', 'account_id': '06167ce9ab31a2836321c4c91983ac291f369e1221b78d4f0abea1c1d0e48cac', 'payment_hash': '24c2a4b6d7a9dc473824d52d98643cf843d5d88559f5465c1fb10e85ced6edd3', 'credit_msat': 10000, 'debit_msat': 0, 'fees_msat': 0, 'tags': ['invoice'], 'timestamp': 1694702919, 'coin_type': 'bcrt'}}
^C
checkrune
As we can in checkrune man page, The checkrune RPC command checks the validity/authorization rights of specified rune for the given nodeid, method, and params.
Let's use it with the rune generated above that authorizes only to
run invoice
method.
If we check that rune against the invoice
method we get a valid
response
◉ tony@tony:~/clnlive:
$ l2-cli -k checkrune rune=SfE5g35cmd6pDQEb7PbVUHyz2e9Q_QOcjd1t2ZgxmW09MSZtZXRob2Q9aW52b2ljZQ== \
► method=invoice
{
"valid": true
}
and if check it against the getinfo
method we get a 1502
error:
◉ tony@tony:~/clnlive:
$ l2-cli -k checkrune rune=SfE5g35cmd6pDQEb7PbVUHyz2e9Q_QOcjd1t2ZgxmW09MSZtZXRob2Q9aW52b2ljZQ== method=getinfo
{
"code": 1502,
"message": "Not permitted: method is not equal to invoice"
}
The checkrune
method is used by clnrest
plugin and can be used by any
other plugin since the last release v23.08.
Terminal session
We ran the following commands in this order:
$ source lightning/contrib/startup_regtest.sh
$ start_ln
$ alias l2-cli
$ l2-cli getinfo | jq .id
$ l2-cli stop
$ lightningd --lightning-dir=/tmp/l2-regtest --rest-port=3010 --daemon
$ nc -z -v localhost 3010
$ curl --insecure -X 'GET' \
► 'https://localhost:3010/v1/list-methods' \
► -H 'accept: application/json'
$ l2-cli createrune
$ l2-cli getinfo
$ curl --insecure -X 'POST' \
► 'https://localhost:3010/v1/getinfo' \
► -H 'accept: application/json' \
► -H 'Rune: FPD_6O81E8UdSkmpy2qtjPcuPVbxVi0lIQ-OMtVic_U9MA==' \
► -H 'Content-Type: application/json' \
► -d '{}'
$ l2-cli createrune null '[["method=invoice"]]'
$ fund_nodes
$ l2-cli listinvoices
$ l1-cli pay lnbcrt100n1pjsxx36sp57zyg0h5s3s0knz2626p9vkm9vdavddavelq03rmxw633e50e6fkqpp5smt5dp0sfyxre7sux0qy28srpq5heajnfrewd4jz4qdxmcr8y8dsdqgwp5h57npxqyjw5qcqp29qxpqysgqaeqhg5t3s754954hg56xucza2rp0u674gk5rp5nt6wsvsut59lnrq5zwkd55lhe9j25ptyrngj3ftcrgps52e5epu0lfnnjf6mqxsqcphcw9la
$ l1-cli pay lnbcrt100n1pjsx8gpsp5ynak3sff5dme03qhn5waccxw47q964fua4r9ufv64eunydfnrqvspp5ynp2fdkh48wywwpy65kesepulppatky9t865vhqlky8gtnkkahfsdqgwp5h57npxqyjw5qcqp29qxpqysgqqa380yun5a7g6npmvnmyh37xszezv8raqhtyp7uernv0eztcpch4755d4y2yjptmwa5mnsfum4g38cdsj56xyt4fpckcpkhh582k2xsqr0t3jz
$ l2-cli -k checkrune rune=SfE5g35cmd6pDQEb7PbVUHyz2e9Q_QOcjd1t2ZgxmW09MSZtZXRob2Q9aW52b2ljZQ== \
► method=invoice
$ l2-cli -k checkrune rune=SfE5g35cmd6pDQEb7PbVUHyz2e9Q_QOcjd1t2ZgxmW09MSZtZXRob2Q9aW52b2ljZQ== method=getinfo
And below you can read the terminal session (command lines and outputs):
◉ tony@tony:~/clnlive:
$ source lightning/contrib/startup_regtest.sh
lightning-cli is /usr/local/bin/lightning-cli
lightningd is /usr/local/bin/lightningd
Useful commands:
start_ln 3: start three nodes, l1, l2, l3
connect 1 2: connect l1 and l2
fund_nodes: connect all nodes with channels, in a row
stop_ln: shutdown
destroy_ln: remove ln directories
◉ tony@tony:~/clnlive:
$ start_ln
Bitcoin Core starting
awaiting bitcoind...
Making "default" bitcoind wallet.
error code: -35
error message:
Wallet "default" is already loaded.
[1] 1646572
[2] 1646618
WARNING: eatmydata not found: install it for faster testing
Commands:
l1-cli, l1-log,
l2-cli, l2-log,
bt-cli, stop_ln, fund_nodes
◉ tony@tony:~/clnlive:
$ alias l2-cli
alias l2-cli='lightning-cli --lightning-dir=/tmp/l2-regtest'
◉ tony@tony:~/clnlive:
$ l2-cli getinfo | jq .id
"03fd22c90bc2aaa17e5a1928eeef20944783d57de7c36a712fd733b63b8149a00e"
◉ tony@tony:~/clnlive:
$ l2-cli stop
"Shutdown complete"
[2]+ Done test -f "/tmp/l$i-$network/lightningd-$network.pid" || $EATMYDATA "$LIGHTNINGD" "--network=$network" "--lightning-dir=/tmp/l$i-$network" "--bitcoin-datadir=$PATH_TO_BITCOIN" "--database-upgrade=true"
◉ tony@tony:~/clnlive:
$ lightningd --lightning-dir=/tmp/l2-regtest --rest-port=3010 --daemon
◉ tony@tony:~/clnlive:
$ nc -z -v localhost 3010
Connection to localhost (127.0.0.1) 3010 port [tcp/*] succeeded!
◉ tony@tony:~/clnlive:
$ curl --insecure -X 'GET' \
► 'https://localhost:3010/v1/list-methods' \
► -H 'accept: application/json'
Command: addgossip message
Category: utility
Description: Inject gossip {message} into gossipd
Verbose: HELP! Please contribute a description for this json_command!
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Command: autoclean-once subsystem age
Category: plugin
Description: Perform a single run of autocleaning on one subsystem
Verbose: Requires {subsystem} and {age}
...
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Command: waitsendpay payment_hash [timeout] [partid] [groupid]
Category: payment
Description: Wait for payment attempt on {payment_hash} to succeed or fail, but only up to {timeout} seconds.
Verbose: HELP! Please contribute a description for this json_command!
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Command: withdraw destination satoshi [feerate] [minconf] [utxos]
Category: plugin
Description: Send funds to {destination} address
Verbose: Send to {destination} {satoshi} (or 'all') at optional {feerate} using utxos from {minconf} or {utxos}.
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------
◉ tony@tony:~/clnlive:
$ l2-cli createrune
{
"rune": "FPD_6O81E8UdSkmpy2qtjPcuPVbxVi0lIQ-OMtVic_U9MA==",
"unique_id": "0",
"warning_unrestricted_rune": "WARNING: This rune has no restrictions! Anyone who has access to this rune could drain funds from your node. Be careful when giving this to apps that you don't trust. Consider using the restrictions parameter to only allow access to specific rpc methods."
}
◉ tony@tony:~/clnlive:
$ l2-cli getinfo
{
"id": "03fd22c90bc2aaa17e5a1928eeef20944783d57de7c36a712fd733b63b8149a00e",
"alias": "LOUDPHOTO",
"color": "03fd22",
"num_peers": 0,
"num_pending_channels": 0,
"num_active_channels": 0,
"num_inactive_channels": 0,
"address": [],
"binding": [
{
"type": "ipv4",
"address": "127.0.0.1",
"port": 7272
}
],
"version": "v23.08.1",
"blockheight": 1,
"network": "regtest",
"fees_collected_msat": 0,
"lightning-dir": "/tmp/l2-regtest/regtest",
"our_features": {
"init": "08a0000a0269a2",
"node": "88a0000a0269a2",
"channel": "",
"invoice": "02000002024100"
}
}
◉ tony@tony:~/clnlive:
$ curl --insecure -X 'POST' \
► 'https://localhost:3010/v1/getinfo' \
► -H 'accept: application/json' \
► -H 'Rune: FPD_6O81E8UdSkmpy2qtjPcuPVbxVi0lIQ-OMtVic_U9MA==' \
► -H 'Content-Type: application/json' \
► -d '{}'
{"id": "03fd22c90bc2aaa17e5a1928eeef20944783d57de7c36a712fd733b63b8149a00e", "alias": "LOUDPHOTO", "color": "03fd22", "num_peers": 0, "num_pending_channels": 0, "num_active_channels": 0, "num_inactive_channels": 0, "address": [], "binding": [{"type": "ipv4", "address": "127.0.0.1", "port": 7272}], "version": "v23.08.1", "blockheight": 1, "network": "regtest", "fees_collected_msat": "0msat", "lightning-dir": "/tmp/l2-regtest/regtest", "our_features": {"init": "08a0000a0269a2", "node": "88a0000a0269a2", "channel": "", "invoice": "02000002024100"}}
◉ tony@tony:~/clnlive:
$ l2-cli createrune null '[["method=invoice"]]'
{
"rune": "SfE5g35cmd6pDQEb7PbVUHyz2e9Q_QOcjd1t2ZgxmW09MSZtZXRob2Q9aW52b2ljZQ==",
"unique_id": "1"
}
◉ tony@tony:~/clnlive:
$ fund_nodes
Mining into address bcrt1qcqm8vdlk7xpgd69fp5994gextw3qtvf8zaqxj5... done.
bitcoind balance: 50.00000000
Waiting for lightning node funds... found.
Funding channel from node 1 to node 2. Waiting for confirmation... done.
◉ tony@tony:~/clnlive:
$ l2-cli listinvoices
{
"invoices": [
{
"label": "inv",
"bolt11": "lnbcrt100n1pjsxx36sp57zyg0h5s3s0knz2626p9vkm9vdavddavelq03rmxw633e50e6fkqpp5smt5dp0sfyxre7sux0qy28srpq5heajnfrewd4jz4qdxmcr8y8dsdqgwp5h57npxqyjw5qcqp29qxpqysgqaeqhg5t3s754954hg56xucza2rp0u674gk5rp5nt6wsvsut59lnrq5zwkd55lhe9j25ptyrngj3ftcrgps52e5epu0lfnnjf6mqxsqcphcw9la",
"payment_hash": "86d74685f0490c3cfa1c33c0451e0308297cf65348f2e6d642a81a6de06721db",
"amount_msat": 10000,
"status": "unpaid",
"description": "pizza",
"expires_at": 1695306938,
"created_index": 1
}
]
}
◉ tony@tony:~/clnlive:
$ l1-cli pay lnbcrt100n1pjsxx36sp57zyg0h5s3s0knz2626p9vkm9vdavddavelq03rmxw633e50e6fkqpp5smt5dp0sfyxre7sux0qy28srpq5heajnfrewd4jz4qdxmcr8y8dsdqgwp5h57npxqyjw5qcqp29qxpqysgqaeqhg5t3s754954hg56xucza2rp0u674gk5rp5nt6wsvsut59lnrq5zwkd55lhe9j25ptyrngj3ftcrgps52e5epu0lfnnjf6mqxsqcphcw9la
{
"destination": "03fd22c90bc2aaa17e5a1928eeef20944783d57de7c36a712fd733b63b8149a00e",
"payment_hash": "86d74685f0490c3cfa1c33c0451e0308297cf65348f2e6d642a81a6de06721db",
"created_at": 1694702327.026,
"parts": 1,
"amount_msat": 10000,
"amount_sent_msat": 10000,
"payment_preimage": "15dec389fb7135f807ff9fe0915f08d00e81d959fc7f54c8dc06e647ed01d2be",
"status": "complete"
}
◉ tony@tony:~/clnlive:
$ l1-cli pay lnbcrt100n1pjsx8gpsp5ynak3sff5dme03qhn5waccxw47q964fua4r9ufv64eunydfnrqvspp5ynp2fdkh48wywwpy65kesepulppatky9t865vhqlky8gtnkkahfsdqgwp5h57npxqyjw5qcqp29qxpqysgqqa380yun5a7g6npmvnmyh37xszezv8raqhtyp7uernv0eztcpch4755d4y2yjptmwa5mnsfum4g38cdsj56xyt4fpckcpkhh582k2xsqr0t3jz
{
"destination": "03fd22c90bc2aaa17e5a1928eeef20944783d57de7c36a712fd733b63b8149a00e",
"payment_hash": "24c2a4b6d7a9dc473824d52d98643cf843d5d88559f5465c1fb10e85ced6edd3",
"created_at": 1694702917.711,
"parts": 1,
"amount_msat": 10000,
"amount_sent_msat": 10000,
"payment_preimage": "3bee0d00e7ea124111e4ad1649e0878eed26826b20b93eb04e5d8fb949d31670",
"status": "complete"
}
◉ tony@tony:~/clnlive:
$ l2-cli -k checkrune rune=SfE5g35cmd6pDQEb7PbVUHyz2e9Q_QOcjd1t2ZgxmW09MSZtZXRob2Q9aW52b2ljZQ== \
► method=invoice
{
"valid": true
}
◉ tony@tony:~/clnlive:
$ l2-cli -k checkrune rune=SfE5g35cmd6pDQEb7PbVUHyz2e9Q_QOcjd1t2ZgxmW09MSZtZXRob2Q9aW52b2ljZQ== method=getinfo
{
"code": 1502,
"message": "Not permitted: method is not equal to invoice"
}
TERMINAL #2
◉ tony@tony:~/clnlive:
$ npm i socket.io-client
added 9 packages in 1s
◉ tony@tony:~/clnlive:
$ node clnrest-websocket.js
I'm connected!
I received a message: {'invoice_creation': {'msat': '10000msat', 'preimage': '3bee0d00e7ea124111e4ad1649e0878eed26826b20b93eb04e5d8fb949d31670', 'label': 'inv-1'}}
I received a message: {'invoice_payment': {'msat': '10000msat', 'preimage': '3bee0d00e7ea124111e4ad1649e0878eed26826b20b93eb04e5d8fb949d31670', 'label': 'inv-1'}}
I received a message: {'coin_movement': {'version': 2, 'node_id': '03fd22c90bc2aaa17e5a1928eeef20944783d57de7c36a712fd733b63b8149a00e', 'type': 'channel_mvt', 'account_id': '06167ce9ab31a2836321c4c91983ac291f369e1221b78d4f0abea1c1d0e48cac', 'payment_hash': '24c2a4b6d7a9dc473824d52d98643cf843d5d88559f5465c1fb10e85ced6edd3', 'credit_msat': 10000, 'debit_msat': 0, 'fees_msat': 0, 'tags': ['invoice'], 'timestamp': 1694702919, 'coin_type': 'bcrt'}}
^C
Core Lightning source code
@rpcns.route("/")
@rpcns.route("/<rpc_method>") in lightning:plugins/clnrest/utilities/rpc_routes.py
@rpcns.route("/<rpc_method>")
class RpcMethodResource(Resource):
@rpcns.doc(security=[{"rune": []}])
@rpcns.doc(params={"rpc_method": (f"Name of the RPC method to be called")})
@rpcns.expect(payload_model, validate=False)
@rpcns.response(201, "Success")
@rpcns.response(500, "Server error")
def post(self, rpc_method):
"""Call any valid core lightning method (check list-methods response)"""
try:
is_valid_rune = verify_rune(plugin, request)
if "error" in is_valid_rune:
plugin.log(f"Error: {is_valid_rune}", "error")
raise Exception(is_valid_rune)
except Exception as err:
return json5.loads(str(err)), 403
try:
if request.is_json:
if len(request.data) != 0:
payload = request.get_json()
else:
payload = {}
else:
payload = request.form.to_dict()
return call_rpc_method(plugin, rpc_method, payload), 201
except Exception as err:
plugin.log(f"Error: {err}", "error")
return json5.loads(str(err)), 500
call_rpc_method
call_rpc_method in lightning:plugins/clnrest/utilities/shared.py
def call_rpc_method(plugin, rpc_method, payload):
try:
response = plugin.rpc.call(rpc_method, payload)
if '"error":' in str(response).lower():
raise Exception(response)
else:
plugin.log(f"{response}", "debug")
if '"result":' in str(response).lower():
# Use json5.loads ONLY when necessary, as it increases processing time significantly
return json.loads(response)["result"]
else:
return response
except Exception as err:
plugin.log(f"Error: {err}", "error")
if "error" in str(err).lower():
match_err_obj = re.search(r'"error":\{.*?\}', str(err))
if match_err_obj is not None:
err = "{" + match_err_obj.group() + "}"
else:
match_err_str = re.search(r"error: \{.*?\}", str(err))
if match_err_str is not None:
err = "{" + match_err_str.group() + "}"
raise Exception(err)
verify_rune
verify_rune in lightning:plugins/clnrest/utilities/shared.py
def verify_rune(plugin, request):
rune = request.headers.get("rune", None)
if rune is None:
raise Exception('{ "error": {"code": 403, "message": "Not authorized: Missing rune"} }')
if request.is_json:
if len(request.data) != 0:
rpc_params = request.get_json()
else:
rpc_params = {}
else:
rpc_params = request.form.to_dict()
return call_rpc_method(plugin, "checkrune",
{"rune": rune,
"method": request.view_args["rpc_method"],
"params": rpc_params})
Source code
clnrest-websocket.js
Note that starting with Core Lightning v23.11, we need to provide a readonly
rune to the websocket client to connect to clnrest
plugin (see CLNRest
changes from v23.08.1 to v23.11).
const io = require('socket.io-client');
const socket = io.connect('https://127.0.0.1:3010', {rejectUnauthorized: false});
socket.on('connect', function() {
console.log("I'm connected!");
});
socket.on('message', function(data) {
console.log('I received a message: ', data);
});
socket.on('disconnect', function() {
console.log("I'm disconnected!");
});
Logs
/tmp/l2-regtest/log
2023-09-14T14:10:07.019Z INFO lightningd: Creating configuration directory /tmp/l2-regtest/regtest
2023-09-14T14:10:07.019Z DEBUG lightningd: Opened log file /tmp/l2-regtest/log
2023-09-14T14:10:07.023Z DEBUG plugin-manager: started(1646626) /usr/local/libexec/c-lightning/plugins/autoclean
2023-09-14T14:10:07.034Z DEBUG plugin-manager: started(1646627) /usr/local/libexec/c-lightning/plugins/chanbackup
2023-09-14T14:10:07.038Z DEBUG plugin-manager: started(1646628) /usr/local/libexec/c-lightning/plugins/bcli
2023-09-14T14:10:07.045Z DEBUG plugin-manager: started(1646629) /usr/local/libexec/c-lightning/plugins/commando
2023-09-14T14:10:07.049Z DEBUG plugin-manager: started(1646630) /usr/local/libexec/c-lightning/plugins/fetchinvoice
2023-09-14T14:10:07.052Z DEBUG plugin-manager: started(1646631) /usr/local/libexec/c-lightning/plugins/funder
2023-09-14T14:10:07.056Z DEBUG plugin-manager: started(1646632) /usr/local/libexec/c-lightning/plugins/topology
2023-09-14T14:10:07.059Z DEBUG plugin-manager: started(1646633) /usr/local/libexec/c-lightning/plugins/keysend
2023-09-14T14:10:07.062Z DEBUG plugin-manager: started(1646634) /usr/local/libexec/c-lightning/plugins/offers
2023-09-14T14:10:07.066Z DEBUG plugin-manager: started(1646635) /usr/local/libexec/c-lightning/plugins/pay
2023-09-14T14:10:07.069Z DEBUG plugin-manager: started(1646636) /usr/local/libexec/c-lightning/plugins/txprepare
2023-09-14T14:10:07.072Z DEBUG plugin-manager: started(1646637) /usr/local/libexec/c-lightning/plugins/cln-renepay
2023-09-14T14:10:07.075Z DEBUG plugin-manager: started(1646638) /usr/local/libexec/c-lightning/plugins/spenderp
2023-09-14T14:10:07.078Z DEBUG plugin-manager: started(1646639) /usr/local/libexec/c-lightning/plugins/sql
2023-09-14T14:10:07.081Z DEBUG plugin-manager: started(1646640) /usr/local/libexec/c-lightning/plugins/bookkeeper
2023-09-14T14:10:07.087Z DEBUG plugin-manager: started(1646641) /usr/local/libexec/c-lightning/plugins/clnrest/clnrest.py
2023-09-14T14:10:07.809Z DEBUG lightningd: io_break: check_plugins_manifests
2023-09-14T14:10:07.809Z DEBUG lightningd: io_loop_with_timers: plugins_init
2023-09-14T14:10:07.809Z DEBUG lightningd: testing /usr/local/libexec/c-lightning/lightning_channeld
2023-09-14T14:10:07.811Z DEBUG lightningd: testing /usr/local/libexec/c-lightning/lightning_closingd
2023-09-14T14:10:07.812Z DEBUG lightningd: testing /usr/local/libexec/c-lightning/lightning_connectd
2023-09-14T14:10:07.813Z DEBUG lightningd: testing /usr/local/libexec/c-lightning/lightning_gossipd
2023-09-14T14:10:07.814Z DEBUG lightningd: testing /usr/local/libexec/c-lightning/lightning_hsmd
2023-09-14T14:10:07.815Z DEBUG lightningd: testing /usr/local/libexec/c-lightning/lightning_onchaind
2023-09-14T14:10:07.817Z DEBUG lightningd: testing /usr/local/libexec/c-lightning/lightning_openingd
2023-09-14T14:10:07.818Z DEBUG hsmd: pid 1646664, msgfd 50
2023-09-14T14:10:07.845Z DEBUG hsmd: capability +WIRE_HSMD_CHECK_PUBKEY
2023-09-14T14:10:07.845Z DEBUG hsmd: capability +WIRE_HSMD_SIGN_ANY_DELAYED_PAYMENT_TO_US
2023-09-14T14:10:07.845Z DEBUG hsmd: capability +WIRE_HSMD_SIGN_ANCHORSPEND
2023-09-14T14:10:07.845Z DEBUG hsmd: capability +WIRE_HSMD_SIGN_HTLC_TX_MINGLE
2023-09-14T14:10:07.845Z DEBUG hsmd: capability +WIRE_HSMD_SIGN_SPLICE_TX
2023-09-14T14:10:07.846Z INFO lightningd: Creating database
2023-09-14T14:10:08.104Z DEBUG connectd: pid 1646665, msgfd 54
2023-09-14T14:10:08.104Z UNUSUAL hsmd: HSM: created new hsm_secret file
2023-09-14T14:10:08.104Z DEBUG hsmd: Client: Received message 27 from client
2023-09-14T14:10:08.104Z DEBUG hsmd: Client: Received message 27 from client
2023-09-14T14:10:08.104Z DEBUG hsmd: new_client: 0
2023-09-14T14:10:08.105Z DEBUG plugin-clnrest.py: Notification: {'warning': {'level': 'warn', 'time': '1694700608.104590967', 'timestamp': '2023-09-14T14:10:08.104Z', 'source': 'hsmd', 'log': 'HSM: created new hsm_secret file'}}
2023-09-14T14:10:08.123Z DEBUG connectd: Created listener on 127.0.0.1:7272
2023-09-14T14:10:08.123Z DEBUG connectd: REPLY WIRE_CONNECTD_INIT_REPLY with 0 fds
2023-09-14T14:10:08.123Z DEBUG lightningd: io_break: connect_init_done
2023-09-14T14:10:08.123Z DEBUG lightningd: io_loop: connectd_init
2023-09-14T14:10:08.188Z INFO plugin-bcli: bitcoin-cli initialized and connected to bitcoind.
2023-09-14T14:10:08.188Z DEBUG lightningd: io_break: plugin_config_cb
2023-09-14T14:10:08.188Z DEBUG lightningd: io_loop_with_timers: config_plugin
2023-09-14T14:10:08.188Z DEBUG lightningd: All Bitcoin plugin commands registered
2023-09-14T14:10:08.241Z DEBUG lightningd: Adding block 0: 0f9188f13cb7b2c71f2a335e3a4fc328bf5beb436012afca590b1a11466e2206
2023-09-14T14:10:08.241Z DEBUG lightningd: io_break: maybe_completed_init
2023-09-14T14:10:08.287Z DEBUG lightningd: io_loop_with_timers: setup_topology
2023-09-14T14:10:08.287Z DEBUG wallet: Loaded 0 channels from DB
2023-09-14T14:10:08.288Z DEBUG gossipd: pid 1646676, msgfd 53
2023-09-14T14:10:08.288Z DEBUG hsmd: new_client: 0
2023-09-14T14:10:08.289Z DEBUG gossipd: total store load time: 0 msec
2023-09-14T14:10:08.289Z DEBUG gossipd: gossip_store: Read 0/0/0/0 cannounce/cupdate/nannounce/cdelete from store (0 deleted) in 1 bytes
2023-09-14T14:10:08.289Z DEBUG gossipd: seeker: state = STARTING_UP New seeker
2023-09-14T14:10:08.289Z DEBUG gossipd: REPLY WIRE_GOSSIPD_INIT_REPLY with 0 fds
2023-09-14T14:10:08.289Z DEBUG lightningd: io_break: gossipd_init_done
2023-09-14T14:10:08.289Z DEBUG lightningd: io_loop: gossip_init
2023-09-14T14:10:08.290Z DEBUG lightningd: Looking for [autoclean,succeededforwards,num]
2023-09-14T14:10:08.291Z DEBUG lightningd: Looking for [autoclean,failedforwards,num]
2023-09-14T14:10:08.291Z DEBUG hsmd: Client: Received message 27 from client
2023-09-14T14:10:08.292Z DEBUG plugin-clnrest.py: Killing plugin: disabled itself at init: `rest-port` option is not configured
2023-09-14T14:10:08.293Z DEBUG lightningd: Looking for [autoclean,succeededpays,num]