Exemplo n.º 1
0
class LightningDaemon(object):
    def __init__(self, daemon_rpc):
        self.rpc = LightningRpc(daemon_rpc)

    def invoice_c_lightning(self, msatoshi, label, description):
        result = self.rpc.invoice(msatoshi,
                                  label,
                                  description,
                                  expiry=INVOICE_EXPIRY)
        log(json.dumps(result, indent=1, sort_keys=True))
        return result

    def get_c_lightning_invoices(self):
        result = self.rpc.listinvoices()
        #log(json.dumps(result, indent=1, sort_keys=True))
        return result

    def delete(self, label, state="paid"):
        result = self.rpc.delinvoice(label, state)
        #        log(json.dumps(result, indent=1, sort_keys=True))
        return result

    def getinfo(self):
        return self.rpc.getinfo()

    def listfunds(self):
        return self.rpc.listfunds()

    def listnodes(self):
        return self.rpc.listnodes()
Exemplo n.º 2
0
class CLightningWallet(Wallet):

    def __init__(self):
        self.l1 = LightningRpc(getenv("CLIGHTNING_RPC"))
        
    def create_invoice(self, amount: int, memo: str = "") -> InvoiceResponse:
        label = "lbl{}".format(random.random())  
        r = self.l1.invoice(amount*1000, label, memo, exposeprivatechannels=True)
        ok, checking_id, payment_request, error_message = True, r["payment_hash"], r["bolt11"], None
        return InvoiceResponse(ok, checking_id, payment_request, error_message)

    def pay_invoice(self, bolt11: str) -> PaymentResponse:
        r = self.l1.pay(bolt11)
        ok, checking_id, fee_msat, error_message = True, None, None, None
        return PaymentResponse(ok, checking_id, fee_msat, error_message)

    def get_invoice_status(self, checking_id: str) -> PaymentStatus:
        r = self.l1.listinvoices(checking_id)
        if r['invoices'][0]['status'] == 'unpaid':
            return PaymentStatus(False)
        return PaymentStatus(True)

    def get_payment_status(self, checking_id: str) -> PaymentStatus:
        r = self.l1.listsendpays(checking_id)
        if not r.ok:
            return PaymentStatus(r, None)
        payments = [p for p in r.json()["payments"] if p["payment_hash"] == payment_hash]
        payment = payments[0] if payments else None
        statuses = {"UNKNOWN": None, "IN_FLIGHT": None, "SUCCEEDED": True, "FAILED": False}
        return PaymentStatus(statuses[payment["status"]] if payment else None)
Exemplo n.º 3
0
class RealDaemon(Daemon):
    """ calls c-lightning via the rpc """
    def __init__(self, path):
        super().__init__()
        self.path = path
        print("rpc path: %s" % self.path)
        self.rpc = LightningRpc(self.path)

    def invoice_c_lightning(self, msatoshi, label, description, expiry,
                            preimage):
        print("invoice real")
        try:
            result = self.rpc.invoice(msatoshi, label, description,
                                      expiry=expiry, preimage=preimage)
        except:
            return None, "c-lightning invoice exception"
        print(json.dumps(result, indent=1, sort_keys=True))
        return result, None

    def get_c_lightning_invoices(self):
        try:
            result = self.rpc.listinvoices()
        except:
            return None, "c-lightning listinvoices exception"

        print(json.dumps(result, indent=1, sort_keys=True))
        return result['invoices'], None

    def delete(self, label, state='paid'):
        try:
            result = self.rpc.delinvoice(label, state)
        except:
            return None, "c-lightning delinvoice exception"
        print(json.dumps(result, indent=1, sort_keys=True))
        return result, None
