Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

Message channel over c-lightning #1000

Closed
wants to merge 12 commits into from
Closed

Message channel over c-lightning #1000

wants to merge 12 commits into from

Conversation

AdamISZ
Copy link
Member

@AdamISZ AdamISZ commented Aug 31, 2021

I made several updates to this description on 29 Dec 2021 as it was substantially out of date.

See commit message for a brief technical summary of implementation in code.

For an explanation of the reasoning for creating this, see the first section of https://github.com/JoinMarket-Org/joinmarket-clientserver/blob/3f8fa0ea8156eeabe40c2a62a3c3e38026dae31f/docs/lightning-message-channels.md.

Some extra points relevant to review and further progress:

  • Transactions work. And on regtest/localhost they are a lot faster than using our existing IRC tests (miniircd), which is encouraging, if not hugely meaningful.
  • No tests have yet been added (and indeed some existing tests are broken, though that is probably trivial).
  • This should work correctly with a mixture of IRC+LN message channels.

Those are more trivial points, but the bigger ones:

  • I don't want to go whole-hog to a mainnet ready implementation until others like @chris-belcher @undeath @kristapsk and others have had a chance to give their thoughts. In particular: does this kind of "meta-layer" of communication need some extra features? My best guess is that for now we should embed a version number in all the LN-sent messages such that we can support an upgrade in future (i.e. new bots with a better system can happily talk to old bots on the old system .. this usually means version range). done
  • The most important thing that this doesn't do yet is: pass messages over hops. Although bots can always !privmsg directly to other bots, if they have a connection, there is not currently implemented, even an attempt to connect to bots other than the directory nodes that we connect to at the start - see later comments, we now switch to direct messaging once we learn of peers via !fill and !offer messages. This means that it's more the old IRC model of "privmsgs are end to end encrypted" and not really decentralized further than the existing model; but that's just because I haven't tried to code that yet, not because it can't be done. In a similar vein, while the user can configure a list of directory nodes, the code currently only uses the first directory node in the list. This second sentence is also now out of date, multiple directory nodes are supported.
  • A more long term one but important will be: the directory node's DOS control measures. I envisage issuance of tokens against small Lightning payments, but you could conceivably use one of the two methods we've already used against Sybil/DOS: PoDLE or fidelity bonds. I like the Chaumian tokens against small LN payments personally, but that's a bunch of new stuff (idea: directory issues its own tokens, user pays a tiny fraction on a per message basis, see e.g. Wabisabi MACs, although that's just one example, maybe such denomination flexibility not needed here). Anything that prevents "million messages per second from one guy" could do as a starting point.

Points of discussion at the code/design level:

About the messaging, the most important thing to read is the set of comments at the top of jmdaemon/lnonion.py (this has been moved to a PR in Joinmarket-Docs) which explains how we translate from (Joinmarket text formatted messages) -> (a slightly extend string containing to/from information to be passed into Lightning) -> (the contents of the sendcustommsg message).

Design-wise, pretty much everything here is arguable. The main goal was to have a class which inherits from jmdaemon.message_channel.MessageChannel and implement it, as irc.py does, and that is achieved here. The slightly obscure differences between privmsg and pubmsg are not as easy to reason about as they might be, but, it's OK. The layers of encoding are kind of painful, but at least we maintain consistency.

The actual message parsing is "asymmetric" in a weird way: messages come in via the plugin, via this hook:

@plugin.hook("custommsg")
on_custommsg(peer_id, payload, plugin, **kwargs):

and they are then handed over to jmdaemon over TCP port (default 49100) to a twisted.protocols.basic.LineReceiver. The messages go out, however, by sending the RPC command sendcustommsg (same format, of course). See this method in LNOnionMessageChannel:

    def _send(self, peerid: str, message: bytes) -> None:

