Skip to content

Commit

Permalink
move route filters to logic class
Browse files Browse the repository at this point in the history
fixes C-Otto#30
  • Loading branch information
C-Otto committed Jan 6, 2019
1 parent 74ac83d commit f8f6ecf
Show file tree
Hide file tree
Showing 3 changed files with 61 additions and 57 deletions.
54 changes: 49 additions & 5 deletions logic.py
Original file line number Diff line number Diff line change
@@ -1,25 +1,28 @@
import sys
from routes import Routes

HIGH_FEES_THRESHOLD_MSAT = 3000000


def debug(message):
sys.stderr.write(message + "\n")


class Logic:
def __init__(self, lnd, first_hop_channel_id, last_hop_channel_id, amount):
def __init__(self, lnd, first_hop_channel_id, last_hop_channel, amount):
self.lnd = lnd
self.first_hop_channel_id = first_hop_channel_id
self.last_hop_channel_id = last_hop_channel_id
self.last_hop_channel = last_hop_channel
self.amount = amount

def rebalance(self):
debug(("Sending {:,} satoshis to rebalance to channel with ID %d" % self.last_hop_channel_id).format(self.amount))
debug(("Sending {:,} satoshis to rebalance to channel with ID %d"
% self.last_hop_channel.chan_id).format(self.amount))
if self.first_hop_channel_id:
debug("Forced first channel has ID %d" % self.first_hop_channel_id)

payment_request = self.generate_invoice()
routes = Routes(self.lnd, payment_request, self.first_hop_channel_id, self.last_hop_channel_id)
routes = Routes(self.lnd, payment_request, self.first_hop_channel_id, self.last_hop_channel)

if not routes.has_next():
debug("Could not find any suitable route")
Expand All @@ -28,6 +31,8 @@ def rebalance(self):
tried_routes = []
while routes.has_next():
route = routes.get_next()
if self.route_is_invalid(route):
continue
tried_routes.append(route)

debug("Trying route #%d" % len(tried_routes))
Expand All @@ -52,6 +57,45 @@ def rebalance(self):
debug("Error: %s" % response.payment_error)
return None

def route_is_invalid(self, route):
first_hop = route.hops[0]
if self.does_not_have_requested_first_hop(first_hop):
return True
if self.low_local_ratio_after_sending(first_hop, route.total_amt_msat):
return True
if self.target_is_first_hop(first_hop):
return True
if route.total_fees_msat > HIGH_FEES_THRESHOLD_MSAT:
return True
return False

def low_local_ratio_after_sending(self, first_hop, total_amount_msat):
channel_id = first_hop.chan_id
channel = self.get_channel_for_channel_id(channel_id)

amount = total_amount_msat // 1000
debug("amount: %d" % amount)
debug("before local: %d" % channel.local_balance)
debug("before remote: %d" % channel.remote_balance)
remote = channel.remote_balance + amount
local = channel.local_balance - amount
ratio = float(local) / (remote + local)
debug("after ratio: %f" % ratio)
return ratio < 0.5

def target_is_first_hop(self, first_hop):
return first_hop.chan_id == self.last_hop_channel.chan_id

def does_not_have_requested_first_hop(self, first_hop):
if not self.first_hop_channel_id:
return False
return first_hop.chan_id != self.first_hop_channel_id

def generate_invoice(self):
memo = "Rebalance of channel to %d" % self.last_hop_channel_id
memo = "Rebalance of channel with ID %d" % self.last_hop_channel.chan_id
return self.lnd.generate_invoice(memo, self.amount)

def get_channel_for_channel_id(self, channel_id):
for channel in self.lnd.get_channels():
if channel.chan_id == channel_id:
return channel
11 changes: 5 additions & 6 deletions rebalance.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,27 +41,26 @@ def main():
index = int(to_channel) - 1
candidates = get_incoming_rebalance_candidates()
candidate = candidates[index]
last_hop_channel_id = candidate.chan_id
last_hop_channel = candidate.chan_id
else:
# else the channel argument should be the channel ID
last_hop_channel_id = to_channel
last_hop_channel = get_channel_for_channel_id(to_channel)

