示例#1
0
    async def resolve_invoice_subscription(self,
                                           info,
                                           add_index=None,
                                           settle_index=None):
        try:
            if not info.context["user"].is_authenticated:
                yield Unauthenticated()
        except AttributeError as exc:
            print(exc)
            yield ServerError(
                "A server internal error (AttributeError) has occurred. :-(")

        res = LNDWallet.objects.filter(owner=info.context["user"])

        if not res:
            yield WalletInstanceNotFound()

        cfg = build_lnd_wallet_config(res.first().pk)

        channel_data = build_grpc_channel_manual(
            rpc_server="127.0.0.1",
            rpc_port=cfg.rpc_listen_port_ipv4,
            cert_path=cfg.tls_cert_path,
            macaroon_path=cfg.admin_macaroon_path,
            is_async=True)

        if channel_data.error is not None:
            yield ServerError(error_message=channel_data.error)

        try:
            stub = lnrpc.LightningStub(channel_data.channel)
            request = ln.InvoiceSubscription(
                add_index=add_index,
                settle_index=settle_index,
            )
        except Exception as exc:
            print(exc)
            yield ServerError(error_message=exc)

        try:
            async for response in stub.SubscribeInvoices(
                    request, metadata=[('macaroon', channel_data.macaroon)]):
                if not info.context["user"].is_authenticated:
                    yield Unauthenticated()
                else:
                    json_data = json.loads(MessageToJson(response))
                    invoice = InvoiceSubSuccess(LnInvoice(json_data))
                    yield invoice
        except Exception as exc:
            print(exc)
            yield ServerError(error_message=exc)
示例#2
0
def gen_seed_query(
    wallet: LNDWallet,
    aezeed_passphrase: str,
    seed_entropy: str,
):
    cfg = build_lnd_wallet_config(wallet.pk)

    channel_data = build_grpc_channel_manual(
        rpc_server="127.0.0.1",
        rpc_port=cfg.rpc_listen_port_ipv4,
        cert_path=cfg.tls_cert_path,
    )

    if channel_data.error is not None:
        return channel_data.error

    stub = lnrpc.WalletUnlockerStub(channel_data.channel)
    request = ln.GenSeedRequest(aezeed_passphrase=aezeed_passphrase,
                                seed_entropy=seed_entropy)
    try:
        response = stub.GenSeed(request)
    except grpc.RpcError as exc:
        # pylint: disable=E1101
        print(exc)
        return ServerError.generic_rpc_error(exc.code(), exc.details())

    json_data = json.loads(
        MessageToJson(
            response,
            preserving_proto_field_name=True,
            including_default_value_fields=True,
        ))
    return GenSeedSuccess(ln_seed=LnGenSeedResponse(json_data))
