Skip to content

Commit

Permalink
add reckless mode, adapt readme
Browse files Browse the repository at this point in the history
  • Loading branch information
C-Otto committed Jul 27, 2021
1 parent b225291 commit f3e5d8b
Show file tree
Hide file tree
Showing 3 changed files with 56 additions and 11 deletions.
14 changes: 12 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -182,6 +182,8 @@ However, keep in mind that you will only earn those fees if your node actually f
The rebalance transaction is not performed if the transaction fees plus the implicit costs (1) are higher than the
possible future earnings (2).

**If you really want to, you may disable these safety checks with `--reckless`.**

### Example
You have lots of funds in channel `11111111` and nothing in channel `22222222`.
You would like to send funds through channel `11111111` (source channel) through the lightning network, and finally
Expand Down Expand Up @@ -237,7 +239,8 @@ Please make sure to set realistic fee rates, which at best are already known to

### Command line arguments
```
usage: rebalance.py [-h] [--lnddir LNDDIR] [--grpc GRPC] [-l] [--show-all] [-o | -i] [-f CHANNEL] [-t CHANNEL] [-a AMOUNT] [--min-amount MIN_AMOUNT] [-e EXCLUDE] [--fee-factor FEE_FACTOR | --fee-limit FEE_LIMIT | --fee-ppm-limit FEE_PPM_LIMIT]
usage: rebalance.py [-h] [--lnddir LNDDIR] [--grpc GRPC] [-l] [--show-all] [-o | -i] [-f CHANNEL] [-t CHANNEL] [-a AMOUNT | -p PERCENTAGE] [--min-amount MIN_AMOUNT] [--min-local MIN_LOCAL] [--min-remote MIN_REMOTE] [-e EXCLUDE] [--reckless]
[--fee-factor FEE_FACTOR | --fee-limit FEE_LIMIT | --fee-ppm-limit FEE_PPM_LIMIT]
optional arguments:
-h, --help show this help message and exit
Expand All @@ -262,13 +265,20 @@ rebalance:
Channel ID of the incoming channel (funds will be sent to this channel). You may also use -1 to choose a random candidate.
-a AMOUNT, --amount AMOUNT
Amount of the rebalance, in satoshis. If not specified, the amount computed for a perfect rebalance will be used (up to the maximum of 4,294,967 satoshis)
-p PERCENTAGE, --percentage PERCENTAGE
Set the amount to a percentage of the computed amount. As an example, if this is set to 50, half of the computed amount will be used. See --amount.
--min-amount MIN_AMOUNT
(Default: 10,000) If the given or computed rebalance amount is below this limit, nothing is done.
--min-local MIN_LOCAL
(Default: 1,000,000) Ensure that the channels have at least this amount as outbound liquidity.
--min-remote MIN_REMOTE
(Default: 1,000,000) Ensure that the channels have at least this amount as inbound liquidity.
-e EXCLUDE, --exclude EXCLUDE
Exclude the given channel ID as the outgoing channel (no funds will be taken out of excluded channels)
--reckless Allow rebalance transactions that are not economically viable. You might also want to set --min-local 0 and --min-local 0. If set, you also need to set --amount and either --fee-limit or --fee-ppm-limit.
--fee-factor FEE_FACTOR
(default: 1.0) Compare the costs against the expected income, scaled by this factor. As an example, with --fee-factor 1.5, routes that cost at most 150% of the expected earnings are tried. Use values smaller than 1.0 to restrict
routes to only consider those earning more/costing less.
routes to only consider those earning more/costing less. This factor is ignored with --reckless.
--fee-limit FEE_LIMIT
If set, only consider rebalance transactions that cost up to the given number of satoshis.
--fee-ppm-limit FEE_PPM_LIMIT
Expand Down
21 changes: 15 additions & 6 deletions logic.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import math

import output
from output import Output, format_alias, format_fee_msat, format_ppm, format_amount, format_boring_string, \
format_fee_sat, format_warning, format_error, format_earning, format_fee_msat_red
from routes import Routes
Expand All @@ -24,7 +25,8 @@ def __init__(
fee_ppm_limit,
min_local,
min_remote,
output: Output
output: Output,
reckless
):
self.lnd = lnd
self.first_hop_channel = first_hop_channel
Expand All @@ -38,6 +40,7 @@ def __init__(
self.min_local = min_local
self.min_remote = min_remote
self.output = output
self.reckless = reckless
if not self.fee_factor:
self.fee_factor = 1.0

Expand Down Expand Up @@ -93,7 +96,10 @@ def get_fee_limit_msat(self):
if self.fee_limit_sat:
fee_limit_msat = self.fee_limit_sat * 1_000
elif self.fee_ppm_limit:
fee_limit_msat = max(1_000, self.fee_ppm_limit * self.amount / 1_000)
if self.reckless:
fee_limit_msat = self.fee_ppm_limit * self.amount / 1_000
else:
fee_limit_msat = max(1_000, self.fee_ppm_limit * self.amount / 1_000)
elif self.last_hop_channel:
fee_rate = self.lnd.get_ppm_to(self.last_hop_channel.chan_id)
last_hop_alias = self.lnd.get_node_alias(self.last_hop_channel.remote_pubkey)
Expand Down Expand Up @@ -322,10 +328,12 @@ def get_channel_for_channel_id(self, channel_id):
self.output.print_line(f"Unable to find channel with id {channel_id}!")

def initialize_ignored_channels(self, routes, fee_limit_msat, min_ppm_last_hop):
if self.reckless:
self.output.print_line(output.format_error("Not ignoring economically unviable channels."))
if self.first_hop_channel:
if min_ppm_last_hop:
if min_ppm_last_hop and not self.reckless:
self.ignore_low_ppm_channels_for_last_hop(min_ppm_last_hop, routes)
if not self.last_hop_channel:
if not self.last_hop_channel and not self.reckless:
self.ignore_last_hops_with_low_inbound(routes)

# avoid me - X - me via the same channel/peer
Expand All @@ -336,15 +344,16 @@ def initialize_ignored_channels(self, routes, fee_limit_msat, min_ppm_last_hop):
chan_id, from_pub_key, to_pub_key, show_message=False
)
if self.last_hop_channel:
self.ignore_first_hops_with_fee_rate_higher_than_last_hop(routes)
if not self.reckless:
self.ignore_first_hops_with_fee_rate_higher_than_last_hop(routes)
# avoid me - X - me via the same channel/peer
chan_id = self.last_hop_channel.chan_id
from_pub_key = self.lnd.get_own_pubkey()
to_pub_key = self.last_hop_channel.remote_pubkey
routes.ignore_edge_from_to(
chan_id, from_pub_key, to_pub_key, show_message=False
)
if self.last_hop_channel and fee_limit_msat:
if self.last_hop_channel and fee_limit_msat and not self.reckless:
# ignore first hops with high fee rate configured by our node (causing high missed future fees)
max_fee_rate_first_hop = math.ceil(fee_limit_msat * 1_000 / self.amount)
for channel in self.lnd.get_channels():
Expand Down
32 changes: 29 additions & 3 deletions rebalance.py
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,11 @@ def get_rebalance_amount(self, channel):

def get_amount(self):
if self.arguments.amount:
return min(self.arguments.amount, MAX_SATOSHIS_PER_TRANSACTION)
if self.arguments.reckless and self.arguments.amount > MAX_SATOSHIS_PER_TRANSACTION:
self.output.print_line(output.format_error("Trying to send wumbo transaction"))
return self.arguments.amount
else:
return min(self.arguments.amount, MAX_SATOSHIS_PER_TRANSACTION)

should_send = 0
can_send = 0
Expand Down Expand Up @@ -195,6 +199,9 @@ def start(self):
f"nothing to do (see --min-amount)")
sys.exit(0)

if self.arguments.reckless:
self.output.print_line(output.format_error("Reckless mode enabled!"))

fee_factor = self.arguments.fee_factor
fee_limit_sat = self.arguments.fee_limit
fee_ppm_limit = self.arguments.fee_ppm_limit
Expand All @@ -210,7 +217,8 @@ def start(self):
fee_ppm_limit,
self.min_local,
self.min_remote,
self.output
self.output,
self.arguments.reckless
).rebalance()

def get_first_hop_candidates(self):
Expand Down Expand Up @@ -243,6 +251,16 @@ def main():
argument_parser.print_help()
sys.exit(1)

if arguments.reckless and not arguments.amount:
print("You need to specify an amount for --reckless")
argument_parser.print_help()
sys.exit(1)

if arguments.reckless and not arguments.fee_limit and not arguments.fee_ppm_limit:
print("You need to specify a fee limit (-fee-limit or --fee-ppm-limit) for --reckless")
argument_parser.print_help()
sys.exit(1)

first_hop_channel_id = vars(arguments)["from"]
last_hop_channel_id = arguments.to
if not arguments.list_candidates and last_hop_channel_id is None and first_hop_channel_id is None:
Expand Down Expand Up @@ -366,6 +384,14 @@ def get_argument_parser():
help="Exclude the given channel ID as the outgoing channel (no funds will be taken "
"out of excluded channels)",
)
rebalance_group.add_argument(
"--reckless",
action="store_true",
default=False,
help="Allow rebalance transactions that are not economically viable. "
"You might also want to set --min-local 0 and --min-local 0. "
"If set, you also need to set --amount and either --fee-limit or --fee-ppm-limit."
)
fee_group = rebalance_group.add_mutually_exclusive_group()
fee_group.add_argument(
"--fee-factor",
Expand All @@ -375,7 +401,7 @@ def get_argument_parser():
"income, scaled by this factor. As an example, with --fee-factor 1.5, "
"routes that cost at most 150%% of the expected earnings are tried. Use values "
"smaller than 1.0 to restrict routes to only consider those earning "
"more/costing less.",
"more/costing less. This factor is ignored with --reckless.",
)
fee_group.add_argument(
"--fee-limit",
Expand Down

0 comments on commit f3e5d8b

Please sign in to comment.