mirror of
https://github.com/lnbits/lnbits-legend.git
synced 2025-03-03 17:37:06 +01:00
make lndgrpc work using the purerpc library and a manually-declared method.
This commit is contained in:
parent
9994e61615
commit
f5b8ed8fc6
6 changed files with 94 additions and 27 deletions
|
@ -34,7 +34,7 @@ You will need to copy `.env.example` to `.env`, then set variables there.
|
|||

|
||||
|
||||
You might also need to install additional packages, depending on the [backend wallet](../guide/wallets.md) you use.
|
||||
E.g. when you want to use LND you have to `pipenv run pip install lndgrpc`.
|
||||
E.g. when you want to use LND you have to `pipenv run pip install lndgrpc` and `pipenv run pip install pureprc`.
|
||||
|
||||
Take a look at [Polar][polar] for an excellent way of spinning up a Lightning Network dev environment.
|
||||
|
||||
|
|
|
@ -32,4 +32,5 @@ E.g. when you want to use LND you have to run:
|
|||
|
||||
```sh
|
||||
./venv/bin/pip install lndgrpc
|
||||
./venv/bin/pip install purerpc
|
||||
```
|
||||
|
|
|
@ -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` Python package.
|
||||
Using this wallet requires the installation of the `lndgrpc` and `purerpc` Python packages.
|
||||
|
||||
- `LNBITS_BACKEND_WALLET_CLASS`: **LndWallet**
|
||||
- `LND_GRPC_ENDPOINT`: ip_address
|
||||
|
|
|
@ -4,6 +4,12 @@ try:
|
|||
except ImportError: # pragma: nocover
|
||||
lndgrpc = None
|
||||
|
||||
try:
|
||||
import purerpc # type: ignore
|
||||
except ImportError: # pragma: nocover
|
||||
purerpc = None
|
||||
|
||||
import trio # type: ignore
|
||||
import binascii
|
||||
import base64
|
||||
import hashlib
|
||||
|
@ -34,33 +40,31 @@ class LndWallet(Wallet):
|
|||
if lndgrpc is None: # pragma: nocover
|
||||
raise ImportError("The `lndgrpc` library must be installed to use `LndWallet`.")
|
||||
|
||||
if purerpc is None:
|
||||
import warnings
|
||||
|
||||
warnings.warn("To enable invoices subscription on `LndWallet` the `purerpc` library must be nistalled.")
|
||||
|
||||
endpoint = getenv("LND_GRPC_ENDPOINT")
|
||||
endpoint = endpoint[:-1] if endpoint.endswith("/") else endpoint
|
||||
port = getenv("LND_GRPC_PORT")
|
||||
cert = getenv("LND_GRPC_CERT") or getenv("LND_CERT")
|
||||
auth_admin = getenv("LND_GRPC_ADMIN_MACAROON") or getenv("LND_ADMIN_MACAROON")
|
||||
auth_invoices = getenv("LND_GRPC_INVOICE_MACAROON") or getenv("LND_INVOICE_MACAROON")
|
||||
self.endpoint = endpoint[:-1] if endpoint.endswith("/") else endpoint
|
||||
self.port = int(getenv("LND_GRPC_PORT"))
|
||||
self.cert_path = getenv("LND_GRPC_CERT") or getenv("LND_CERT")
|
||||
self.auth_admin = getenv("LND_GRPC_ADMIN_MACAROON") or getenv("LND_ADMIN_MACAROON")
|
||||
self.auth_invoices = getenv("LND_GRPC_INVOICE_MACAROON") or getenv("LND_INVOICE_MACAROON")
|
||||
network = getenv("LND_GRPC_NETWORK", "mainnet")
|
||||
|
||||
self.admin_rpc = lndgrpc.LNDClient(
|
||||
endpoint + ":" + port,
|
||||
cert_filepath=cert,
|
||||
f"{self.endpoint}:{self.port}",
|
||||
cert_filepath=self.cert_path,
|
||||
network=network,
|
||||
macaroon_filepath=auth_admin,
|
||||
macaroon_filepath=self.auth_admin,
|
||||
)
|
||||
|
||||
self.invoices_rpc = lndgrpc.LNDClient(
|
||||
endpoint + ":" + port,
|
||||
cert_filepath=cert,
|
||||
f"{self.endpoint}:{self.port}",
|
||||
cert_filepath=self.cert_path,
|
||||
network=network,
|
||||
macaroon_filepath=auth_invoices,
|
||||
)
|
||||
|
||||
self.async_rpc = lndgrpc.AsyncLNDClient(
|
||||
endpoint + ":" + port,
|
||||
cert_filepath=cert,
|
||||
network=network,
|
||||
macaroon_filepath=auth_invoices,
|
||||
macaroon_filepath=self.auth_invoices,
|
||||
)
|
||||
|
||||
def create_invoice(
|
||||
|
@ -114,9 +118,71 @@ class LndWallet(Wallet):
|
|||
return PaymentStatus(True)
|
||||
|
||||
async def paid_invoices_stream(self) -> AsyncGenerator[str, None]:
|
||||
async for inv in self.async_rpc._ln_stub.SubscribeInvoices(ln.InvoiceSubscription()):
|
||||
if not inv.settled:
|
||||
continue
|
||||
if not purerpc:
|
||||
trio.sleep(5)
|
||||
yield ""
|
||||
|
||||
checking_id = stringify_checking_id(inv.r_hash)
|
||||
yield checking_id
|
||||
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,
|
||||
),
|
||||
)
|
||||
macaroon = load_macaroon(self.auth_admin)
|
||||
|
||||
async for inv in subscribe_invoices(
|
||||
ln.InvoiceSubscription(),
|
||||
metadata=[("macaroon", macaroon)],
|
||||
):
|
||||
if not inv.settled:
|
||||
continue
|
||||
|
||||
checking_id = stringify_checking_id(inv.r_hash)
|
||||
yield checking_id
|
||||
|
||||
|
||||
def get_ssl_context(cert_path: str):
|
||||
import ssl
|
||||
|
||||
context = ssl.SSLContext(ssl.PROTOCOL_TLS)
|
||||
context.options |= ssl.OP_NO_SSLv2
|
||||
context.options |= ssl.OP_NO_SSLv3
|
||||
context.options |= ssl.OP_NO_TLSv1
|
||||
context.options |= ssl.OP_NO_TLSv1_1
|
||||
context.options |= ssl.OP_NO_COMPRESSION
|
||||
context.set_ciphers(
|
||||
":".join(
|
||||
[
|
||||
"ECDHE+AESGCM",
|
||||
"ECDHE+CHACHA20",
|
||||
"DHE+AESGCM",
|
||||
"DHE+CHACHA20",
|
||||
"ECDH+AESGCM",
|
||||
"DH+AESGCM",
|
||||
"ECDH+AES",
|
||||
"DH+AES",
|
||||
"RSA+AESGCM",
|
||||
"RSA+AES",
|
||||
"!aNULL",
|
||||
"!eNULL",
|
||||
"!MD5",
|
||||
"!DSS",
|
||||
]
|
||||
)
|
||||
)
|
||||
context.load_verify_locations(capath=cert_path)
|
||||
return context
|
||||
|
||||
|
||||
def load_macaroon(macaroon_path: str):
|
||||
with open(macaroon_path, "rb") as f:
|
||||
macaroon_bytes = f.read()
|
||||
return macaroon_bytes.hex()
|
||||
|
|
|
@ -95,6 +95,6 @@ class LNPayWallet(Wallet):
|
|||
)
|
||||
data = r.json()
|
||||
if data["settled"]:
|
||||
self.send.send(lntx_id)
|
||||
await self.send.send(lntx_id)
|
||||
|
||||
return "", HTTPStatus.NO_CONTENT
|
||||
|
|
|
@ -97,5 +97,5 @@ class OpenNodeWallet(Wallet):
|
|||
print("invalid webhook, not from opennode")
|
||||
return "", HTTPStatus.NO_CONTENT
|
||||
|
||||
self.send.send(charge_id)
|
||||
await self.send.send(charge_id)
|
||||
return "", HTTPStatus.NO_CONTENT
|
||||
|
|
Loading…
Add table
Reference in a new issue