diff --git a/docs/grpc/python.md b/docs/grpc/python.md index 578735b64..867183349 100644 --- a/docs/grpc/python.md +++ b/docs/grpc/python.md @@ -53,9 +53,14 @@ import rpc_pb2_grpc as lnrpc import grpc import os +# 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' + # Lnd cert is at ~/.lnd/tls.cert on Linux and # ~/Library/Application Support/Lnd/tls.cert on Mac -cert = open(os.path.expanduser('~/.lnd/tls.cert')).read() +cert = open(os.path.expanduser('~/.lnd/tls.cert'), 'rb').read() creds = grpc.ssl_channel_credentials(cert) channel = grpc.secure_channel('localhost:10009', creds) stub = lnrpc.LightningStub(channel) @@ -72,7 +77,7 @@ is at the default `localhost:10009`, with an open channel between the two nodes. ```python # Retrieve and display the wallet balance response = stub.WalletBalance(ln.WalletBalanceRequest(witness_only=True)) -print response.total_balance +print(response.total_balance) ``` #### Response-streaming RPC @@ -80,7 +85,7 @@ print response.total_balance ```python request = ln.InvoiceSubscription() for invoice in stub.SubscribeInvoices(request): - print invoice + print(invoice) ``` Now, create an invoice for your node at `localhost:10009`and send a payment to @@ -124,10 +129,55 @@ dest_bytes = codecs.decode(dest_hex, 'hex') request_iterable = request_generator(dest=dest_bytes, amt=100) for payment in stub.SendPayment(request_iterable): - print payment + print(payment) ``` This example will send a payment of 100 satoshis every 2 seconds. +#### Using Macaroons + +To authenticate using macaroons you need to include the macaroon in the metadata of the request. + +```python +# Lnd admin macaroon is at ~/.lnd/admin.macaroon on Linux and +# ~/Library/Application Support/Lnd/admin.macaroon on Mac +with open('~/.lnd/admin.macaroon', 'rb') as f: + macaroon_bytes = f.read() + macaroon = codecs.decode(macaroon_bytes, 'hex') +``` + +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 + callback([('macaroon', self.macaroon)], None) + + +# 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()) +``` + + ### Conclusion With the above, you should have all the `lnd` related `gRPC` dependencies