(Since it's only referenced in the doc, tagging here: #415 ).

@AdamISZ
Copy link
Member Author

AdamISZ commented Aug 31, 2021

Running a bot on signet here:

03e5db5523642fef5d65b9a7cedfda9cfe3a4054565c9aefbe32e5d72d086d6b34@m7t5zow7fugzjymfiacq37bxz7niq5pfwult6ukbqibtgzgbyb3hbeid.onion:9735 see below.

... which you can set as a directory node. I'll try to keep it up.

I'll be adding a patch immediately to read the getinfo output correctly for this Tor onion scenario (it currently reads binding which is wrong).

For info on how to set up for a persistent Tor v3 onion, if you're not already (and you probably are, if you run bitcoind with Tor on the machine), check the detailed instructions here: https://lightning.readthedocs.io/TOR.html

.. and then add (or create) this in your ~./lightning/config:

proxy=127.0.0.1:9050
bind-addr=127.0.0.1:9735
addr=statictor:127.0.0.1:9051
always-use-proxy=true

If you're planning on messing around testing, like me, with multiple bots, just set different ports in bind-addr.

Edit: sanity checked i could use it, seemed to work, created this tx with another bot on a different onion/LN node: https://explorer.bc-2.jp/tx/533901e14c7f3ee7532485061d4b018675d67da39c6ab7cc363c152d7323c428

@AdamISZ AdamISZ changed the title Message channel over c-lightning [WIP] Message channel over c-lightning Sep 1, 2021
docs/lightning-message-channels.md Outdated Show resolved Hide resolved
docs/lightning-message-channels.md Outdated Show resolved Hide resolved
@AdamISZ
Copy link
Member Author

AdamISZ commented Sep 14, 2021

@kristapsk thanks for taking a look. actually due to me swapping around computers, i think the node I listed above is not currently running, but I'll probably bring it back up shortly after I finish something else (just in case it's useful).

@kristapsk
Copy link
Member

I plan to setup and run a signet instance permanently (at least for some time) too.

@AdamISZ
Copy link
Member Author

AdamISZ commented Oct 27, 2021

As of c8c2227 things will be quite broken; pushing just to help with testing of installation and setup in fresh env.

@AdamISZ
Copy link
Member Author

AdamISZ commented Oct 28, 2021

