示例#1
0
def index(request):
    # Bitcoin RPC Credentials (you need to change these)
    rpc_port = "8332"
    rpc_user = "******"
    rpc_password = "******"

    # LIGHTNING NETWORK

    # Lightning Network Socket file (you might need to change this)
    ln = LightningRpc("/home/pi/.lightning/lightning-rpc")

    try:
        l_info = ln.getinfo()
        l = LightningViewData(True)
        l.block_height = l_info["blockheight"]
        l.version = l_info["version"]
        l.version = l.version.replace("v", "")

        l_peers = ln.listpeers()
        l.peer_count = len(l_peers["peers"])

        l_funds = ln.listfunds()
        l.channel_count = len(l_funds["channels"])
    except:
        l = LightningViewData(False)

# BITCOIN

    b = BitcoinViewData(True)

    try:
        rpc_connection = AuthServiceProxy("http://%s:%[email protected]:%s" %
                                          (rpc_user, rpc_password, rpc_port))
        b_conn_count = rpc_connection.getconnectioncount()
        if b_conn_count > 0:
            b.online = True
    except Exception as e:
        b.running = False

    if b.running == True:
        try:
            b.block_height = rpc_connection.getblockcount()
            b_network_info = rpc_connection.getnetworkinfo()
            b.peer_count = b_network_info["connections"]
            b.version = b_network_info["subversion"]
            b.version = b.version.replace("/", "")
            b.version = b.version.replace("Satoshi:", "")
        except Exception as e:
            b.message = str(e)


# RETURN VIEW DATA

    return render(request, 'dashboard/index.html', {
        'lightning': l,
        'bitcoin': b
    })
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
class CLightning_autopilot(Autopilot):
    def __init__(self, path, input=None, dont_store=None):
        self.__add_clogger()

        self.__rpc_interface = LightningRpc(path)
        self.__clogger.info("connection to RPC interface successful")

        G = None
        if input:
            try:
                self.__clogger.info("Try to load graph from file system at:" +
                                    input)
                with open(input, "rb") as infile:
                    G = pickle.load(infile)
                    self.__clogger.info(
                        "Successfully restored the lightning network graph from data/networkx_graph"
                    )
            except FileNotFoundError:
                self.__clogger.info(
                    "input file not found. Load the graph from the peers of the lightning network"
                )
                G = self.__download_graph()
        else:
            self.__clogger.info("no input specified download graph from peers")
            G = self.__download_graph()

        if dont_store is None:
            with open("lightning_networkx_graph.pickle", "wb") as outfile:
                pickle.dump(G, outfile, pickle.HIGHEST_PROTOCOL)

        Autopilot.__init__(self, G)

    def __add_clogger(self):
        """ initiates the logging service for this class """
        # FIXME: adapt to the settings that are proper for you
        self.__clogger = logging.getLogger('clightning-autopilot')
        self.__clogger.setLevel(logging.INFO)
        ch = logging.StreamHandler()
        ch.setLevel(logging.INFO)
        formatter = logging.Formatter(
            '%(asctime)s - %(name)s - %(levelname)s - %(message)s')
        ch.setFormatter(formatter)
        self.__clogger.addHandler(ch)
        self.__clogger.info("set up logging infrastructure")

    def __get_seed_keys(self):
        """
        retrieve the nodeids of the ln seed nodes from lseed.bitcoinstats.com
        """
        domain = "lseed.bitcoinstats.com"
        srv_records = dns.resolver.query(domain, "SRV")
        res = []
        for srv in srv_records:
            bech32 = str(srv.target).rstrip(".").split(".")[0]
            data = bech32_decode(bech32)[1]
            decoded = convertbits(data, 5, 4)
            res.append("".join(
                ['{:1x}'.format(integer) for integer in decoded])[:-1])
        return res

    def __connect_to_seeds(self):
        """
        sets up peering connection to seed nodes of the lightning network
        
        This is necessary in case the node operating the autopilot has never
        been connected to the lightning network.
        """
        try:
            for nodeid in random.shuffle(self.__get_seed_keys()):
                self.__clogger.info("peering with node: " + nodeid)
                self.__rpc_interface.connect(nodeid)
                # FIXME: better strategy than sleep(2) for building up
                time.sleep(2)
        except:
            pass

    def __download_graph(self):
        """
        Downloads a local copy of the nodes view of the lightning network
        
        This copy is retrieved by listnodes and listedges RPC calls and will
        thus be incomplete as peering might not be ready yet.
        """

        # FIXME: it is a real problem that we don't know how many nodes there
        # could be. In particular billion nodes networks will outgrow memory
        G = nx.Graph()
        self.__clogger.info(
            "Instantiated networkx graph to store the lightning network")

        nodes = []
        try:
            self.__clogger.info(
                "Attempt RPC-call to download nodes from the lightning network"
            )
            while len(nodes) == 0:
                peers = self.__rpc_interface.listpeers()["peers"]
                if len(peers) < 1:
                    self.__connect_to_seeds()
                nodes = self.__rpc_interface.listnodes()["nodes"]
        except ValueError as e:
            self.__clogger.info(
                "Node list could not be retrieved from the peers of the lightning network"
            )
            self.__clogger.debug("RPC error: " + str(e))
            raise e

        for node in nodes:
            G.add_node(node["nodeid"], **node)

        self.__clogger.info(
            "Number of nodes found and added to the local networkx graph: {}".
            format(len(nodes)))

        channels = {}
        try:
            self.__clogger.info(
                "Attempt RPC-call to download channels from the lightning network"
            )
            channels = self.__rpc_interface.listchannels()["channels"]
            self.__clogger.info("Number of retrieved channels: {}".format(
                len(channels)))
        except ValueError as e:
            self.__clogger.info(
                "Channel list could not be retrieved from the peers of the lightning network"
            )
            self.__clogger.debug("RPC error: " + str(e))
            return False

        for channel in channels:
            G.add_edge(channel["source"], channel["destination"], **channel)

        return G

    def connect(self, candidates, balance=1000000):
        pdf = self.calculate_statistics(candidates)
        connection_dict = self.calculate_proposed_channel_capacities(
            pdf, balance)
        for nodeid, fraction in connection_dict.items():
            try:
                satoshis = math.ceil(balance * fraction)
                self.__clogger.info(
                    "Try to open channel with a capacity of {} to node {}".
                    format(satoshis, nodeid))
                self.__rpc_interface.fundchannel(nodeid, satoshis)
            except ValueError as e:
                self.__clogger.info(
                    "Could not open a channel to {} with capacity of {}. Error: {}"
                    .format(nodeid, satoshis, str(e)))