Exemplo n.º 4
0
class CLightningWallet(Wallet):
    def __init__(self):
        if LightningRpc is None:  # pragma: nocover
            raise ImportError(
                "The `pylightning` library must be installed to use `CLightningWallet`."
            )

        self.l1 = LightningRpc(getenv("CLIGHTNING_RPC"))

    def create_invoice(self,
                       amount: int,
                       memo: str = "",
                       description_hash: bytes = b"") -> InvoiceResponse:
        if description_hash:
            raise Unsupported("description_hash")

        label = "lbl{}".format(random.random())
        r = self.l1.invoice(amount * 1000,
                            label,
                            memo,
                            exposeprivatechannels=True)
        ok, checking_id, payment_request, error_message = True, r[
            "payment_hash"], r["bolt11"], None
        return InvoiceResponse(ok, checking_id, payment_request, error_message)

    def pay_invoice(self, bolt11: str) -> PaymentResponse:
        r = self.l1.pay(bolt11)
        ok, checking_id, fee_msat, error_message = True, r[
            "payment_hash"], r["msatoshi_sent"] - r["msatoshi"], None
        return PaymentResponse(ok, checking_id, fee_msat, error_message)

    def get_invoice_status(self, checking_id: str) -> PaymentStatus:
        r = self.l1.listinvoices(checking_id)
        if not r["invoices"]:
            return PaymentStatus(False)
        if r["invoices"][0]["label"] == checking_id:
            return PaymentStatus(r["pays"][0]["status"] == "paid")
        raise KeyError("supplied an invalid checking_id")

    def get_payment_status(self, checking_id: str) -> PaymentStatus:
        r = self.l1.listpays(payment_hash=checking_id)
        if not r["pays"]:
            return PaymentStatus(False)
        if r["pays"][0]["payment_hash"] == checking_id:
            status = r["pays"][0]["status"]
            if status == "complete":
                return PaymentStatus(True)
            elif status == "failed":
                return PaymentStatus(False)
            return PaymentStatus(None)
        raise KeyError("supplied an invalid checking_id")
Exemplo n.º 5
0
def make_many_payments(
    sender: LightningRpc,
    receiver: LightningRpc,
    num_payments: int,
    msatoshi_per_payment: int,
) -> None:
    # in case the receiver is evil, the secret will not be returned and the call
    # to LightningRpc.pay will be stuck, waiting for the secret. therefore we
    # use the lower-level 'sendpay' method which doesn't wait for payment completion

    for i in range(num_payments):
        invoice = receiver.invoice(
            msatoshi=msatoshi_per_payment,
            label=f"label_{time.time()}",  # a unique label is needed
            description="",
        )
        route = sender.getroute(
            node_id=get_id(receiver),
            msatoshi=msatoshi_per_payment,
            riskfactor=1,
        )["route"]

        sender.sendpay(route=route, payment_hash=invoice["payment_hash"])
Exemplo n.º 6
0
def generate_invoice():
    # Generate the invoice
    l1 = LightningRpc("/home/admin/.lightning/lightning-rpc")
    invoice = l1.invoice(10000,"1n1{}".format(random.random()),"static-discharge")
    return invoice['bolt11']
