forked from C-Otto/rebalance-lnd
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathroutes.py
115 lines (95 loc) · 3.74 KB
/
routes.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
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))