From 0ad2de38c26da5a9e4955de43c6a459cfbb2b796 Mon Sep 17 00:00:00 2001 From: Tim Horie Date: Thu, 7 Dec 2023 17:03:31 +0900 Subject: [PATCH 01/13] Set the max_htlc based on local balance --- examples/max-htlc-proportional.config | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 examples/max-htlc-proportional.config diff --git a/examples/max-htlc-proportional.config b/examples/max-htlc-proportional.config new file mode 100644 index 0000000..f8264b8 --- /dev/null +++ b/examples/max-htlc-proportional.config @@ -0,0 +1,19 @@ +# all channels max_htlc set to a value proportional to +# local balance, with specified number of divisions +# e.g. +# slices = 10 +# channel_size = 1_000_000 sats +# max_htlc values: +# 100_000, 200_000, 300_000, 400_000, 500_000 +# 600_000, 700_000, 800_000, 900_000, 1_000_000 +# +# slices = 2 +# channel_size = 800_000_sats +# max_htlc values: +# 400_000, 800_000 +# +# Rationale: avoid insufficient local balance failures +# to improve your node's reputation of successful forwarding. + +[default] +max_htlc_proportional_slices = 6 \ No newline at end of file From 91f29983f19c92b19602dc148008b5b6fc3b7b8e Mon Sep 17 00:00:00 2001 From: Tim Horie Date: Thu, 7 Dec 2023 17:54:03 +0900 Subject: [PATCH 02/13] Added proportional max_htlc strategy --- README.md | 1 + charge_lnd/charge_lnd.py | 2 ++ charge_lnd/strategy.py | 19 +++++++++++++++++++ charge_lnd/test1.py | 21 +++++++++++++++++++++ examples/max-htlc-proportional.config | 5 +++++ 5 files changed, 48 insertions(+) create mode 100644 charge_lnd/test1.py diff --git a/README.md b/README.md index aa71729..71ad7fd 100644 --- a/README.md +++ b/README.md @@ -203,6 +203,7 @@ All strategies (except the ignore strategy) will apply the following properties | **min_htlc_msat** | Minimum size (in msat) of HTLC to allow | # msat | | **max_htlc_msat** | Maximum size (in msat) of HTLC to allow | # msat | | **max_htlc_msat_ratio** | Maximum size of HTLC to allow as a fraction of total channel capacity | 0..1 | +| **max_htlc_proportional_slices** | Maximum size of HTLC set proportionally to local balance with slices number of steps | # slices | | **time_lock_delta** | Time Lock Delta | # blocks | | **min_fee_ppm_delta** | Minimum change in fees (ppm) before updating channel | ppm delta | diff --git a/charge_lnd/charge_lnd.py b/charge_lnd/charge_lnd.py index acf64b2..059f8fa 100755 --- a/charge_lnd/charge_lnd.py +++ b/charge_lnd/charge_lnd.py @@ -123,6 +123,8 @@ def main(): if time_lock_delta_changed: s = ' ➜ ' + fmt.col_hi(new_time_lock_delta) print(" time_lock_delta: %s%s" % (fmt.col_hi(my_policy.time_lock_delta), s) ) + #debugging - just exit after one + return True return True diff --git a/charge_lnd/strategy.py b/charge_lnd/strategy.py index 2b2e1fc..ebae832 100644 --- a/charge_lnd/strategy.py +++ b/charge_lnd/strategy.py @@ -19,6 +19,20 @@ def call_strategy(*args, **kwargs): return call_strategy return register_strategy +def calculate_slices(max_value, current_value, num_slices): + # Calculate the size of each slice + slice_size = max_value // num_slices + + # Find the slice number containing the current_value + current_slice = min(current_value // slice_size, num_slices - 1) + + # Determine the upper value of the slice closest to current without going over + slice_point = min((current_slice + 1) * slice_size - 1, max_value) + + print(f"max: {max_value}, current: {current_value}, slices: {num_slices}") + print(f"slice_point: {slice_point}") + + return slice_point class StrategyDelegate: STRATEGIES = {} @@ -48,6 +62,11 @@ def execute(self, channel): def effective_max_htlc_msat(self, channel): result = self.policy.getint('max_htlc_msat') + + slices = self.policy.getint('max_htlc_proportional_slices') + if slices: + result = calculate_slices(channel.capacity, channel.local_balance, slices) + ratio = self.policy.getfloat('max_htlc_msat_ratio') if ratio: ratio = max(0,min(1,ratio)) diff --git a/charge_lnd/test1.py b/charge_lnd/test1.py new file mode 100644 index 0000000..b33a1ae --- /dev/null +++ b/charge_lnd/test1.py @@ -0,0 +1,21 @@ +def calculate_slices(max_value, current_value, num_slices): + # Calculate the size of each slice + slice_size = max_value // num_slices + + # Find the slice number containing the current_value + current_slice = min(current_value // slice_size, num_slices - 1) + + # Determine the upper value of the slice closest to current without going over + slice_point = min((current_slice + 1) * slice_size - 1, max_value) + + return slice_point + +# Example usage +max_value = 1000000 +current_value = 1000000 +num_slices = 10 + +slice_point = calculate_slices(max_value, current_value, num_slices) + +print(f"max: {max_value}, current: {current_value}, slices: {num_slices}") +print(f"slice_point: {slice_point}") \ No newline at end of file diff --git a/examples/max-htlc-proportional.config b/examples/max-htlc-proportional.config index f8264b8..936dd7c 100644 --- a/examples/max-htlc-proportional.config +++ b/examples/max-htlc-proportional.config @@ -16,4 +16,9 @@ # to improve your node's reputation of successful forwarding. [default] +strategy = ignore + +[proportional_htlc] +chan.max_local_balance = 30_000_000 +strategy = static max_htlc_proportional_slices = 6 \ No newline at end of file From 06982ad6db4857b73b831fe8228a969e92381947 Mon Sep 17 00:00:00 2001 From: Tim Horie Date: Thu, 7 Dec 2023 17:55:50 +0900 Subject: [PATCH 03/13] Remove debugging --- charge_lnd/charge_lnd.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/charge_lnd/charge_lnd.py b/charge_lnd/charge_lnd.py index 059f8fa..acf64b2 100755 --- a/charge_lnd/charge_lnd.py +++ b/charge_lnd/charge_lnd.py @@ -123,8 +123,6 @@ def main(): if time_lock_delta_changed: s = ' ➜ ' + fmt.col_hi(new_time_lock_delta) print(" time_lock_delta: %s%s" % (fmt.col_hi(my_policy.time_lock_delta), s) ) - #debugging - just exit after one - return True return True From 595315be4386868034f57e73569165057bfbfd64 Mon Sep 17 00:00:00 2001 From: Tim Horie Date: Thu, 7 Dec 2023 17:56:30 +0900 Subject: [PATCH 04/13] Remove debugging --- charge_lnd/strategy.py | 3 --- charge_lnd/test1.py | 21 --------------------- 2 files changed, 24 deletions(-) delete mode 100644 charge_lnd/test1.py diff --git a/charge_lnd/strategy.py b/charge_lnd/strategy.py index ebae832..565aef7 100644 --- a/charge_lnd/strategy.py +++ b/charge_lnd/strategy.py @@ -29,9 +29,6 @@ def calculate_slices(max_value, current_value, num_slices): # Determine the upper value of the slice closest to current without going over slice_point = min((current_slice + 1) * slice_size - 1, max_value) - print(f"max: {max_value}, current: {current_value}, slices: {num_slices}") - print(f"slice_point: {slice_point}") - return slice_point class StrategyDelegate: diff --git a/charge_lnd/test1.py b/charge_lnd/test1.py deleted file mode 100644 index b33a1ae..0000000 --- a/charge_lnd/test1.py +++ /dev/null @@ -1,21 +0,0 @@ -def calculate_slices(max_value, current_value, num_slices): - # Calculate the size of each slice - slice_size = max_value // num_slices - - # Find the slice number containing the current_value - current_slice = min(current_value // slice_size, num_slices - 1) - - # Determine the upper value of the slice closest to current without going over - slice_point = min((current_slice + 1) * slice_size - 1, max_value) - - return slice_point - -# Example usage -max_value = 1000000 -current_value = 1000000 -num_slices = 10 - -slice_point = calculate_slices(max_value, current_value, num_slices) - -print(f"max: {max_value}, current: {current_value}, slices: {num_slices}") -print(f"slice_point: {slice_point}") \ No newline at end of file From 97a705f1cd4527d43d1016e3a1e4e96fb4ca04b5 Mon Sep 17 00:00:00 2001 From: Tim Horie Date: Thu, 7 Dec 2023 20:39:07 +0900 Subject: [PATCH 05/13] Calculate the peer inbound weighted ppm rate --- README.md | 1 + charge_lnd/charge_lnd.py | 4 +- charge_lnd/strategy.py | 128 ++++++++++++++++++ ...ghted-average-of-peer-incoming-rate.config | 36 +++++ 4 files changed, 168 insertions(+), 1 deletion(-) create mode 100644 examples/weighted-average-of-peer-incoming-rate.config diff --git a/README.md b/README.md index 71ad7fd..4b519b6 100644 --- a/README.md +++ b/README.md @@ -189,6 +189,7 @@ Available strategies: |**ignore_fees** | don't make any fee changes, only update htlc size limits and time_lock_delta|| |**static** | sets fixed base fee and fee rate values.| **fee_ppm**| |**match_peer** | sets the same base fee and fee rate values as the peer|if **base_fee_msat** or **fee_ppm** are set the override the peer values| +|**match_peer_inbound_weighted_average** | sets the fee rate to the peer's inbound weighted average fee rate|| |**cost** | calculate cost for opening channel, and set ppm to cover cost when channel depletes.|**cost_factor**| |**onchain_fee** | sets the fees to a % equivalent of a standard onchain payment (Requires --electrum-server to be specified.)| **onchain_fee_btc** BTC
within **onchain_fee_numblocks** blocks.| |**proportional** | sets fee ppm according to balancedness.|**min_fee_ppm**
**max_fee_ppm**
**sum_peer_chans** consider all channels with peer for balance calculations| diff --git a/charge_lnd/charge_lnd.py b/charge_lnd/charge_lnd.py index acf64b2..9854f72 100755 --- a/charge_lnd/charge_lnd.py +++ b/charge_lnd/charge_lnd.py @@ -12,6 +12,7 @@ from .config import Config from .electrum import Electrum import charge_lnd.fmt as fmt +from pprint import pprint def debug(message): sys.stderr.write(message + "\n") @@ -123,7 +124,8 @@ def main(): if time_lock_delta_changed: s = ' ➜ ' + fmt.col_hi(new_time_lock_delta) print(" time_lock_delta: %s%s" % (fmt.col_hi(my_policy.time_lock_delta), s) ) - + #debugging + #return True return True def get_argument_parser(): diff --git a/charge_lnd/strategy.py b/charge_lnd/strategy.py index 565aef7..16f71c9 100644 --- a/charge_lnd/strategy.py +++ b/charge_lnd/strategy.py @@ -5,6 +5,10 @@ from . import fmt from .config import Config from .electrum import Electrum +from pprint import pprint +import pickle + +edges_cache = None def debug(message): sys.stderr.write(message + "\n") @@ -134,6 +138,130 @@ def strategy_match_peer(channel, policy, **kwargs): return (policy.getint('base_fee_msat', peernode_policy.fee_base_msat), policy.getint('fee_ppm', peernode_policy.fee_rate_milli_msat)) +@strategy(name = 'match_peer_inbound_weighted_average') +def strategy_match_peer_inbound_weighted_average(channel, policy, **kwargs): + lnd = kwargs['lnd'] + chan_info = lnd.get_chan_info(channel.chan_id) + my_pubkey = lnd.get_own_pubkey() + + peer_node_id = chan_info.node1_pub if chan_info.node2_pub == my_pubkey else chan_info.node2_pub + + #print("peer_node_id: %s" % (peer_node_id) ) + + #peer_node_info = lnd.get_node_info(peer_node_id) + #peer_inbound_weighted_average = 0 + + global edges_cache + + if not edges_cache: + #print('getting fresh copy of edges') + # edges = lnd.get_edges() + with open('edges.pkl', 'rb') as file: + # Use pickle.load to deserialize and read the object from the file + edges = pickle.load(file) + + # all_edges = [] + # for edge in edges: + # my_edge = { + # "node1_pub": edge.node1_pub, + # "node2_pub": edge.node2_pub, + # 'capacity': edge.capacity, + # "node1_policy": { + # 'fee_rate_milli_msat': edge.node1_policy.fee_rate_milli_msat + # }, + # "node2_policy": { + # 'fee_rate_milli_msat': edge.node2_policy.fee_rate_milli_msat + # } + # } + # #pprint(my_edge) + # all_edges.append(my_edge) + + # #json_string = json.dumps(all_edges, indent=4) + # #pprint(json_string) + + # #pprint(edges) + # with open('edges.pkl', 'wb') as file: + # # Use pickle.dump to serialize and write the object to the file + # pickle.dump(all_edges, file) + edges_cache = edges + else: + #print('using cache of edges') + edges = edges_cache + + + + # edges = [{ + # 'channel_id': 901732575861473280, + # 'chan_point': "c3fbe954405ba1570f17f72b77bbf14afe4e95b7fb766560b3ceb4db78fe4f27:0", + # 'last_update': 1701938542, + # 'node1_pub': "034f3f792988c43f41c65a839acdfa48647204bb99aca7de426f7c80b0dcf7a4a6", + # 'node2_pub': "03ceeaec6cb017d1ea8ad04a5dfb3facb24a28399d24624ecce8f319973de361d9", + # 'capacity': 4002000, + # 'node1_policy': { + # 'time_lock_delta': 80, + # 'min_htlc': 1000, + # 'fee_base_msat': 1000, + # 'fee_rate_milli_msat': 1, + # 'max_htlc_msat': 3961980000, + # 'last_update': 1701938542, + # }, + # 'node2_policy': { + # 'time_lock_delta': 80, + # 'min_htlc': 1000, + # 'fee_base_msat': 1000, + # 'fee_rate_milli_msat': 450, + # 'max_htlc_msat': 3961980000, + # 'last_update': 1701938541, + # } + # }] + + # Try to find all the channels for the peer. + + peer_inbound = [] + + total_peer_capacity = 0 + weighted_average_inbound_fee = 0 + + for edge in edges: + if edge['node1_pub'] == peer_node_id: + # We will take node2_policy because we want inbound policy. + inbound = { + 'capacity': edge['capacity'], + 'fee_rate_milli_msat': edge['node2_policy']['fee_rate_milli_msat'] + } + total_peer_capacity += edge['capacity'] + peer_inbound.append(inbound) + elif edge['node2_pub'] == peer_node_id: + inbound = { + 'capacity': edge['capacity'], + 'fee_rate_milli_msat': edge['node1_policy']['fee_rate_milli_msat'] + } + peer_inbound.append(inbound) + total_peer_capacity += edge['capacity'] + + # Calculate the weighted average inbound fee by multiplying each fee by + # the adjusted ratio and taking the sum. + + max_usable_ppm = policy.getint('inbound_skip_fee_rate_above_ppm') + + for inbound in peer_inbound: + if inbound['fee_rate_milli_msat'] >= max_usable_ppm: + # ignore fee rate values over 10,000 in our calculation + continue + #pprint(inbound) + weighted_average_inbound_fee += int((inbound['capacity']/total_peer_capacity)*inbound['fee_rate_milli_msat']) + + #print('fee rate', (weighted_average_inbound_fee)) + + premium_pct = policy.getint('inbound_weighted_average_fee_rate_premium_percent') + + if premium_pct: + premium = int(weighted_average_inbound_fee * (premium_pct/100)) + #print('adding premium: %i', (premium)) + weighted_average_inbound_fee += premium + + return (policy.getint('fee_ppm'), weighted_average_inbound_fee) + @strategy(name = 'cost') def strategy_cost(channel, policy, **kwargs): lnd = kwargs['lnd'] diff --git a/examples/weighted-average-of-peer-incoming-rate.config b/examples/weighted-average-of-peer-incoming-rate.config new file mode 100644 index 0000000..2cc6a20 --- /dev/null +++ b/examples/weighted-average-of-peer-incoming-rate.config @@ -0,0 +1,36 @@ +[default] +# 'default' is special, it is used if no other policy matches a channel +strategy = static +base_fee_msat = 0 +fee_ppm = 50_000 +min_fee_ppm_delta = 50 +max_htlc_proportional_slices = 6 + +# Ignore inactive nodes +[inactive-nodes] +node.max_shared_channels_active = 0 +strategy = ignore + +# Use the weighted average of the peer node's channels inbound rate. +# Example: +# - Let's suppose you have a channel with Peer XYZ. +# - Peer XYZ has 4 channels. +# - Those 4 channels are 1M, 2M, 3M, and 4M sats capacity. +# - The inbound fee rates for those channels are 100 ppm, 200 ppm, +# 300 ppm, and 400 ppm. +# - The weighted average is the sum of fees multiplied by the +# channel's capacity. In this case, 300 ppm. Note, it's higher +# than the plain average, because more capacity is at the 400 ppm +# rate compared to the lower ppm rate. +# +# The inbound_weighted_average_fee_rate_premium_percent value adds a +# multiple of the weighted average fee. For example, a value of 25 +# means that a 200 ppm weighted average will be set to 250 ppm. + +[peer-adjusted] +strategy = match_peer_inbound_weighted_average +base_fee_msat = 0 +min_fee_ppm_delta = 50 +max_htlc_proportional_slices = 6 +inbound_skip_fee_rate_above_ppm = 10000 +inbound_weighted_average_fee_rate_premium_percent = 100 \ No newline at end of file From e67f7717ae47a6c603aeb252dfcee98f79b116f5 Mon Sep 17 00:00:00 2001 From: Tim Horie Date: Thu, 7 Dec 2023 21:03:07 +0900 Subject: [PATCH 06/13] Updated --- README.md | 8 ++++ charge_lnd/charge_lnd.py | 2 - charge_lnd/strategy.py | 89 +++++++++------------------------------- 3 files changed, 27 insertions(+), 72 deletions(-) diff --git a/README.md b/README.md index 4b519b6..44e243c 100644 --- a/README.md +++ b/README.md @@ -196,6 +196,14 @@ Available strategies: |**disable** | disables the channel in the outgoing direction. Channel will be re-enabled again if it matches another policy (except when that policy uses an 'ignore' strategy).|| |**use_config** | process channel according to rules defined in another config file.|**config_file**| +Strategy for match peer inbound weighted average will apply the following properties if defined: + +|Property|Description|Values| +|:--|:--|:--| +| **inbound_skip_fee_rate_above_ppm** | Inbound rate of peer to ignore exceeds this value | ppm | +| **inbound_weighted_average_fee_rate_premium_percent** | Premium added to the final peer inbound weighted average | percent | + + All strategies (except the ignore strategy) will apply the following properties if defined: |Property|Description|Values| diff --git a/charge_lnd/charge_lnd.py b/charge_lnd/charge_lnd.py index 9854f72..8ac37bf 100755 --- a/charge_lnd/charge_lnd.py +++ b/charge_lnd/charge_lnd.py @@ -124,8 +124,6 @@ def main(): if time_lock_delta_changed: s = ' ➜ ' + fmt.col_hi(new_time_lock_delta) print(" time_lock_delta: %s%s" % (fmt.col_hi(my_policy.time_lock_delta), s) ) - #debugging - #return True return True def get_argument_parser(): diff --git a/charge_lnd/strategy.py b/charge_lnd/strategy.py index 16f71c9..884c85e 100644 --- a/charge_lnd/strategy.py +++ b/charge_lnd/strategy.py @@ -146,77 +146,30 @@ def strategy_match_peer_inbound_weighted_average(channel, policy, **kwargs): peer_node_id = chan_info.node1_pub if chan_info.node2_pub == my_pubkey else chan_info.node2_pub - #print("peer_node_id: %s" % (peer_node_id) ) - - #peer_node_info = lnd.get_node_info(peer_node_id) - #peer_inbound_weighted_average = 0 - + # avoid having to fetch get_edges() multiple times global edges_cache if not edges_cache: - #print('getting fresh copy of edges') - # edges = lnd.get_edges() - with open('edges.pkl', 'rb') as file: - # Use pickle.load to deserialize and read the object from the file - edges = pickle.load(file) - - # all_edges = [] - # for edge in edges: - # my_edge = { - # "node1_pub": edge.node1_pub, - # "node2_pub": edge.node2_pub, - # 'capacity': edge.capacity, - # "node1_policy": { - # 'fee_rate_milli_msat': edge.node1_policy.fee_rate_milli_msat - # }, - # "node2_policy": { - # 'fee_rate_milli_msat': edge.node2_policy.fee_rate_milli_msat - # } - # } - # #pprint(my_edge) - # all_edges.append(my_edge) - - # #json_string = json.dumps(all_edges, indent=4) - # #pprint(json_string) - - # #pprint(edges) - # with open('edges.pkl', 'wb') as file: - # # Use pickle.dump to serialize and write the object to the file - # pickle.dump(all_edges, file) + edges_list = lnd.get_edges() + # cache only the data we need + edges = [] + for edge in edges_list: + the_edge = { + "node1_pub": edge.node1_pub, + "node2_pub": edge.node2_pub, + 'capacity': edge.capacity, + "node1_policy": { + 'fee_rate_milli_msat': edge.node1_policy.fee_rate_milli_msat + }, + "node2_policy": { + 'fee_rate_milli_msat': edge.node2_policy.fee_rate_milli_msat + } + } + edges.append(the_edge) edges_cache = edges else: - #print('using cache of edges') edges = edges_cache - - - # edges = [{ - # 'channel_id': 901732575861473280, - # 'chan_point': "c3fbe954405ba1570f17f72b77bbf14afe4e95b7fb766560b3ceb4db78fe4f27:0", - # 'last_update': 1701938542, - # 'node1_pub': "034f3f792988c43f41c65a839acdfa48647204bb99aca7de426f7c80b0dcf7a4a6", - # 'node2_pub': "03ceeaec6cb017d1ea8ad04a5dfb3facb24a28399d24624ecce8f319973de361d9", - # 'capacity': 4002000, - # 'node1_policy': { - # 'time_lock_delta': 80, - # 'min_htlc': 1000, - # 'fee_base_msat': 1000, - # 'fee_rate_milli_msat': 1, - # 'max_htlc_msat': 3961980000, - # 'last_update': 1701938542, - # }, - # 'node2_policy': { - # 'time_lock_delta': 80, - # 'min_htlc': 1000, - # 'fee_base_msat': 1000, - # 'fee_rate_milli_msat': 450, - # 'max_htlc_msat': 3961980000, - # 'last_update': 1701938541, - # } - # }] - - # Try to find all the channels for the peer. - peer_inbound = [] total_peer_capacity = 0 @@ -224,7 +177,7 @@ def strategy_match_peer_inbound_weighted_average(channel, policy, **kwargs): for edge in edges: if edge['node1_pub'] == peer_node_id: - # We will take node2_policy because we want inbound policy. + # We will take node2_policy because we want inbound policy, not outbound inbound = { 'capacity': edge['capacity'], 'fee_rate_milli_msat': edge['node2_policy']['fee_rate_milli_msat'] @@ -246,18 +199,14 @@ def strategy_match_peer_inbound_weighted_average(channel, policy, **kwargs): for inbound in peer_inbound: if inbound['fee_rate_milli_msat'] >= max_usable_ppm: - # ignore fee rate values over 10,000 in our calculation + # ignore fee rate values over max_usable_ppm in our calculation continue - #pprint(inbound) weighted_average_inbound_fee += int((inbound['capacity']/total_peer_capacity)*inbound['fee_rate_milli_msat']) - #print('fee rate', (weighted_average_inbound_fee)) - premium_pct = policy.getint('inbound_weighted_average_fee_rate_premium_percent') if premium_pct: premium = int(weighted_average_inbound_fee * (premium_pct/100)) - #print('adding premium: %i', (premium)) weighted_average_inbound_fee += premium return (policy.getint('fee_ppm'), weighted_average_inbound_fee) From e8679d23fb8543cd27552e447c9f68c9d5737e84 Mon Sep 17 00:00:00 2001 From: Tim Horie Date: Thu, 7 Dec 2023 21:04:42 +0900 Subject: [PATCH 07/13] Cleanup --- charge_lnd/charge_lnd.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/charge_lnd/charge_lnd.py b/charge_lnd/charge_lnd.py index 8ac37bf..acf64b2 100755 --- a/charge_lnd/charge_lnd.py +++ b/charge_lnd/charge_lnd.py @@ -12,7 +12,6 @@ from .config import Config from .electrum import Electrum import charge_lnd.fmt as fmt -from pprint import pprint def debug(message): sys.stderr.write(message + "\n") @@ -124,6 +123,7 @@ def main(): if time_lock_delta_changed: s = ' ➜ ' + fmt.col_hi(new_time_lock_delta) print(" time_lock_delta: %s%s" % (fmt.col_hi(my_policy.time_lock_delta), s) ) + return True def get_argument_parser(): From da53ce52080c9667cfc988cb0a7f372376a4df04 Mon Sep 17 00:00:00 2001 From: Tim Horie Date: Thu, 7 Dec 2023 21:15:24 +0900 Subject: [PATCH 08/13] Remove debugging --- charge_lnd/strategy.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/charge_lnd/strategy.py b/charge_lnd/strategy.py index 884c85e..25b79c4 100644 --- a/charge_lnd/strategy.py +++ b/charge_lnd/strategy.py @@ -5,8 +5,6 @@ from . import fmt from .config import Config from .electrum import Electrum -from pprint import pprint -import pickle edges_cache = None From c2429877b2bffd077a6ec2f736449086266a6631 Mon Sep 17 00:00:00 2001 From: Tim Horie Date: Thu, 7 Dec 2023 21:48:45 +0900 Subject: [PATCH 09/13] I think this is supposed to be base_fee_msat --- charge_lnd/strategy.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/charge_lnd/strategy.py b/charge_lnd/strategy.py index 25b79c4..d9b472b 100644 --- a/charge_lnd/strategy.py +++ b/charge_lnd/strategy.py @@ -207,7 +207,7 @@ def strategy_match_peer_inbound_weighted_average(channel, policy, **kwargs): premium = int(weighted_average_inbound_fee * (premium_pct/100)) weighted_average_inbound_fee += premium - return (policy.getint('fee_ppm'), weighted_average_inbound_fee) + return (policy.getint('base_fee_msat'), weighted_average_inbound_fee) @strategy(name = 'cost') def strategy_cost(channel, policy, **kwargs): From e7dfd08548b2ba3124479c9c1bdd02c2a3cb36a8 Mon Sep 17 00:00:00 2001 From: Tim Horie Date: Thu, 7 Dec 2023 22:13:19 +0900 Subject: [PATCH 10/13] Forgot to muliply by 1000 --- charge_lnd/strategy.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/charge_lnd/strategy.py b/charge_lnd/strategy.py index d9b472b..1bf8beb 100644 --- a/charge_lnd/strategy.py +++ b/charge_lnd/strategy.py @@ -64,7 +64,7 @@ def effective_max_htlc_msat(self, channel): slices = self.policy.getint('max_htlc_proportional_slices') if slices: - result = calculate_slices(channel.capacity, channel.local_balance, slices) + result = calculate_slices(channel.capacity, channel.local_balance, slices) * 1000 ratio = self.policy.getfloat('max_htlc_msat_ratio') if ratio: From 85106076fc78dd8cc34263a680936177ebd1e7f5 Mon Sep 17 00:00:00 2001 From: Tim Horie Date: Thu, 7 Dec 2023 23:38:49 +0900 Subject: [PATCH 11/13] Adjustments based on feedback --- README.md | 2 +- charge_lnd/strategy.py | 13 +++++++++--- ...ghted-average-of-peer-incoming-rate.config | 20 ++----------------- 3 files changed, 13 insertions(+), 22 deletions(-) diff --git a/README.md b/README.md index 44e243c..794fba2 100644 --- a/README.md +++ b/README.md @@ -200,7 +200,7 @@ Strategy for match peer inbound weighted average will apply the following proper |Property|Description|Values| |:--|:--|:--| -| **inbound_skip_fee_rate_above_ppm** | Inbound rate of peer to ignore exceeds this value | ppm | +| **inbound_weighted_average_fee_rate_cutoff_ppm** | Inbound rate of peer to ignore exceeds this value | ppm | | **inbound_weighted_average_fee_rate_premium_percent** | Premium added to the final peer inbound weighted average | percent | diff --git a/charge_lnd/strategy.py b/charge_lnd/strategy.py index 1bf8beb..53c8c0f 100644 --- a/charge_lnd/strategy.py +++ b/charge_lnd/strategy.py @@ -23,7 +23,7 @@ def call_strategy(*args, **kwargs): def calculate_slices(max_value, current_value, num_slices): # Calculate the size of each slice - slice_size = max_value // num_slices + slice_size = max_value // max(num_slices, 10) # Find the slice number containing the current_value current_slice = min(current_value // slice_size, num_slices - 1) @@ -175,16 +175,23 @@ def strategy_match_peer_inbound_weighted_average(channel, policy, **kwargs): for edge in edges: if edge['node1_pub'] == peer_node_id: - # We will take node2_policy because we want inbound policy, not outbound + if edge['node2_pub'] == my_pubkey: + # ignore this edge if it's shared between our node and peer + continue inbound = { 'capacity': edge['capacity'], + # We will take node2_policy because we want inbound policy, not outbound 'fee_rate_milli_msat': edge['node2_policy']['fee_rate_milli_msat'] } total_peer_capacity += edge['capacity'] peer_inbound.append(inbound) elif edge['node2_pub'] == peer_node_id: + if edge['node1_pub'] == my_pubkey: + # ignore this edge if it's shared between our node and peer + continue inbound = { 'capacity': edge['capacity'], + # We will take node1_policy because we want inbound policy, not outbound 'fee_rate_milli_msat': edge['node1_policy']['fee_rate_milli_msat'] } peer_inbound.append(inbound) @@ -193,7 +200,7 @@ def strategy_match_peer_inbound_weighted_average(channel, policy, **kwargs): # Calculate the weighted average inbound fee by multiplying each fee by # the adjusted ratio and taking the sum. - max_usable_ppm = policy.getint('inbound_skip_fee_rate_above_ppm') + max_usable_ppm = policy.getint('inbound_weighted_average_fee_rate_cutoff_ppm') for inbound in peer_inbound: if inbound['fee_rate_milli_msat'] >= max_usable_ppm: diff --git a/examples/weighted-average-of-peer-incoming-rate.config b/examples/weighted-average-of-peer-incoming-rate.config index 2cc6a20..faf3fde 100644 --- a/examples/weighted-average-of-peer-incoming-rate.config +++ b/examples/weighted-average-of-peer-incoming-rate.config @@ -1,16 +1,3 @@ -[default] -# 'default' is special, it is used if no other policy matches a channel -strategy = static -base_fee_msat = 0 -fee_ppm = 50_000 -min_fee_ppm_delta = 50 -max_htlc_proportional_slices = 6 - -# Ignore inactive nodes -[inactive-nodes] -node.max_shared_channels_active = 0 -strategy = ignore - # Use the weighted average of the peer node's channels inbound rate. # Example: # - Let's suppose you have a channel with Peer XYZ. @@ -29,8 +16,5 @@ strategy = ignore [peer-adjusted] strategy = match_peer_inbound_weighted_average -base_fee_msat = 0 -min_fee_ppm_delta = 50 -max_htlc_proportional_slices = 6 -inbound_skip_fee_rate_above_ppm = 10000 -inbound_weighted_average_fee_rate_premium_percent = 100 \ No newline at end of file +inbound_weighted_average_fee_rate_cutoff_ppm = 10000 +inbound_weighted_average_fee_rate_premium_percent = 25 \ No newline at end of file From 001f620090e4bbc7d93b2f3bfe42f545505a685e Mon Sep 17 00:00:00 2001 From: Tim Horie Date: Sun, 10 Dec 2023 15:44:17 +0900 Subject: [PATCH 12/13] Use a proportional strategy together with weighted average --- README.md | 10 +- charge_lnd/strategy.py | 154 +++++++++++++----- ...ghted-average-of-peer-incoming-rate.config | 40 ++++- 3 files changed, 146 insertions(+), 58 deletions(-) diff --git a/README.md b/README.md index 794fba2..a1273ee 100644 --- a/README.md +++ b/README.md @@ -189,21 +189,13 @@ Available strategies: |**ignore_fees** | don't make any fee changes, only update htlc size limits and time_lock_delta|| |**static** | sets fixed base fee and fee rate values.| **fee_ppm**| |**match_peer** | sets the same base fee and fee rate values as the peer|if **base_fee_msat** or **fee_ppm** are set the override the peer values| -|**match_peer_inbound_weighted_average** | sets the fee rate to the peer's inbound weighted average fee rate|| |**cost** | calculate cost for opening channel, and set ppm to cover cost when channel depletes.|**cost_factor**| |**onchain_fee** | sets the fees to a % equivalent of a standard onchain payment (Requires --electrum-server to be specified.)| **onchain_fee_btc** BTC
within **onchain_fee_numblocks** blocks.| |**proportional** | sets fee ppm according to balancedness.|**min_fee_ppm**
**max_fee_ppm**
**sum_peer_chans** consider all channels with peer for balance calculations| +|**proportional_peer_inbound** | sets the fee rate according to balancedness around a range based on the peer's inbound weighted average fee rate|**min_fee_ppm**
**max_fee_ppm**
**sum_peer_chans** consider all channels with peer for balance calculations
**fee_avg_calc_cutoff_ppm** Ignore peer inbound ppm above this value
**avg_fee_ppm_multiplier** Tweak avg ppm by this multiplier (0..1)
**upper_fee_ppm_multiplier** Tweak upper ppm by this multiplier; max_fee_ppm will still be honored (0..1)| |**disable** | disables the channel in the outgoing direction. Channel will be re-enabled again if it matches another policy (except when that policy uses an 'ignore' strategy).|| |**use_config** | process channel according to rules defined in another config file.|**config_file**| -Strategy for match peer inbound weighted average will apply the following properties if defined: - -|Property|Description|Values| -|:--|:--|:--| -| **inbound_weighted_average_fee_rate_cutoff_ppm** | Inbound rate of peer to ignore exceeds this value | ppm | -| **inbound_weighted_average_fee_rate_premium_percent** | Premium added to the final peer inbound weighted average | percent | - - All strategies (except the ignore strategy) will apply the following properties if defined: |Property|Description|Values| diff --git a/charge_lnd/strategy.py b/charge_lnd/strategy.py index 53c8c0f..54d5189 100644 --- a/charge_lnd/strategy.py +++ b/charge_lnd/strategy.py @@ -5,6 +5,7 @@ from . import fmt from .config import Config from .electrum import Electrum +from pprint import pprint edges_cache = None @@ -28,11 +29,37 @@ def calculate_slices(max_value, current_value, num_slices): # Find the slice number containing the current_value current_slice = min(current_value // slice_size, num_slices - 1) - # Determine the upper value of the slice closest to current without going over - slice_point = min((current_slice + 1) * slice_size - 1, max_value) + # Determine the upper value of the current slice without going over + slice_point = max(1, min(current_slice * slice_size, max_value)) return slice_point +def get_ratio(channel, policy, **kwargs): + if policy.getbool('sum_peer_chans', False): + lnd = kwargs['lnd'] + shared_chans=lnd.get_shared_channels(channel.remote_pubkey) + local_balance = 0 + remote_balance = 0 + for c in (shared_chans): + # Include balance of all active channels with peer + if c.active: + local_balance += c.local_balance + remote_balance += c.remote_balance + total_balance = local_balance + remote_balance + if total_balance == 0: + # Sum inactive channels because the node is likely offline with no active channels. + # When they come back online their fees won't be changed. + for c in (shared_chans): + if not c.active: + local_balance += c.local_balance + remote_balance += c.remote_balance + total_balance = local_balance + remote_balance + ratio = local_balance/total_balance + else: + ratio = channel.local_balance/(channel.local_balance + channel.remote_balance) + + return ratio + class StrategyDelegate: STRATEGIES = {} def __init__(self, policy): @@ -99,28 +126,7 @@ def strategy_proportional(channel, policy, **kwargs): if ppm_min is None or ppm_max is None: raise Exception('proportional strategy requires min_fee_ppm and max_fee_ppm properties') - if policy.getbool('sum_peer_chans', False): - lnd = kwargs['lnd'] - shared_chans=lnd.get_shared_channels(channel.remote_pubkey) - local_balance = 0 - remote_balance = 0 - for c in (shared_chans): - # Include balance of all active channels with peer - if c.active: - local_balance += c.local_balance - remote_balance += c.remote_balance - total_balance = local_balance + remote_balance - if total_balance == 0: - # Sum inactive channels because the node is likely offline with no active channels. - # When they come back online their fees won't be changed. - for c in (shared_chans): - if not c.active: - local_balance += c.local_balance - remote_balance += c.remote_balance - total_balance = local_balance + remote_balance - ratio = local_balance/total_balance - else: - ratio = channel.local_balance/(channel.local_balance + channel.remote_balance) + ratio = get_ratio(channel, policy, **kwargs) ppm = int(ppm_min + (1.0 - ratio) * (ppm_max - ppm_min)) # clamp to 0..inf @@ -136,12 +142,14 @@ def strategy_match_peer(channel, policy, **kwargs): return (policy.getint('base_fee_msat', peernode_policy.fee_base_msat), policy.getint('fee_ppm', peernode_policy.fee_rate_milli_msat)) -@strategy(name = 'match_peer_inbound_weighted_average') -def strategy_match_peer_inbound_weighted_average(channel, policy, **kwargs): +@strategy(name = 'proportional_peer_inbound') +def strategy_proportional_peer_inbound(channel, policy, **kwargs): lnd = kwargs['lnd'] chan_info = lnd.get_chan_info(channel.chan_id) my_pubkey = lnd.get_own_pubkey() + pprint(my_pubkey) + peer_node_id = chan_info.node1_pub if chan_info.node2_pub == my_pubkey else chan_info.node2_pub # avoid having to fetch get_edges() multiple times @@ -152,15 +160,18 @@ def strategy_match_peer_inbound_weighted_average(channel, policy, **kwargs): # cache only the data we need edges = [] for edge in edges_list: + #pprint(edge) the_edge = { "node1_pub": edge.node1_pub, "node2_pub": edge.node2_pub, 'capacity': edge.capacity, "node1_policy": { - 'fee_rate_milli_msat': edge.node1_policy.fee_rate_milli_msat + 'fee_rate_milli_msat': edge.node1_policy.fee_rate_milli_msat, + 'max_htlc_msat': edge.node1_policy.max_htlc_msat }, "node2_policy": { - 'fee_rate_milli_msat': edge.node2_policy.fee_rate_milli_msat + 'fee_rate_milli_msat': edge.node2_policy.fee_rate_milli_msat, + 'max_htlc_msat': edge.node2_policy.max_htlc_msat } } edges.append(the_edge) @@ -171,7 +182,7 @@ def strategy_match_peer_inbound_weighted_average(channel, policy, **kwargs): peer_inbound = [] total_peer_capacity = 0 - weighted_average_inbound_fee = 0 + ppm_avg = 0 for edge in edges: if edge['node1_pub'] == peer_node_id: @@ -179,42 +190,103 @@ def strategy_match_peer_inbound_weighted_average(channel, policy, **kwargs): # ignore this edge if it's shared between our node and peer continue inbound = { - 'capacity': edge['capacity'], + #'capacity': edge['capacity'], + # We will use the max_htlc_msat // 1000 as the estimated capacity + 'capacity': edge['node2_policy']['max_htlc_msat'] // 1000, # We will take node2_policy because we want inbound policy, not outbound 'fee_rate_milli_msat': edge['node2_policy']['fee_rate_milli_msat'] } - total_peer_capacity += edge['capacity'] + total_peer_capacity += inbound['capacity'] peer_inbound.append(inbound) elif edge['node2_pub'] == peer_node_id: if edge['node1_pub'] == my_pubkey: # ignore this edge if it's shared between our node and peer continue inbound = { - 'capacity': edge['capacity'], + #'capacity': edge['capacity'], + # We will use the max_htlc_msat // 1000 as the estimated capacity + 'capacity': edge['node1_policy']['max_htlc_msat'] // 1000, # We will take node1_policy because we want inbound policy, not outbound 'fee_rate_milli_msat': edge['node1_policy']['fee_rate_milli_msat'] } peer_inbound.append(inbound) - total_peer_capacity += edge['capacity'] + total_peer_capacity += inbound['capacity'] # Calculate the weighted average inbound fee by multiplying each fee by # the adjusted ratio and taking the sum. - max_usable_ppm = policy.getint('inbound_weighted_average_fee_rate_cutoff_ppm') + fee_avg_calc_cutoff_ppm = policy.getint('fee_avg_calc_cutoff_ppm') for inbound in peer_inbound: - if inbound['fee_rate_milli_msat'] >= max_usable_ppm: + if inbound['fee_rate_milli_msat'] >= fee_avg_calc_cutoff_ppm: # ignore fee rate values over max_usable_ppm in our calculation continue - weighted_average_inbound_fee += int((inbound['capacity']/total_peer_capacity)*inbound['fee_rate_milli_msat']) + ppm_avg += int((inbound['capacity']/total_peer_capacity)*inbound['fee_rate_milli_msat']) - premium_pct = policy.getint('inbound_weighted_average_fee_rate_premium_percent') + # Use the same channel ratio calculation as proportional strategy + ratio = get_ratio(channel, policy, **kwargs) + pprint("ratio="+str(ratio)) - if premium_pct: - premium = int(weighted_average_inbound_fee * (premium_pct/100)) - weighted_average_inbound_fee += premium + ppm_min = policy.getint('min_fee_ppm') + ppm_max = policy.getint('max_fee_ppm') + avg_fee_ppm_multiplier = policy.getfloat('avg_fee_ppm_multiplier') + upper_fee_ppm_multiplier = policy.getfloat('upper_fee_ppm_multiplier') + + pprint("ppm_min="+str(ppm_min)) + pprint("ppm_max="+str(ppm_max)) + pprint("avg_fee_ppm_multiplier="+str(avg_fee_ppm_multiplier)) + pprint("upper_fee_ppm_multiplier="+str(upper_fee_ppm_multiplier)) + + if ppm_min is None or ppm_max is None or avg_fee_ppm_multiplier is None or upper_fee_ppm_multiplier is None: + raise Exception('proportional inbound weighted strategy requires min_fee_ppm, max_fee_ppm, avg_fee_ppm_multiplier, and upper_fee_ppm_multiplier properties') + + if ppm_min >= ppm_max: + raise Exception('ppm_min should be less than ppm_max') + + # The avg_fee_ppm_multiplier can tweak the ppm_avg to be slightly + # lower or higher, changing the center-point of the calculation. + # You might do this if you think the average values are all + # too cheap or too expensive. We will also make sure the average + # is not lower than ppm_min here, or higher than ppm_max. + # It's probably perfectly fine to leave this multiplier at 1. + + ppm_avg = min(ppm_max, max(ppm_min, ppm_avg * avg_fee_ppm_multiplier)) + pprint("ppm_avg="+str(ppm_avg)) + + # The upper_fee_ppm_multiplier sets the upper maximum when calculating + # the ppm when the local balance proportion drops below 0.5. A value + # of 2 means that the upper maximum is double the ppm_avg. If you + # wanted to increase fees more aggressively as the local balance falls, + # you could choose a higher multiplier. + # It's probably perfectly fine to leave this multiplier at 2. + + ppm_upper = ppm_avg * upper_fee_ppm_multiplier + pprint("ppm_upper="+str(ppm_upper)) + + # When the ratio is near half, we want the ppm to be exactly + # the ppm_avg. When the ratio is lower, we want a higher ppm that + # is between ppm_avg and ppm_upper. When the ratio is higher, + # we want a lower ppm between ppm_avg and ppm_min. Since the range + # between can be unequal, e.g. average = 500, min = 400, max + # = 3000, we don't want to make the 0.5 ratio be the middle + # of the range 400 - 3000. It's much larger than the target + # average of 500. So we calculate the two sides separately. + + if ratio < 0.5: + ppm = int(ppm_upper + 2 * (ppm_avg - ppm_upper) * ratio) + elif ratio > 0.5: + ppm = int(ppm_min + 2 * (ppm_avg - ppm_min) * (1 - ratio)) + else: + ppm = ppm_avg + + # Cap it to the max + ppm = min(ppm, ppm_max) - return (policy.getint('base_fee_msat'), weighted_average_inbound_fee) + # clamp to 0..inf + ppm = max(ppm, 0) + + pprint("ppm="+str(ppm)) + return (policy.getint('base_fee_msat'), ppm) @strategy(name = 'cost') def strategy_cost(channel, policy, **kwargs): diff --git a/examples/weighted-average-of-peer-incoming-rate.config b/examples/weighted-average-of-peer-incoming-rate.config index faf3fde..dcd41c0 100644 --- a/examples/weighted-average-of-peer-incoming-rate.config +++ b/examples/weighted-average-of-peer-incoming-rate.config @@ -1,4 +1,7 @@ -# Use the weighted average of the peer node's channels inbound rate. +# Use a fee that is proportional to the channel's local balance with +# the ppm range surrounding the weighted average of the peer node's +# inbound ppm rate. +# # Example: # - Let's suppose you have a channel with Peer XYZ. # - Peer XYZ has 4 channels. @@ -10,11 +13,32 @@ # than the plain average, because more capacity is at the 400 ppm # rate compared to the lower ppm rate. # -# The inbound_weighted_average_fee_rate_premium_percent value adds a -# multiple of the weighted average fee. For example, a value of 25 -# means that a 200 ppm weighted average will be set to 250 ppm. +# The `min_fee_ppm` and `max_fee_ppm` are absolute, and will override +# whatever calculations are made. +# +# The `fee_avg_calc_cutoff_ppm` is a cutoff maximum value when +# considering the peer's inbound channel ppm. We can exclude these +# extreme values from the calculation to get a more reasonable avg. +# +# The `avg_fee_ppm_multiplier` shifts the calculated peer's avg to +# higher or lower. This is useful if you think the avg is too low +# or too high. +# +# The `upper_fee_ppm_multiplier` determines how aggresively you want +# your ppm to rise as the local channel balance falls. A multiplier +# of 2 sets the upper ppm fee to be double as balance approaches 0. + +[proportional_peer_inbound] +strategy = proportional_peer_inbound +node.min_shared_channels_active = 1 +base_fee_msat = 0 +min_fee_ppm_delta = 50 +max_htlc_proportional_slices = 6 + +min_fee_ppm = 1 +max_fee_ppm = 99_999 +fee_avg_calc_cutoff_ppm = 5_000 +avg_fee_ppm_multiplier = 1.0 +upper_fee_ppm_multiplier = 2.0 -[peer-adjusted] -strategy = match_peer_inbound_weighted_average -inbound_weighted_average_fee_rate_cutoff_ppm = 10000 -inbound_weighted_average_fee_rate_premium_percent = 25 \ No newline at end of file +time_lock_delta = 18 \ No newline at end of file From eade0e8a1fdd6ebdf8f4837697245108b820ff51 Mon Sep 17 00:00:00 2001 From: Tim Horie Date: Sun, 10 Dec 2023 15:52:35 +0900 Subject: [PATCH 13/13] Remove debugging --- charge_lnd/strategy.py | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/charge_lnd/strategy.py b/charge_lnd/strategy.py index 54d5189..d3f1e8c 100644 --- a/charge_lnd/strategy.py +++ b/charge_lnd/strategy.py @@ -5,7 +5,6 @@ from . import fmt from .config import Config from .electrum import Electrum -from pprint import pprint edges_cache = None @@ -148,8 +147,6 @@ def strategy_proportional_peer_inbound(channel, policy, **kwargs): chan_info = lnd.get_chan_info(channel.chan_id) my_pubkey = lnd.get_own_pubkey() - pprint(my_pubkey) - peer_node_id = chan_info.node1_pub if chan_info.node2_pub == my_pubkey else chan_info.node2_pub # avoid having to fetch get_edges() multiple times @@ -160,7 +157,6 @@ def strategy_proportional_peer_inbound(channel, policy, **kwargs): # cache only the data we need edges = [] for edge in edges_list: - #pprint(edge) the_edge = { "node1_pub": edge.node1_pub, "node2_pub": edge.node2_pub, @@ -225,18 +221,12 @@ def strategy_proportional_peer_inbound(channel, policy, **kwargs): # Use the same channel ratio calculation as proportional strategy ratio = get_ratio(channel, policy, **kwargs) - pprint("ratio="+str(ratio)) ppm_min = policy.getint('min_fee_ppm') ppm_max = policy.getint('max_fee_ppm') avg_fee_ppm_multiplier = policy.getfloat('avg_fee_ppm_multiplier') upper_fee_ppm_multiplier = policy.getfloat('upper_fee_ppm_multiplier') - pprint("ppm_min="+str(ppm_min)) - pprint("ppm_max="+str(ppm_max)) - pprint("avg_fee_ppm_multiplier="+str(avg_fee_ppm_multiplier)) - pprint("upper_fee_ppm_multiplier="+str(upper_fee_ppm_multiplier)) - if ppm_min is None or ppm_max is None or avg_fee_ppm_multiplier is None or upper_fee_ppm_multiplier is None: raise Exception('proportional inbound weighted strategy requires min_fee_ppm, max_fee_ppm, avg_fee_ppm_multiplier, and upper_fee_ppm_multiplier properties') @@ -251,7 +241,6 @@ def strategy_proportional_peer_inbound(channel, policy, **kwargs): # It's probably perfectly fine to leave this multiplier at 1. ppm_avg = min(ppm_max, max(ppm_min, ppm_avg * avg_fee_ppm_multiplier)) - pprint("ppm_avg="+str(ppm_avg)) # The upper_fee_ppm_multiplier sets the upper maximum when calculating # the ppm when the local balance proportion drops below 0.5. A value @@ -261,7 +250,6 @@ def strategy_proportional_peer_inbound(channel, policy, **kwargs): # It's probably perfectly fine to leave this multiplier at 2. ppm_upper = ppm_avg * upper_fee_ppm_multiplier - pprint("ppm_upper="+str(ppm_upper)) # When the ratio is near half, we want the ppm to be exactly # the ppm_avg. When the ratio is lower, we want a higher ppm that @@ -285,7 +273,6 @@ def strategy_proportional_peer_inbound(channel, policy, **kwargs): # clamp to 0..inf ppm = max(ppm, 0) - pprint("ppm="+str(ppm)) return (policy.getint('base_fee_msat'), ppm) @strategy(name = 'cost')