Exemplo n.º 7
0
class LightningNode(object):

    displayName = 'lightning'

    def __init__(self,
                 lightning_dir,
                 lightning_port,
                 btc,
                 executor=None,
                 node_id=0):
        self.bitcoin = btc
        self.executor = executor
        self.daemon = LightningD(lightning_dir,
                                 self.bitcoin,
                                 port=lightning_port)
        socket_path = os.path.join(lightning_dir,
                                   "lightning-rpc").format(node_id)
        self.invoice_count = 0
        self.logger = logging.getLogger(
            'lightning-node({})'.format(lightning_port))

        self.rpc = LightningRpc(socket_path, self.executor)

        orig_call = self.rpc._call

        def rpc_call(method, args):
            self.logger.debug("Calling {} with arguments {}".format(
                method, json.dumps(args, indent=4, sort_keys=True)))
            r = orig_call(method, args)
            self.logger.debug("Call returned {}".format(
                json.dumps(r, indent=4, sort_keys=True)))
            return r

        self.rpc._call = rpc_call
        self.myid = None

    def peers(self):
        return [p['id'] for p in self.rpc.listpeers()['peers']]

    def getinfo(self):
        if not self.info:
            self.info = self.rpc.getinfo()
        return self.info

    def id(self):
        if not self.myid:
            self.myid = self.rpc.getinfo()['id']
        return self.myid

    def openchannel(self, node_id, host, port, satoshis):
        # Make sure we have a connection already
        if node_id not in self.peers():
            raise ValueError("Must connect to node before opening a channel")
        return self.rpc.fundchannel(node_id, satoshis)

    def getaddress(self):
        return self.rpc.newaddr()['address']

    def addfunds(self, bitcoind, satoshis):
        addr = self.getaddress()
        txid = bitcoind.rpc.sendtoaddress(addr, float(satoshis) / 10**8)
        bitcoind.rpc.getrawtransaction(txid)
        while len(self.rpc.listfunds()['outputs']) == 0:
            time.sleep(1)
            bitcoind.rpc.generate(1)

    def ping(self):
        """ Simple liveness test to see if the node is up and running

        Returns true if the node is reachable via RPC, false otherwise.
        """
        try:
            self.rpc.help()
            return True
        except:
            return False

    def check_channel(self, remote, require_both=False):
        """Make sure that we have an active channel with remote

        `require_both` must be False unless the other side supports
        sending a `channel_announcement` and `channel_update` on
        `funding_locked`. This doesn't work for eclair for example.

        """
        remote_id = remote.id()
        self_id = self.id()
        peer = None
        for p in self.rpc.listpeers()['peers']:
            if remote.id() == p['id']:
                peer = p
                break
        if not peer:
            self.logger.debug('Peer {} not found in listpeers'.format(remote))
            return False

        if len(peer['channels']) < 1:
            self.logger.debug(
                'Peer {} has no channel open with us'.format(remote))
            return False

        state = p['channels'][0]['state']
        self.logger.debug("Channel {} -> {} state: {}".format(
            self_id, remote_id, state))

        if state != 'CHANNELD_NORMAL' or not p['connected']:
            self.logger.debug(
                'Channel with peer {} is not in state normal ({}) or peer is not connected ({})'
                .format(remote_id, state, p['connected']))
            return False

        # Make sure that gossipd sees a local channel_update for routing
        scid = p['channels'][0]['short_channel_id']

        channels = self.rpc.listchannels(scid)['channels']

        if not require_both and len(channels) >= 1:
            return channels[0]['active']

        if len(channels) != 2:
            self.logger.debug(
                'Waiting for both channel directions to be announced: 2 != {}'.
                format(len(channels)))
            return False

        return channels[0]['active'] and channels[1]['active']

    def getchannels(self):
        result = []
        for c in self.rpc.listchannels()['channels']:
            result.append((c['source'], c['destination']))
        return set(result)

    def getnodes(self):
        return set([n['nodeid'] for n in self.rpc.listnodes()['nodes']])

    def invoice(self, amount):
        invoice = self.rpc.invoice(amount, "invoice%d" % (self.invoice_count),
                                   "description")
        self.invoice_count += 1
        return invoice['bolt11']

    def send(self, req):
        result = self.rpc.pay(req)
        return result['payment_preimage']

    def connect(self, host, port, node_id):
        return self.rpc.connect(node_id, host, port)

    def info(self):
        r = self.rpc.getinfo()
        return {
            'id': r['id'],
            'blockheight': r['blockheight'],
        }

    def block_sync(self, blockhash):
        time.sleep(1)

    def restart(self):
        self.daemon.stop()
        time.sleep(5)
        self.daemon.start()
        time.sleep(1)

    def stop(self):
        self.daemon.stop()

    def start(self):
        self.daemon.start()

    def check_route(self, node_id, amount):
        try:
            r = self.rpc.getroute(node_id, amount, 1.0)
        except ValueError as e:
            if (str(e).find("Could not find a route") > 0):
                return False
            raise
        return True
