mirror of
https://github.com/curly60e/pyblock.git
synced 2026-08-13 12:33:15 +02:00
115 lines
3.7 KiB
Python
115 lines
3.7 KiB
Python
import base64
|
|
import sys
|
|
|
|
MAX_ROUTES_TO_REQUEST = 100
|
|
|
|
|
|
def debug(message):
|
|
sys.stderr.write(message + "\n")
|
|
|
|
|
|
def debugnobreak(message):
|
|
sys.stderr.write(message)
|
|
|
|
|
|
class Routes:
|
|
def __init__(self, lnd, payment_request, first_hop_channel, last_hop_channel):
|
|
self.lnd = lnd
|
|
self.payment_request = payment_request
|
|
self.first_hop_channel = first_hop_channel
|
|
self.last_hop_channel = last_hop_channel
|
|
self.all_routes = []
|
|
self.returned_routes = []
|
|
self.ignored_edges = []
|
|
self.ignored_nodes = []
|
|
self.num_requested_routes = 0
|
|
|
|
def has_next(self):
|
|
self.update_routes()
|
|
return self.returned_routes < self.all_routes
|
|
|
|
def get_next(self):
|
|
self.update_routes()
|
|
for route in self.all_routes:
|
|
if route not in self.returned_routes:
|
|
self.returned_routes.append(route)
|
|
return route
|
|
return None
|
|
|
|
def update_routes(self):
|
|
while True:
|
|
if self.returned_routes < self.all_routes:
|
|
return
|
|
if self.num_requested_routes >= MAX_ROUTES_TO_REQUEST:
|
|
return
|
|
self.request_route()
|
|
|
|
def request_route(self):
|
|
amount = self.get_amount()
|
|
if self.last_hop_channel:
|
|
last_hop_pubkey = self.last_hop_channel.remote_pubkey
|
|
else:
|
|
last_hop_pubkey = None
|
|
if self.first_hop_channel:
|
|
first_hop_channel_id = self.first_hop_channel.chan_id
|
|
else:
|
|
first_hop_channel_id = None
|
|
routes = self.lnd.get_route(last_hop_pubkey, amount, self.ignored_edges,
|
|
self.ignored_nodes, first_hop_channel_id)
|
|
if routes is None:
|
|
self.num_requested_routes = MAX_ROUTES_TO_REQUEST
|
|
else:
|
|
self.num_requested_routes += 1
|
|
for route in routes:
|
|
self.add_route(route)
|
|
|
|
def add_route(self, route):
|
|
if route is None:
|
|
return
|
|
if route not in self.all_routes:
|
|
self.all_routes.append(route)
|
|
|
|
@staticmethod
|
|
def print_route(route):
|
|
route_str = " -> ".join(str(h.chan_id) for h in route.hops)
|
|
return route_str
|
|
|
|
def get_amount(self):
|
|
return self.payment_request.num_satoshis
|
|
|
|
def ignore_first_hop(self, channel, show_message=True):
|
|
own_key = self.lnd.get_own_pubkey()
|
|
other_key = channel.remote_pubkey
|
|
self.ignore_edge_from_to(channel.chan_id, own_key, other_key, show_message)
|
|
|
|
def ignore_edge_on_route(self, failure_source_pubkey, route):
|
|
ignore_next = False
|
|
for hop in route.hops:
|
|
if ignore_next:
|
|
self.ignore_edge_from_to(hop.chan_id, failure_source_pubkey, hop.pub_key)
|
|
return
|
|
if hop.pub_key == failure_source_pubkey:
|
|
ignore_next = True
|
|
|
|
def ignore_node_with_highest_fee(self, route):
|
|
max_fee_msat = 0
|
|
max_fee_hop = None
|
|
for hop in route.hops:
|
|
if hop.fee_msat > max_fee_msat:
|
|
max_fee_msat = hop.fee_msat
|
|
max_fee_hop = hop
|
|
|
|
pub_key = max_fee_hop.pub_key
|
|
debugnobreak("High fees (%s msat), " % max_fee_msat)
|
|
self.ignore_node(pub_key)
|
|
|
|
def ignore_edge_from_to(self, chan_id, from_pubkey, to_pubkey, show_message=True):
|
|
if show_message:
|
|
debug("ignoring channel %s (from %s to %s)" % (chan_id, from_pubkey, to_pubkey))
|
|
direction_reverse = from_pubkey > to_pubkey
|
|
edge = {"channel_id": chan_id, "direction_reverse": direction_reverse}
|
|
self.ignored_edges.append(edge)
|
|
|
|
def ignore_node(self, pub_key):
|
|
debug("ignoring node %s" % pub_key)
|
|
self.ignored_nodes.append(base64.b16decode(pub_key, True))
|