示例#3
0
def get_info_query(wallet: LNDWallet) -> LnInfoType:
    cfg = build_lnd_wallet_config(wallet.pk)

    channel_data = build_grpc_channel_manual(
        rpc_server="127.0.0.1",
        rpc_port=cfg.rpc_listen_port_ipv4,
        cert_path=cfg.tls_cert_path,
        macaroon_path=cfg.admin_macaroon_path)

    if channel_data.error is not None:
        return channel_data.error

    stub = lnrpc.LightningStub(channel_data.channel)
    request = ln.GetInfoRequest()

    try:
        response = stub.GetInfo(request,
                                metadata=[('macaroon', channel_data.macaroon)])
    except grpc.RpcError as exc:
        # pylint: disable=E1101
        return ServerError.generic_rpc_error(exc.code(), exc.details())

    json_data = json.loads(
        MessageToJson(
            response,
            preserving_proto_field_name=True,
            including_default_value_fields=True,
        ))

    ln_info = LnInfoType(json_data)
    ip = IPAddress.objects.get(pk=1)  # type: IPAddress
    ln_info.current_ip = ip.ip_address
    ln_info.current_port = cfg.listen_port_ipv4
    return GetInfoSuccess(ln_info)
    def resolve_ln_list_payments(self, info, index_offset, num_max_payments,
                                 reverse):
        """https://api.lightning.community/?python#listpayments
        
        LND does not have paging in this call yet. Every gRPC
        call will always return the complete payments dataset.
        The paging functionality is implemented on top of the
        full dataset we get from the LND daemon.
        """

        if not info.context.user.is_authenticated:
            return Unauthenticated()

        res = LNDWallet.objects.filter(owner=info.context.user)

        if not res:
            return WalletInstanceNotFound()

        cfg = build_lnd_wallet_config(res.first().pk)

        channel_data = build_grpc_channel_manual(
            rpc_server="127.0.0.1",
            rpc_port=cfg.rpc_listen_port_ipv4,
            cert_path=cfg.tls_cert_path,
            macaroon_path=cfg.admin_macaroon_path)
        if channel_data.error is not None:
            return channel_data.error

        stub = lnrpc.LightningStub(channel_data.channel)
        request = ln.ListPaymentsRequest()

        try:
            response = stub.ListPayments(request,
                                         metadata=[('macaroon',
                                                    channel_data.macaroon)])
        except grpc.RpcError as exc:
            # pylint: disable=E1101
            print(exc)
            return ServerError.generic_rpc_error(exc.code(), exc.details())

        json_data = json.loads(
            MessageToJson(
                response,
                preserving_proto_field_name=True,
                including_default_value_fields=True,
            ))

        if reverse:
            # reverse the list
            rev = json_data["payments"][::-1]
            payments = rev[index_offset:index_offset + num_max_payments]
        else:
            payments = json_data["payments"][index_offset:index_offset +
                                             num_max_payments]

        return ListPaymentsSuccess(index_offset,
                                   index_offset + num_max_payments, payments)
示例#5
0
    def _open_channel(self, rpc_server, rpc_port, cert_path, macaroon_path,
                      is_async) -> ChannelData:
        try:
            macaroon = ""
            if macaroon_path is not None:
                with open(macaroon_path, 'rb') as f:
                    macaroon_bytes = f.read()
                    macaroon = codecs.encode(macaroon_bytes, 'hex')

            rpc_url = "{}:{}".format(rpc_server, rpc_port)

            cert = open(cert_path, "rb").read()
        except FileNotFoundError as file_error:
            print(file_error)
            return ChannelData(
                channel=None,
                macaroon=None,
                error=ServerError(error_message=str(file_error)))

        try:
            if is_async:
                creds = aiogrpc.ssl_channel_credentials(cert)
                channel = aiogrpc.secure_channel(rpc_url, creds)
            else:
                creds = grpc.ssl_channel_credentials(cert)
                channel = grpc.secure_channel(rpc_url, creds)
                grpc.channel_ready_future(channel).result(timeout=2)

        except grpc.RpcError as exc:
            # pylint: disable=E1101
            print(exc)
            return ChannelData(
                channel=None,
                macaroon=None,
                error=ServerError.generic_rpc_error(exc.code(), exc.details()))
        except grpc.FutureTimeoutError as exc:
            print(exc)
            return ChannelData(
                channel=None, macaroon=None, error=WalletInstanceNotRunning())

        return ChannelData(channel=channel, macaroon=macaroon, error=None)
