Learn how to test libraries/apps that interact with CLN nodes
In this live we see how how to test lnsocket/go library using pyln-testing
library.
Transcript with corrections and improvements
Tests are tools like any other.
They are useful in at least two ways:
For designing: if we have the chance to start building our program/system writing the tests at the same time, we can see the parts that shouldn't be together, separate them and test them separately,
For regression: once we have our tests in place, we can add some features or simplify/rewrite some ugly parts fearlessly. Running the tests will tell us if we broke something!
As a tool we can use them to test the dependencies of our program on other libraries or applications.
In this live we try to see how can we ensure that a library depending on Core Lightning nodes continues to work as expected when we switch from a version of Core Lightning to another.
To do so we take lnsocket commando client library as an example and we write some tests with pyln-testing Python library.
That library allows:
to spin up nodes running on a regtest chain,
to manage those nodes with Python and
to test their behavior.
For instance we can ask a node to generate an invoice and another to pay that invoice and finally check if that invoice has been effectively paid.
So if we write a library that talks to a node we can use pyln-testing
to mock the Lightning Network, connect our library to one of the
nodes and test our library's behavior.
Black box tests in Core Lightning
In the tests
directory of Core Lightning we can find a lot of tests
written with pyln-testing
. This is a good place to start to get
inspired. For instance:
if we want to test a plugin written in Rust we can look at lightning:tests/test_cln_rs.py file,
if we need to create invoices in our tests we can look at lightning:tests/test_invoices.py file,
...
In number this is what we have, 22494 lines of Python code that we can leverage to write our tests:
◉ tony@tony:~/clnlive/lightning/tests:[git»(HEAD detached at v23.08.1)]
$ cloc .
499 text files.
463 unique files.
376 files ignored.
github.com/AlDanial/cloc v 1.90 T=0.69 s (180.3 files/s, 53330.0 lines/s)
-------------------------------------------------------------------------------
Language files blank comment code
-------------------------------------------------------------------------------
Python 97 6910 5755 22494
C 20 220 145 1054
C/C++ Header 2 35 39 128
make 2 10 1 73
JSON 2 0 0 63
Bourne Shell 2 9 3 35
-------------------------------------------------------------------------------
SUM: 125 7184 5943 23847
-------------------------------------------------------------------------------
lnsocket
A few months ago, when I was trying to fix something in lnsocket
(it
happened that there were already a PR open with the fix) I wrote a
test using pyln-testing
that we are going to use today.
We are going to look at it, but first what is lnsocket
written for?
The Go lnsocket
library lets us send commando messages to lightning
nodes, so with the right hostname and the name of the node (a rune
also), we can connect to that node and send commando messages.
And the commando
plugin allows to run commands even if we are not the
node.
With lnsocket
we are an application, we connect to the node and we say
for example "Hey, please run some bookkeeper commands and send me back
the response".
For an example see Simple CLN bookkeeper web app powered by lnsocket & Golang - part 1.
Deprecate commando JSON commands without an id in v23.02
If we are the author of that library (lnsocket
), at some point we
might want to test that library against Core Lightning to be sure that
when Core Lightning changes, our library continues to work as
expected.
For instance, in v23.02 release, something changed in the commando
plugin that affects libraries that send commando
messages like
lnsocket
:
Deprecated
Note: You should always set allow-deprecated-apis=false to test for
changes.
- ...
- plugins: commando JSON commands without an id (see
doc/lightningd-rpc.7.md for how to construct a good id
field). ([#5866])
What does that mean?
Before v23.02, the json part of a commando
message must contain:
the method we want to run,
a rune that authorizes to run that method and
its parameters.
Now, from v23.02, in that json part we also have to pass and id
.
So if our library doesn't send commando
messages with that id
we'll
get an error.
With no test at all (and if we don't read Core Lightning changelog) we won't catch that change that breaks our library.
Be if we wrote some tests beforehand (they don't have to be fancy nor exhaustive), we could catch that error due to the library's dependency on Core Lightning nodes.
Having those tests in place and running it regularly (for each new release of CLN for instance) and adapting our library if necessary, we could prevent to pass the error to the library's user that are switching to a new version of Core Lightning.
Note that with Core Lightning deprecation cycle, when a 'feature' is
deprecated we can still use it during some time by setting
allow-deprecated-apis
config option to true
Encode function in lnsocket/go
The function Encode in lnsocket:go/lnsocket.go file was affected by
Core Lightning deprecation described above and has been fixed by
adding the line
buf.WriteString("\",\"id\":\"d0\",\"jsonrpc\":\"2.0\"}")
as we can see
here:
func (msg *CommandoMsg) Encode(buf *bytes.Buffer, pver uint32) error {
if err := lnwire.WriteUint64(buf, msg.RequestId); err != nil {
return err
}
buf.WriteString("{\"method\": \"")
buf.WriteString(msg.Method)
buf.WriteString("\",\"params\":")
buf.WriteString(msg.Params)
buf.WriteString(",\"rune\":\"")
buf.WriteString(msg.Rune)
buf.WriteString("\",\"id\":\"d0\",\"jsonrpc\":\"2.0\"}")
return nil
}
Testing lnsocket/go
Now the question is how can we write a test using pyln-testing
library
to test lnsocket/go
library that would have passed before CLN v23.02
and failed when we switched to CLN v23.02?
If the library that we want to test was written in Python this would be easier because we could use the library directly in the test program (written in Python).
But this in not the case of lnsocket/go
.
No problem, we still can write an application or a small script that
uses our library and prints out some data. Then we run that application
in our test connecting it to a regtest node started by pyln-testing
and we retrieve its output and finally check it against whatever we
want.
getinfo.go script using lnsocket/go library
We've already clone lnsocket
repository under lnsocket
directory.
Let's jump into its go
subdirectory where lnsocket/go
is implemented:
◉ tony@tony:~/clnlive:
$ cd lnsocket/go/
Then we copy the test directory that contains the tests we are going to use today in the current directory:
◉ tony@tony:~/clnlive/lnsocket/go:[git»master]
$ cp -r ../../test/ .
◉ tony@tony:~/clnlive/lnsocket/go:[git»master]
$ ls
test/ go.mod go.sum lnsocket.go
Then we start 2 lightning nodes running on regtest using
contrib/startup_regtest.sh
script from lightning
repository and print
getinfo
information of l1
node:
◉ tony@tony:~/clnlive/lnsocket/go:[git»master]
$ source ../../lightning/contrib/startup_regtest.sh
...
◉ tony@tony:~/clnlive/lnsocket/go:[git»master]
$ start_ln
...
◉ tony@tony:~/clnlive/lnsocket/go:[git»master]
$ alias l1-cli
alias l1-cli='lightning-cli --lightning-dir=/tmp/l1-regtest'
◉ tony@tony:~/clnlive/lnsocket/go:[git»master]
$ l1-cli getinfo
{
"id": "0252b837dc56fc76497f8e485993494bcaeaa1eca095c332bc8aac4922ce4d5d85",
"alias": "PEEVEDSPAWN",
"color": "0252b8",
"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": 7171
}
],
"version": "v23.08.1",
"blockheight": 1,
"network": "regtest",
"fees_collected_msat": 0,
"lightning-dir": "/tmp/l1-regtest/regtest",
"our_features": {
"init": "08a0000a0269a2",
"node": "88a0000a0269a2",
"channel": "",
"invoice": "02000002024100"
}
}
Now we run getinfo.go
program in the test
directory which takes 3
arguments, the node id, the hostname of the node and a rune and
returns the node id retrieved using lnsocket/go
library:
package main
import (
"fmt"
"os"
"github.com/tidwall/gjson"
lnsocket "github.com/jb55/lnsocket/go"
)
func main() {
nodeid := os.Args[1]
hostname := os.Args[2]
rune := os.Args[3]
ln := lnsocket.LNSocket{}
ln.GenKey()
err := ln.ConnectAndInit(hostname, nodeid)
if err != nil {
panic(err)
}
body, err := ln.Rpc(rune, "getinfo", "[]")
if err != nil {
panic(err)
}
getinfoNodeid := gjson.Get(body, "result.id").String()
fmt.Printf(getinfoNodeid)
}
To do so, we create a rune on l1
node
◉ tony@tony:~/clnlive/lnsocket/go:[git»master]
$ l1-cli createrune
{
"rune": "srRc7kl_g-_7aRfsfhG_Y0PdKzgrTgEDQY7dG7P2SWM9MA==",
"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 install the program dependencies
◉ tony@tony:~/clnlive/lnsocket/go:[git»master]
$ go get github.com/tidwall/gjson
go: added github.com/tidwall/gjson v1.17.0
go: added github.com/tidwall/match v1.1.1
go: added github.com/tidwall/pretty v1.2.0
and we run it:
◉ tony@tony:~/clnlive/lnsocket/go:[git»master]
$ cd test/
◉ tony@tony:~/clnlive/lnsocket/go/test:[git»master]
$ go run getinfo.go 0252b837dc56fc76497f8e485993494bcaeaa1eca095c332bc8aac4922ce4d5d85 127.0.0.1:7171 srRc7kl_g-_7aRfsfhG_Y0PdKzgrTgEDQY7dG7P2SWM9MA==
0252b837dc56fc76497f8e485993494bcaeaa1eca095c332bc8aac4922ce4d5d85
As we are running CLN v23.08.1 and the patched version of lnsocket/go
,
everything worked well.
Using getinfo.go in the test
Now we look at test_lnsocket.py
test file written with pyln-testing
library and that uses getinfo.go
program:
from pyln.testing.fixtures import *
import os
def test_getinfo(node_factory):
node = node_factory.get_node()
node_info = node.rpc.getinfo()
node_id = node_info["id"]
node_address = node_info["binding"][0]["address"]
node_port = node_info["binding"][0]["port"]
node_hostname = node_address + ":" + str(node_port)
# when `commando-rune` deprecated, we'll use `createrune` instead
# rune = node.rpc.createrune()["rune"]
rune = node.rpc.commando_rune()["rune"]
getinfo_cmd = f"go run getinfo.go {node_id} {node_hostname} {rune}"
assert os.popen(getinfo_cmd).read() == node_id
Note that we test lnsocket/go
library by testing getinfo.go
program
behavior.
Let's install pyln-testing
in a Python virtual environment
◉ tony@tony:~/clnlive/lnsocket/go/test:[git»master]
$ python -m venv .venv
◉ tony@tony:~/clnlive/lnsocket/go/test:[git»master]
$ source .venv/bin/activate
(.venv) ◉ tony@tony:~/clnlive/lnsocket/go/test:[git»master]
$ pip install pyln-testing
...
and run that test:
(.venv) ◉ tony@tony:~/clnlive/lnsocket/go/test:[git»master]
$ pytest test_lnsocket.py
======================================= test session starts ========================================
platform linux -- Python 3.10.12, pytest-7.4.2, pluggy-1.3.0
rootdir: /home/tony/clnlive/lnsocket/go/test
collected 1 item
test_lnsocket.py . [100%]
======================================== 1 passed in 24.12s ========================================
As we are running CLN v23.08.1 and the patched version of lnsocket/go
,
the test passes.
Failing test at with lnsocket at commit b7d9bce
Now, let's checkout at commit b7d9bce
in lnsocket
repository.
The function Encode
no longer include an id
field in the json part of
the commando
message:
func (msg *CommandoMsg) Encode(buf *bytes.Buffer, pver uint32) error {
if err := lnwire.WriteUint64(buf, msg.RequestId); err != nil {
return err
}
buf.WriteString("{\"method\": \"")
buf.WriteString(msg.Method)
buf.WriteString("\",\"params\":")
buf.WriteString(msg.Params)
buf.WriteString(",\"rune\":\"")
buf.WriteString(msg.Rune)
buf.WriteString("\"}")
return nil
}
And as we are running CLN v23.08.1 which expects that id
, the test
fails:
(.venv) ◉ tony@tony:~/clnlive/lnsocket/go/test:[git»(HEAD detached at b7d9bce)]
$ pytest test_lnsocket.py
======================================= test session starts ========================================
platform linux -- Python 3.10.12, pytest-7.4.2, pluggy-1.3.0
rootdir: /home/tony/clnlive/lnsocket/go/test
collected 1 item
test_lnsocket.py F [100%]
============================================= FAILURES =============================================
___________________________________________ test_getinfo ___________________________________________
node_factory = <pyln.testing.utils.NodeFactory object at 0x7f9251624430>
def test_getinfo(node_factory):
node = node_factory.get_node()
node_info = node.rpc.getinfo()
node_id = node_info["id"]
node_address = node_info["binding"][0]["address"]
node_port = node_info["binding"][0]["port"]
node_hostname = node_address + ":" + str(node_port)
# when `commando-rune` deprecated, we'll use `createrune` instead
# rune = node.rpc.createrune()["rune"]
rune = node.rpc.commando_rune()["rune"]
getinfo_cmd = f"go run getinfo.go {node_id} {node_hostname} {rune}"
> assert os.popen(getinfo_cmd).read() == node_id
E AssertionError: assert '' == '0266e4598d1d...283b315c03518'
E - 0266e4598d1d3c415f572a8488830b60f7e744ed9235eb0b1ba93283b315c03518
test_lnsocket.py:15: AssertionError
-------------------------------------- Captured stdout setup ---------------------------------------
Running tests in /tmp/ltests-km5ej2sv
--------------------------------------- Captured stdout call ---------------------------------------
lightningd-1 2023-09-28T14:51:34.248Z DEBUG lightningd: Opened log file -
lightningd-1 2023-09-28T14:51:34.248Z DEBUG lightningd: Opened log file /tmp/ltests-km5ej2sv/test_getinfo_1/lightning-1/log
lightningd-1 2023-09-28T14:51:34.251Z DEBUG plugin-manager: started(1683553) /usr/local/libexec/c-lightning/plugins/autoclean
lightningd-1 2023-09-28T14:51:34.253Z DEBUG plugin-manager: started(1683554) /usr/local/libexec/c-lightning/plugins/chanbackup
lightningd-1 2023-09-28T14:51:34.257Z DEBUG plugin-manager: started(1683555) /usr/local/libexec/c-lightning/plugins/bcli
lightningd-1 2023-09-28T14:51:34.260Z DEBUG plugin-manager: started(1683556) /usr/local/libexec/c-lightning/plugins/commando
lightningd-1 2023-09-28T14:51:34.262Z DEBUG plugin-manager: started(1683557) /usr/local/libexec/c-lightning/plugins/fetchinvoice
lightningd-1 2023-09-28T14:51:34.266Z DEBUG plugin-manager: started(1683558) /usr/local/libexec/c-lightning/plugins/funder
lightningd-1 2023-09-28T14:51:34.269Z DEBUG plugin-manager: started(1683559) /usr/local/libexec/c-lightning/plugins/topology
lightningd-1 2023-09-28T14:51:34.274Z DEBUG plugin-manager: started(1683560) /usr/local/libexec/c-lightning/plugins/keysend
lightningd-1 2023-09-28T14:51:34.277Z DEBUG plugin-manager: started(1683561) /usr/local/libexec/c-lightning/plugins/offers
lightningd-1 2023-09-28T14:51:34.281Z DEBUG plugin-manager: started(1683562) /usr/local/libexec/c-lightning/plugins/pay
lightningd-1 2023-09-28T14:51:34.289Z DEBUG plugin-manager: started(1683563) /usr/local/libexec/c-lightning/plugins/txprepare
lightningd-1 2023-09-28T14:51:34.294Z DEBUG plugin-manager: started(1683564) /usr/local/libexec/c-lightning/plugins/cln-renepay
lightningd-1 2023-09-28T14:51:34.297Z DEBUG plugin-manager: started(1683565) /usr/local/libexec/c-lightning/plugins/spenderp
lightningd-1 2023-09-28T14:51:34.301Z DEBUG plugin-manager: started(1683566) /usr/local/libexec/c-lightning/plugins/sql
lightningd-1 2023-09-28T14:51:34.305Z DEBUG plugin-manager: started(1683567) /usr/local/libexec/c-lightning/plugins/bookkeeper
lightningd-1 2023-09-28T14:51:34.308Z DEBUG plugin-manager: started(1683568) /usr/local/libexec/c-lightning/plugins/clnrest/clnrest.py
lightningd-1 2023-09-28T14:51:34.352Z INFO plugin-clnrest.py: Killing plugin: disabled itself: No module named 'gunicorn'
lightningd-1 2023-09-28T14:51:34.352Z DEBUG lightningd: io_break: check_plugins_manifests
lightningd-1 2023-09-28T14:51:34.352Z DEBUG lightningd: io_loop_with_timers: plugins_init
lightningd-1 2023-09-28T14:51:34.353Z DEBUG lightningd: testing /usr/local/libexec/c-lightning/lightning_channeld
lightningd-1 2023-09-28T14:51:34.354Z DEBUG lightningd: testing /usr/local/libexec/c-lightning/lightning_closingd
lightningd-1 2023-09-28T14:51:34.355Z DEBUG lightningd: testing /usr/local/libexec/c-lightning/lightning_connectd
lightningd-1 2023-09-28T14:51:34.357Z DEBUG lightningd: testing /usr/local/libexec/c-lightning/lightning_gossipd
lightningd-1 2023-09-28T14:51:34.358Z DEBUG lightningd: testing /usr/local/libexec/c-lightning/lightning_hsmd
lightningd-1 2023-09-28T14:51:34.359Z DEBUG lightningd: testing /usr/local/libexec/c-lightning/lightning_onchaind
lightningd-1 2023-09-28T14:51:34.360Z DEBUG lightningd: testing /usr/local/libexec/c-lightning/lightning_openingd
lightningd-1 2023-09-28T14:51:34.361Z DEBUG hsmd: pid 1683576, msgfd 48
lightningd-1 2023-09-28T14:51:34.362Z DEBUG hsmd: capability +WIRE_HSMD_CHECK_PUBKEY
lightningd-1 2023-09-28T14:51:34.362Z DEBUG hsmd: capability +WIRE_HSMD_SIGN_ANY_DELAYED_PAYMENT_TO_US
lightningd-1 2023-09-28T14:51:34.362Z DEBUG hsmd: capability +WIRE_HSMD_SIGN_ANCHORSPEND
lightningd-1 2023-09-28T14:51:34.362Z DEBUG hsmd: capability +WIRE_HSMD_SIGN_HTLC_TX_MINGLE
lightningd-1 2023-09-28T14:51:34.362Z DEBUG hsmd: capability +WIRE_HSMD_SIGN_SPLICE_TX
lightningd-1 2023-09-28T14:51:34.362Z INFO lightningd: Creating database
lightningd-1 2023-09-28T14:51:34.940Z DEBUG connectd: pid 1683577, msgfd 52
lightningd-1 2023-09-28T14:51:34.941Z DEBUG hsmd: Client: Received message 27 from client
lightningd-1 2023-09-28T14:51:34.941Z DEBUG hsmd: Client: Received message 27 from client
lightningd-1 2023-09-28T14:51:34.941Z DEBUG hsmd: new_client: 0
lightningd-1 2023-09-28T14:51:34.942Z DEBUG connectd: Created listener on 127.0.0.1:44233
lightningd-1 2023-09-28T14:51:34.942Z DEBUG connectd: REPLY WIRE_CONNECTD_INIT_REPLY with 0 fds
lightningd-1 2023-09-28T14:51:34.942Z DEBUG lightningd: io_break: connect_init_done
lightningd-1 2023-09-28T14:51:34.942Z DEBUG lightningd: io_loop: connectd_init
lightningd-1 2023-09-28T14:51:35.070Z INFO plugin-bcli: bitcoin-cli initialized and connected to bitcoind.
lightningd-1 2023-09-28T14:51:35.070Z DEBUG lightningd: io_break: plugin_config_cb
lightningd-1 2023-09-28T14:51:35.070Z DEBUG lightningd: io_loop_with_timers: config_plugin
lightningd-1 2023-09-28T14:51:35.070Z DEBUG lightningd: All Bitcoin plugin commands registered
lightningd-1 2023-09-28T14:51:35.196Z DEBUG lightningd: Adding block 100: 6e5b51ac4fdc2a9d1892290d616bfb2771c0d59fa9ab7adf8f7797b618ee311b
lightningd-1 2023-09-28T14:51:35.196Z DEBUG lightningd: io_break: maybe_completed_init
lightningd-1 2023-09-28T14:51:35.242Z DEBUG lightningd: io_loop_with_timers: setup_topology
lightningd-1 2023-09-28T14:51:35.242Z DEBUG wallet: Loaded 0 channels from DB
lightningd-1 2023-09-28T14:51:35.243Z DEBUG gossipd: pid 1683587, msgfd 51
lightningd-1 2023-09-28T14:51:35.243Z DEBUG hsmd: new_client: 0
lightningd-1 2023-09-28T14:51:35.244Z DEBUG gossipd: total store load time: 0 msec
lightningd-1 2023-09-28T14:51:35.245Z DEBUG gossipd: gossip_store: Read 0/0/0/0 cannounce/cupdate/nannounce/cdelete from store (0 deleted) in 1 bytes
lightningd-1 2023-09-28T14:51:35.245Z DEBUG gossipd: seeker: state = STARTING_UP New seeker
lightningd-1 2023-09-28T14:51:35.245Z DEBUG gossipd: REPLY WIRE_GOSSIPD_INIT_REPLY with 0 fds
lightningd-1 2023-09-28T14:51:35.245Z DEBUG lightningd: io_break: gossipd_init_done
lightningd-1 2023-09-28T14:51:35.245Z DEBUG lightningd: io_loop: gossip_init
lightningd-1 2023-09-28T14:51:35.253Z DEBUG lightningd: Looking for [autoclean,succeededforwards,num]
lightningd-1 2023-09-28T14:51:35.254Z DEBUG lightningd: Looking for [autoclean,failedforwards,num]
lightningd-1 2023-09-28T14:51:35.255Z DEBUG lightningd: Looking for [autoclean,succeededpays,num]
lightningd-1 2023-09-28T14:51:35.255Z DEBUG lightningd: Looking for [autoclean,failedpays,num]
lightningd-1 2023-09-28T14:51:35.255Z DEBUG plugin-fetchinvoice: Killing plugin: disabled itself at init: offers not enabled in config
lightningd-1 2023-09-28T14:51:35.256Z DEBUG hsmd: Client: Received message 27 from client
lightningd-1 2023-09-28T14:51:35.256Z DEBUG lightningd: Looking for [autoclean,paidinvoices,num]
lightningd-1 2023-09-28T14:51:35.257Z DEBUG lightningd: Looking for [autoclean,expiredinvoices,num]
lightningd-1 2023-09-28T14:51:35.257Z DEBUG hsmd: Client: Received message 27 from client
lightningd-1 2023-09-28T14:51:35.329Z DEBUG plugin-chanbackup: Chanbackup Initialised!
lightningd-1 2023-09-28T14:51:35.329Z INFO plugin-chanbackup: Creating Emergency Recovery
lightningd-1 2023-09-28T14:51:35.400Z DEBUG plugin-bookkeeper: Setting up database at sqlite3://accounts.sqlite3
lightningd-1 2023-09-28T14:51:35.400Z INFO plugin-bookkeeper: Creating database
lightningd-1 2023-09-28T14:51:35.400Z DEBUG connectd: REPLY WIRE_CONNECTD_ACTIVATE_REPLY with 0 fds
lightningd-1 2023-09-28T14:51:35.400Z DEBUG lightningd: io_break: connect_activate_done
lightningd-1 2023-09-28T14:51:35.400Z DEBUG lightningd: io_loop: connectd_activate
lightningd-1 2023-09-28T14:51:35.400Z INFO lightningd: --------------------------------------------------
lightningd-1 2023-09-28T14:51:35.400Z INFO lightningd: Server started with public key 0266e4598d1d3c415f572a8488830b60f7e744ed9235eb0b1ba93283b315c03518, alias JUNIORBEAM (color #0266e4) and lightningd v23.08.1
lightningd-1 2023-09-28T14:51:35.411Z DEBUG lightningd: Adding block 101: 2e829364aa8a973634277a9f4f1e40b7b75a1b0260d8d63e84f410f2e777fdd1
lightningd-1 2023-09-28T14:51:35.531Z DEBUG gossipd: REPLY WIRE_GOSSIPD_NEW_BLOCKHEIGHT_REPLY with 0 fds
lightningd-1 2023-09-28T14:51:35.587Z DEBUG plugin-bookkeeper: account wallet has balance 0msat
lightningd-1 2023-09-28T14:51:35.587Z DEBUG plugin-bookkeeper: Snapshot balance does not equal ondisk reported 0msat, off by (+0msat/-0msat) (account wallet) Logging journal entry.
lightningd-1 2023-09-28T14:51:35.587Z INFO plugin-bookkeeper: account wallet not found, adding along with new balance
lightningd-1 2023-09-28T14:51:35.587Z DEBUG plugin-bookkeeper: Snapshot balances updated
lightningd-1 2023-09-28T14:51:36.569Z DEBUG 0266e4598d1d3c415f572a8488830b60f7e744ed9235eb0b1ba93283b315c03518-hsmd: Got WIRE_HSMD_ECDH_REQ
lightningd-1 2023-09-28T14:51:36.569Z DEBUG hsmd: Client: Received message 1 from client
lightningd-1 2023-09-28T14:51:36.570Z DEBUG 027127434a55ebb1cd027583c2282892be24657800eeddefe685c48af70e8947d9-connectd: Connect IN
lightningd-1 2023-09-28T14:51:36.570Z DEBUG 027127434a55ebb1cd027583c2282892be24657800eeddefe685c48af70e8947d9-connectd: peer_out WIRE_INIT
lightningd-1 2023-09-28T14:51:36.570Z DEBUG 027127434a55ebb1cd027583c2282892be24657800eeddefe685c48af70e8947d9-connectd: peer_in WIRE_INIT
lightningd-1 2023-09-28T14:51:36.570Z DEBUG lightningd: Calling peer_connected hook of plugin chanbackup
lightningd-1 2023-09-28T14:51:36.570Z DEBUG 027127434a55ebb1cd027583c2282892be24657800eeddefe685c48af70e8947d9-connectd: Handed peer, entering loop
lightningd-1 2023-09-28T14:51:36.570Z DEBUG lightningd: Plugin chanbackup returned from peer_connected hook call
lightningd-1 2023-09-28T14:51:36.570Z DEBUG 027127434a55ebb1cd027583c2282892be24657800eeddefe685c48af70e8947d9-connectd: peer_in INVALID 19535
lightningd-1 2023-09-28T14:51:36.570Z DEBUG lightningd: Calling custommsg hook of plugin chanbackup
lightningd-1 2023-09-28T14:51:36.571Z DEBUG lightningd: Plugin chanbackup returned from custommsg hook call
lightningd-1 2023-09-28T14:51:36.571Z DEBUG lightningd: Calling custommsg hook of plugin commando
lightningd-1 2023-09-28T14:51:36.571Z DEBUG lightningd: Plugin commando returned from custommsg hook call
lightningd-1 2023-09-28T14:51:36.571Z DEBUG 027127434a55ebb1cd027583c2282892be24657800eeddefe685c48af70e8947d9-connectd: peer_out INVALID 22861
lightningd-1 2023-09-28T14:51:36.572Z DEBUG connectd: drain_peer
lightningd-1 2023-09-28T14:51:36.572Z DEBUG 027127434a55ebb1cd027583c2282892be24657800eeddefe685c48af70e8947d9-lightningd: peer_disconnect_done
lightningd-1 2023-09-28T14:51:36.572Z DEBUG 027127434a55ebb1cd027583c2282892be24657800eeddefe685c48af70e8947d9-lightningd: Not reconnecting: no active channel
lightningd-1 2023-09-28T14:51:36.572Z DEBUG connectd: maybe_free_peer freeing peer!
lightningd-1 2023-09-28T14:51:36.572Z DEBUG plugin-funder: Cleaning up inflights for peer id 027127434a55ebb1cd027583c2282892be24657800eeddefe685c48af70e8947d9
------------------------------------- Captured stdout teardown -------------------------------------
lightningd-1 2023-09-28T14:51:36.641Z UNUSUAL lightningd: JSON-RPC shutdown
lightningd-1 2023-09-28T14:51:36.641Z DEBUG lightningd: io_break: start_json_stream
lightningd-1 2023-09-28T14:51:36.641Z DEBUG lightningd: io_loop_with_timers: main
lightningd-1 2023-09-28T14:51:36.641Z DEBUG connectd: REPLY WIRE_CONNECTD_START_SHUTDOWN_REPLY with 0 fds
lightningd-1 2023-09-28T14:51:36.641Z DEBUG lightningd: io_break: connectd_start_shutdown_reply
lightningd-1 2023-09-28T14:51:36.641Z DEBUG plugin-autoclean: Killing plugin: exited during normal operation
lightningd-1 2023-09-28T14:51:36.642Z DEBUG plugin-chanbackup: Killing plugin: exited during normal operation
lightningd-1 2023-09-28T14:51:36.642Z DEBUG plugin-bcli: Killing plugin: exited during normal operation
lightningd-1 2023-09-28T14:51:36.642Z DEBUG plugin-commando: Killing plugin: exited during normal operation
lightningd-1 2023-09-28T14:51:36.642Z DEBUG plugin-funder: Killing plugin: exited during normal operation
lightningd-1 2023-09-28T14:51:36.642Z DEBUG plugin-topology: Killing plugin: exited during normal operation
lightningd-1 2023-09-28T14:51:36.642Z DEBUG plugin-keysend: Killing plugin: exited during normal operation
lightningd-1 2023-09-28T14:51:36.642Z DEBUG plugin-offers: Killing plugin: exited during normal operation
lightningd-1 2023-09-28T14:51:36.642Z DEBUG plugin-pay: Killing plugin: exited during normal operation
lightningd-1 2023-09-28T14:51:36.642Z DEBUG plugin-txprepare: Killing plugin: exited during normal operation
lightningd-1 2023-09-28T14:51:36.642Z DEBUG plugin-cln-renepay: Killing plugin: exited during normal operation
lightningd-1 2023-09-28T14:51:36.642Z DEBUG plugin-spenderp: Killing plugin: exited during normal operation
lightningd-1 2023-09-28T14:51:36.642Z DEBUG plugin-sql: Killing plugin: exited during normal operation
lightningd-1 2023-09-28T14:51:36.642Z DEBUG lightningd: io_break: destroy_plugin
lightningd-1 2023-09-28T14:51:36.642Z DEBUG plugin-bookkeeper: Killing plugin: exited during normal operation
lightningd-1 2023-09-28T14:51:36.642Z DEBUG lightningd: Command returned result after jcon close
lightningd-1 2023-09-28T14:51:36.643Z DEBUG connectd: Shutting down
lightningd-1 2023-09-28T14:51:36.643Z DEBUG gossipd: Shutting down
lightningd-1 2023-09-28T14:51:36.643Z DEBUG hsmd: Shutting down
===================================== short test summary info ======================================
FAILED test_lnsocket.py::test_getinfo - AssertionError: assert '' == '0266e4598d1d...283b315c03518'
======================================== 1 failed in 23.17s ========================================
Terminal session
We ran the following commands in this order:
$ cd lnsocket/go/
$ cp -r ../../test/ .
$ ls
$ source ../../lightning/contrib/startup_regtest.sh
$ start_ln
$ alias l1-cli
$ l1-cli getinfo
$ l1-cli createrune
$ go get github.com/tidwall/gjson
$ cd test/
$ go run getinfo.go 0252b837dc56fc76497f8e485993494bcaeaa1eca095c332bc8aac4922ce4d5d85 127.0.0.1:7171 srRc7kl_g-_7aRfsfhG_Y0PdKzgrTgEDQY7dG7P2SWM9MA==
$ l1-cli getinfo | jq -r .id
$ python -m venv .venv
$ source .venv/bin/activate
$ pip install pyln-testing
$ pytest test_lnsocket.py
$ pytest test_lnsocket.py
And below you can read the terminal session (command lines and outputs):
◉ tony@tony:~/clnlive:
$ cd lnsocket/go/
◉ tony@tony:~/clnlive/lnsocket/go:[git»master]
$ cp -r ../../test/ .
◉ tony@tony:~/clnlive/lnsocket/go:[git»master]
$ ls
test/ go.mod go.sum lnsocket.go
◉ tony@tony:~/clnlive/lnsocket/go:[git»master]
$ 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/lnsocket/go:[git»master]
$ start_ln
Bitcoin Core starting
awaiting bitcoind...
Making "default" bitcoind wallet.
error code: -35
error message:
Wallet "default" is already loaded.
[1] 1681267
[2] 1681312
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/lnsocket/go:[git»master]
$ alias l1-cli
alias l1-cli='lightning-cli --lightning-dir=/tmp/l1-regtest'
◉ tony@tony:~/clnlive/lnsocket/go:[git»master]
$ l1-cli getinfo
{
"id": "0252b837dc56fc76497f8e485993494bcaeaa1eca095c332bc8aac4922ce4d5d85",
"alias": "PEEVEDSPAWN",
"color": "0252b8",
"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": 7171
}
],
"version": "v23.08.1",
"blockheight": 1,
"network": "regtest",
"fees_collected_msat": 0,
"lightning-dir": "/tmp/l1-regtest/regtest",
"our_features": {
"init": "08a0000a0269a2",
"node": "88a0000a0269a2",
"channel": "",
"invoice": "02000002024100"
}
}
◉ tony@tony:~/clnlive/lnsocket/go:[git»master]
$ l1-cli createrune
{
"rune": "srRc7kl_g-_7aRfsfhG_Y0PdKzgrTgEDQY7dG7P2SWM9MA==",
"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/lnsocket/go:[git»master]
$ go get github.com/tidwall/gjson
go: added github.com/tidwall/gjson v1.17.0
go: added github.com/tidwall/match v1.1.1
go: added github.com/tidwall/pretty v1.2.0
◉ tony@tony:~/clnlive/lnsocket/go:[git»master]
$ cd test/
◉ tony@tony:~/clnlive/lnsocket/go/test:[git»master]
$ go run getinfo.go 0252b837dc56fc76497f8e485993494bcaeaa1eca095c332bc8aac4922ce4d5d85 127.0.0.1:7171 srRc7kl_g-_7aRfsfhG_Y0PdKzgrTgEDQY7dG7P2SWM9MA==
0252b837dc56fc76497f8e485993494bcaeaa1eca095c332bc8aac4922ce4d5d85
◉ tony@tony:~/clnlive/lnsocket/go/test:[git»master]
$ l1-cli getinfo | jq -r .id
0252b837dc56fc76497f8e485993494bcaeaa1eca095c332bc8aac4922ce4d5d85
◉ tony@tony:~/clnlive/lnsocket/go/test:[git»master]
$ python -m venv .venv
◉ tony@tony:~/clnlive/lnsocket/go/test:[git»master]
$ source .venv/bin/activate
(.venv) ◉ tony@tony:~/clnlive/lnsocket/go/test:[git»master]
$ pip install pyln-testing
...
(.venv) ◉ tony@tony:~/clnlive/lnsocket/go/test:[git»master]
$ pytest test_lnsocket.py
======================================= test session starts ========================================
platform linux -- Python 3.10.12, pytest-7.4.2, pluggy-1.3.0
rootdir: /home/tony/clnlive/lnsocket/go/test
collected 1 item
test_lnsocket.py . [100%]
======================================== 1 passed in 24.12s ========================================
(.venv) ◉ tony@tony:~/clnlive/lnsocket/go/test:[git»master]
$ pytest test_lnsocket.py
======================================= test session starts ========================================
platform linux -- Python 3.10.12, pytest-7.4.2, pluggy-1.3.0
rootdir: /home/tony/clnlive/lnsocket/go/test
collected 1 item
test_lnsocket.py F [100%]
============================================= FAILURES =============================================
___________________________________________ test_getinfo ___________________________________________
node_factory = <pyln.testing.utils.NodeFactory object at 0x7f9251624430>
def test_getinfo(node_factory):
node = node_factory.get_node()
node_info = node.rpc.getinfo()
node_id = node_info["id"]
node_address = node_info["binding"][0]["address"]
node_port = node_info["binding"][0]["port"]
node_hostname = node_address + ":" + str(node_port)
# when `commando-rune` deprecated, we'll use `createrune` instead
# rune = node.rpc.createrune()["rune"]
rune = node.rpc.commando_rune()["rune"]
getinfo_cmd = f"go run getinfo.go {node_id} {node_hostname} {rune}"
> assert os.popen(getinfo_cmd).read() == node_id
E AssertionError: assert '' == '0266e4598d1d...283b315c03518'
E - 0266e4598d1d3c415f572a8488830b60f7e744ed9235eb0b1ba93283b315c03518
test_lnsocket.py:15: AssertionError
-------------------------------------- Captured stdout setup ---------------------------------------
Running tests in /tmp/ltests-km5ej2sv
--------------------------------------- Captured stdout call ---------------------------------------
lightningd-1 2023-09-28T14:51:34.248Z DEBUG lightningd: Opened log file -
lightningd-1 2023-09-28T14:51:34.248Z DEBUG lightningd: Opened log file /tmp/ltests-km5ej2sv/test_getinfo_1/lightning-1/log
lightningd-1 2023-09-28T14:51:34.251Z DEBUG plugin-manager: started(1683553) /usr/local/libexec/c-lightning/plugins/autoclean
lightningd-1 2023-09-28T14:51:34.253Z DEBUG plugin-manager: started(1683554) /usr/local/libexec/c-lightning/plugins/chanbackup
lightningd-1 2023-09-28T14:51:34.257Z DEBUG plugin-manager: started(1683555) /usr/local/libexec/c-lightning/plugins/bcli
lightningd-1 2023-09-28T14:51:34.260Z DEBUG plugin-manager: started(1683556) /usr/local/libexec/c-lightning/plugins/commando
lightningd-1 2023-09-28T14:51:34.262Z DEBUG plugin-manager: started(1683557) /usr/local/libexec/c-lightning/plugins/fetchinvoice
lightningd-1 2023-09-28T14:51:34.266Z DEBUG plugin-manager: started(1683558) /usr/local/libexec/c-lightning/plugins/funder
lightningd-1 2023-09-28T14:51:34.269Z DEBUG plugin-manager: started(1683559) /usr/local/libexec/c-lightning/plugins/topology
lightningd-1 2023-09-28T14:51:34.274Z DEBUG plugin-manager: started(1683560) /usr/local/libexec/c-lightning/plugins/keysend
lightningd-1 2023-09-28T14:51:34.277Z DEBUG plugin-manager: started(1683561) /usr/local/libexec/c-lightning/plugins/offers
lightningd-1 2023-09-28T14:51:34.281Z DEBUG plugin-manager: started(1683562) /usr/local/libexec/c-lightning/plugins/pay
lightningd-1 2023-09-28T14:51:34.289Z DEBUG plugin-manager: started(1683563) /usr/local/libexec/c-lightning/plugins/txprepare
lightningd-1 2023-09-28T14:51:34.294Z DEBUG plugin-manager: started(1683564) /usr/local/libexec/c-lightning/plugins/cln-renepay
lightningd-1 2023-09-28T14:51:34.297Z DEBUG plugin-manager: started(1683565) /usr/local/libexec/c-lightning/plugins/spenderp
lightningd-1 2023-09-28T14:51:34.301Z DEBUG plugin-manager: started(1683566) /usr/local/libexec/c-lightning/plugins/sql
lightningd-1 2023-09-28T14:51:34.305Z DEBUG plugin-manager: started(1683567) /usr/local/libexec/c-lightning/plugins/bookkeeper
lightningd-1 2023-09-28T14:51:34.308Z DEBUG plugin-manager: started(1683568) /usr/local/libexec/c-lightning/plugins/clnrest/clnrest.py
lightningd-1 2023-09-28T14:51:34.352Z INFO plugin-clnrest.py: Killing plugin: disabled itself: No module named 'gunicorn'
lightningd-1 2023-09-28T14:51:34.352Z DEBUG lightningd: io_break: check_plugins_manifests
lightningd-1 2023-09-28T14:51:34.352Z DEBUG lightningd: io_loop_with_timers: plugins_init
lightningd-1 2023-09-28T14:51:34.353Z DEBUG lightningd: testing /usr/local/libexec/c-lightning/lightning_channeld
lightningd-1 2023-09-28T14:51:34.354Z DEBUG lightningd: testing /usr/local/libexec/c-lightning/lightning_closingd
lightningd-1 2023-09-28T14:51:34.355Z DEBUG lightningd: testing /usr/local/libexec/c-lightning/lightning_connectd
lightningd-1 2023-09-28T14:51:34.357Z DEBUG lightningd: testing /usr/local/libexec/c-lightning/lightning_gossipd
lightningd-1 2023-09-28T14:51:34.358Z DEBUG lightningd: testing /usr/local/libexec/c-lightning/lightning_hsmd
lightningd-1 2023-09-28T14:51:34.359Z DEBUG lightningd: testing /usr/local/libexec/c-lightning/lightning_onchaind
lightningd-1 2023-09-28T14:51:34.360Z DEBUG lightningd: testing /usr/local/libexec/c-lightning/lightning_openingd
lightningd-1 2023-09-28T14:51:34.361Z DEBUG hsmd: pid 1683576, msgfd 48
lightningd-1 2023-09-28T14:51:34.362Z DEBUG hsmd: capability +WIRE_HSMD_CHECK_PUBKEY
lightningd-1 2023-09-28T14:51:34.362Z DEBUG hsmd: capability +WIRE_HSMD_SIGN_ANY_DELAYED_PAYMENT_TO_US
lightningd-1 2023-09-28T14:51:34.362Z DEBUG hsmd: capability +WIRE_HSMD_SIGN_ANCHORSPEND
lightningd-1 2023-09-28T14:51:34.362Z DEBUG hsmd: capability +WIRE_HSMD_SIGN_HTLC_TX_MINGLE
lightningd-1 2023-09-28T14:51:34.362Z DEBUG hsmd: capability +WIRE_HSMD_SIGN_SPLICE_TX
lightningd-1 2023-09-28T14:51:34.362Z INFO lightningd: Creating database
lightningd-1 2023-09-28T14:51:34.940Z DEBUG connectd: pid 1683577, msgfd 52
lightningd-1 2023-09-28T14:51:34.941Z DEBUG hsmd: Client: Received message 27 from client
lightningd-1 2023-09-28T14:51:34.941Z DEBUG hsmd: Client: Received message 27 from client
lightningd-1 2023-09-28T14:51:34.941Z DEBUG hsmd: new_client: 0
lightningd-1 2023-09-28T14:51:34.942Z DEBUG connectd: Created listener on 127.0.0.1:44233
lightningd-1 2023-09-28T14:51:34.942Z DEBUG connectd: REPLY WIRE_CONNECTD_INIT_REPLY with 0 fds
lightningd-1 2023-09-28T14:51:34.942Z DEBUG lightningd: io_break: connect_init_done
lightningd-1 2023-09-28T14:51:34.942Z DEBUG lightningd: io_loop: connectd_init
lightningd-1 2023-09-28T14:51:35.070Z INFO plugin-bcli: bitcoin-cli initialized and connected to bitcoind.
lightningd-1 2023-09-28T14:51:35.070Z DEBUG lightningd: io_break: plugin_config_cb
lightningd-1 2023-09-28T14:51:35.070Z DEBUG lightningd: io_loop_with_timers: config_plugin
lightningd-1 2023-09-28T14:51:35.070Z DEBUG lightningd: All Bitcoin plugin commands registered
lightningd-1 2023-09-28T14:51:35.196Z DEBUG lightningd: Adding block 100: 6e5b51ac4fdc2a9d1892290d616bfb2771c0d59fa9ab7adf8f7797b618ee311b
lightningd-1 2023-09-28T14:51:35.196Z DEBUG lightningd: io_break: maybe_completed_init
lightningd-1 2023-09-28T14:51:35.242Z DEBUG lightningd: io_loop_with_timers: setup_topology
lightningd-1 2023-09-28T14:51:35.242Z DEBUG wallet: Loaded 0 channels from DB
lightningd-1 2023-09-28T14:51:35.243Z DEBUG gossipd: pid 1683587, msgfd 51
lightningd-1 2023-09-28T14:51:35.243Z DEBUG hsmd: new_client: 0
lightningd-1 2023-09-28T14:51:35.244Z DEBUG gossipd: total store load time: 0 msec
lightningd-1 2023-09-28T14:51:35.245Z DEBUG gossipd: gossip_store: Read 0/0/0/0 cannounce/cupdate/nannounce/cdelete from store (0 deleted) in 1 bytes
lightningd-1 2023-09-28T14:51:35.245Z DEBUG gossipd: seeker: state = STARTING_UP New seeker
lightningd-1 2023-09-28T14:51:35.245Z DEBUG gossipd: REPLY WIRE_GOSSIPD_INIT_REPLY with 0 fds
lightningd-1 2023-09-28T14:51:35.245Z DEBUG lightningd: io_break: gossipd_init_done
lightningd-1 2023-09-28T14:51:35.245Z DEBUG lightningd: io_loop: gossip_init
lightningd-1 2023-09-28T14:51:35.253Z DEBUG lightningd: Looking for [autoclean,succeededforwards,num]
lightningd-1 2023-09-28T14:51:35.254Z DEBUG lightningd: Looking for [autoclean,failedforwards,num]
lightningd-1 2023-09-28T14:51:35.255Z DEBUG lightningd: Looking for [autoclean,succeededpays,num]
lightningd-1 2023-09-28T14:51:35.255Z DEBUG lightningd: Looking for [autoclean,failedpays,num]
lightningd-1 2023-09-28T14:51:35.255Z DEBUG plugin-fetchinvoice: Killing plugin: disabled itself at init: offers not enabled in config
lightningd-1 2023-09-28T14:51:35.256Z DEBUG hsmd: Client: Received message 27 from client
lightningd-1 2023-09-28T14:51:35.256Z DEBUG lightningd: Looking for [autoclean,paidinvoices,num]
lightningd-1 2023-09-28T14:51:35.257Z DEBUG lightningd: Looking for [autoclean,expiredinvoices,num]
lightningd-1 2023-09-28T14:51:35.257Z DEBUG hsmd: Client: Received message 27 from client
lightningd-1 2023-09-28T14:51:35.329Z DEBUG plugin-chanbackup: Chanbackup Initialised!
lightningd-1 2023-09-28T14:51:35.329Z INFO plugin-chanbackup: Creating Emergency Recovery
lightningd-1 2023-09-28T14:51:35.400Z DEBUG plugin-bookkeeper: Setting up database at sqlite3://accounts.sqlite3
lightningd-1 2023-09-28T14:51:35.400Z INFO plugin-bookkeeper: Creating database
lightningd-1 2023-09-28T14:51:35.400Z DEBUG connectd: REPLY WIRE_CONNECTD_ACTIVATE_REPLY with 0 fds
lightningd-1 2023-09-28T14:51:35.400Z DEBUG lightningd: io_break: connect_activate_done
lightningd-1 2023-09-28T14:51:35.400Z DEBUG lightningd: io_loop: connectd_activate
lightningd-1 2023-09-28T14:51:35.400Z INFO lightningd: --------------------------------------------------
lightningd-1 2023-09-28T14:51:35.400Z INFO lightningd: Server started with public key 0266e4598d1d3c415f572a8488830b60f7e744ed9235eb0b1ba93283b315c03518, alias JUNIORBEAM (color #0266e4) and lightningd v23.08.1
lightningd-1 2023-09-28T14:51:35.411Z DEBUG lightningd: Adding block 101: 2e829364aa8a973634277a9f4f1e40b7b75a1b0260d8d63e84f410f2e777fdd1
lightningd-1 2023-09-28T14:51:35.531Z DEBUG gossipd: REPLY WIRE_GOSSIPD_NEW_BLOCKHEIGHT_REPLY with 0 fds
lightningd-1 2023-09-28T14:51:35.587Z DEBUG plugin-bookkeeper: account wallet has balance 0msat
lightningd-1 2023-09-28T14:51:35.587Z DEBUG plugin-bookkeeper: Snapshot balance does not equal ondisk reported 0msat, off by (+0msat/-0msat) (account wallet) Logging journal entry.
lightningd-1 2023-09-28T14:51:35.587Z INFO plugin-bookkeeper: account wallet not found, adding along with new balance
lightningd-1 2023-09-28T14:51:35.587Z DEBUG plugin-bookkeeper: Snapshot balances updated
lightningd-1 2023-09-28T14:51:36.569Z DEBUG 0266e4598d1d3c415f572a8488830b60f7e744ed9235eb0b1ba93283b315c03518-hsmd: Got WIRE_HSMD_ECDH_REQ
lightningd-1 2023-09-28T14:51:36.569Z DEBUG hsmd: Client: Received message 1 from client
lightningd-1 2023-09-28T14:51:36.570Z DEBUG 027127434a55ebb1cd027583c2282892be24657800eeddefe685c48af70e8947d9-connectd: Connect IN
lightningd-1 2023-09-28T14:51:36.570Z DEBUG 027127434a55ebb1cd027583c2282892be24657800eeddefe685c48af70e8947d9-connectd: peer_out WIRE_INIT
lightningd-1 2023-09-28T14:51:36.570Z DEBUG 027127434a55ebb1cd027583c2282892be24657800eeddefe685c48af70e8947d9-connectd: peer_in WIRE_INIT
lightningd-1 2023-09-28T14:51:36.570Z DEBUG lightningd: Calling peer_connected hook of plugin chanbackup
lightningd-1 2023-09-28T14:51:36.570Z DEBUG 027127434a55ebb1cd027583c2282892be24657800eeddefe685c48af70e8947d9-connectd: Handed peer, entering loop
lightningd-1 2023-09-28T14:51:36.570Z DEBUG lightningd: Plugin chanbackup returned from peer_connected hook call
lightningd-1 2023-09-28T14:51:36.570Z DEBUG 027127434a55ebb1cd027583c2282892be24657800eeddefe685c48af70e8947d9-connectd: peer_in INVALID 19535
lightningd-1 2023-09-28T14:51:36.570Z DEBUG lightningd: Calling custommsg hook of plugin chanbackup
lightningd-1 2023-09-28T14:51:36.571Z DEBUG lightningd: Plugin chanbackup returned from custommsg hook call
lightningd-1 2023-09-28T14:51:36.571Z DEBUG lightningd: Calling custommsg hook of plugin commando
lightningd-1 2023-09-28T14:51:36.571Z DEBUG lightningd: Plugin commando returned from custommsg hook call
lightningd-1 2023-09-28T14:51:36.571Z DEBUG 027127434a55ebb1cd027583c2282892be24657800eeddefe685c48af70e8947d9-connectd: peer_out INVALID 22861
lightningd-1 2023-09-28T14:51:36.572Z DEBUG connectd: drain_peer
lightningd-1 2023-09-28T14:51:36.572Z DEBUG 027127434a55ebb1cd027583c2282892be24657800eeddefe685c48af70e8947d9-lightningd: peer_disconnect_done
lightningd-1 2023-09-28T14:51:36.572Z DEBUG 027127434a55ebb1cd027583c2282892be24657800eeddefe685c48af70e8947d9-lightningd: Not reconnecting: no active channel
lightningd-1 2023-09-28T14:51:36.572Z DEBUG connectd: maybe_free_peer freeing peer!
lightningd-1 2023-09-28T14:51:36.572Z DEBUG plugin-funder: Cleaning up inflights for peer id 027127434a55ebb1cd027583c2282892be24657800eeddefe685c48af70e8947d9
------------------------------------- Captured stdout teardown -------------------------------------
lightningd-1 2023-09-28T14:51:36.641Z UNUSUAL lightningd: JSON-RPC shutdown
lightningd-1 2023-09-28T14:51:36.641Z DEBUG lightningd: io_break: start_json_stream
lightningd-1 2023-09-28T14:51:36.641Z DEBUG lightningd: io_loop_with_timers: main
lightningd-1 2023-09-28T14:51:36.641Z DEBUG connectd: REPLY WIRE_CONNECTD_START_SHUTDOWN_REPLY with 0 fds
lightningd-1 2023-09-28T14:51:36.641Z DEBUG lightningd: io_break: connectd_start_shutdown_reply
lightningd-1 2023-09-28T14:51:36.641Z DEBUG plugin-autoclean: Killing plugin: exited during normal operation
lightningd-1 2023-09-28T14:51:36.642Z DEBUG plugin-chanbackup: Killing plugin: exited during normal operation
lightningd-1 2023-09-28T14:51:36.642Z DEBUG plugin-bcli: Killing plugin: exited during normal operation
lightningd-1 2023-09-28T14:51:36.642Z DEBUG plugin-commando: Killing plugin: exited during normal operation
lightningd-1 2023-09-28T14:51:36.642Z DEBUG plugin-funder: Killing plugin: exited during normal operation
lightningd-1 2023-09-28T14:51:36.642Z DEBUG plugin-topology: Killing plugin: exited during normal operation
lightningd-1 2023-09-28T14:51:36.642Z DEBUG plugin-keysend: Killing plugin: exited during normal operation
lightningd-1 2023-09-28T14:51:36.642Z DEBUG plugin-offers: Killing plugin: exited during normal operation
lightningd-1 2023-09-28T14:51:36.642Z DEBUG plugin-pay: Killing plugin: exited during normal operation
lightningd-1 2023-09-28T14:51:36.642Z DEBUG plugin-txprepare: Killing plugin: exited during normal operation
lightningd-1 2023-09-28T14:51:36.642Z DEBUG plugin-cln-renepay: Killing plugin: exited during normal operation
lightningd-1 2023-09-28T14:51:36.642Z DEBUG plugin-spenderp: Killing plugin: exited during normal operation
lightningd-1 2023-09-28T14:51:36.642Z DEBUG plugin-sql: Killing plugin: exited during normal operation
lightningd-1 2023-09-28T14:51:36.642Z DEBUG lightningd: io_break: destroy_plugin
lightningd-1 2023-09-28T14:51:36.642Z DEBUG plugin-bookkeeper: Killing plugin: exited during normal operation
lightningd-1 2023-09-28T14:51:36.642Z DEBUG lightningd: Command returned result after jcon close
lightningd-1 2023-09-28T14:51:36.643Z DEBUG connectd: Shutting down
lightningd-1 2023-09-28T14:51:36.643Z DEBUG gossipd: Shutting down
lightningd-1 2023-09-28T14:51:36.643Z DEBUG hsmd: Shutting down
===================================== short test summary info ======================================
FAILED test_lnsocket.py::test_getinfo - AssertionError: assert '' == '0266e4598d1d...283b315c03518'
======================================== 1 failed in 23.17s ========================================
lnsocket/go source code
lnsocket.go
package lnsocket
import (
"bytes"
"encoding/hex"
"fmt"
"io"
"net"
"github.com/btcsuite/btcd/btcec/v2"
"github.com/lightningnetwork/lnd/brontide"
"github.com/lightningnetwork/lnd/keychain"
"github.com/lightningnetwork/lnd/lnwire"
"github.com/lightningnetwork/lnd/tor"
)
const (
COMMANDO_CMD = 0x4c4f
COMMANDO_REPLY_CONTINUES = 0x594b
COMMANDO_REPLY_TERM = 0x594d
)
type CommandoMsg struct {
Rune string
Method string
Params string
RequestId uint64
}
func NewCommandoMsg(token string, method string, params string) CommandoMsg {
return CommandoMsg{
Rune: token,
Method: method,
Params: params,
}
}
// A compile time check to ensure Init implements the lnwire.Message
// interface.
func (msg *CommandoMsg) MsgType() lnwire.MessageType {
return COMMANDO_CMD
}
func (msg *CommandoMsg) Decode(reader io.Reader, size uint32) error {
return fmt.Errorf("implememt commando decode?")
}
func (msg *CommandoMsg) Encode(buf *bytes.Buffer, pver uint32) error {
if err := lnwire.WriteUint64(buf, msg.RequestId); err != nil {
return err
}
buf.WriteString("{\"method\": \"")
buf.WriteString(msg.Method)
buf.WriteString("\",\"params\":")
buf.WriteString(msg.Params)
buf.WriteString(",\"rune\":\"")
buf.WriteString(msg.Rune)
buf.WriteString("\",\"id\":\"d0\",\"jsonrpc\":\"2.0\"}")
return nil
}
type LNSocket struct {
Conn net.Conn
PrivKeyECDH *keychain.PrivKeyECDH
}
func (ln *LNSocket) GenKey() {
remotePriv, _ := btcec.NewPrivateKey()
ln.PrivKeyECDH = &keychain.PrivKeyECDH{PrivKey: remotePriv}
}
func (ln *LNSocket) ConnectWith(netAddr *lnwire.NetAddress) error {
conn, err := brontide.Dial(ln.PrivKeyECDH, netAddr, tor.DefaultConnTimeout, net.DialTimeout)
ln.Conn = conn
return err
}
func (ln *LNSocket) Connect(hostname string, pubkey string) error {
addr, err := net.ResolveTCPAddr("tcp", hostname)
if err != nil {
return err
}
bytes, err := hex.DecodeString(pubkey)
if err != nil {
return err
}
key, err := btcec.ParsePubKey(bytes)
if err != nil {
return err
}
netAddr := &lnwire.NetAddress{
IdentityKey: key,
Address: addr,
}
return ln.ConnectWith(netAddr)
}
func (ln *LNSocket) PerformInit() error {
no_features := lnwire.NewRawFeatureVector()
init_reply_msg := lnwire.NewInitMessage(no_features, no_features)
var b bytes.Buffer
_, err := lnwire.WriteMessage(&b, init_reply_msg, 0)
if err != nil {
return err
}
_, err = ln.Conn.Write(b.Bytes())
// receive the first init msg
_, _, err = ln.Recv()
if err != nil {
return err
}
return nil
}
func (ln *LNSocket) Rpc(token string, method string, params string) (string, error) {
commando_msg := NewCommandoMsg(token, method, params)
var b bytes.Buffer
_, err := lnwire.WriteMessage(&b, &commando_msg, 0)
if err != nil {
return "", err
}
bs := b.Bytes()
_, err = ln.Conn.Write(bs)
if err != nil {
return "", err
}
return ln.rpcReadAll()
}
func ParseMsgType(bytes []byte) uint16 {
return uint16(bytes[0])<<8 | uint16(bytes[1])
}
func (ln *LNSocket) Recv() (uint16, []byte, error) {
res := make([]byte, 65535)
n, err := ln.Conn.Read(res)
if err != nil {
return 0, nil, err
}
if n < 2 {
return 0, nil, fmt.Errorf("read too small")
}
res = res[:n]
msgtype := ParseMsgType(res)
return msgtype, res[2:], nil
}
func (ln *LNSocket) rpcReadAll() (string, error) {
all := []byte{}
for {
msgtype, res, err := ln.Recv()
if err != nil {
return "", err
}
switch msgtype {
case COMMANDO_REPLY_CONTINUES:
all = append(all, res[8:]...)
continue
case COMMANDO_REPLY_TERM:
all = append(all, res[8:]...)
return string(all), nil
default:
continue
}
}
}
func (ln *LNSocket) Disconnect() {
ln.Conn.Close()
}
func (ln *LNSocket) ConnectAndInit(hostname string, pubkey string) error {
err := ln.Connect(hostname, pubkey)
if err != nil {
return err
}
return ln.PerformInit()
}
Source code
getinfo.go
package main
import (
"fmt"
"os"
"github.com/tidwall/gjson"
lnsocket "github.com/jb55/lnsocket/go"
)
// Print the node id of the CLN node given as input using
// commando plugin and lnsocket/go.
// Usage:
//
// $ go run getinfo.go node_id hostname rune
//
// with for instance
// node_id: 034fa9ed201192c7e865f0fc67001725620e79422347186f0ae4578aac08f4df3d
// hostname: 127.0.0.1:7171
// rune: sxKlx_DW_LtN1kxbTEEfvJN4ytGLMNfyKH_8AjK9yx89MA==
func main() {
nodeid := os.Args[1]
hostname := os.Args[2]
rune := os.Args[3]
ln := lnsocket.LNSocket{}
ln.GenKey()
err := ln.ConnectAndInit(hostname, nodeid)
if err != nil {
panic(err)
}
body, err := ln.Rpc(rune, "getinfo", "[]")
if err != nil {
panic(err)
}
getinfoNodeid := gjson.Get(body, "result.id").String()
fmt.Printf(getinfoNodeid)
}
README.md
# lnsocket test
We use `pyln-testing` python library to write the tests.
The Go program `getinfo.go` we use to test `lnsocket` depends on
`tidwall/gjson` library.
Before, we run the tests, we set up a virtual environment, install
`pyln-testing` Python library and `gjson` Go package:
python -m venv .venv
source .venv/bin/activate
pip install pyln-testing
go get github.com/tidwall/gjson
Now we can run the tests in `.venv` environment like this:
pytest test_lnsocket.py
test_lnsocket.py
from pyln.testing.fixtures import *
import os
def test_getinfo(node_factory):
node = node_factory.get_node()
node_info = node.rpc.getinfo()
node_id = node_info["id"]
node_address = node_info["binding"][0]["address"]
node_port = node_info["binding"][0]["port"]
node_hostname = node_address + ":" + str(node_port)
# when `commando-rune` deprecated, we'll use `createrune` instead
# rune = node.rpc.createrune()["rune"]
rune = node.rpc.commando_rune()["rune"]
getinfo_cmd = f"go run getinfo.go {node_id} {node_hostname} {rune}"
assert os.popen(getinfo_cmd).read() == node_id