mirror of
https://github.com/aljazceru/plugins.git
synced 2026-01-06 06:44:21 +01:00
feeadjuster: adds imbalance limiter
This commit is contained in:
committed by
Christian Decker
parent
ad9c5df9ef
commit
75c4194b03
@@ -28,6 +28,12 @@ def maybe_adjust_fees(plugin: Plugin, scids: list):
|
||||
percentage = our / total
|
||||
last_percentage = plugin.adj_balances[scid].get("last_percentage")
|
||||
|
||||
# reset to normal fees if imbalance is not high enough
|
||||
if (percentage > plugin.imbalance and percentage < 1 - plugin.imbalance):
|
||||
plugin.rpc.setchannelfee(scid) # applies default values
|
||||
plugin.log("Set default fees as imbalance is too low: {}".format(scid))
|
||||
return
|
||||
|
||||
# Only update on substantial balance moves to avoid flooding, and add
|
||||
# some pseudo-randomness to avoid too easy channel balance probing
|
||||
update_threshold = plugin.update_threshold
|
||||
@@ -101,14 +107,22 @@ def init(options: dict, configuration: dict, plugin: Plugin, **kwargs):
|
||||
plugin.our_node_id = plugin.rpc.getinfo()["id"]
|
||||
plugin.deactivate_fuzz = options.get("feeadjuster-deactivate-fuzz", False)
|
||||
plugin.update_threshold = float(options.get("feeadjuster-threshold", "0.05"))
|
||||
plugin.imbalance = float(options.get("feeadjuster-imbalance", 0.5))
|
||||
config = plugin.rpc.listconfigs()
|
||||
plugin.adj_basefee = config["fee-base"]
|
||||
plugin.adj_ppmfee = config["fee-per-satoshi"]
|
||||
|
||||
plugin.log("Plugin feeadjuster initialized ({} base / {} ppm) with a "
|
||||
"threshold of {}"
|
||||
.format(plugin.adj_basefee, plugin.adj_ppmfee,
|
||||
plugin.update_threshold))
|
||||
# normalize the imbalance percentage value to 0%-50%
|
||||
if plugin.imbalance < 0 or plugin.imbalance > 1:
|
||||
raise ValueError("feeadjuster-imbalance must be between 0 and 1.")
|
||||
if plugin.imbalance > 0.5:
|
||||
plugin.imbalance = 1 - plugin.imbalance
|
||||
|
||||
plugin.log("Plugin feeadjuster initialized ({} base / {} ppm) with an "
|
||||
"imbalance of {}%/{}%".format(plugin.adj_basefee,
|
||||
plugin.adj_ppmfee,
|
||||
int(100*plugin.imbalance),
|
||||
int(100*(1-plugin.imbalance))))
|
||||
|
||||
|
||||
plugin.add_option(
|
||||
@@ -124,4 +138,13 @@ plugin.add_option(
|
||||
"Note: it's also fuzzed by 1.5%",
|
||||
"string"
|
||||
)
|
||||
plugin.add_option(
|
||||
"feeadjuster-imbalance",
|
||||
"0.5",
|
||||
"Ratio at which channel imbalance the feeadjuster should start acting. "
|
||||
"Default: 0.5 (always). Set higher or lower values to limit feeadjuster's "
|
||||
"activity to more imbalanced channels. "
|
||||
"E.g. 0.3 for '70/30'% or 0.6 for '40/60'%.",
|
||||
"string"
|
||||
)
|
||||
plugin.run()
|
||||
|
||||
@@ -124,3 +124,66 @@ def test_feeadjuster_adjusts(node_factory):
|
||||
" 4.".format(scid_A)) is not None)
|
||||
wait_for(lambda: l2.daemon.is_in_log("Adjusted fees of {} with a ratio of"
|
||||
" 0.2".format(scid_B)) is not None)
|
||||
|
||||
|
||||
@unittest.skipIf(not DEVELOPER, "Too slow without fast gossip")
|
||||
def test_feeadjuster_imbalance(node_factory):
|
||||
"""
|
||||
A rather simple network:
|
||||
|
||||
A B
|
||||
l1 <========> l2 <=========> l3
|
||||
|
||||
l2 will adjust its configuration-set base and proportional fees for
|
||||
channels A and B as l1 and l3 exchange payments.
|
||||
"""
|
||||
base_fee = 5000
|
||||
ppm_fee = 300
|
||||
l2_opts = {
|
||||
"fee-base": base_fee,
|
||||
"fee-per-satoshi": ppm_fee,
|
||||
"plugin": plugin_path,
|
||||
"feeadjuster-deactivate-fuzz": None,
|
||||
"feeadjuster-imbalance": 0.7, # should be normalized to 30/70
|
||||
}
|
||||
l1, l2, l3 = node_factory.line_graph(3, opts=[{}, l2_opts, {}],
|
||||
wait_for_announce=True)
|
||||
|
||||
chan_A = l2.rpc.listpeers(l1.info["id"])["peers"][0]["channels"][0]
|
||||
chan_B = l2.rpc.listpeers(l3.info["id"])["peers"][0]["channels"][0]
|
||||
scid_A = chan_A["short_channel_id"]
|
||||
scid_B = chan_B["short_channel_id"]
|
||||
l2_scids = [scid_A, scid_B]
|
||||
|
||||
chan_total = int(chan_A["total_msat"])
|
||||
assert chan_total == int(chan_B["total_msat"])
|
||||
l2.daemon.wait_for_log('imbalance of 30%/70%')
|
||||
|
||||
# First bring channel to somewhat of a blanance
|
||||
amount = int(chan_total * 0.5)
|
||||
pay(l1, l3, amount)
|
||||
l2.daemon.wait_for_log('Set default fees as imbalance is too low')
|
||||
for scid in l2_scids:
|
||||
sync_gossip(l3, l2, scid)
|
||||
sync_gossip(l1, l2, scid)
|
||||
fees_before = [get_chan_fees(l2, scid) for scid in [scid_A, scid_B]]
|
||||
assert fees_before == [(base_fee, ppm_fee), (base_fee, ppm_fee)]
|
||||
|
||||
# Because of the 70/30 imbalance limiter, a 15% payment must not yet trigger
|
||||
# 50% + 15% = 65% .. which is < 70%
|
||||
amount = int(chan_total * 0.15)
|
||||
pay(l1, l3, amount)
|
||||
for scid in l2_scids:
|
||||
sync_gossip(l3, l2, scid)
|
||||
sync_gossip(l1, l2, scid)
|
||||
fees_before = [get_chan_fees(l2, scid) for scid in [scid_A, scid_B]]
|
||||
assert fees_before == [get_chan_fees(l2, scid) for scid in l2_scids]
|
||||
assert not l2.daemon.is_in_log("Adjusted fees")
|
||||
|
||||
# Sending another 20% must now trigger because the imbalance
|
||||
pay(l1, l3, amount)
|
||||
l2.daemon.wait_for_log("Adjusted fees")
|
||||
|
||||
# Bringing it back must cause default fees
|
||||
pay(l3, l1, amount)
|
||||
l2.daemon.wait_for_log('Set default fees as imbalance is too low')
|
||||
|
||||
Reference in New Issue
Block a user