示例#6
0
    def mutate(self, info, pubkey: str, host: str, perm: bool):
        """https://api.lightning.community/?python#connectpeer"""

        if not info.context.user.is_authenticated:
            return Unauthenticated()

        res: QuerySet = LNDWallet.objects.filter(owner=info.context.user)

        if not res:
            return WalletInstanceNotFound()

        wallet: LNDWallet = res.first()

        cfg: LNDWalletConfig = build_lnd_wallet_config(wallet.pk)

        channel_data = build_grpc_channel_manual(
            rpc_server="127.0.0.1",
            rpc_port=cfg.rpc_listen_port_ipv4,
            cert_path=cfg.tls_cert_path,
            macaroon_path=cfg.admin_macaroon_path,
        )

        if channel_data.error is not None:
            return channel_data.error

        stub = lnrpc.LightningStub(channel_data.channel)
        request = ln.ConnectPeerRequest(addr={
            "pubkey": pubkey,
            "host": host
        },
                                        perm=perm)
        try:
            response = stub.ConnectPeer(request,
                                        metadata=[('macaroon',
                                                   channel_data.macaroon)])
        except grpc.RpcError as exc:
            # pylint: disable=E1101
            print(exc)
            if "dial tcp {}: connect: connection refused".format(
                    host) in exc.details():
                return ConnectPeerError(
                    error_message="Peer refused to connect",
                    pubkey=pubkey,
                    host=host)
            if "already connected to peer: {}".format(host) in exc.details():
                return ConnectPeerError(
                    error_message="Already connected to peer",
                    pubkey=pubkey,
                    host=host)

            return ServerError.generic_rpc_error(exc.code(), exc.details())

        return ConnectPeerSuccess(pubkey=pubkey)
示例#7
0
    def mutate(self,
               info,
               payment_raw: LnRawPaymentInput = None,
               payment_request: str = "",
               final_cltv_delta: int = 0,
               fee_limit: LnFeeLimit = None):

        if not info.context.user.is_authenticated:
            return SendPaymentMutation(payment_result=Unauthenticated())

        res = LNDWallet.objects.filter(owner=info.context.user)

        if not res:
            return SendPaymentMutation(payment_result=WalletInstanceNotFound())

        cfg = build_lnd_wallet_config(res.first().pk)

        channel_data = build_grpc_channel_manual(
            rpc_server="127.0.0.1",
            rpc_port=cfg.rpc_listen_port_ipv4,
            cert_path=cfg.tls_cert_path,
            macaroon_path=cfg.admin_macaroon_path,
        )
        if channel_data.error is not None:
            return SendPaymentMutation(payment_result=channel_data.error)

        stub = lnrpc.LightningStub(channel_data.channel)
        request = ln.SendRequest(payment_request=payment_request)
        try:
            response = stub.SendPaymentSync(request,
                                            metadata=[('macaroon',
                                                       channel_data.macaroon)])
        except RpcError as exc:
            # pylint: disable=E1101
            print(exc)
            if exc.details().startswith("invoice expired"):
                return SendPaymentMutation(
                    payment_result=SendPaymentError(exc.details()))
            return SendPaymentMutation(
                payment_result=ServerError.generic_rpc_error(
                    exc.code(), exc.details()))

        json_data = json.loads(MessageToJson(response))

        if response.payment_error:
            err = SendPaymentError(payment_error=response.payment_error)
            return SendPaymentMutation(payment_result=err)

        res = SendPaymentSuccess(payment_preimage=response.payment_preimage,
                                 payment_route=LnRoute(
                                     json_data["payment_route"]))
        return SendPaymentMutation(payment_result=res)