Exemplo n.º 8
0
class CLightningWallet(Wallet):
    def __init__(self):
        if LightningRpc is None:  # pragma: nocover
            raise ImportError(
                "The `pylightning` library must be installed to use `CLightningWallet`."
            )

        self.rpc = getenv("CLIGHTNING_RPC")
        self.ln = LightningRpc(self.rpc)

        # check description_hash support (could be provided by a plugin)
        self.supports_description_hash = False
        try:
            answer = self.ln.help("invoicewithdescriptionhash")
            if answer["help"][0]["command"].startswith(
                    "invoicewithdescriptionhash msatoshi label description_hash",
            ):
                self.supports_description_hash = True
        except:
            pass

        # check last payindex so we can listen from that point on
        self.last_pay_index = 0
        invoices = self.ln.listinvoices()
        for inv in invoices["invoices"][::-1]:
            if "pay_index" in inv:
                self.last_pay_index = inv["pay_index"]
                break

    def create_invoice(
            self,
            amount: int,
            memo: Optional[str] = None,
            description_hash: Optional[bytes] = None) -> InvoiceResponse:
        label = "lbl{}".format(random.random())
        msat = amount * 1000

        try:
            if description_hash:
                if not self.supports_description_hash:
                    raise Unsupported("description_hash")

                params = [msat, label, description_hash.hex()]
                r = self.ln.call("invoicewithdescriptionhash", params)
                return InvoiceResponse(True, label, r["bolt11"], "")
            else:
                r = self.ln.invoice(msat,
                                    label,
                                    memo,
                                    exposeprivatechannels=True)
                return InvoiceResponse(True, label, r["bolt11"], "")
        except RpcError as exc:
            error_message = f"lightningd '{exc.method}' failed with '{exc.error}'."
            return InvoiceResponse(False, label, None, error_message)

    def pay_invoice(self, bolt11: str) -> PaymentResponse:
        r = self.ln.pay(bolt11)
        return PaymentResponse(True, r["payment_hash"],
                               r["msatoshi_sent"] - r["msatoshi"], None)

    def get_invoice_status(self, checking_id: str) -> PaymentStatus:
        r = self.ln.listinvoices(checking_id)
        if not r["invoices"]:
            return PaymentStatus(False)
        if r["invoices"][0]["label"] == checking_id:
            return PaymentStatus(r["invoices"][0]["status"] == "paid")
        raise KeyError("supplied an invalid checking_id")

    def get_payment_status(self, checking_id: str) -> PaymentStatus:
        r = self.ln.call("listpays", {"payment_hash": checking_id})
        if not r["pays"]:
            return PaymentStatus(False)
        if r["pays"][0]["payment_hash"] == checking_id:
            status = r["pays"][0]["status"]
            if status == "complete":
                return PaymentStatus(True)
            elif status == "failed":
                return PaymentStatus(False)
            return PaymentStatus(None)
        raise KeyError("supplied an invalid checking_id")

    async def paid_invoices_stream(self) -> AsyncGenerator[str, None]:
        stream = await trio.open_unix_socket(self.rpc)

        i = 0
        while True:
            call = json.dumps({
                "method": "waitanyinvoice",
                "id": 0,
                "params": [self.last_pay_index],
            })

            await stream.send_all(call.encode("utf-8"))

            data = await stream.receive_some()
            paid = json.loads(data.decode("ascii"))

            paid = self.ln.waitanyinvoice(self.last_pay_index)
            self.last_pay_index = paid["pay_index"]
            yield paid["label"]

            i += 1
Exemplo n.º 9
0
"""
Challenge:
rpc3 generates an invoice and returns details to rpc1. rpc1 then does a sendpay only to
*rpc2*, who, upon not recognising the payment hash will generate an onion which forwards
the payment to rpc3.
"""


rpc1 = LightningRpc("/tmp/l1-regtest/regtest/lightning-rpc")
rpc2 = LightningRpc("/tmp/l2-regtest/regtest/lightning-rpc")
rpc3 = LightningRpc("/tmp/l3-regtest/regtest/lightning-rpc")


# rpc3 adds an invoice and returns the decoded invoice
try:
    inv = rpc3.decodepay(rpc3.invoice(10000, uuid4().hex, uuid4().hex)["bolt11"])
except RpcError:
    raise


# get rpc2 node_id
rpc2_node_id = rpc2.getinfo()["id"]

# rpc1 gets a route to rpc2
# we add 10 satoshi to amount (10 hops max x 1 satoshi fee each)
# we add 60 to cltv (10 hops max, CLTV of 6 each)
amt_msat = inv["msatoshi"] + 10
cltv = 9 + 60

