Skip to content

Commit

Permalink
fix for lndgrpc
Browse files Browse the repository at this point in the history
  • Loading branch information
callebtc committed Sep 8, 2024
1 parent 1655e09 commit a569a71
Show file tree
Hide file tree
Showing 2 changed files with 57 additions and 40 deletions.
94 changes: 54 additions & 40 deletions cashu/lightning/lnd_grpc/lnd_grpc.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,39 +45,43 @@
lnrpc.Invoice.InvoiceState.ACCEPTED: None,
}

class LndRPCWallet(LightningBackend):

class LndRPCWallet(LightningBackend):
supports_mpp = settings.mint_lnd_enable_mpp
supports_incoming_payment_stream = True
supported_units = set([Unit.sat, Unit.msat])
supports_description: bool = True

unit = Unit.sat

def __init__(self, unit: Unit = Unit.sat, **kwargs):
self.assert_unit_supported(unit)
self.unit = unit
self.endpoint = settings.mint_lnd_rpc_endpoint
cert_path = settings.mint_lnd_rpc_cert

macaroon_path = settings.mint_lnd_rpc_macaroon

if not self.endpoint:
if not settings.mint_lnd_rpc_endpoint:
raise Exception("cannot initialize LndRPCWallet: no endpoint")

self.endpoint = settings.mint_lnd_rpc_endpoint

if not macaroon_path:
raise Exception("cannot initialize LndRPCWallet: no macaroon")

if not cert_path:
raise Exception("no certificate for LndRPCWallet provided")

self.macaroon = codecs.encode(open(macaroon_path, 'rb').read(), 'hex')
self.macaroon = codecs.encode(open(macaroon_path, "rb").read(), "hex")

def metadata_callback(context, callback):
callback([('macaroon', self.macaroon)], None)
callback([("macaroon", self.macaroon)], None)

auth_creds = grpc.metadata_call_credentials(metadata_callback)

# create SSL credentials
os.environ['GRPC_SSL_CIPHER_SUITES'] = 'HIGH+ECDSA'
cert = open(cert_path, 'rb').read()
os.environ["GRPC_SSL_CIPHER_SUITES"] = "HIGH+ECDSA"
cert = open(cert_path, "rb").read()
ssl_creds = grpc.ssl_channel_credentials(cert)

# combine macaroon and SSL credentials
Expand All @@ -86,21 +90,21 @@ def metadata_callback(context, callback):
if self.supports_mpp:
logger.info("LndRPCWallet enabling MPP feature")


async def status(self) -> StatusResponse:
r = None
try:
async with grpc.aio.secure_channel(self.endpoint, self.combined_creds) as channel:
async with grpc.aio.secure_channel(
self.endpoint, self.combined_creds
) as channel:
lnstub = lightningstub.LightningStub(channel)
r = await lnstub.ChannelBalance(lnrpc.ChannelBalanceRequest())
except AioRpcError as e:
return StatusResponse(
error_message=f"Error calling Lnd gRPC: {e}", balance=0
)
# NOTE: `balance` field is deprecated. Change this.
return StatusResponse(error_message=None, balance=r.balance*1000)
return StatusResponse(error_message=None, balance=r.balance * 1000)