示例#8
0
    def mutate(
        self,
        info,
    ):
        """https://api.lightning.community/?python#stopdaemon"""

        if not info.context.user.is_authenticated:
            return Unauthenticated()

        res: QuerySet = LNDWallet.objects.filter(owner=info.context.user)

        if not res:
            return WalletInstanceNotFound()

        wallet: LNDWallet = res.first()

        cfg: LNDWalletConfig = build_lnd_wallet_config(wallet.pk)

        channel_data = build_grpc_channel_manual(
            rpc_server="127.0.0.1",
            rpc_port=cfg.rpc_listen_port_ipv4,
            cert_path=cfg.tls_cert_path,
            macaroon_path=cfg.admin_macaroon_path,
        )

        if channel_data.error is not None:
            return channel_data.error

        # stop daemon
        stub = lnrpc.LightningStub(channel_data.channel)
        request = ln.StopRequest()
        try:
            response = stub.StopDaemon(request,
                                       metadata=[('macaroon',
                                                  channel_data.macaroon)])
        except grpc.RpcError as exc:
            # pylint: disable=E1101
            print(exc)
            return ServerError.generic_rpc_error(exc.code(), exc.details())

        start = time.time()
        while True:
            if not lnd_instance_is_running(cfg):
                return StopDaemonSuccess()

            if time.time() - start >= 10:
                return StopDaemonError(
                    error_message=
                    "Unable to shutdown the process within 10 seconds")

            time.sleep(1)
    def resolve_get_ln_wallet_status(self, info, **kwargs):
        """retrieve the current state of the wallet"""

        if not info.context.user.is_authenticated:
            return Unauthenticated()

        res = LNDWallet.objects.filter(owner=info.context.user)

        # LND instance is not yet created.
        # User should call createWallet
        if not res:
            return WalletInstanceNotFound()

        # Wallet database object was created but
        # it is not yet initialized
        if not res.first().initialized:
            return GetLnWalletStatusNotInitialized()

        cfg = build_lnd_wallet_config(res.first().pk)

        channel_data = build_grpc_channel_manual(
            rpc_server="127.0.0.1",
            rpc_port=cfg.rpc_listen_port_ipv4,
            cert_path=cfg.tls_cert_path,
            macaroon_path=cfg.admin_macaroon_path)
        if channel_data.error is not None:
            return channel_data.error

        stub = lnrpc.LightningStub(channel_data.channel)
        request = ln.GetInfoRequest()

        try:
            stub.GetInfo(request,
                         metadata=[('macaroon', channel_data.macaroon)])
        except grpc.RpcError as exc:
            # pylint: disable=E1101

            # This is a wanted exception.
            # When GetInfo returns UNIMPLEMENTED the wallet is likely locked
            if exc.code() == grpc.StatusCode.UNIMPLEMENTED:
                return GetLnWalletStatusLocked()

            # Unexpected exception
            LOGGER.exception(exc)
            return ServerError.generic_rpc_error(exc.code(), exc.details())

        return GetLnWalletStatusOperational()
示例#10
0
    def resolve_ln_list_invoices(self, info, pending_only, index_offset,
                                 num_max_invoices, reverse):
        """https://api.lightning.community/?python#listinvoices"""

        if not info.context.user.is_authenticated:
            return Unauthenticated()

        res = LNDWallet.objects.filter(owner=info.context.user)

        if not res:
            return WalletInstanceNotFound()

        cfg = build_lnd_wallet_config(res.first().pk)

        channel_data = build_grpc_channel_manual(
            rpc_server="127.0.0.1",
            rpc_port=cfg.rpc_listen_port_ipv4,
            cert_path=cfg.tls_cert_path,
            macaroon_path=cfg.admin_macaroon_path)
        if channel_data.error is not None:
            return channel_data.error

        stub = lnrpc.LightningStub(channel_data.channel)
        request = ln.ListInvoiceRequest(
            pending_only=pending_only,
            index_offset=index_offset,
            num_max_invoices=num_max_invoices,
            reversed=reverse,
        )

        try:
            response = stub.ListInvoices(request,
                                         metadata=[('macaroon',
                                                    channel_data.macaroon)])
        except grpc.RpcError as exc:
            # pylint: disable=E1101
            print(exc)
            return ServerError.generic_rpc_error(exc.code(), exc.details())

        json_data = json.loads(
            MessageToJson(
                response,
                preserving_proto_field_name=True,
                including_default_value_fields=True,
            ))
        return ListInvoicesSuccess(json_data)