amount = get_amount(arguments, first_hop_channel_id, last_hop_channel_id)
amount = get_amount(arguments, first_hop_channel_id, last_hop_channel)

if amount == 0:
print("Amount is 0, nothing to do")
sys.exit()

response = Logic(lnd, first_hop_channel_id, last_hop_channel_id, amount).rebalance()
response = Logic(lnd, first_hop_channel_id, last_hop_channel, amount).rebalance()
if response:
print(response)


def get_amount(arguments, first_hop_channel_id, last_hop_channel_id):
def get_amount(arguments, first_hop_channel_id, last_hop_channel):
if arguments.amount:
amount = int(arguments.amount)
else:
last_hop_channel = get_channel_for_channel_id(last_hop_channel_id)
amount = get_rebalance_amount(last_hop_channel)
if first_hop_channel_id:
first_hop_channel = get_channel_for_channel_id(first_hop_channel_id)
Expand Down
53 changes: 7 additions & 46 deletions routes.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,24 +3,22 @@

MAX_ROUTES_TO_REQUEST = 60
ROUTE_REQUEST_INCREMENT = 15
HIGH_FEES_THRESHOLD_MSAT = 3000000


def debug(message):
sys.stderr.write(message + "\n")


class Routes:
def __init__(self, lnd, payment_request, first_hop_channel_id, last_hop_channel_id):
def __init__(self, lnd, payment_request, first_hop_channel_id, last_hop_channel):
self.lnd = lnd
self.payment = payment_request
self.payment_request = payment_request
self.first_hop_channel_id = first_hop_channel_id
self.last_hop_channel_id = last_hop_channel_id
self.rebalance_channel = self.get_channel_for_channel_id(self.last_hop_channel_id)
self.last_hop_channel = last_hop_channel
self.all_routes = []
self.returned_routes = []
self.num_requested_routes = 0
self.route_extension = RouteExtension(self.lnd, self.rebalance_channel, self.payment)
self.route_extension = RouteExtension(self.lnd, last_hop_channel, self.payment_request)

def has_next(self):
self.update_routes()
Expand All @@ -45,7 +43,7 @@ def update_routes(self):
self.request_routes(num_routes_to_request)

def request_routes(self, num_routes_to_request):
routes = self.lnd.get_routes(self.rebalance_channel.remote_pubkey, self.get_amount(), num_routes_to_request)
routes = self.lnd.get_routes(self.last_hop_channel.remote_pubkey, self.get_amount(), num_routes_to_request)
self.num_requested_routes = num_routes_to_request
for route in routes:
modified_route = self.add_rebalance_channel(route)
Expand All @@ -55,52 +53,15 @@ def add_rebalance_channel(self, route):
return self.route_extension.add_rebalance_channel(route)

def add_route(self, route):
if self.route_is_invalid(route):
if route is None:
return

if route not in self.all_routes:
self.all_routes.append(route)

def route_is_invalid(self, route):
if route is None:
return True
first_hop = route.hops[0]
if self.does_not_have_requested_first_hop(first_hop):
return True
if self.low_local_ratio_after_sending(first_hop):
return True
if self.target_is_first_hop(first_hop):
return True
if route.total_fees_msat > HIGH_FEES_THRESHOLD_MSAT:
return True
return False

def does_not_have_requested_first_hop(self, first_hop):
if not self.first_hop_channel_id:
return False
return first_hop.chan_id != self.first_hop_channel_id

def low_local_ratio_after_sending(self, first_hop):
channel_id = first_hop.chan_id
channel = self.get_channel_for_channel_id(channel_id)

remote = channel.remote_balance + self.get_amount()
local = channel.local_balance - self.get_amount()
ratio = float(local) / (remote + local)
return ratio < 0.5

def target_is_first_hop(self, first_hop):
return first_hop.chan_id == self.rebalance_channel.chan_id

@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.num_satoshis

def get_channel_for_channel_id(self, channel_id):
for channel in self.lnd.get_channels():
if channel.chan_id == channel_id:
return channel
return self.payment_request.num_satoshis

0 comments on commit f8f6ecf

Please sign in to comment.