github.com/decred/dcrlnd@v0.7.6/docs/grpc/python.md (about)

     1  # How to write a Python gRPC client for the Lightning Network Daemon
     2  
     3  This section enumerates what you need to do to write a client that communicates
     4  with `lnd` in Python.
     5  
     6  ## Setup and Installation
     7  
     8  Lnd uses the gRPC protocol for communication with clients like lncli. gRPC is
     9  based on protocol buffers and as such, you will need to compile the lnd proto
    10  file in Python before you can use it to communicate with lnd.
    11  
    12  1. Create a virtual environment for your project
    13      ```
    14      $ virtualenv lnd
    15      ```
    16  2. Activate the virtual environment
    17      ```
    18      $ source lnd/bin/activate
    19      ```
    20  3. Install dependencies (googleapis-common-protos is required due to the use of
    21    google/api/annotations.proto)
    22      ```
    23      (lnd)$ pip install grpcio grpcio-tools googleapis-common-protos
    24      ```
    25  4. Clone the google api's repository (required due to the use of
    26    google/api/annotations.proto)
    27      ```
    28      (lnd)$ git clone https://github.com/googleapis/googleapis.git
    29      ```
    30  5. Copy the lnd lightning.proto file (you'll find this at
    31    [lnrpc/lightning.proto](https://github.com/lightningnetwork/lnd/blob/master/lnrpc/lightning.proto))
    32    or just download it
    33      ```shell
    34      lnd ⛰  curl -o lightning.proto -s https://raw.githubusercontent.com/lightningnetwork/lnd/master/lnrpc/lightning.proto
    35      ```
    36  6. Compile the proto file
    37      ```shell
    38      lnd ⛰  python -m grpc_tools.protoc --proto_path=googleapis:. --python_out=. --grpc_python_out=. lightning.proto
    39      ```
    40  
    41  After following these steps, two files `lightning_pb2.py` and
    42  `lightning_pb2_grpc.py` will be generated. These files will be imported in your
    43  project anytime you use Python gRPC.
    44  
    45  ### Generating RPC modules for subservers
    46  
    47  If you want to use any of the subservers' functionality, you also need to
    48  generate the python modules for them.
    49  
    50  For example, if you want to generate the RPC modules for the `Router` subserver
    51  (located/defined in `routerrpc/router.proto`), you need to run the following two
    52  extra steps (after completing all 6 step described above) to get the
    53  `router_pb2.py` and `router_pb2_grpc.py`:
    54  
    55  ```
    56  (lnd)$ curl -o router.proto -s https://raw.githubusercontent.com/lightningnetwork/lnd/master/lnrpc/routerrpc/router.proto
    57  (lnd)$ python -m grpc_tools.protoc --proto_path=googleapis:. --python_out=. --grpc_python_out=. router.proto
    58  ```
    59  
    60  ### Imports and Client
    61  
    62  Every time you use Python gRPC, you will have to import the generated rpc modules
    63  and set up a channel and stub to your connect to your `lnd` node.
    64  
    65  Note that when an IP address is used to connect to the node (e.g. 192.168.1.21 instead of localhost) you need to add `--tlsextraip=192.168.1.21` to your `lnd` configuration and re-generate the certificate (delete tls.cert and tls.key and restart lnd).
    66  
    67  ```python
    68  import lightning_pb2 as ln
    69  import lightning_pb2_grpc as lnrpc
    70  import grpc
    71  import os
    72  
    73  # Due to updated ECDSA generated tls.cert we need to let gprc know that
    74  # we need to use that cipher suite otherwise there will be a handhsake
    75  # error when we communicate with the lnd rpc server.
    76  os.environ["GRPC_SSL_CIPHER_SUITES"] = 'HIGH+ECDSA'
    77  
    78  # Lnd cert is at ~/.lnd/tls.cert on Linux and
    79  # ~/Library/Application Support/Lnd/tls.cert on Mac
    80  cert = open(os.path.expanduser('~/.lnd/tls.cert'), 'rb').read()
    81  creds = grpc.ssl_channel_credentials(cert)
    82  channel = grpc.secure_channel('localhost:10009', creds)
    83  stub = lnrpc.LightningStub(channel)
    84  ```
    85  
    86  ## Examples
    87  
    88  Let's walk through some examples of Python gRPC clients. These examples assume
    89  that you have at least two `lnd` nodes running, the RPC location of one of which
    90  is at the default `localhost:10009`, with an open channel between the two nodes.
    91  
    92  ### Simple RPC
    93  
    94  ```python
    95  # Retrieve and display the wallet balance
    96  response = stub.WalletBalance(ln.WalletBalanceRequest())
    97  print(response.total_balance)
    98  ```
    99  
   100  ### Response-streaming RPC
   101  
   102  ```python
   103  request = ln.InvoiceSubscription()
   104  for invoice in stub.SubscribeInvoices(request):
   105      print(invoice)
   106  ```
   107  
   108  Now, create an invoice for your node at `localhost:10009`and send a payment to
   109  it from another node.
   110  ```bash
   111  $ lncli addinvoice --amt=100
   112  {
   113  	"r_hash": <R_HASH>,
   114  	"pay_req": <PAY_REQ>
   115  }
   116  $ lncli sendpayment --pay_req=<PAY_REQ>
   117  ```
   118  
   119  Your Python console should now display the details of the recently satisfied
   120  invoice.
   121  
   122  ### Bidirectional-streaming RPC
   123  
   124  ```python
   125  from time import sleep
   126  import codecs
   127  
   128  def request_generator(dest, amt):
   129        # Initialization code here
   130        counter = 0
   131        print("Starting up")
   132        while True:
   133            request = ln.SendRequest(
   134                dest=dest,
   135                amt=amt,
   136            )
   137            yield request
   138            # Alter parameters here
   139            counter += 1
   140            sleep(2)
   141  
   142  # Outputs from lncli are hex-encoded
   143  dest_hex = <RECEIVER_ID_PUBKEY>
   144  dest_bytes = codecs.decode(dest_hex, 'hex')
   145  
   146  request_iterable = request_generator(dest=dest_bytes, amt=100)
   147  
   148  for payment in stub.SendPayment(request_iterable):
   149      print(payment)
   150  ```
   151  This example will send a payment of 100 atoms every 2 seconds.
   152  
   153  ### Using Macaroons
   154  
   155  To authenticate using macaroons you need to include the macaroon in the metadata of the request.
   156  
   157  ```python
   158  import codecs
   159  
   160  # Lnd admin macaroon is at ~/.lnd/data/chain/bitcoin/simnet/admin.macaroon on Linux and
   161  # ~/Library/Application Support/Lnd/data/chain/bitcoin/simnet/admin.macaroon on Mac
   162  with open(os.path.expanduser('~/.lnd/data/chain/bitcoin/simnet/admin.macaroon'), 'rb') as f:
   163      macaroon_bytes = f.read()
   164      macaroon = codecs.encode(macaroon_bytes, 'hex')
   165  ```
   166  
   167  The simplest approach to use the macaroon is to include the metadata in each request as shown below.
   168  
   169  ```python
   170  stub.GetInfo(ln.GetInfoRequest(), metadata=[('macaroon', macaroon)])
   171  ```
   172  
   173  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.
   174  
   175  ```python
   176  def metadata_callback(context, callback):
   177      # for more info see grpc docs
   178      callback([('macaroon', macaroon)], None)
   179  
   180  
   181  # build ssl credentials using the cert the same as before
   182  cert_creds = grpc.ssl_channel_credentials(cert)
   183  
   184  # now build meta data credentials
   185  auth_creds = grpc.metadata_call_credentials(metadata_callback)
   186  
   187  # combine the cert credentials and the macaroon auth credentials
   188  # such that every call is properly encrypted and authenticated
   189  combined_creds = grpc.composite_channel_credentials(cert_creds, auth_creds)
   190  
   191  # finally pass in the combined credentials when creating a channel
   192  channel = grpc.secure_channel('localhost:10009', combined_creds)
   193  stub = lnrpc.LightningStub(channel)
   194  
   195  # now every call will be made with the macaroon already included
   196  stub.GetInfo(ln.GetInfoRequest())
   197  ```
   198  
   199  
   200  ## Conclusion
   201  
   202  With the above, you should have all the `lnd` related `gRPC` dependencies
   203  installed locally into your virtual environment. In order to get up to speed
   204  with `protofbuf` usage from Python, see [this official `protobuf` tutorial for
   205  Python](https://developers.google.com/protocol-buffers/docs/pythontutorial).
   206  Additionally, [this official gRPC
   207  resource](http://www.grpc.io/docs/tutorials/basic/python.html) provides more
   208  details around how to drive `gRPC` from Python.
   209  
   210  ## API documentation
   211  
   212  There is an [online API documentation](https://api.lightning.community?python)
   213  available that shows all currently existing RPC methods, including code snippets
   214  on how to use them.
   215  
   216  ## Special Scenarios
   217  
   218  Due to a conflict between lnd's `UpdateChannelPolicy` gRPC endpoint and the python reserved word list, the follow syntax is required in order to use `PolicyUpdateRequest` with the `global` variable.
   219  Here is an example of a working format that allows for use of a reserved word `global` in this scenario.
   220  
   221  ```
   222  args = {'global': True, 'base_fee_msat': 1000, 'fee_rate': 0.000001, 'time_lock_delta': 40}
   223  stub.UpdateChannelPolicy(ln.PolicyUpdateRequest(**args))
   224  ```