示例#11
0
def init_wallet_mutation(wallet: LNDWallet, wallet_password: str,
                         cipher_seed_mnemonic: [], aezeed_passphrase: str,
                         recovery_window: int):
    cfg = build_lnd_wallet_config(wallet.pk)

    channel_data = build_grpc_channel_manual(
        rpc_server="127.0.0.1",
        rpc_port=cfg.rpc_listen_port_ipv4,
        cert_path=cfg.tls_cert_path,
    )

    if channel_data.error is not None:
        return channel_data.error

    # init wallet
    stub = lnrpc.WalletUnlockerStub(channel_data.channel)
    request = ln.InitWalletRequest(
        wallet_password=wallet_password.encode(),
        cipher_seed_mnemonic=cipher_seed_mnemonic,
        aezeed_passphrase=aezeed_passphrase.encode()
        if aezeed_passphrase is not None else None,
        recovery_window=recovery_window)
    try:
        response = stub.InitWallet(request,
                                   metadata=[('macaroon',
                                              channel_data.macaroon)])

        # LND requires some time seconds to startup.
        # So, check until the macaroon files exist and then return
        # TODO: find a better solution to this
        file = pathlib.Path(cfg.admin_macaroon_path)
        while 1:
            if file.is_file():
                break
            time.sleep(2)
        time.sleep(5)
    except grpc.RpcError as exc:
        # pylint: disable=E1101
        print(exc)
        return ServerError.generic_rpc_error(exc.code(), exc.details())

    return InitWalletSuccess(status="OK")
    def mutate(self, info, pubkey: str):
        """https://api.lightning.community/?python#disconnectpeer"""

        if not info.context.user.is_authenticated:
            return Unauthenticated()

        res: QuerySet = LNDWallet.objects.filter(owner=info.context.user)

        if not res:
            return WalletInstanceNotFound()

        wallet: LNDWallet = res.first()

        cfg: LNDWalletConfig = build_lnd_wallet_config(wallet.pk)

        channel_data = build_grpc_channel_manual(
            rpc_server="127.0.0.1",
            rpc_port=cfg.rpc_listen_port_ipv4,
            cert_path=cfg.tls_cert_path,
            macaroon_path=cfg.admin_macaroon_path,
        )

        if channel_data.error is not None:
            return channel_data.error

        stub = lnrpc.LightningStub(channel_data.channel)
        request = ln.DisconnectPeerRequest(pub_key=pubkey)
        try:
            stub.DisconnectPeer(request,
                                metadata=[('macaroon', channel_data.macaroon)])
        except grpc.RpcError as exc:
            # pylint: disable=E1101
            print(exc)
            if "unable to disconnect peer: peer {} is not connected".format(
                    pubkey) in exc.details():
                return DisconnectPeerError(error_message="Peer not connected",
                                           pubkey=pubkey)

            return ServerError.generic_rpc_error(exc.code(), exc.details())

        return DisconnectPeerSuccess(pubkey=pubkey)
示例#13
0
    def mutate(self, info, value, memo: str = ""):
        if not info.context.user.is_authenticated:
            return AddInvoiceMutation(result=Unauthenticated())

        res = LNDWallet.objects.filter(owner=info.context.user)

        if not res:
            return AddInvoiceMutation(result=WalletInstanceNotFound())

        cfg = build_lnd_wallet_config(res.first().pk)

        channel_data = build_grpc_channel_manual(
            rpc_server="127.0.0.1",
            rpc_port=cfg.rpc_listen_port_ipv4,
            cert_path=cfg.tls_cert_path,
            macaroon_path=cfg.admin_macaroon_path,
        )
        if channel_data.error is not None:
            return AddInvoiceMutation(result=channel_data.error)

        stub = lnrpc.LightningStub(channel_data.channel)
        request = ln.Invoice(
            value=value,
            memo=memo,
            add_index=1,
        )

        try:
            response = stub.AddInvoice(request,
                                       metadata=[('macaroon',
                                                  channel_data.macaroon)])
        except RpcError as exc:
            # pylint: disable=E1101
            print(exc)
            return AddInvoiceMutation(result=ServerError.generic_rpc_error(
                exc.code(), exc.details()))

        json_data = json.loads(MessageToJson(response))
        return AddInvoiceMutation(
            result=AddInvoiceSuccess(LnAddInvoiceResponse(json_data)))