try:
    route = rpc1.getroute(
Exemplo n.º 10
0
class CLightningWallet(Wallet):
    def __init__(self):
        if LightningRpc is None:  # pragma: nocover
            raise ImportError(
                "The `pylightning` library must be installed to use `CLightningWallet`."
            )

        self.rpc = getenv("CLIGHTNING_RPC")
        self.ln = LightningRpc(self.rpc)

        # check description_hash support (could be provided by a plugin)
        self.supports_description_hash = False
        try:
            answer = self.ln.help("invoicewithdescriptionhash")
            if answer["help"][0]["command"].startswith(
                    "invoicewithdescriptionhash msatoshi label description_hash",
            ):
                self.supports_description_hash = True
        except:
            pass

        # check last payindex so we can listen from that point on
        self.last_pay_index = 0
        invoices = self.ln.listinvoices()
        for inv in invoices["invoices"][::-1]:
            if "pay_index" in inv:
                self.last_pay_index = inv["pay_index"]
                break

    async def status(self) -> StatusResponse:
        try:
            funds = self.ln.listfunds()
            return StatusResponse(
                None,
                sum([ch["channel_sat"] * 1000 for ch in funds["channels"]]),
            )
        except RpcError as exc:
            error_message = f"lightningd '{exc.method}' failed with '{exc.error}'."
            return StatusResponse(error_message, 0)

    async def create_invoice(
        self,
        amount: int,
        memo: Optional[str] = None,
        description_hash: Optional[bytes] = None,
    ) -> InvoiceResponse:
        label = "lbl{}".format(random.random())
        msat = amount * 1000

        try:
            if description_hash:
                if not self.supports_description_hash:
                    raise Unsupported("description_hash")

                params = [msat, label, description_hash.hex()]
                r = self.ln.call("invoicewithdescriptionhash", params)
                return InvoiceResponse(True, label, r["bolt11"], "")
            else:
                r = self.ln.invoice(msat,
                                    label,
                                    memo,
                                    exposeprivatechannels=True)
                return InvoiceResponse(True, label, r["bolt11"], "")
        except RpcError as exc:
            error_message = f"lightningd '{exc.method}' failed with '{exc.error}'."
            return InvoiceResponse(False, label, None, error_message)

    # WARNING: correct handling of fee_limit_msat is required to avoid security vulnerabilities!
    # The backend MUST NOT spend satoshis above invoice amount + fee_limit_msat.
    async def pay_invoice(self, bolt11: str,
                          fee_limit_msat: int) -> PaymentResponse:
        invoice = lnbits_bolt11.decode(bolt11)
        fee_limit_percent = fee_limit_msat / invoice.amount_msat * 100

        payload = {
            "bolt11": bolt11,
            "maxfeepercent": "{:.11}".format(fee_limit_percent),
            "exemptfee":
            0  # so fee_limit_percent is applied even on payments with fee under 5000 millisatoshi (which is default value of exemptfee)
        }

        try:
            r = self.ln.call("pay", payload)
        except RpcError as exc:
            return PaymentResponse(False, None, 0, None, str(exc))

        fee_msat = r["msatoshi_sent"] - r["msatoshi"]
        preimage = r["payment_preimage"]
        return PaymentResponse(True, r["payment_hash"], fee_msat, preimage,
                               None)

    async def get_invoice_status(self, checking_id: str) -> PaymentStatus:
        r = self.ln.listinvoices(checking_id)
        if not r["invoices"]:
            return PaymentStatus(False)
        if r["invoices"][0]["label"] == checking_id:
            return PaymentStatus(r["invoices"][0]["status"] == "paid")
        raise KeyError("supplied an invalid checking_id")

    async def get_payment_status(self, checking_id: str) -> PaymentStatus:
        r = self.ln.call("listpays", {"payment_hash": checking_id})
        if not r["pays"]:
            return PaymentStatus(False)
        if r["pays"][0]["payment_hash"] == checking_id:
            status = r["pays"][0]["status"]
            if status == "complete":
                return PaymentStatus(True)
            elif status == "failed":
                return PaymentStatus(False)
            return PaymentStatus(None)
        raise KeyError("supplied an invalid checking_id")

    async def paid_invoices_stream(self) -> AsyncGenerator[str, None]:
        stream = await trio.open_unix_socket(self.rpc)

        i = 0
        while True:
            call = json.dumps({
                "method": "waitanyinvoice",
                "id": 0,
                "params": [self.last_pay_index],
            })

            await stream.send_all(call.encode("utf-8"))

            data = await stream.receive_some()
            paid = json.loads(data.decode("ascii"))

            paid = self.ln.waitanyinvoice(self.last_pay_index)
            self.last_pay_index = paid["pay_index"]
            yield paid["label"]

            i += 1
Exemplo n.º 11
0
def generate_invoice():
    # Generate the invoice
    l1 = LightningRpc("/home/admin/.lightning/lightning-rpc")
    invoice = l1.invoice(500, "lb1{}".format(random.random()), "testpay")
    return invoice['bolt11']
Exemplo n.º 12
0
class LightningNode(object):
    def __init__(self,
                 lightning_dir,
                 lightning_port,
                 btc,
                 executor=None,
                 node_id=0):
        self.bitcoin = btc
        self.executor = executor
        self.daemon = LightningD(lightning_dir,
                                 btc.bitcoin_dir,
                                 port=lightning_port)
        socket_path = os.path.join(lightning_dir,
                                   "lightning-rpc").format(node_id)
        self.invoice_count = 0
        self.rpc = LightningRpc(socket_path, self.executor)
        self.logger = logging.getLogger(
            'lightning-node({})'.format(lightning_port))

    def peers(self):
        return [p['peerid'] for p in self.rpc.getpeers()['peers']]

    def id(self):
        return self.rpc.getinfo()['id']

    def openchannel(self, node_id, host, port, satoshis):
        # Make sure we have a connection already
        if node_id not in self.peers():
            raise ValueError("Must connect to node before opening a channel")
        return self.rpc.fundchannel(node_id, satoshis)

    def getaddress(self):
        return self.rpc.newaddr()['address']

    def addfunds(self, bitcoind, satoshis):
        addr = self.getaddress()
        txid = bitcoind.rpc.sendtoaddress(addr, float(satoshis) / 10**8)
        tx = bitcoind.rpc.getrawtransaction(txid)
        self.rpc.addfunds(tx)

    def ping(self):
        """ Simple liveness test to see if the node is up and running

        Returns true if the node is reachable via RPC, false otherwise.
        """
        try:
            self.rpc.help()
            return True
        except:
            return False

    def check_channel(self, remote):
        """ Make sure that we have an active channel with remote
        """
        remote_id = remote.id()
        self_id = self.id()
        for p in self.rpc.getpeers()['peers']:
            if remote.id() == p['peerid']:
                self.logger.debug("Channel {} -> {} state: {}".format(
                    self_id, remote_id, p['state']))
                return p['state'] == 'CHANNELD_NORMAL'

        self.logger.warning("Channel {} -> {} not found".format(
            self_id, remote_id))
        return False

    def getchannels(self):
        result = []
        for c in self.rpc.getchannels()['channels']:
            result.append((c['source'], c['destination']))
        return set(result)

    def getnodes(self):
        return set([n['nodeid'] for n in self.rpc.getnodes()['nodes']])

    def invoice(self, amount):
        invoice = self.rpc.invoice(amount, "invoice%d" % (self.invoice_count),
                                   "description")
        self.invoice_count += 1
        print(invoice)
        return invoice['bolt11']

    def send(self, req):
        result = self.rpc.pay(req)
        return result['preimage']

    def connect(self, host, port, node_id):
        return self.rpc.connect(node_id, "{}:{}".format(host, port))

    def info(self):
        r = self.rpc.getinfo()
        return {
            'id': r['id'],
            'blockheight': r['blockheight'],
        }
Exemplo n.º 13
0
class CLightning(LnNode):
    def __init__(self):
        super().__init__()
        self.lnrpc = ''
        self.rpc_file = '/tmp/lightningrpc'

    def setup(self, ipaddr='127.0.0.1', port=9735, argv=None):
        self.ipaddr = ipaddr
        self.port = port
        if argv is not None:
            self.rpc_file = argv
        self.lnrpc = LightningRpc(self.rpc_file)

    def get_name(self):
        return 'c-lightning'

    '''
    enum channel_state {
        /* In channeld, still waiting for lockin. */
        CHANNELD_AWAITING_LOCKIN = 2,

        /* Normal operating state. */
        CHANNELD_NORMAL,

        /* We are closing, pending HTLC resolution. */
        CHANNELD_SHUTTING_DOWN,

        /* Exchanging signatures on closing tx. */
        CLOSINGD_SIGEXCHANGE,

        /* Waiting for onchain event. */
        CLOSINGD_COMPLETE,

        /* Waiting for unilateral close to hit blockchain. */
        AWAITING_UNILATERAL,

        /* We've seen the funding spent, we're waiting for onchaind. */
        FUNDING_SPEND_SEEN,

        /* On chain */
        ONCHAIN
    };
    '''

    def get_status(self, peer):
        channel_sat = 0
        try:
            result = self.lnrpc.listpeers()
            if ('peers' not in result) or (len(result['peers']) == 0):
                print('(status=none)')
                return LnNode.Status.NONE, 0
            peer_status = ''
            current_ch = None
            for p in result['peers']:
                if p['id'] == peer:
                    for ch in p['channels']:
                        if ch['state'] != 'ONCHAIN':
                            # onchainなものは「済」と判断して無視する
                            current_ch = ch
                            peer_status = ch['state']
                            break
            print('(status=', peer_status + ')')
            if peer_status == 'CHANNELD_NORMAL':
                status = LnNode.Status.NORMAL
                channel_sat = current_ch['msatoshi_to_us']
            elif peer_status == 'CHANNELD_AWAITING_LOCKIN':
                status = LnNode.Status.FUNDING
            elif peer_status == 'CHANNELD_SHUTTING_DOWN' or\
                    peer_status == 'CLOSINGD_SIGEXCHANGE' or\
                    peer_status == 'CLOSINGD_COMPLETE' or\
                    peer_status == 'AWAITING_UNILATERAL' or\
                    peer_status == 'FUNDING_SPEND_SEEN':
                status = LnNode.Status.CLOSING
            else:
                status = LnNode.Status.NONE
        except:
            print('traceback.format_exc():\n%s' % traceback.format_exc())
            os.kill(os.getpid(), signal.SIGKILL)
        return status, channel_sat

    def get_nodeid(self):
        try:
            info = self.lnrpc.getinfo()
            return info['id']
        except:
            print('traceback.format_exc():\n%s' % traceback.format_exc())
            os.kill(os.getpid(), signal.SIGKILL)

    # result[1] = "OK" or "NG"
    def connect(self, node_id, ipaddr, port):
        try:
            res = self.lnrpc.connect(node_id, ipaddr, port)
            print('connect=', res)
            res = '{"result": ["connect","OK","' + node_id + '"]}'
        except RpcError as e:
            print('traceback.format_exc():\n%s' % traceback.format_exc())
            print('fail connect')
            res = '{"result": ["connect","NG","' + node_id + '","' + e.error[
                'message'] + '"]}'
        except:
            print('traceback.format_exc():\n%s' % traceback.format_exc())
            print('fail connect')
            res = '{"result": ["connect","NG","' + node_id + '"]}'
        return res

    # result[1] = "OK" or "NG"
    def disconnect(self, node_id):
        print('disconnect: ' + node_id)
        try:
            res = self.lnrpc.disconnect(node_id, force=True)
            print('disconnect=', res)
            res = '{"result": ["disconnect","OK","' + node_id + '"]}'
        except RpcError as e:
            print('traceback.format_exc():\n%s' % traceback.format_exc())
            print('fail disconnect')
            res = '{"result": ["disconnect","NG","' + node_id + '","' + e.error[
                'message'] + '"]}'
        except:
            print('traceback.format_exc():\n%s' % traceback.format_exc())
            print('fail disconnect')
            res = '{"result": ["disconnect","NG","' + node_id + '"]}'
        return res

    # result[1] = "OK" or "NG"
    def open_channel(self, node_id, amount):
        try:
            res = self.lnrpc.fundchannel(node_id, amount)
            print('open_channel=', res)
            res = '{"result": ["openchannel","OK","' + node_id + '"]}'
        except RpcError as e:
            print('traceback.format_exc():\n%s' % traceback.format_exc())
            print('fail openchannel')
            res = '{"result": ["openchannel","NG","' + node_id + '","' + e.error[
                'message'] + '"]}'
        except:
            print('traceback.format_exc():\n%s' % traceback.format_exc())
            print('fail open_channel')
            res = '{"result": ["openchannel","NG","' + node_id + '"]}'
        return res

    # result[1] = BOLT11 or "NG"
    def get_invoice(self, amount_msat, label=''):
        try:
            res = self.lnrpc.invoice(amount_msat,
                                     "lbl{}".format(random.random()),
                                     "testpayment")
            print('invoice=', res)
            res = '{"result": ["invoice","' + res[
                'bolt11'] + '","' + label + '"]}'
        except RpcError as e:
            print('traceback.format_exc():\n%s' % traceback.format_exc())
            print('fail invoice')
            res = '{"result": ["invoice","NG","' + label + '","' + e.error[
                'message'] + '"]}'
        except:
            print('traceback.format_exc():\n%s' % traceback.format_exc())
            print('fail invoice')
            res = '{"result": ["invoice","NG","' + label + '"]}'
        return res

    # result[1] = "OK" or "NG"
    def pay(self, invoice):
        try:
            res = self.lnrpc.pay(invoice, riskfactor=100)
            print('pay=', res)
            res = '{"result": ["pay","OK","' + invoice + '"]}'
        except RpcError as e:
            print('traceback.format_exc():\n%s' % traceback.format_exc())
            print('fail pay: ' + invoice)
            res = '{"result": ["pay","NG","' + invoice + '","' + e.error[
                'message'] + '"]}'
        except:
            print('traceback.format_exc():\n%s' % traceback.format_exc())
            print('fail pay: ' + invoice)
            res = '{"result": ["pay","NG","' + invoice + '"]}'
        return res

    # result[1] = "OK" or "NG"
    def close_mutual(self, node_id):
        print('close_mutual')
        return self._close(node_id, False)

    # result[1] = "OK" or "NG"
    def close_force(self, node_id):
        print('close_force')
        self.disconnect(node_id)
        return self._close(node_id, True)

    # result[1] = "OK" or "NG"
    def _close(self, node_id, force):
        str_force = 'force' if force else 'mutual'
        try:
            res = self.lnrpc.close(node_id, force=force)
            print('close=', res)
            res = '{"result": ["closechannel","OK","' + node_id + '","' + str_force + '"]}'
        except RpcError as e:
            print('traceback.format_exc():\n%s' % traceback.format_exc())
            print('fail closechannel')
            res = '{"result": ["closechannel","NG","' + node_id + '","' + e.error[
                'message'] + '"]}'
        except:
            print('traceback.format_exc():\n%s' % traceback.format_exc())
            print('fail closechannel')
            res = '{"result": ["closechannel","NG","' + node_id + '","' + str_force + '"]}'
        return res
Exemplo n.º 14
0
# """
# Challenge:
# rpc3 generates an invoice and returns details to rpc1. rpc1 then does a sendpay only to
# *rpc2*, who, upon not recognising the payment hash will generate an onion which forwards
# to rpc3.
# """

rpc1 = LightningRpc("/tmp/l1-regtest/regtest/lightning-rpc")
rpc2 = LightningRpc("/tmp/l2-regtest/regtest/lightning-rpc")

# rpc2 adds an invoice and returns the decoded invoice
try:
    inv = rpc2.decodepay(
        rpc2.invoice(10000,
                     uuid4().hex,
                     uuid4().hex)["bolt11"])
except RpcError:
    raise

# get rpc2 node_id
rpc2_node_id = rpc2.getinfo()["id"]

# rpc1 gets a route to rpc2
# we add 10 satoshi to amount (10 hops max x 1 satoshi fee each)
# we add 60 to cltv (10 hops max, CLTV of 6 each)
amt_msat = inv["msatoshi"] + 10
cltv = 9 + 60

try:
    route = rpc1.getroute(node_id=rpc2_node_id,