diff --git a/checkring.py b/checkring.py new file mode 100644 index 0000000..30f4f37 --- /dev/null +++ b/checkring.py @@ -0,0 +1,84 @@ +import os +import grpc +from time import sleep + +from output import format_channel_error, format_error, clear_screen, format_channel +from yachalk import chalk + +LOOP_SLEEP_TIME = 10 + + +class CheckRing: + def __init__(self, lnd, output, pubkeys_file, show_fees): + self.lnd = lnd + self.output = output + self.pubkeys_file = pubkeys_file + self.show_fees = show_fees + + def read_file(self, file): + if not os.path.isfile(file): + self.handle_error("File does not exist") + else: + with open(self.pubkeys_file) as file: + return file.read().splitlines() + + def run(self): + self.once() + + + def once(self): + pubkeys = self.read_file(self.pubkeys_file) + # response = self.lnd.get_node(pubkeys[0].split(',')[0]) + # print(response) + for idx, pubkeyInfo in enumerate(pubkeys): + pubkey = pubkeyInfo.split(',') + try: + #print(pubkey[0], idx) + response = self.lnd.get_node_channels(pubkey[0]) + + print("%s" % + (chalk.yellow(response.node.alias))) + + # print("Number of channels: %s" % len(response.channels)) + channelTo = pubkeys[(idx+1) % (len(pubkeys))].split(',')[0] + hasChannel = False + channelId = 0 + channelInfo = {} + + for channel in response.channels: + if (channel.node1_pub == channelTo) or (channel.node2_pub == channelTo): + hasChannel = True + channelId = channel.channel_id + channelInfo = channel + + if hasChannel: + outputHas = chalk.green('✅') + else: + outputHas = chalk.red('🙌🏻') + print("%s %s\r\n%s" % + (outputHas, pubkey[1], pubkey[0])) + + if hasChannel: + print(chalk.green("Channel is open with ID: %s") % channelId) + + if self.show_fees: + response = self.lnd.get_edge(int(channelId)) + node1 = self.lnd.get_node(response.node1_pub) + node2 = self.lnd.get_node(response.node2_pub) + disabled = response.node1_policy.disabled or response.node2_policy.disabled + self.print_channel( + channelInfo, node1.alias, node2.alias, disabled) + else: + print(chalk.red("Should open to node with pubkey %s") % channelTo) + except grpc.RpcError as e: + self.output.print_line(format_channel_error(pubkey, repr(e))) + except Exception as error: + self.output.print_line( + format_channel_error(pubkey, repr(error))) + + def print_channel(self, channel, node1_alias, node2_alias, chan_disabled): + self.output.print_line(format_channel( + channel, node1_alias, node2_alias, chan_disabled, self.show_fees)) + + def handle_error(self, error): + self.output.print_line(format_error(error)) diff --git a/lnd.py b/lnd.py index 3f4727d..7912d07 100644 --- a/lnd.py +++ b/lnd.py @@ -48,6 +48,13 @@ class Lnd: def get_edge(self, channel_id): return self.stub.GetChanInfo(ln.ChanInfoRequest(chan_id=channel_id)) + + @lru_cache(maxsize=None) + def get_node_channels(self, pubkey): + return self.stub.GetNodeInfo(ln.NodeInfoRequest( + + pub_key=pubkey, include_channels=True)) + @lru_cache(maxsize=None) def get_node_alias(self, pub_key): return self.stub.GetNodeInfo( diff --git a/pubkeys.txt b/pubkeys.txt new file mode 100644 index 0000000..9232011 --- /dev/null +++ b/pubkeys.txt @@ -0,0 +1,21 @@ +0294e9ad2727d623fb22870e32f167d4d014e2f7adccb0926802f0bd4d17959093,@akkorokamui +028e748c8f24acb985cd428eb072d3d71d1a692acd38a4d22b14fb7e6bf6513f33,@MBTC_1 +03a3c59c4081ec3f0f5b889ca16c8193d22d1c4aec94d1e6e3873e95c9c3592763,@Kippers37 +02258a9aa9463749bf729511af78b1ea339ecdb36b37a6e18a8c8caa895228bfcb,@PeteDoo +02fa5c81d1d41e8d8001e6169fe454441360cfb876dc6c5b82fb5d20c0da5b9a51,Chefke +02719ddac30c16dd856bb61ec4a52a5984d345da078c1855baeef856976e9f312a,Jobe[Jotne-Nodenor] +03aba668b98dbe9550cd998648878c445118c7eff35471f6583c526ad0f39f68aa,@Frodo7 +037305dfd540c28353120b42cabd6debf3a832283a18679a7ef205684223998e85,@WolligSchaap +026776c241841182e8f44648b7972249b3a1ba1291a8e1af5c383b3219864cb027,@SatStekker +021d70a400e9b8b0ebc1a8816da9c3294eba17d01beaafa210e5870233aee13d98,@RDdeBruyn +023d153b512346a3a6026859ecf906d7f6912bc9fa4214ed4439ffafe47ba53cef,@TReader01 +02b74b259fbfb180e5fac9369204b27aa889cffcc4c348ce7a2b99b52eb0d11af9,@BentedeBitcoinBoer +031ff1fa0ce00bece0879270798ee06d29a54f54e9a4ac632beeddcc74f000e217,@1665 +02c23df35912b9393b92cd16761e22e122651b7960720e94a13c01697bfdd27aa1,@commaCamel (Comma) +027ce2952b775e3cc4700d159d82b53f2559dc1f53faf2ca05c7ef28a26d90ac43,Roy +03706a7c275576f161d916e28704f0fe0a487758168147d3722e90855d18cc4336,@J_A_C_C_O (JACCO) +02b6b8e6b683811f358e9602f8271694951b92dd66ff0841501f2ce9ddcf7bc2fc,@I2Sappig +0334aadd6b72f00168c87385c081a171e1a1a1936435c2952d25dd10d2f17d6c43,@GrunnBliksems +037280da8985d5b1b143adec8277d182b709414fcfd9771aaeb31f57bbe81d5b83,@Knetsooj +035c709aae4bcb860ebf07da75e6454172ce27b0dc2131c7263479696e2f1fe6bd,@kapital8one +0205a19356bbb7482057356aef070285a2ce6141d2448545210e9d575b57eddd37,@dsbaars diff --git a/ringtools.py b/ringtools.py index 6b99093..80bdffb 100644 --- a/ringtools.py +++ b/ringtools.py @@ -5,7 +5,7 @@ from lnd import Lnd from output import Output from status import Status from utils import is_umbrel - +from checkring import CheckRing class RingTools: def __init__(self, arguments): @@ -20,6 +20,11 @@ class RingTools: self.arguments.channels_file, self.arguments.loop, self.arguments.show_fees).run() + elif self.arguments.function == "check": + CheckRing(self.lnd, + self.output, + self.arguments.pubkeys_file, + self.arguments.show_fees).run() pass @@ -34,7 +39,7 @@ def get_argument_parser(): # This is needed for the cert and macaroon of LND parser.add_argument( dest="function", - choices=['status'], + choices=['status', 'check'], help="Choose which function of the RingTools you would " "like to use", default="help", @@ -56,6 +61,13 @@ def get_argument_parser(): dest="grpc", help="(default localhost:10009) lnd gRPC endpoint", ) + check_group = parser.add_argument( + "-pubkeys-file", + "-pk", + default="./pubkeys.txt", + dest="pubkeys_file", + help="(default ./pubkeys.txt) pubkeys file" + ) status_group = parser.add_argument_group( "status", "Get the current status of all channels", @@ -67,6 +79,7 @@ def get_argument_parser(): dest="channels_file", help="(default ./channels.txt) channels file" ) + status_group.add_argument( "-l", "--loop",