示例#14
0
def test_get_ln_wallet_status(monkeypatch: MonkeyPatch):
    channel_data = ChannelData(
        channel=object(), macaroon="macaroon_data".encode(), error=None)
    monkeypatch.setattr(
        backend.lnd.implementations.queries.get_ln_wallet_status,
        "build_grpc_channel_manual",
        lambda rpc_server, rpc_port, cert_path, macaroon_path: channel_data)

    monkeypatch.setattr(
        backend.lnd.implementations.queries.get_ln_wallet_status,
        "build_lnd_wallet_config", lambda pk: utils.fake_lnd_wallet_config())

    query = GetLnWalletStatusQuery()
    req = RequestFactory().get("/")
    req.user = AnonymousUser()
    resolve_info = utils.mock_resolve_info(req)

    query = GetLnWalletStatusQuery()
    ret = query.resolve_get_ln_wallet_status(resolve_info)

    assert isinstance(
        ret, Unauthenticated), "Should be an instance of Unauthenticated"

    # "login" a user
    req.user = mixer.blend("auth.User")
    ret = query.resolve_get_ln_wallet_status(resolve_info)
    assert isinstance(ret, WalletInstanceNotFound
                      ), "Should be an instance of WalletInstanceNotFound"

    wallet = LNDWallet()
    wallet.owner = req.user
    wallet.public_alias = "public_alias"
    wallet.name = "name"
    wallet.testnet = True
    wallet.initialized = False
    wallet.save()

    ret = query.resolve_get_ln_wallet_status(resolve_info)
    assert isinstance(
        ret, GetLnWalletStatusNotInitialized
    ), "Should be an instance of GetLnWalletStatusNotInitialized"

    wallet.initialized = True
    wallet.save()

    # Test build channel failure
    monkeypatch.setattr(
        backend.lnd.implementations.queries.get_ln_wallet_status,
        "build_grpc_channel_manual",
        lambda *args, **kwargs: utils.fake_build_grpc_channel_manual(
            ServerError(error_message="Some error occurred!")))

    ret = query.resolve_get_ln_wallet_status(resolve_info)
    assert isinstance(ret, ServerError), "Should be an instance of ServerError"

    # Test the get info request
    monkeypatch.setattr(
        backend.lnd.implementations.queries.get_ln_wallet_status,
        "build_grpc_channel_manual",
        lambda *args, **kwargs: utils.fake_build_grpc_channel_manual())

    monkeypatch.setattr(
        backend.lnd.implementations.queries.get_ln_wallet_status.lnrpc,
        "LightningStub", FakeLightningStubUnimplemented)

    monkeypatch.setattr(
        backend.lnd.implementations.queries.get_ln_wallet_status.ln,
        "GetInfoRequest", object)

    ret = query.resolve_get_ln_wallet_status(resolve_info)
    assert isinstance(ret, GetLnWalletStatusLocked
                      ), "Should be an instance of GetLnWalletStatusLocked"

    monkeypatch.setattr(
        backend.lnd.implementations.queries.get_ln_wallet_status.lnrpc,
        "LightningStub", FakeLightningStubNoError)

    ret = query.resolve_get_ln_wallet_status(resolve_info)
    assert isinstance(
        ret, GetLnWalletStatusOperational
    ), "Should be an instance of GetLnWalletStatusOperational"