After f0e44bf this is hopefully getting significantly easier to test. If you run the install from scratch with ./install.sh --with-ln-messaging it will build c-lightning and install it in deps (compiled with onion messaging flag; with release version it doesn't work). Then, setting sensible config in the created default [MESSAGING:lightning1] should allow you to run tests in some --datadir=.. setting; in that directory, you'll see a new sub-folder lightning under which you get all the c-lightning data and config (it's all done automatically). For example you can run a few nodes on signet all on your own machine like this.

I'll drop a note here that I think it's maybe too hard to keep the network layer separation pure here; if we end up using these lightning nodes for payments then they're not performing pure message handling any more; right now, I need the message channel to have access to the rpc socket that c-lightning gives, and it's too much of a pain to figure out how to isolate that messaging, so for now, this PR is not compatible with having jmdaemon run on a separate environment to jmclient. But I think most people aren't too bothered.

@AdamISZ
Copy link
Member Author

AdamISZ commented Oct 28, 2021

As of 1f11993 I can do coinjoins with the lightningd instances connecting over onion services remotely. I will next alter the documentation to explain how to set it up now; it'll be quite a lot easier. done.

But there are a lot of details still to address, noting them here (and may add more):

  • Include in docs the diff for setup of a directory node (just statictor not autotor basically so you can share the onion address). done.
  • Make sure the lightningd instance shuts down for sendpayment; currently it's not getting the shutdown signal when sendpayment terminates. done.
  • Add some tests of jmdaemon/jmdaemon/lnonion.py and get the test suite passing. done.
  • Fix bug where disconnection of dn or non-dn raises RPC error. done.

@AdamISZ
Copy link
Member Author

AdamISZ commented Oct 28, 2021

@kristapsk at some point if you could find time to run through the installation changes in install.sh I would appreciate it; you are much more knowledgeable on that so no doubt you will see some things needing improving.

Both you and maybe @openoms perhaps might find time to try the installation and see if you can get a bot running based on what's in the updated doc here. Or anyone else of course :)

@AdamISZ
Copy link
Member Author

AdamISZ commented Oct 29, 2021

Updated my directory host and port:

0344bc51c0b0cf58ebfee222bdd8ff4855ac3becd7a9c8bff8ff08100771179047@mvm5ffyipzf4tis2g753w7q25evcqmvj6qnnwgr3dkpyukomykzvwuad.onion:9736

This is working atm, please try to break it :)

@AdamISZ AdamISZ force-pushed the ln-onion-mc branch 2 times, most recently from 682f225 to 4fff271 Compare October 29, 2021 18:50
@AdamISZ
Copy link
Member Author

AdamISZ commented Oct 29, 2021

Rebased on master as of 4fff271

Working on tests now.

@AdamISZ AdamISZ changed the title [WIP] Message channel over c-lightning Message channel over c-lightning Oct 31, 2021
@AdamISZ
Copy link
Member Author

AdamISZ commented Oct 31, 2021

Now test suite is passing and also I've addressed the minor bug points above, I'm removed [WIP] from the title. It's not ready to be merged but definitely ready to start getting detailed test results and review.

Summary for reviewers:

  • An installation change in install.sh which bundles c-lightning using the flag --with-ln-messaging. While such bundling is only preferable for certain use cases (many might prefer to use their existing node), there is currently no choice as we use the --experimental.. features and require a build with that flag, and can't expect users to compile that way themselves. The installation embeds the compiled binaries similar to how we deal with our other compiled dependencies.
  • A new messaging section in the config, which is parsed in configure.py to know how to start the local node with our joinmarket plugin, and how to connect that over TCP to our actual joinmarket process.
  • A new LNOnionMessageChannel child class of MessageChannel analogous, of course, to IRCMessageChannel and implementing the same interface, this is in jmdaemon/lnonion.py, which also has a number of classes to represent the interaction with the lightning node, in particular the concept of the RPC call sendonionmessage. Note that there are no code changes in jmdaemon/message_channel.py, by design. Note that the top of this module is a wall of text describing the translation between these onionmessage objects passed over lightning-rpc, and the Joinmarket's existing message protocol syntax. Some details about this, such as the integer message types, or the absence of any version or ping/pong messages, are very much open to discussion and ideally before we start using this!
  • The plugin itself is also located in the jmdaemon package and is called jmcl.py. It is very simple, providing hooks for when our LN node receives onion message, or connect and disconnect calls. The data is passed completely transparently over a TCP socket to the joinmarket process. This is just passed as a parameter when we start up the lightningd process, which we do on startup of our Joinmarket script, if we can see from the config, that it is required (because we have a lightning message channel configured).
  • Confused about the data flow? Understandable because it's asymmetrical. Inbound data goes (p2p ln) -> our lightningd -> our plugin hooks -> tcp socket -> the running joinmarket script -> LNOnionMessageChannel.receive_msg. Outbound data goes LNOnionMessageChannel._send() -> LightningRpc object (from new dependency pyln_client) -> our lightningd with the sendonionmessage call -> (p2p ln).
  • Test suite additions in jmdaemon/test/test_lnonion_message_channel.py.

@AdamISZ AdamISZ force-pushed the ln-onion-mc branch 3 times, most recently from c39e3d0 to 6e712b2 Compare November 1, 2021 13:15
@AdamISZ
Copy link
Member Author

AdamISZ commented Nov 1, 2021

After 6e712b2 the coinjoin peers are successfully passing messages peer to peer for the privmsg part of the conversation, i.e. bypassing the directory node(s) entirely.

While it's still fairly primitive, this was the level of decentralization I was hoping to implement here. Pubmsgs will go over multiple "public" directory nodes, acting essentially just as IRC servers do today for that part of the flow, while the transaction negotiation can be mostly or entirely happening p2p. This will take a lot of the load off of the directory nodes and be an extra layer of metadata privacy on top of the existing end-to-end encryption.

install.sh Outdated Show resolved Hide resolved
install.sh Outdated Show resolved Hide resolved
@kristapsk
Copy link
Member

Random thought - if we build c-lightning inside jmvenv, why can't we also do the same with Tor? That would allow enabling it by default, without the need for the user to configure Tor settings manually. Tor daemon is not very hungry process, don't think there should be any problems even with running multiple instances in parallel.

@AdamISZ
Copy link
Member Author

AdamISZ commented Nov 2, 2021

Random thought - if we build c-lightning inside jmvenv, why can't we also do the same with Tor? That would allow enabling it by default, without the need for the user to configure Tor settings manually. Tor daemon is not very hungry process, don't think there should be any problems even with running multiple instances in parallel.

It seems reasonable, but I'm loth to say "Yes!" without having tried it :) If someone else can add that into the installation that'd be cool indeed. Maybe in an additional PR.

@kristapsk
Copy link
Member

I will try to hack it together as a separate PR.

install.sh Outdated
'zlib1g-dev' \
'libsodium-dev' \
'gettext' )
deb_deps_install "${ln_deps[@]}"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This currently only works for Debian, somebody should look at required Darwin (macOS) deps and add them here too, like in deps_install().

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also, [[ ${use_os_deps_check} != '1' ]] check should be added too.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Partially done in 7a5e4c3 .

