2017-08-03 04:53:53 +03:00
# How to write a Python gRPC client for the Lightning Network Daemon
2017-03-01 02:49:10 +03:00
2017-03-01 03:09:35 +03:00
This section enumerates what you need to do to write a client that communicates
2017-12-20 04:28:38 +03:00
with `lnd` in Python.
2017-03-01 02:49:10 +03:00
2020-05-04 10:52:49 +03:00
## Setup and Installation
2017-08-03 04:53:53 +03:00
2017-03-01 03:09:35 +03:00
Lnd uses the gRPC protocol for communication with clients like lncli. gRPC is
based on protocol buffers and as such, you will need to compile the lnd proto
2017-08-03 04:53:53 +03:00
file in Python before you can use it to communicate with lnd.
2017-03-01 02:49:10 +03:00
2020-05-04 10:52:49 +03:00
1. Create a virtual environment for your project
2021-01-17 16:58:57 +03:00
```shell
⛰ virtualenv lnd
2020-05-04 10:52:49 +03:00
```
2. Activate the virtual environment
2021-01-17 16:58:57 +03:00
```shell
⛰ source lnd/bin/activate
2020-05-04 10:52:49 +03:00
```
3. Install dependencies (googleapis-common-protos is required due to the use of
2017-03-01 03:09:35 +03:00
google/api/annotations.proto)
2021-01-17 16:58:57 +03:00
```shell
lnd ⛰ pip install grpcio grpcio-tools googleapis-common-protos
2020-05-04 10:52:49 +03:00
```
4. Clone the google api's repository (required due to the use of
2017-03-01 03:09:35 +03:00
google/api/annotations.proto)
2021-01-17 16:58:57 +03:00
```shell
lnd ⛰ git clone https://github.com/googleapis/googleapis.git
2020-05-04 10:52:49 +03:00
```
5. Copy the lnd rpc.proto file (you'll find this at
2017-08-03 04:53:53 +03:00
[lnrpc/rpc.proto ](https://github.com/lightningnetwork/lnd/blob/master/lnrpc/rpc.proto ))
or just download it
2021-01-17 16:58:57 +03:00
```shell
lnd ⛰ curl -o rpc.proto -s https://raw.githubusercontent.com/lightningnetwork/lnd/master/lnrpc/rpc.proto
2020-05-04 10:52:49 +03:00
```
6. Compile the proto file
2021-01-17 16:58:57 +03:00
```shell
lnd ⛰ python -m grpc_tools.protoc --proto_path=googleapis:. --python_out=. --grpc_python_out=. rpc.proto
2020-05-04 10:52:49 +03:00
```
2017-03-01 02:49:10 +03:00
2017-03-01 03:09:35 +03:00
After following these steps, two files `rpc_pb2.py` and `rpc_pb2_grpc.py` will
2017-08-03 04:53:53 +03:00
be generated. These files will be imported in your project anytime you use
Python gRPC.
2017-03-01 02:49:10 +03:00
2020-05-04 10:53:07 +03:00
### Generating RPC modules for subservers
If you want to use any of the subservers' functionality, you also need to
generate the python modules for them.
For example, if you want to generate the RPC modules for the `Router` subserver
(located/defined in `routerrpc/router.proto` ), you need to run the following two
extra steps (after completing all 6 step described above) to get the
`router_pb2.py` and `router_pb2_grpc.py` :
2021-01-17 16:58:57 +03:00
```shell
lnd ⛰ curl -o router.proto -s https://raw.githubusercontent.com/lightningnetwork/lnd/master/lnrpc/routerrpc/router.proto
lnd ⛰ python -m grpc_tools.protoc --proto_path=googleapis:. --python_out=. --grpc_python_out=. router.proto
2020-05-04 10:53:07 +03:00
```
2020-05-04 10:52:49 +03:00
### Imports and Client
2017-03-01 02:49:10 +03:00
2018-02-07 06:11:11 +03:00
Every time you use Python gRPC, you will have to import the generated rpc modules
2017-08-03 04:53:53 +03:00
and set up a channel and stub to your connect to your `lnd` node:
2017-03-01 02:49:10 +03:00
2017-08-03 04:53:53 +03:00
```python
2017-03-01 02:49:10 +03:00
import rpc_pb2 as ln
import rpc_pb2_grpc as lnrpc
2017-08-03 04:53:53 +03:00
import grpc
2017-12-28 17:04:01 +03:00
import os
2017-03-01 02:49:10 +03:00
2018-03-21 03:54:19 +03:00
# Due to updated ECDSA generated tls.cert we need to let gprc know that
# we need to use that cipher suite otherwise there will be a handhsake
# error when we communicate with the lnd rpc server.
os.environ["GRPC_SSL_CIPHER_SUITES"] = 'HIGH+ECDSA'
2017-08-09 08:30:51 +03:00
# Lnd cert is at ~/.lnd/tls.cert on Linux and
# ~/Library/Application Support/Lnd/tls.cert on Mac
2018-03-20 23:42:53 +03:00
cert = open(os.path.expanduser('~/.lnd/tls.cert'), 'rb').read()
2017-08-09 08:30:51 +03:00
creds = grpc.ssl_channel_credentials(cert)
channel = grpc.secure_channel('localhost:10009', creds)
2017-03-01 02:49:10 +03:00
stub = lnrpc.LightningStub(channel)
2017-08-03 04:53:53 +03:00
```
2017-03-01 02:49:10 +03:00
2020-05-04 10:52:49 +03:00
## Examples
2017-08-03 04:53:53 +03:00
2017-08-09 08:30:51 +03:00
Let's walk through some examples of Python gRPC clients. These examples assume
that you have at least two `lnd` nodes running, the RPC location of one of which
is at the default `localhost:10009` , with an open channel between the two nodes.
2017-08-03 04:53:53 +03:00
2020-05-04 10:52:49 +03:00
### Simple RPC
2017-08-03 04:53:53 +03:00
```python
# Retrieve and display the wallet balance
2018-04-09 23:01:39 +03:00
response = stub.WalletBalance(ln.WalletBalanceRequest())
2018-03-20 23:42:53 +03:00
print(response.total_balance)
2017-03-01 02:49:10 +03:00
```
2017-03-01 03:09:35 +03:00
2020-05-04 10:52:49 +03:00
### Response-streaming RPC
2017-08-03 04:53:53 +03:00
```python
request = ln.InvoiceSubscription()
2017-12-28 17:04:01 +03:00
for invoice in stub.SubscribeInvoices(request):
2018-03-20 23:42:53 +03:00
print(invoice)
2017-08-03 04:53:53 +03:00
```
2017-08-09 08:30:51 +03:00
Now, create an invoice for your node at `localhost:10009` and send a payment to
it from another node.
2021-01-17 16:58:57 +03:00
```shell
lnd ⛰ lncli addinvoice --amt=100
2017-08-09 08:30:51 +03:00
{
"r_hash": < R_HASH > ,
"pay_req": < PAY_REQ >
}
2021-01-17 16:58:57 +03:00
lnd ⛰ lncli sendpayment --pay_req=< PAY_REQ >
2017-08-09 08:30:51 +03:00
```
Your Python console should now display the details of the recently satisfied
2017-08-03 04:53:53 +03:00
invoice.
2020-05-04 10:52:49 +03:00
### Bidirectional-streaming RPC
2017-08-03 04:53:53 +03:00
```python
from time import sleep
import codecs
def request_generator(dest, amt):
# Initialization code here
counter = 0
print("Starting up")
while True:
request = ln.SendRequest(
dest=dest,
amt=amt,
)
yield request
# Alter parameters here
counter += 1
sleep(2)
# Outputs from lncli are hex-encoded
dest_hex = < RECEIVER_ID_PUBKEY >
dest_bytes = codecs.decode(dest_hex, 'hex')
request_iterable = request_generator(dest=dest_bytes, amt=100)
for payment in stub.SendPayment(request_iterable):
2018-03-20 23:42:53 +03:00
print(payment)
2017-08-03 04:53:53 +03:00
```
This example will send a payment of 100 satoshis every 2 seconds.
2020-05-04 10:52:49 +03:00
### Using Macaroons
2018-03-19 19:55:31 +03:00
To authenticate using macaroons you need to include the macaroon in the metadata of the request.
```python
2018-03-23 08:28:11 +03:00
import codecs
2018-08-22 23:11:20 +03:00
# Lnd admin macaroon is at ~/.lnd/data/chain/bitcoin/simnet/admin.macaroon on Linux and
# ~/Library/Application Support/Lnd/data/chain/bitcoin/simnet/admin.macaroon on Mac
with open(os.path.expanduser('~/.lnd/data/chain/bitcoin/simnet/admin.macaroon'), 'rb') as f:
2018-03-19 19:55:31 +03:00
macaroon_bytes = f.read()
2018-03-23 08:28:11 +03:00
macaroon = codecs.encode(macaroon_bytes, 'hex')
2018-03-19 19:55:31 +03:00
```
The simplest approach to use the macaroon is to include the metadata in each request as shown below.
```python
stub.GetInfo(ln.GetInfoRequest(), metadata=[('macaroon', macaroon)])
```
However, this can get tiresome to do for each request, so to avoid explicitly including the macaroon we can update the credentials to include it automatically.
```python
def metadata_callback(context, callback):
# for more info see grpc docs
2018-03-23 08:28:11 +03:00
callback([('macaroon', macaroon)], None)
2018-03-19 19:55:31 +03:00
# build ssl credentials using the cert the same as before
cert_creds = grpc.ssl_channel_credentials(cert)
# now build meta data credentials
auth_creds = grpc.metadata_call_credentials(metadata_callback)
# combine the cert credentials and the macaroon auth credentials
# such that every call is properly encrypted and authenticated
combined_creds = grpc.composite_channel_credentials(cert_creds, auth_creds)
# finally pass in the combined credentials when creating a channel
channel = grpc.secure_channel('localhost:10009', combined_creds)
stub = lnrpc.LightningStub(channel)
# now every call will be made with the macaroon already included
stub.GetInfo(ln.GetInfoRequest())
```
2020-05-04 10:52:49 +03:00
## Conclusion
2017-08-03 04:53:53 +03:00
2017-03-01 03:09:35 +03:00
With the above, you should have all the `lnd` related `gRPC` dependencies
installed locally into your virtual environment. In order to get up to speed
with `protofbuf` usage from Python, see [this official `protobuf` tutorial for
Python](https://developers.google.com/protocol-buffers/docs/pythontutorial).
Additionally, [this official gRPC
2017-08-03 04:53:53 +03:00
resource](http://www.grpc.io/docs/tutorials/basic/python.html) provides more
details around how to drive `gRPC` from Python.
2020-05-04 10:54:50 +03:00
## API documentation
There is an [online API documentation ](https://api.lightning.community?python )
available that shows all currently existing RPC methods, including code snippets
on how to use them.