示例#4
0
class LightningOperator:

	rpc_interface = None
	__network = None

	def __init__(self, network):

		self.__network = network

		if self.__network == "mainnet":
			self.rpc_interface = LightningRpc(expanduser("~")+"/.mainnet/lightning-rpc")


			self.rpc_interface.connect("02f6725f9c1c40333b67faea92fd211c183050f28df32cac3f9d69685fe9665432@104.198.32.198:9735")
			#self.rpc_interface.connect("030fe6f75d41d7112afee0f6f0e230095d9036abf19c7f88f416cc7b9ab9e9ef3e@203.206.164.188:9735")
			#self.rpc_interface.connect("03abf6f44c355dec0d5aa155bdbdd6e0c8fefe318eff402de65c6eb2e1be55dc3e@52.15.79.245:9735")
			#self.rpc_interface.connect("03cb7983dc247f9f81a0fa2dfa3ce1c255365f7279c8dd143e086ca333df10e278@46.28.204.21:9735")
			#self.rpc_interface.connect("03e50492eab4107a773141bb419e107bda3de3d55652e6e1a41225f06a0bbf2d56@35.172.33.197:9735")

		else:
			self.rpc_interface = LightningRpc(expanduser("~")+"/.lightning/lightning-rpc")

			self.rpc_interface.connect("03236a685d30096b26692dce0cf0fa7c8528bdf61dbf5363a3ef6d5c92733a3016@50.116.3.223:9734")
			#self.rpc_interface.connect("03782bb858e1ec9c0a4a5ac665ed658c97ced02e723eafc3c56137ab4e2e3caebf@52.8.119.71:9736")
			#self.rpc_interface.connect("02ec66fb12dd5d4943d63e7a1a35d063aec015e1c8b89cee6c9f2db3faf0f6687f@3.93.159.131:19735")
			#self.rpc_interface.connect("0218b92d19de937ef740154d20d3a6f37c44e6381ca72b95789295073664cfdd36@5.95.80.47:9735")

		print(type(self.rpc_interface.getinfo()))

		print(self.rpc_interface.listpeers())

	def isMainnet(self):
		return __network == "mainnet"

	def populate_graph(self, graph):

		print("Attempt RPC-call to download nodes and channels from the lightning network")
		nodes = []
		print(self.rpc_interface)
		try:
			while len(nodes) == 0:
				peers = self.rpc_interface.listpeers()["peers"]
				if len(peers) < 1:
					time.sleep(2)
				nodes = self.rpc_interface.listnodes()["nodes"]
		except ValueError as e:
			print("Cannot download nodes from the network, are you connected to a peer?")
			print("RPC error: " + str(e))
			return False

		print("Number of nodes found: {}".format(len(nodes)))

		for node in nodes:
			graph.add_node(node["nodeid"], object=node)

		"""
		Grab the channels
		"""
		if len(graph.nodes) == 0:
			print("Cannot download channels if nodes do not exist. ")
			return False

		try:

			channels = self.rpc_interface.listchannels()["channels"]
			print("Number of retrieved channels: {}".format(len(channels)))
		except ValueError as e:
			print("Cannot download channels from the network, are you connected to a peer?")
			print("RPC error: " + str(e))
			return False

		i = 0
		j = 0
		for channel in channels:

			if (j % 1000) == 0:
				print(j)

			j += 1

			if channel["source"] not in graph.nodes:
				print(channel["source"], "not in list")
				i += 1

			if channel["destination"] not in graph.nodes:
				print(channel["destination"], "not in list")
				i += 1

			graph.add_edge(channel["source"], channel["destination"], **channel)

		print("NOT IN: ", i)
		return True