I added the use_os_deps_check but for the MacOS i've just kind of "given it a start".

Probably someone who runs MacOS and can follow the instructions as per the guide here. From a brief read I note that there are more exceptional conditions to handle here, so it may need a few extra steps.

For now I have just added the basic list of brew install dependencies given there, but it's a shot in the dark. @kristapsk feel free to add commits that correct errors in this stuff.

Adam Gibson and others added 11 commits January 18, 2022 14:27
This commit creates a new MessageChannel
implementation `LNOnionMessageChannel`,
in `lnonion.py`, as well as classes
represeting LN peers and LN onionmessages.
In addition it implements a c-lightning
plugin `jmcl.py`, which forwards messages
received from other LN peers via the
`sendonionmessage` RPC (this is still an
experimental feature in c-lightning).
The messagechannel object must be configured
with a lightning-rpc socket file location,
so that it can send out these messages via
its c-lightning node.
Communcation between the plugin and jmdaemon
is accomplished using a twisted basic.LineReceiver
protocol.
An automatic installation of c-lightning as part
of Joinmarket's installed script is added, which
is activated with the flag --with-ln-messaging.
This instance of c-lightning is auto-started.
Documentation on this feature is added in
docs/lightning-message-channel.md.
Also adds basic lnonion module tests.
After 0.10.2 switched the onionmessage format,
and since we don't yet have a use for these messages
outside of a direct peer connection, and since the
onionmessage format is significantly more complex,
we switch for the time being to the hook and RPC
call for custommsg, instead.
Refactored the plugin to use a pure socket connection
instead of twisted, this avoids confusion since the plugin
fundamentally is blocking on iterating over stdin input, it
also avoids needing a big dependency like twisted when running
the plugin in whatever environment c-lightning is running in.
Secondly, added state management of peers and the requirement
for non-directory peers to handshake with directory peers on
startup, to ensure version match and pass basic info.
Adds config option to use non-bundled c-lightning.
(See comments on clightning-location var in the
default config in configure.py.)
Also modifies the docs and adds a note in the installation
script that including the bundled c-lightning is only required
if you do not intend to use your pre-existing
installation.
Cleans jmcl.py of any joinmarket codebase dependency.
The handshake is changed to include nick
and connection information.
Then we remove the getpeers request from non-dir
nodes, and instead the dir-nodes forward connection
info to clients whenever they get a privmsg from
another client. This avoids too much messaging spam
coming from the directory.
Also, a new test construction is found in
test/e2e-coinjoin-test.py; here, we automate not only the
setup and start of yieldgenerators in regtest, but
also we start up a JMWalletDaemon instance for the
Taker, who then runs a coinjoin with the docoinjoin
request.
e2e-coinjoin-test.py now allows configuration of
multiple directory nodes as well as multiple non-directory
nodes. Also some irrelevant details were removed or cleaned
up.
The documentation of the lnonion messaging protocol was
removed from jmdaemon/lnonion.py and relocated to
JoinMarket-Org/JoinMarket-Docs#9
Adds a subclass of LNOnionPeer, LNOnionDirectoryPeer,
so that the try_to_connect behaviour can be distinct
for the two classes of peer; for dns, we use exponential
backoff to keep trying to reconnect for a long time,
whereas for non-dn peers we try once and give up (as before).
@AdamISZ
Copy link
Member Author

