lightningd: handle fees as blockcount + range.

Rather than have specific-purpose levels, have an array of
[blockcount, feerate], and rebuild the specific-purpose levels
for now on top.

We also keep a *separate* smoothed feerate, so you can ask for that
explicitly.

Since all the plugins used the same formula to derive the different
named fee levels, we apply the reverse to return to the underlying
estimates: updating the interface comes next.

This is ugly for now, but various specific-purpose levels will be
going away, as we shift to deadline-driven fees.

This temporarily breaks the floor calculation, so that test is
disabled.

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
This commit is contained in:
Rusty Russell
2023-04-07 14:09:53 +09:30
parent faae44713b
commit cdb85d5618
6 changed files with 328 additions and 174 deletions

View File

@@ -1556,35 +1556,39 @@ def test_feerates(node_factory):
l1.set_feerates((15000, 0, 0, 0), True)
wait_for(lambda: l1.rpc.feerates('perkw')['perkw']['max_acceptable'] == 15000 * 10)
feerates = l1.rpc.feerates('perkw')
assert feerates['warning_missing_feerates'] == 'Some fee estimates unavailable: bitcoind startup?'
# We only get the warning if *no* feerates are avail.
assert 'warning_missing_feerates' not in feerates
assert 'perkb' not in feerates
assert feerates['perkw']['min_acceptable'] == 253
# With only one data point, this is a terrible guess!
assert feerates['perkw']['min_acceptable'] == 15000 // 2
# assert feerates['perkw']['min_acceptable'] == 253
# Set ECONOMICAL/6 feerate, for unilateral_close and htlc_resolution
l1.set_feerates((15000, 11000, 0, 0), True)
wait_for(lambda: len(l1.rpc.feerates('perkw')['perkw']) == 4)
feerates = l1.rpc.feerates('perkw')
assert feerates['perkw']['unilateral_close'] == 11000
assert feerates['perkw']['htlc_resolution'] == 11000
assert feerates['warning_missing_feerates'] == 'Some fee estimates unavailable: bitcoind startup?'
assert 'warning_missing_feerates' not in feerates
assert 'perkb' not in feerates
assert feerates['perkw']['max_acceptable'] == 15000 * 10
assert feerates['perkw']['min_acceptable'] == 253
# With only two data points, this is a terrible guess!
assert feerates['perkw']['min_acceptable'] == 11000 // 2
# Set ECONOMICAL/12 feerate, for all but min (so, no mutual_close feerate)
l1.set_feerates((15000, 11000, 6250, 0), True)
wait_for(lambda: len(l1.rpc.feerates('perkb')['perkb']) == len(types) - 1 + 2)
feerates = l1.rpc.feerates('perkb')
assert feerates['perkb']['unilateral_close'] == 11000 * 4
assert feerates['perkb']['htlc_resolution'] == 11000 * 4
assert 'mutual_close' not in feerates['perkb']
# We dont' extrapolate, so it uses the same for mutual_close
assert feerates['perkb']['mutual_close'] == 6250 * 4
for t in types:
if t not in ("unilateral_close", "htlc_resolution", "mutual_close"):
assert feerates['perkb'][t] == 25000
assert feerates['warning_missing_feerates'] == 'Some fee estimates unavailable: bitcoind startup?'
assert 'warning_missing_feerates' not in feerates
assert 'perkw' not in feerates
assert feerates['perkb']['max_acceptable'] == 15000 * 4 * 10
assert feerates['perkb']['min_acceptable'] == 253 * 4
# With only three data points, this is a terrible guess!
assert feerates['perkb']['min_acceptable'] == 6250 // 2 * 4
# Set ECONOMICAL/100 feerate for min and mutual_close
l1.set_feerates((15000, 11000, 6250, 5000), True)
@@ -1596,7 +1600,7 @@ def test_feerates(node_factory):
for t in types:
if t not in ("unilateral_close", "htlc_resolution", "mutual_close"):
assert feerates['perkw'][t] == 25000 // 4
assert 'warning' not in feerates
assert 'warning_missing_feerates' not in feerates
assert 'perkb' not in feerates
assert feerates['perkw']['max_acceptable'] == 15000 * 10
assert feerates['perkw']['min_acceptable'] == 5000 // 2
@@ -1910,6 +1914,7 @@ def test_bitcoind_fail_first(node_factory, bitcoind):
@unittest.skipIf(TEST_NETWORK == 'liquid-regtest', "Fees on elements are different")
@unittest.skip("FIXME: temporarily broken")
def test_bitcoind_feerate_floor(node_factory, bitcoind):
"""Don't return a feerate less than minrelaytxfee/mempoolnifee."""
l1 = node_factory.get_node()