示例#15
0
def start_daemon_mutation(wallet: LNDWallet,
                          autopilot: bool,
                          wallet_password: str,
                          recovery_window: int = 0) -> LnInfoType:
    cfg = build_lnd_wallet_config(wallet.pk)

    if lnd_instance_is_running(cfg):
        return StartDaemonInstanceIsAlreadyRunning()

    try:
        args = build_lnd_startup_args(autopilot, wallet)
        # Start LND instance
        subprocess.Popen(
            args["args"],
            cwd=r'{}'.format(args["data_dir"]),
            preexec_fn=os.setpgrp)

        time.sleep(2)
    except grpc.RpcError as exc:
        # pylint: disable=E1101
        print(exc)
        return ServerError.generic_rpc_error(exc.code(), exc.details())

    # build the channel to the newly started daemon

    channel_data = build_grpc_channel_manual(
        rpc_server="127.0.0.1",
        rpc_port=cfg.rpc_listen_port_ipv4,
        cert_path=cfg.tls_cert_path,
        macaroon_path=cfg.admin_macaroon_path)

    if channel_data.error is not None:
        return channel_data.error

    # unlock the wallet
    stub = lnrpc.WalletUnlockerStub(channel_data.channel)
    request = ln.UnlockWalletRequest(
        wallet_password=wallet_password.encode(),
        recovery_window=recovery_window)
    stub.UnlockWallet(request)

    # LND requires a few seconds after unlocking until
    # it's fully operational
    time.sleep(5)

    # Unlocking the wallet requires a rebuild of the channel
    channel_data = build_grpc_channel_manual(
        rpc_server="127.0.0.1",
        rpc_port=cfg.rpc_listen_port_ipv4,
        cert_path=cfg.tls_cert_path,
        macaroon_path=cfg.admin_macaroon_path,
        rebuild=True)

    if channel_data.error is not None:
        return channel_data.error

    # get the latest info
    stub = lnrpc.LightningStub(channel_data.channel)
    request = ln.GetInfoRequest()

    try:
        response = stub.GetInfo(
            request, metadata=[('macaroon', channel_data.macaroon)])
    except grpc.RpcError as exc:
        # pylint: disable=E1101
        print(exc)
        return ServerError.generic_rpc_error(exc.code(), exc.details())

    json_data = json.loads(
        MessageToJson(
            response,
            preserving_proto_field_name=True,
            including_default_value_fields=True,
        ))
    return StartDaemonSuccess(info=LnInfoType(json_data))
示例#16
0
    async def resolve_close_channel_subscription(self,
                                                 info,
                                                 funding_txid,
                                                 output_index,
                                                 force,
                                                 target_conf=None,
                                                 sat_per_byte=None):
        try:
            if not info.context["user"].is_authenticated:
                yield Unauthenticated()
        except AttributeError as exc:
            print(exc)
            yield ServerError(
                "A server internal error (AttributeError) has occurred. :-(")

        res = LNDWallet.objects.filter(owner=info.context["user"])

        if not res:
            yield WalletInstanceNotFound()

        cfg = build_lnd_wallet_config(res.first().pk)

        channel_data = build_grpc_channel_manual(
            rpc_server="127.0.0.1",
            rpc_port=cfg.rpc_listen_port_ipv4,
            cert_path=cfg.tls_cert_path,
            macaroon_path=cfg.admin_macaroon_path,
            is_async=True)

        if channel_data.error is not None:
            yield channel_data.error

        try:
            stub = lnrpc.LightningStub(channel_data.channel)

            request = ln.CloseChannelRequest(
                channel_point={
                    "funding_txid_str": funding_txid,
                    "output_index": output_index
                },
                force=force,
                target_conf=target_conf,
                sat_per_byte=sat_per_byte,
            )
        except Exception as exc:
            print(exc)
            yield ServerError(error_message=str(exc))

        try:
            async for response in stub.CloseChannel(
                    request, metadata=[('macaroon', channel_data.macaroon)]):
                if not info.context["user"].is_authenticated:
                    yield Unauthenticated()
                else:
                    json_data = json.loads(MessageToJson(response))

                    if "close_pending" in json_data:
                        cp = json_data["close_pending"]
                        txid = cp["txid"] if "txid" in cp else ""
                        output_index = cp[
                            "output_index"] if "output_index" in cp else 0

                        yield ChannelClosePendingUpdate(txid=txid)
                    elif "chan_close" in json_data:
                        cc = json_data["chan_close"]
                        txid = cc[
                            "closing_txid"] if "closing_txid" in cc else ""
                        success = cc["success"] if "success" in cc else False
                        yield ChannelCloseUpdate(closing_txid=txid, success=success)
                    else:
                        msg = "Unknown update from LND: {}".format(json_data)
                        print(msg)
                        yield ServerError(error_message=msg)
        except RpcError as grpc_error:
            # pylint: disable=E1101
            print(grpc_error)
            print(grpc_error.details())
            yield CloseChannelError(grpc_error.details())
        except Exception as exc:
            print(exc)
            yield ServerError(error_message=exc)