AdamISZ commented Jan 18, 2022

Rebased on master as of 97cf02c

kristapsk added a commit that referenced this pull request Feb 10, 2022
…re count

c0d6610 Limit number of parallel builds to CPU core count (Kristaps Kaupe)

Pull request description:

  I noticed too much parallel build processes for some time, but somehow missed that `export MAKEFLAGS='-j'` previously. If `-j` is given to `make` without any argument, it means unlimited job count. It may cause problems, especially on machines with limited available RAM amount (see #1000 (comment), for example). And building in parallel with more jobs than CPU cores available does not make much sense.

Top commit has no ACKs.

Tree-SHA512: d59b0cc29d874aeb7079ef124de4bff9ca301995cc0c0a21cbcfebe56c84ca2f84a8196aceedfc763bf0fcc1216434b5f55fd3534d31fffd87bb74351d8024b6
AdamISZ pushed a commit that referenced this pull request Feb 14, 2022
AdamISZ added a commit that referenced this pull request Feb 14, 2022
This follows the same principle as #1000 but does not
use a c-lightning instance as a backend, instead creating
onion services for each node, with special directory nodes,
as before, acting as coordinators.
AdamISZ pushed a commit that referenced this pull request Feb 14, 2022
AdamISZ added a commit that referenced this pull request Feb 14, 2022
This follows the same principle as #1000 but does not
use a c-lightning instance as a backend, instead creating
onion services for each node, with special directory nodes,
as before, acting as coordinators.
AdamISZ pushed a commit that referenced this pull request Feb 22, 2022
AdamISZ added a commit that referenced this pull request Feb 22, 2022
This follows the same principle as #1000 but does not
use a c-lightning instance as a backend, instead creating
onion services for each node, with special directory nodes,
as before, acting as coordinators.
@AdamISZ
Copy link
Member Author

AdamISZ commented Mar 13, 2022

Given developments as per #1182 , closing this. Will not delete the branch, though, in case it's useful.

@AdamISZ AdamISZ closed this Mar 13, 2022
AdamISZ pushed a commit that referenced this pull request Mar 26, 2022
AdamISZ added a commit that referenced this pull request Mar 26, 2022
This follows the same principle as #1000 but does not
use a c-lightning instance as a backend, instead creating
onion services for each node, with special directory nodes,
as before, acting as coordinators.
kristapsk added a commit that referenced this pull request Apr 2, 2022
… jmvenv

5132342 update install.sh to build tor on macOS (jules23)
7a88781 Add support to build and autostart local Tor instance in jmvenv (Kristaps Kaupe)

Pull request description:

  See #1000 (comment) for context.

  This adds new option `--with-local-tor` to `install.sh` which builds Tor locally inside jmvenv. Then, when starting JM scripts that might need Tor connection, it is started automatically if nobody already listens on `127.0.0.1:9050`.

  If no problems are found with his approach in testing, we could switch to this as a default and remove all clearnet IRC configs from default config.

Top commit has no ACKs.

Tree-SHA512: caa7fcac88e57321f65a3f9fc09def94f9659855977026a19e1ac8f2f160a01237fe90220b986561bd622b05534f201ea5a29a9cdbc71013e40301992ed59e4d
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

8 participants