示例#5
0
        gg = int(hh[2:4], 16)
        bb = int(hh[4:6], 16)
        return f'\x1b[38;2;{rr};{gg};{bb}m'
    reset = '\x1b[0m' # reset to terminal defaults

def colorize(color, colorthis):
    '''
    Convert a something (color) to a terminal-colorized string.
    '''
    return T.rgb(color) + colorthis + T.reset

T = TermColors()

node = LightningRpc(os.path.join(os.getenv("HOME"), ".lightning/bitcoin/lightning-rpc"))

peers = node.listpeers()

for peer in peers['peers']:
    if len(peer['channels']) > 0:
        chan_status = peer['channels'][0]['state']
        chan_color = node.listnodes(peer["id"])['nodes'][0]['color']
        try:
            peerAlias = node.listnodes(peer["id"])['nodes'][0]['alias']
        except IndexError:
            peerAlias = "????????????????"
        except KeyError:
            peerAlias = "????????????????"
        print(peer['connected'], str(round((peer["channels"][0]["msatoshi_total"]/100000000), 1)) + " mBTC", peer["id"], colorize(chan_color, peerAlias), chan_status, str(round((peer["channels"][0]["msatoshi_to_us"]/100000000), 1)))
    else:
        if len(node.listnodes(peer["id"])['nodes']) > 0:
            print(peer['connected'], "........", peer["id"], node.listnodes(peer["id"])['nodes'][0]['alias'])
# we assume the channels are already set-up

amount = Millisatoshi("0.0001btc")

wait_to_route(src=n1, dest=n3, msatoshi=amount.millisatoshis)

# send many payments to Charlie, which would result in unresolved HTLCs (assuming charlie is evil)
make_many_payments(
    sender=n1,
    receiver=n3,
    num_payments=480,
    msatoshi_per_payment=amount.millisatoshis,
)

# see the number of HTLCs that node 3 have with each peer
for i, peer in enumerate(n3.listpeers()["peers"]):
    print(f"htlcs with peers {i}: {len(peer['channels'][0]['htlcs'])}")

# Alice is not responsive. Bob can't remove HTLCs gracefully
n1.stop()

# node 3 closes all channels gracefully
for peer in n3.listpeers()["peers"]:
    n3.close(peer_id=peer["id"])

mine(1)

# Bob now has to publish the commitment tx of him and Alice
# slowly mine blocks
for _ in range(20):
    mine(1)
示例#7
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