async def create_invoice(
self,
amount: Amount,
Expand All @@ -124,7 +128,9 @@ async def create_invoice(

r = None
try:
async with grpc.aio.secure_channel(self.endpoint, self.combined_creds) as channel:
async with grpc.aio.secure_channel(
self.endpoint, self.combined_creds
) as channel:
lnstub = lightningstub.LightningStub(channel)
r = await lnstub.AddInvoice(data)
except AioRpcError as e:
Expand All @@ -144,7 +150,7 @@ async def create_invoice(
payment_request=payment_request,
error_message=None,
)

async def pay_invoice(
self, quote: MeltQuote, fee_limit_msat: int
) -> PaymentResponse:
Expand All @@ -159,12 +165,12 @@ async def pay_invoice(
)

# set the fee limit for the payment
feelimit = lnrpc.FeeLimit(
fixed_msat=fee_limit_msat
)
feelimit = lnrpc.FeeLimit(fixed_msat=fee_limit_msat)
r = None
try:
async with grpc.aio.secure_channel(self.endpoint, self.combined_creds) as channel:
async with grpc.aio.secure_channel(
self.endpoint, self.combined_creds
) as channel:
lnstub = lightningstub.LightningStub(channel)
r = await lnstub.SendPaymentSync(
lnrpc.SendRequest(
Expand Down Expand Up @@ -195,14 +201,12 @@ async def pay_invoice(
preimage=preimage,
error_message=None,
)

async def pay_partial_invoice(
self, quote: MeltQuote, amount: Amount, fee_limit_msat: int
) -> PaymentResponse:
# set the fee limit for the payment
feelimit = lnrpc.FeeLimit(
fixed_msat=fee_limit_msat
)
feelimit = lnrpc.FeeLimit(fixed_msat=fee_limit_msat)
invoice = bolt11.decode(quote.request)

invoice_amount = invoice.amount_msat
Expand All @@ -220,7 +224,9 @@ async def pay_partial_invoice(
# get the route
r = None
try:
async with grpc.aio.secure_channel(self.endpoint, self.combined_creds) as channel:
async with grpc.aio.secure_channel(
self.endpoint, self.combined_creds
) as channel:
lnstub = lightningstub.LightningStub(channel)
router_stub = routerstub.RouterStub(channel)
r = await lnstub.QueryRoutes(
Expand All @@ -230,23 +236,27 @@ async def pay_partial_invoice(
fee_limit=feelimit,
)
)
'''
"""
# We need to set the mpp_record for a partial payment
mpp_record = lnrpc.MPPRecord(
payment_addr=bytes.fromhex(payer_addr),
total_amt_msat=total_amount_msat,
)
'''
"""
# modify the mpp_record in the last hop
route_nr = 0
r.routes[route_nr].hops[-1].mpp_record.payment_addr = bytes.fromhex(payer_addr)
r.routes[route_nr].hops[-1].mpp_record.total_amt_msat = total_amount_msat
r.routes[route_nr].hops[-1].mpp_record.payment_addr = bytes.fromhex( # type: ignore
payer_addr
)
r.routes[route_nr].hops[ # type: ignore
-1
].mpp_record.total_amt_msat = total_amount_msat

# Send to route request
r = await router_stub.SendToRouteV2(
routerrpc.SendToRouteRequest(
payment_hash=bytes.fromhex(invoice.payment_hash),
route=r.routes[route_nr],
route=r.routes[route_nr], # type: ignore
)
)
except AioRpcError as e:
Expand Down Expand Up @@ -275,24 +285,24 @@ async def pay_partial_invoice(
preimage=preimage,
error_message=None,
)

async def get_invoice_status(self, checking_id: str) -> PaymentStatus:
r = None
try:
async with grpc.aio.secure_channel(self.endpoint, self.combined_creds) as channel:
async with grpc.aio.secure_channel(
self.endpoint, self.combined_creds
) as channel:
lnstub = lightningstub.LightningStub(channel)
r = await lnstub.LookupInvoice(
lnrpc.PaymentHash(
r_hash=bytes.fromhex(checking_id)
)
lnrpc.PaymentHash(r_hash=bytes.fromhex(checking_id))
)
except AioRpcError as e:
error_message = f"LookupInvoice failed: {e}"
logger.error(error_message)
return PaymentStatus(paid=None)

return PaymentStatus(paid=INVOICE_STATUSES[r.state])

async def get_payment_status(self, checking_id: str) -> PaymentStatus:
"""
This routine checks the payment status using routerpc.TrackPaymentV2.
Expand All @@ -307,7 +317,9 @@ async def get_payment_status(self, checking_id: str) -> PaymentStatus:
request = routerrpc.TrackPaymentRequest(payment_hash=checking_id_bytes)

try:
async with grpc.aio.secure_channel(self.endpoint, self.combined_creds) as channel:
async with grpc.aio.secure_channel(
self.endpoint, self.combined_creds
) as channel:
router_stub = routerstub.RouterStub(channel)
async for payment in router_stub.TrackPaymentV2(request):
if payment is not None and payment.status:
Expand All @@ -325,21 +337,23 @@ async def get_payment_status(self, checking_id: str) -> PaymentStatus:
logger.error(error_message)

return PaymentStatus(paid=None)

async def paid_invoices_stream(self) -> AsyncGenerator[str, None]:
while True:
try:
async with grpc.aio.secure_channel(self.endpoint, self.combined_creds) as channel:
async with grpc.aio.secure_channel(
self.endpoint, self.combined_creds
) as channel:
lnstub = lightningstub.LightningStub(channel)
async for invoice in lnstub.SubscribeInvoices(lnrpc.InvoiceSubscription()):
async for invoice in lnstub.SubscribeInvoices(
lnrpc.InvoiceSubscription()
):
if invoice.state != lnrpc.Invoice.InvoiceState.SETTLED:
continue
payment_hash = invoice.r_hash.hex()
yield payment_hash
except AioRpcError as exc:
logger.error(
f"SubscribeInvoices failed: {exc}. Retrying in 1 sec..."
)
logger.error(f"SubscribeInvoices failed: {exc}. Retrying in 1 sec...")
await asyncio.sleep(1)

async def get_payment_quote(
Expand Down
3 changes: 3 additions & 0 deletions mypy.ini
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,6 @@ ignore_missing_imports = True

[mypy-cashu.nostr.*]
ignore_errors = True

[mypy-cashu.lightning.lnd_grpc.protos.*]
ignore_errors = True

0 comments on commit a569a71

Please sign in to comment.