示例#17
0
    async def resolve_open_channel_subscription(self,
                                                info,
                                                node_pubkey,
                                                local_funding_amount,
                                                push_sat,
                                                private,
                                                min_htlc_msat,
                                                min_confs,
                                                spend_unconfirmed,
                                                sat_per_byte=None,
                                                remote_csv_delay=None,
                                                target_conf=None):
        try:
            if not info.context["user"].is_authenticated:
                yield Unauthenticated()
        except AttributeError as exc:
            print(exc)
            yield ServerError(
                "A server internal error (AttributeError) has occurred. :-(")

        res = LNDWallet.objects.filter(owner=info.context["user"])

        if not res:
            yield WalletInstanceNotFound()

        cfg = build_lnd_wallet_config(res.first().pk)

        channel_data = build_grpc_channel_manual(
            rpc_server="127.0.0.1",
            rpc_port=cfg.rpc_listen_port_ipv4,
            cert_path=cfg.tls_cert_path,
            macaroon_path=cfg.admin_macaroon_path,
            is_async=True)

        if channel_data.error is not None:
            yield channel_data.error

        try:
            stub = lnrpc.LightningStub(channel_data.channel)

            request = ln.OpenChannelRequest(
                node_pubkey=codecs.decode(node_pubkey, 'hex'),
                local_funding_amount=local_funding_amount,
                push_sat=push_sat,
                target_conf=target_conf,
                sat_per_byte=sat_per_byte,
                private=private,
                min_htlc_msat=min_htlc_msat,
                remote_csv_delay=remote_csv_delay,
                min_confs=min_confs,
                # spend_unconfirmed=spend_unconfirmed
            )
        except Exception as exc:
            print(exc)
            yield ServerError(error_message=str(exc))
            return

        try:
            async for response in stub.OpenChannel(request,
                                                   metadata=[
                                                       ('macaroon',
                                                        channel_data.macaroon)
                                                   ]):
                if not info.context["user"].is_authenticated:
                    yield Unauthenticated()
                else:
                    json_data = json.loads(MessageToJson(response))

                    if "chan_pending" in json_data:
                        cp = json_data["chan_pending"]
                        txid = cp["txid"] if "txid" in cp else ""
                        output_index = cp[
                            "output_index"] if "output_index" in cp else 0

                        yield ChannelPendingUpdate(
                            channel_point=ChannelPoint(txid, output_index))
                    elif "confirmation" in json_data:
                        conf = json_data["confirmation"]
                        block_sha = conf[
                            "block_sha"] if "block_sha" in conf else ""
                        block_height = conf[
                            "block_height"] if "block_height" in conf else 0
                        num_confs_left = conf[
                            "num_confs_left"] if "num_confs_left" in conf else 0
                        yield ChannelConfirmationUpdate(
                            block_sha=block_sha,
                            block_height=block_height,
                            num_confs_left=num_confs_left)
                    elif "chan_open" in json_data:
                        co = json_data["chan_open"]["channel_point"]
                        txid = co[
                            "funding_txid_bytes"] if "funding_txid_bytes" in co else ""
                        output_index = cp[
                            "output_index"] if "output_index" in co else 0
                        yield ChannelOpenUpdate(
                            channel_point=ChannelPoint(txid, output_index))
        except RpcError as grpc_error:
            # pylint: disable=E1101
            print(grpc_error)
            print(grpc_error.details())
            yield OpenChannelError(grpc_error.details())
        except Exception as exc:
            print(exc)
            yield ServerError(error_message=exc)