Skip to content

Commit

Permalink
pyln: Split pylightning into multiple pyln modules
Browse files Browse the repository at this point in the history
This is the first step to transition to a better organized python module
structure. Sadly we can't reuse the `pylightning` module as a namespace module
since having importable things in the top level of the namespace is not
allowed in any of the namespace variants [1], hence we just switch over to the
`pyln` namespace. The code the was under `lightning` will now be reachable
under `pyln.client` and we add the `pyln.proto` module for all the things that
are independent of talking to lightningd and can be used for protocol testing.

[1] https://packaging.python.org/guides/packaging-namespace-packages/

Signed-off-by: Christian Decker <decker.christian@gmail.com>
  • Loading branch information
cdecker committed Sep 7, 2019
1 parent cad6c8b commit 4caf76b
Show file tree
Hide file tree
Showing 14 changed files with 661 additions and 2 deletions.
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -38,4 +38,7 @@ tools/headerversions
contrib/pylightning/build/
contrib/pylightning/dist/
contrib/pylightning/pylightning.egg-info/
contrib/pyln-*/build/
contrib/pyln-*/dist/
contrib/pyln-*/pyln_*.egg-info/
devtools/create-gossipstore
2 changes: 0 additions & 2 deletions contrib/pylightning/requirements.txt
Original file line number Diff line number Diff line change
@@ -1,2 +0,0 @@
cryptography==2.7
coincurve==12.0.0
101 changes: 101 additions & 0 deletions contrib/pyln-client/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
# pyln-client: A python client library for lightningd

This package implements the Unix socket based JSON-RPC protocol that
`lightningd` exposes to the rest of the world. It can be used to call
arbitrary functions on the RPC interface, and serves as a basis for plugins
written in python.


## Installation

`pyln-client` is available on `pip`:

```
pip install pyln-client
```

Alternatively you can also install the development version to get access to
currently unreleased features by checking out the c-lightning source code and
installing into your python3 environment:

```bash
git clone https://github.com/ElementsProject/lightning.git
cd lightning/contrib/pyln-client
python3 setup.py develop
```

This will add links to the library into your environment so changing the
checked out source code will also result in the environment picking up these
changes. Notice however that unreleased versions may change API without
warning, so test thoroughly with the released version.

## Examples


### Using the JSON-RPC client
```py
"""
Generate invoice on one daemon and pay it on the other
"""
from pyln.client import LightningRpc
import random

# Create two instances of the LightningRpc object using two different c-lightning daemons on your computer
l1 = LightningRpc("/tmp/lightning1/lightning-rpc")
l5 = LightningRpc("/tmp/lightning5/lightning-rpc")

info5 = l5.getinfo()
print(info5)

# Create invoice for test payment
invoice = l5.invoice(100, "lbl{}".format(random.random()), "testpayment")
print(invoice)

# Get route to l1
route = l1.getroute(info5['id'], 100, 1)
print(route)

# Pay invoice
print(l1.sendpay(route['route'], invoice['payment_hash']))
```

### Writing a plugin

Plugins are programs that `lightningd` can be configured to execute alongside
the main daemon. They allow advanced interactions with and customizations to
the daemon.

```python
#!/usr/bin/env python3
from pyln.client import Plugin

plugin = Plugin()

@plugin.method("hello")
def hello(plugin, name="world"):
"""This is the documentation string for the hello-function.
It gets reported as the description when registering the function
as a method with `lightningd`.
"""
greeting = plugin.get_option('greeting')
s = '{} {}'.format(greeting, name)
plugin.log(s)
return s


@plugin.init()
def init(options, configuration, plugin):
plugin.log("Plugin helloworld.py initialized")


@plugin.subscribe("connect")
def on_connect(plugin, id, address):
plugin.log("Received connect event for peer {}".format(id))


plugin.add_option('greeting', 'Hello', 'The greeting I should use.')
plugin.run()

```
10 changes: 10 additions & 0 deletions contrib/pyln-client/pyln/client/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
from lightning import LightningRpc, Plugin, RpcError, Millisatoshi, __version__, monkey_patch

