Merge pull request #400 from arcbtc/FastAPI
fix: switch from purerpc to grpcio for LND Wallet
This commit is contained in:
commit
5eae8e1b11
|
@ -29,7 +29,7 @@ Using this wallet requires the installation of the `pylightning` Python package.
|
|||
|
||||
### LND (gRPC)
|
||||
|
||||
Using this wallet requires the installation of the `lndgrpc` and `purerpc` Python packages.
|
||||
Using this wallet requires the installation of the `grpcio` Python packages.
|
||||
|
||||
- `LNBITS_BACKEND_WALLET_CLASS`: **LndWallet**
|
||||
- `LND_GRPC_ENDPOINT`: ip_address
|
||||
|
|
0
lnbits/wallets/lnd_grpc_files/__init__.py
Normal file
0
lnbits/wallets/lnd_grpc_files/__init__.py
Normal file
14326
lnbits/wallets/lnd_grpc_files/lightning_pb2.py
Normal file
14326
lnbits/wallets/lnd_grpc_files/lightning_pb2.py
Normal file
File diff suppressed because one or more lines are too long
3340
lnbits/wallets/lnd_grpc_files/lightning_pb2_grpc.py
Normal file
3340
lnbits/wallets/lnd_grpc_files/lightning_pb2_grpc.py
Normal file
File diff suppressed because it is too large
Load Diff
|
@ -1,20 +1,17 @@
|
|||
try:
|
||||
import lndgrpc # type: ignore
|
||||
from lndgrpc.common import ln # type: ignore
|
||||
import grpc
|
||||
except ImportError: # pragma: nocover
|
||||
lndgrpc = None
|
||||
|
||||
try:
|
||||
import purerpc # type: ignore
|
||||
except ImportError: # pragma: nocover
|
||||
purerpc = None
|
||||
grpc = None
|
||||
|
||||
import binascii
|
||||
import base64
|
||||
import hashlib
|
||||
from os import getenv
|
||||
from os import environ, error, getenv
|
||||
from typing import Optional, Dict, AsyncGenerator
|
||||
|
||||
import lnbits.wallets.lnd_grpc_files.lightning_pb2 as ln
|
||||
import lnbits.wallets.lnd_grpc_files.lightning_pb2_grpc as lnrpc
|
||||
|
||||
from .base import (
|
||||
StatusResponse,
|
||||
InvoiceResponse,
|
||||
|
@ -71,16 +68,17 @@ def stringify_checking_id(r_hash: bytes) -> str:
|
|||
return base64.b64encode(r_hash).decode("utf-8").replace("/", "_")
|
||||
|
||||
|
||||
# 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.
|
||||
environ["GRPC_SSL_CIPHER_SUITES"] = "HIGH+ECDSA"
|
||||
|
||||
|
||||
class LndWallet(Wallet):
|
||||
def __init__(self):
|
||||
if lndgrpc is None: # pragma: nocover
|
||||
if grpc is None: # pragma: nocover
|
||||
raise ImportError(
|
||||
"The `lndgrpc` library must be installed to use `LndWallet`."
|
||||
)
|
||||
|
||||
if purerpc is None: # pragma: nocover
|
||||
raise ImportError(
|
||||
"The `purerpc` library must be installed to use `LndWallet`."
|
||||
"The `grpcio` library must be installed to use `GRPC LndWallet`. Alternatively try using the LndRESTWallet."
|
||||
)
|
||||
|
||||
endpoint = getenv("LND_GRPC_ENDPOINT")
|
||||
|
@ -88,25 +86,34 @@ class LndWallet(Wallet):
|
|||
self.port = int(getenv("LND_GRPC_PORT"))
|
||||
self.cert_path = getenv("LND_GRPC_CERT") or getenv("LND_CERT")
|
||||
|
||||
self.macaroon_path = (
|
||||
macaroon_path = (
|
||||
getenv("LND_GRPC_MACAROON")
|
||||
or getenv("LND_GRPC_ADMIN_MACAROON")
|
||||
or getenv("LND_ADMIN_MACAROON")
|
||||
or getenv("LND_GRPC_INVOICE_MACAROON")
|
||||
or getenv("LND_INVOICE_MACAROON")
|
||||
)
|
||||
network = getenv("LND_GRPC_NETWORK", "mainnet")
|
||||
|
||||
self.rpc = lndgrpc.LNDClient(
|
||||
f"{self.endpoint}:{self.port}",
|
||||
cert_filepath=self.cert_path,
|
||||
network=network,
|
||||
macaroon_filepath=self.macaroon_path,
|
||||
if macaroon_path.split(".")[-1] == "macaroon":
|
||||
self.macaroon = load_macaroon(macaroon_path)
|
||||
else:
|
||||
self.macaroon = macaroon_path
|
||||
|
||||
cert = open(self.cert_path, "rb").read()
|
||||
creds = grpc.ssl_channel_credentials(cert)
|
||||
auth_creds = grpc.metadata_call_credentials(self.metadata_callback)
|
||||
composite_creds = grpc.composite_channel_credentials(creds, auth_creds)
|
||||
channel = grpc.aio.secure_channel(
|
||||
f"{self.endpoint}:{self.port}", composite_creds
|
||||
)
|
||||
self.rpc = lnrpc.LightningStub(channel)
|
||||
|
||||
def metadata_callback(self, _, callback):
|
||||
callback([("macaroon", self.macaroon)], None)
|
||||
|
||||
async def status(self) -> StatusResponse:
|
||||
try:
|
||||
resp = self.rpc._ln_stub.ChannelBalance(ln.ChannelBalanceRequest())
|
||||
resp = await self.rpc.ChannelBalance(ln.ChannelBalanceRequest())
|
||||
except Exception as exc:
|
||||
return StatusResponse(str(exc), 0)
|
||||
|
||||
|
@ -127,7 +134,7 @@ class LndWallet(Wallet):
|
|||
|
||||
try:
|
||||
req = ln.Invoice(**params)
|
||||
resp = self.rpc._ln_stub.AddInvoice(req)
|
||||
resp = await self.rpc.AddInvoice(req)
|
||||
except Exception as exc:
|
||||
error_message = str(exc)
|
||||
return InvoiceResponse(False, None, None, error_message)
|
||||
|
@ -137,7 +144,9 @@ class LndWallet(Wallet):
|
|||
return InvoiceResponse(True, checking_id, payment_request, None)
|
||||
|
||||
async def pay_invoice(self, bolt11: str) -> PaymentResponse:
|
||||
resp = self.rpc.send_payment(payment_request=bolt11)
|
||||
resp = await self.rpc.SendPayment(
|
||||
lnrpc.SendPaymentRequest(payment_request=bolt11)
|
||||
)
|
||||
|
||||
if resp.payment_error:
|
||||
return PaymentResponse(False, "", 0, None, resp.payment_error)
|
||||
|
@ -158,7 +167,7 @@ class LndWallet(Wallet):
|
|||
# that use different checking_id formats
|
||||
return PaymentStatus(None)
|
||||
|
||||
resp = self.rpc.lookup_invoice(r_hash.hex())
|
||||
resp = await self.rpc.LookupInvoice(ln.PaymentHash(r_hash=r_hash))
|
||||
if resp.settled:
|
||||
return PaymentStatus(True)
|
||||
|
||||
|
@ -168,29 +177,15 @@ class LndWallet(Wallet):
|
|||
return PaymentStatus(True)
|
||||
|
||||
async def paid_invoices_stream(self) -> AsyncGenerator[str, None]:
|
||||
async with purerpc.secure_channel(
|
||||
self.endpoint, self.port, get_ssl_context(self.cert_path)
|
||||
) as channel:
|
||||
client = purerpc.Client("lnrpc.Lightning", channel)
|
||||
subscribe_invoices = client.get_method_stub(
|
||||
"SubscribeInvoices",
|
||||
purerpc.RPCSignature(
|
||||
purerpc.Cardinality.UNARY_STREAM, ln.InvoiceSubscription, ln.Invoice
|
||||
),
|
||||
)
|
||||
|
||||
if self.macaroon_path.split(".")[-1] == "macaroon":
|
||||
macaroon = load_macaroon(self.macaroon_path)
|
||||
else:
|
||||
macaroon = self.macaroon_path
|
||||
|
||||
async for inv in subscribe_invoices(
|
||||
ln.InvoiceSubscription(), metadata=[("macaroon", macaroon)]
|
||||
):
|
||||
if not inv.settled:
|
||||
request = ln.InvoiceSubscription()
|
||||
try:
|
||||
async for i in self.rpc.SubscribeInvoices(request):
|
||||
if not i.settled:
|
||||
continue
|
||||
|
||||
checking_id = stringify_checking_id(inv.r_hash)
|
||||
checking_id = stringify_checking_id(i.r_hash)
|
||||
yield checking_id
|
||||
except error:
|
||||
print(error)
|
||||
|
||||
print("lost connection to lnd InvoiceSubscription, please restart lnbits.")
|
||||
|
|
Loading…
Reference in New Issue
Block a user