def __init__(self, config_file: Optional[str] = None, lnd_home: Optional[str] = None, lnd_host: Optional[str] = None, regtest=False): """ :param config_file: path to the config file :param lnd_home: path to lnd home folder :param lnd_host: lnd host of format "127.0.0.1:9735" :param regtest: if the node is representing a regtest node """ super().__init__() if config_file: self.config_file = config_file self.config = settings.read_config(self.config_file) else: self.config_file = None self.config = None self.lnd_home = lnd_home self.lnd_host = lnd_host self.regtest = regtest self._rpc = None self._routerrpc = None self.connect_rpcs() self.set_info() self.network = Network(self) self.set_channel_summary() self.update_blockheight()
def _add_channel_annotations(self, channels): """ Appends metadata to existing channel dicts from the configuration file. :param channels: dict :return: dict """ logger.debug("Adding annotations from file %s.", self.node.config_file) # mapping between the channel point and channel id channel_point_mapping = { k: v['channel_point'].split(':')[0] for k, v in channels.items() } # only read annotations if config file is given if self.node.config_file: config = settings.read_config(self.node.config_file) annotations = config['annotations'] else: annotations = {} channel_annotations_funding_id = {} channel_annotations_channel_id = {} for id, annotation in annotations.items(): if len(id) == 18 and id.isnumeric(): # valid channel id channel_annotations_channel_id[int(id)] = \ annotation elif len(id) == 64 and id.isalnum(): # valid funding transaction id channel_annotations_funding_id[id] = \ annotation else: raise ValueError( 'First part needs to be either a channel id or the ' 'funding transaction id. \n' 'The funding transaction id can be found with ' '`lncli listchannels` under the channel point (the ' 'characters before the colon).') for channel_id, channel_values in channels.items(): # get the annotation by channel id first annotation = channel_annotations_channel_id.get(channel_id, None) # if no channel annotation, try with funding id if annotation is None: annotation = channel_annotations_funding_id.get( channel_point_mapping[channel_id], None) if annotation is not None: channels[channel_id]['annotation'] = annotation else: channels[channel_id]['annotation'] = '' return channels
def __init__(self, lncli_path, config_file): self.lncli_path = lncli_path config = settings.read_config(config_file) cert_file = os.path.expanduser(config['network']['tls_cert_file']) macaroon_file = \ os.path.expanduser(config['network']['admin_macaroon_file']) lnd_host = config['network']['lnd_grpc_host'] # assemble the command for lncli for execution with flags self.lncli_command = [ self.lncli_path, '--rpcserver=' + lnd_host, '--macaroonpath=' + macaroon_file, '--tlscertpath=' + cert_file ]
def _add_channel_annotations(self, channels: Dict) -> Dict: """Appends metadata to existing channel dicts from the configuration file.""" if self.node.config: logger.debug("Adding annotations from file %s.", self.node.config_file) # mapping between the channel point and channel id channel_point_mapping = { k: v["channel_point"].split(":")[0] for k, v in channels.items() } # only read annotations if config file is given if self.node.config_file: config = settings.read_config(self.node.config_file) annotations = config["annotations"] else: annotations = {} channel_annotations_funding_id = {} channel_annotations_channel_id = {} for chan_id, annotation in annotations.items(): if len(chan_id) == 18 and chan_id.isnumeric(): # valid channel id channel_annotations_channel_id[int(chan_id)] = annotation elif len(chan_id) == 64 and chan_id.isalnum(): # valid funding transaction id channel_annotations_funding_id[chan_id] = annotation else: raise ValueError( "First part needs to be either a channel id or the " "funding transaction id. \n" "The funding transaction id can be found with " "`lncli listchannels` under the channel point (the " "characters before the colon)." ) for channel_id, channel_values in channels.items(): # get the annotation by channel id first annotation = channel_annotations_channel_id.get(channel_id, None) # if no channel annotation, try with funding id if annotation is None: annotation = channel_annotations_funding_id.get( channel_point_mapping[channel_id], None ) if annotation is not None: channels[channel_id]["annotation"] = annotation else: channels[channel_id]["annotation"] = "" return channels
def connect_rpcs(self): """ Establishes a connection to lnd using the hostname, tls certificate, and admin macaroon defined in settings. """ macaroons = True os.environ['GRPC_SSL_CIPHER_SUITES'] = \ 'ECDHE-RSA-AES128-GCM-SHA256:' \ 'ECDHE-RSA-AES128-SHA256:' \ 'ECDHE-RSA-AES256-SHA384:' \ 'ECDHE-RSA-AES256-GCM-SHA384:' \ 'ECDHE-ECDSA-AES128-GCM-SHA256:' \ 'ECDHE-ECDSA-AES128-SHA256:' \ 'ECDHE-ECDSA-AES256-SHA384:' \ 'ECDHE-ECDSA-AES256-GCM-SHA384' # if no lnd_home is given, then use the paths from the config, # else override them with default file paths in lnd_home if self.lnd_home is not None: cert_file = os.path.join(self.lnd_home, 'tls.cert') bitcoin_network = 'regtest' if self.regtest else 'mainnet' macaroon_file = os.path.join(self.lnd_home, 'data/chain/bitcoin/', bitcoin_network, 'admin.macaroon') if self.lnd_host is None: raise ValueError( 'if lnd_home is given, lnd_host must be given also') lnd_host = self.lnd_host else: config = settings.read_config(self.config_file) cert_file = os.path.expanduser(config['network']['tls_cert_file']) macaroon_file = \ os.path.expanduser(config['network']['admin_macaroon_file']) lnd_host = config['network']['lnd_grpc_host'] cert = None try: with open(cert_file, 'rb') as f: cert = f.read() except FileNotFoundError: logger.error("tls.cert not found, please configure %s.", self.config_file) exit(1) if macaroons: try: with open(macaroon_file, 'rb') as f: macaroon_bytes = f.read() macaroon = codecs.encode(macaroon_bytes, 'hex') except FileNotFoundError: logger.error("admin.macaroon not found, please configure %s.", self.config_file) exit(1) def metadata_callback(context, callback): callback([('macaroon', macaroon)], None) cert_creds = grpc.ssl_channel_credentials(cert) auth_creds = grpc.metadata_call_credentials(metadata_callback) creds = grpc.composite_channel_credentials(cert_creds, auth_creds) else: creds = grpc.ssl_channel_credentials(cert) # necessary to circumvent standard size limitation channel = grpc.secure_channel(lnd_host, creds, options=[ ('grpc.max_receive_message_length', 50 * 1024 * 1024) ]) # establish connections to rpc servers self._rpc = lndrpc.LightningStub(channel) self._routerrpc = lndrouterrpc.RouterStub(channel)