class TestRouter(TestCase): def setUp(self): self.node = LndNode() self.router = Router(self.node) def test_get_routes_along_nodes(self): node_from = '000000000000000000000000000000000000000000000000000000000000000000' node_to = '000000000000000000000000000000000000000000000000000000000000000000' amt = 100 routes = self.router.get_routes_from_to_nodes(node_from, node_to, amt, number_of_routes=2) print(routes) def test_queryroute_external(self): node_from = '000000000000000000000000000000000000000000000000000000000000000000' node_to = '000000000000000000000000000000000000000000000000000000000000000000' amt = 100 channel_route = self.node.queryroute_external(node_from, node_to, amt) print(channel_route) channel_route = self.node.queryroute_external( node_from, node_to, amt, ignored_channels=[000000000000000000]) print(channel_route) def test_route(self): """ to test a route, run $ lncli queryroutes source amt and copy-paste channel ids here and compare the results """ route = Route( self.node, [000000000000000000, 000000000000000000], '000000000000000000000000000000000000000000000000000000000000000000', 333000) route._debug_route() print('\nFinal route with reverse chain of fees:') print(self.node.lnd_route(route)) def test_node_route_to_channel_route(self): hops = self.router._node_route_to_channel_route([ '000000000000000000000000000000000000000000000000000000000000000000', '000000000000000000000000000000000000000000000000000000000000000000', '000000000000000000000000000000000000000000000000000000000000000000', ], amt_msat=100) print(hops) def test_get_routes_for_advanced_rebalancing(self): self.router.get_routes_for_rebalancing(000000000000000000, 000000000000000000, 100)
class TestRebalance(TestCase): def setUp(self): self.node = LndNode() def test_manual_rebalance(self): manual_rebalance(self.node, 000000000000000000, 000000000000000000, amt=141248, number_of_routes=5) def test_auto_rebalance(self): rebalancer = Rebalancer(self.node, max_effective_fee_rate=1, budget_sat=10) invoice_r_hash = self.node.get_rebalance_invoice(memo='autorebalance test') rebalancer.rebalance_two_channels(000000000000000000, 000000000000000000, amt_sat=1, invoice_r_hash=invoice_r_hash, budget_sat=10) def test_rebalance(self): rebalancer = Rebalancer(self.node, max_effective_fee_rate=0.0001, budget_sat=50) channel_id = 000000000000000000 fee = rebalancer.rebalance(channel_id) print(fee)
def setUp(self): if self.network_definition is None: self.skipTest("This class doesn't represent a real test case.") raise NotImplementedError("A network definition path needs to be " "given.") # we delete previous test data try: shutil.rmtree(lndmanage_home) except FileNotFoundError: pass os.mkdir(lndmanage_home) self.testnet = Network( binary_folder=bin_dir, network_definition_location=self.network_definition, nodedata_folder=test_data_dir, node_limit='H', from_scratch=True) self.testnet.run_nocleanup() # to run the lightning network in the background and do some testing # here, run: # $ lnregtest --nodedata_folder /path/to/lndmanage/test/test_data/ # self.testnet.run_from_background() # logger.info("Generated network information:") # logger.info(format_dict(self.testnet.node_mapping)) # logger.info(format_dict(self.testnet.channel_mapping)) # logger.info(format_dict(self.testnet.assemble_graph())) master_node_data_dir = self.testnet.master_node.data_dir master_node_port = self.testnet.master_node._grpc_port self.master_node_graph_view = self.testnet.master_node_graph_view() self.lndnode = LndNode(lnd_home=master_node_data_dir, lnd_host='localhost:' + str(master_node_port), regtest=True) self.graph_test()
break else: invoice_r_hash = self.node.get_rebalance_invoice( memo=f"lndmanage: Rebalance of channel {channel_id}.") except NoRouteError: logger.error( "There was no route cheap enough or with enough capacity.\n" ) except DryRunException: logger.info( "Would have tried this route now, but it was a dry run.\n") except RebalanceFailure: logger.error("Failed to rebalance with this channel.\n") except TooExpensive: logger.error("Too expensive.\n") return total_fees_msat if __name__ == "__main__": import logging.config logging.config.dictConfig(_settings.logger_config) from lib.node import LndNode nd = LndNode() chan = 000000000000000000 max_fee_rate = 0.0001 rebalancer = Rebalancer(nd, max_fee_rate, budget_sat=20) fee = rebalancer.rebalance(chan) print(fee)
import _settings from lib.network_info import NetworkAnalysis from lib.node import LndNode import logging.config logging.config.dictConfig(_settings.logger_config) logger = logging.getLogger(__name__) if __name__ == '__main__': node = LndNode() network_analysis = NetworkAnalysis(node) network_analysis.print_node_overview(node.pub_key) logger.info('-------- Nodes with highest capacity: --------') for n in network_analysis.get_sorted_nodes_by_property(): logger.info(n) logger.info('-------- Nodes with highest degree: --------') for n in network_analysis.get_sorted_nodes_by_property(key='degree'): logger.info(n) logger.info('-------- Nodes with highest capacity/channel: --------') for n in network_analysis.get_sorted_nodes_by_property( key='capacity_per_channel', min_degree=10): logger.info(n) logger.info('-------- Nodes with lowest capacity/channel: --------') for n in network_analysis.get_sorted_nodes_by_property( key='capacity_per_channel', min_degree=20, decrementing=False): logger.info(n) logger.info('-------- Nodes with most user nodes: --------') for n in network_analysis.get_sorted_nodes_by_property(key='user_nodes',
def main(): parser = Parser() args = parser.parse_arguments() # print(args) if args.cmd is None: parser.parser.print_help() return 0 # program execution if args.loglevel: # update the loglevel of the stdout handler to the user choice logger.handlers[0].setLevel(args.loglevel) node = LndNode() if args.cmd == 'status': node.print_status() elif args.cmd == 'listchannels': if not args.subcmd: print_channels_rebalance(node, unbalancedness_greater_than=0) if args.subcmd == 'rebalance': print_channels_rebalance(node, args.unbalancedness, sort_by='ub') elif args.subcmd == 'inactive': print_channels_hygiene(node) elif args.subcmd == 'forwardings': # convert time interval into unix timestamp time_from = time.time() - args.from_days_ago * 24 * 60 * 60 time_to = time.time() - args.to_days_ago * 24 * 60 * 60 print_channels_forwardings(node, sort_by=args.sort_by, time_interval_start=time_from, time_interval_end=time_to) elif args.cmd == 'rebalance': if args.target: logger.warning( "Warning: Target is set, this is still an experimental feature." ) rebalancer = Rebalancer(node, args.max_fee_rate, args.max_fee_sat) try: rebalancer.rebalance(args.channel, dry=not args.reckless, chunksize=args.chunksize, target=args.target, allow_unbalancing=args.allow_unbalancing, strategy=args.strategy) except RebalanceFailure as e: logger.error(f"Error: {e}") elif args.cmd == 'circle': rebalancer = Rebalancer(node, args.max_fee_rate, args.max_fee_sat) invoice_r_hash = node.get_rebalance_invoice(memo='circular payment') try: rebalancer.rebalance_two_channels(args.channel_from, args.channel_to, args.amt_sats, invoice_r_hash, args.max_fee_sat, dry=not args.reckless) except DryRunException: logger.info("This was just a dry run.") except TooExpensive: logger.error( "Payment failed. This is likely due to a too low default --max-fee-rate." ) except PaymentTimeOut: logger.error( "Payment failed because the payment timed out. This is an unresolved issue." ) elif args.cmd == 'recommend-nodes': if not args.subcmd: parser.parser_recommend_nodes.print_help() return 0 recommend_nodes = RecommendNodes(node, show_connected=args.show_connected, show_addresses=args.show_addresses) if args.subcmd == 'good-old': recommend_nodes.print_good_old(number_of_nodes=args.nnodes, sort_by=args.sort_by)
channels_in[f['chan_id_in']] += f['amt_in'] total_amount += f['amt_in'] total_fees += f['fee_msat'] transactions += 1 fee_rate += f['effective_fee'] fee_rate /= transactions print("-------- Forwarding statistics --------") print("Number of forwardings: {}".format(transactions)) print("Total forwardings [sats]: {}".format(total_amount)) print("Total fees earned [sats]: {:.3f}".format(total_fees / 1000.)) print("Average fee rate: {:.6f}".format(fee_rate)) print("-------- Popular channels --------") print("Popular channels out:") for w in sorted(channels_out, key=channels_out.get, reverse=True)[:10]: print(w, channels_out[w]) print("Popular channels in:") for w in sorted(channels_in, key=channels_in.get, reverse=True)[:10]: print(w, channels_in[w]) if __name__ == '__main__': node = LndNode() forwardings = node.get_forwarding_events() # plot_forwardings(forwardings) # plot_fees(forwardings) statistics_forwardings(forwardings)
import _settings from lib.listchannels import print_channels_rebalance from lib.node import LndNode import logging.config logging.config.dictConfig(_settings.logger_config) if __name__ == '__main__': node = LndNode() node.print_status() print_channels_rebalance( node, unbalancedness_greater_than=_settings.UNBALANCED_CHANNEL)
def setUp(self): self.node = LndNode()
@staticmethod def _sorting_order(sort_string): """ Determines the sorting string and the sorting order. If sort_string starts with 'rev_', the sorting order is reversed. :param sort_string: str :return: bool """ reverse_sorting = True if sort_string[:4] == 'rev_': reverse_sorting = False sort_string = sort_string[4:] sort_string = PRINT_CHANNELS_FORMAT[sort_string]['dict_key'] return sort_string, reverse_sorting if __name__ == '__main__': import logging.config from lib.node import LndNode import _settings logging.config.dictConfig(_settings.logger_config) node_instance = LndNode() listchannels = ListChannels(node_instance)
def setUp(self): self.node = LndNode() self.router = Router(self.node)