Skip to content

Commit 50bf1c1

Browse files
committed
QA: feature_fee_estimation: Add tests for dustrelayfeedynamic
1 parent bcb0dd8 commit 50bf1c1

File tree

1 file changed

+72
-0
lines changed

1 file changed

+72
-0
lines changed

test/functional/feature_fee_estimation.py

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424

2525
MAX_FILE_AGE = 60
2626
SECONDS_PER_HOUR = 60 * 60
27+
target_success_threshold = 0.8
2728

2829
def small_txpuzzle_randfee(
2930
wallet, from_node, conflist, unconflist, amount, min_fee, fee_increment, batch_reqs
@@ -137,6 +138,19 @@ def check_fee_estimates_btw_modes(node, expected_conservative, expected_economic
137138
assert_equal(fee_est_default, expected_economical)
138139

139140

141+
def get_feerate_into_mempool(node, kB):
142+
mempool_entries = list(node.getrawmempool(verbose=True).values())
143+
for entry in mempool_entries:
144+
entry['feerate_BTC/vB'] = entry['fees']['modified'] / entry['vsize']
145+
mempool_entries.sort(key=lambda entry: entry['feerate_BTC/vB'], reverse=True)
146+
bytes_remaining = kB * 1000
147+
for entry in mempool_entries:
148+
bytes_remaining -= entry['vsize']
149+
if bytes_remaining <= 0:
150+
return satoshi_round(entry['feerate_BTC/vB'] * 1000)
151+
raise AssertionError('Entire mempool is smaller than %s kB' % (kB,))
152+
153+
140154
class EstimateFeeTest(BitcoinTestFramework):
141155
def set_test_params(self):
142156
self.num_nodes = 3
@@ -237,6 +251,62 @@ def sanity_check_estimates_range(self):
237251
self.log.info("Final estimates after emptying mempools")
238252
check_estimates(self.nodes[1], self.fees_per_kb)
239253

254+
def test_feerate_dustrelayfee(self):
255+
node = self.nodes[0]
256+
257+
# test dustdynamic=target:<blocks>
258+
for dustfee_target in (2, 8, 1008):
259+
dust_mode = f"target:{dustfee_target}"
260+
dust_parameter = f"-dustdynamic={dust_mode}"
261+
self.log.info(f"Test dust limit setting {dust_parameter} (fee estimation for {dustfee_target} blocks)")
262+
self.restart_node(0, extra_args=[dust_parameter])
263+
assert_equal(node.getmempoolinfo()['dustdynamic'], dust_mode)
264+
with node.busy_wait_for_debug_log([b'Updating dust feerate']):
265+
node.mockscheduler(SECONDS_PER_HOUR)
266+
fee_est = node.estimaterawfee(dustfee_target, target_success_threshold)['long']['feerate']
267+
mempool_info = node.getmempoolinfo()
268+
assert_equal(mempool_info['dustrelayfee'], fee_est)
269+
assert mempool_info['dustrelayfee'] > mempool_info['dustrelayfeefloor']
270+
271+
# Fill mempool up
272+
mempool_size = 0
273+
batch_sendtx_reqs = []
274+
min_fee = Decimal("0.00001")
275+
while mempool_size < 52000:
276+
(tx_bytes, fee) = small_txpuzzle_randfee(
277+
self.wallet,
278+
self.nodes[0],
279+
self.confutxo,
280+
self.memutxo,
281+
Decimal("0.005"),
282+
min_fee,
283+
min_fee,
284+
batch_sendtx_reqs,
285+
)
286+
mempool_size += tx_bytes
287+
node.batch(batch_sendtx_reqs)
288+
289+
# test dustdynamic=mempool:<kB>
290+
for dustfee_kB in (1, 10, 50):
291+
dust_mode = f"mempool:{dustfee_kB}"
292+
dust_parameter = f"-dustdynamic={dust_mode}"
293+
self.log.info(f"Test dust limit setting {dust_parameter} (fee estimation for {dustfee_kB} kB into mempool)")
294+
self.restart_node(0, extra_args=[dust_parameter])
295+
assert_equal(node.getmempoolinfo()['dustdynamic'], dust_mode)
296+
with node.busy_wait_for_debug_log([b'Updating dust feerate']):
297+
node.mockscheduler(SECONDS_PER_HOUR)
298+
feerate_into_mempool = get_feerate_into_mempool(node, dustfee_kB)
299+
mempool_info = node.getmempoolinfo()
300+
assert_equal(mempool_info['dustrelayfee'], feerate_into_mempool)
301+
assert mempool_info['dustrelayfee'] > mempool_info['dustrelayfeefloor']
302+
303+
# Restore nodes to a normal state, wiping the mempool
304+
self.stop_node(0)
305+
(self.nodes[0].chain_path / 'mempool.dat').unlink()
306+
self.start_node(0)
307+
self.connect_nodes(1, 0)
308+
self.connect_nodes(0, 2)
309+
240310
def test_feerate_mempoolminfee(self):
241311
high_val = 3 * self.nodes[1].estimatesmartfee(1)["feerate"]
242312
self.restart_node(1, extra_args=[f"-minrelaytxfee={high_val}"])
@@ -450,6 +520,8 @@ def run_test(self):
450520
self.log.info("Test fee_estimates.dat is flushed periodically")
451521
self.test_estimate_dat_is_flushed_periodically()
452522

523+
self.test_feerate_dustrelayfee()
524+
453525
# check that the effective feerate is greater than or equal to the mempoolminfee even for high mempoolminfee
454526
self.log.info(
455527
"Test fee rate estimation after restarting node with high MempoolMinFee"

0 commit comments

Comments
 (0)