__all__ = [
"LightningRpc",
"Plugin",
"RpcError",
"Millisatoshi",
"__version__",
"monkey_patch"
]
1 change: 1 addition & 0 deletions contrib/pyln-client/requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
pylightning==0.0.7.3
24 changes: 24 additions & 0 deletions contrib/pyln-client/setup.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
from setuptools import setup
from pyln import client
import io


with io.open('README.md', encoding='utf-8') as f:
long_description = f.read()

with io.open('requirements.txt', encoding='utf-8') as f:
requirements = [r for r in f.read().split('\n') if len(r)]

setup(name='pyln-client',
version=client.__version__,
description='Client library for lightningd',
long_description=long_description,
long_description_content_type='text/markdown',
url='http://github.com/ElementsProject/lightning',
author='Christian Decker',
author_email='decker.christian@gmail.com',
license='MIT',
packages=['pyln.client'],
scripts=[],
zip_safe=True,
install_requires=requirements)
30 changes: 30 additions & 0 deletions contrib/pyln-proto/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
# pyln-proto: Lightning Network protocol implementation

This package implements some of the Lightning Network protocol in pure
python. It is intended for protocol testing and some minor tooling only. It is
not deemed secure enough to handle any amount of real funds (you have been
warned!).


## Installation

`pyln-proto` is available on `pip`:

```
pip install pyln-proto
```

Alternatively you can also install the development version to get access to
currently unreleased features by checking out the c-lightning source code and
installing into your python3 environment:

```bash
git clone https://github.com/ElementsProject/lightning.git
cd lightning/contrib/pyln-proto
python3 setup.py develop
```

This will add links to the library into your environment so changing the
checked out source code will also result in the environment picking up these
changes. Notice however that unreleased versions may change API without
warning, so test thoroughly with the released version.
23 changes: 23 additions & 0 deletions contrib/pyln-proto/examples/connect.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
#!/usr/bin/env python3
"""Simple connect and read test
Connects to a peer, performs handshake and then just prints all the messages
it gets.
"""

from pyln.proto.wire import connect, PrivateKey, PublicKey
from binascii import unhexlify, hexlify

ls_privkey = PrivateKey(unhexlify(
b'1111111111111111111111111111111111111111111111111111111111111111'
))
remote_pubkey = PublicKey(unhexlify(
b'03b31e5bbf2cdbe115b485a2b480e70a1ef3951a0dc6df4b1232e0e56f3dce18d6'
))

lc = connect(ls_privkey, remote_pubkey, '127.0.0.1', 9375)
lc.send_message(b'\x00\x10\x00\x00\x00\x01\xaa')

while True:
print(hexlify(lc.read_message()).decode('ASCII'))
47 changes: 47 additions & 0 deletions contrib/pyln-proto/examples/listen.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
#!/usr/bin/env python3
"""A simple handshake and encryption test.
This script will listen on port 9736 for incoming Lightning Network protocol
connections, perform the cryptographic handshake, send 10k small pings, and
then exit, closing the connection. This is useful to check the correct
rotation of send- and receive-keys in the implementation.
"""


from pyln.proto.wire import LightningServerSocket, PrivateKey
from binascii import hexlify, unhexlify
import time
import threading

ls_privkey = PrivateKey(unhexlify(
b'1111111111111111111111111111111111111111111111111111111111111111'
))
listener = LightningServerSocket(ls_privkey)
print("Node ID: {}".format(ls_privkey.public_key()))

listener.bind(('0.0.0.0', 9735))
listener.listen()
c, a = listener.accept()

c.send_message(b'\x00\x10\x00\x00\x00\x01\xaa')
print(c.read_message())

num_pings = 10000


def read_loop(c):
for i in range(num_pings):
print("Recv", i, hexlify(c.read_message()))


t = threading.Thread(target=read_loop, args=(c,))
t.daemon = True
t.start()
for i in range(num_pings):
m = b'\x00\x12\x00\x01\x00\x01\x00'
c.send_message(m)
print("Sent", i, hexlify(m))
time.sleep(0.01)

t.join()
1 change: 1 addition & 0 deletions contrib/pyln-proto/pyln/proto/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
__version__ = '0.0.1'
Loading

0 comments on commit 4caf76b

Please sign in to comment.