mirror of
https://github.com/bitcoin/bitcoin.git
synced 2026-09-11 21:20:39 +02:00
fees: move fee_estimates.dat into fees directory
Move block policy fee estimates from fee_estimates.dat to
fees/block_policy_estimates.dat.
On startup, migrate the legacy file to the new path when only the legacy
file exists. If both files exist, keep the new file and remove the
legacy file.
Rename the block policy estimator args source files to the generic
estimator_args.{cpp,h} names and rename FeeestPath to
BlockPolicyFeeEstPath while the path helper is moved into the shared fee
estimator argument code.
This commit is contained in:
@@ -31,6 +31,7 @@ SECONDS_PER_HOUR = 60 * 60
|
||||
MIN_BUCKET_FEERATE = Decimal(100) / Decimal(COIN)
|
||||
TXS_COUNT = 24
|
||||
BLOCK_POLICY_ESTIMATOR_ERROR = "Insufficient data or no feerate found"
|
||||
BLOCK_POLICY_ESTIMATOR_FILE_PATH = "fees/block_policy_estimates.dat"
|
||||
|
||||
def small_txpuzzle_randfee(
|
||||
wallet, from_node, conflist, unconflist, amount, min_fee, fee_increment, batch_reqs
|
||||
@@ -333,69 +334,91 @@ class EstimateFeeTest(BitcoinTestFramework):
|
||||
self.restart_node(0)
|
||||
assert_equal(self.nodes[0].estimatesmartfee(1, "economical", {"fee_rate_estimator": "block_policy"})["feerate"], fee_rate)
|
||||
|
||||
fee_dat = self.nodes[0].chain_path / "fee_estimates.dat"
|
||||
block_policy_fee_dat = self.nodes[0].chain_path / BLOCK_POLICY_ESTIMATOR_FILE_PATH
|
||||
legacy_fee_dat = self.nodes[0].chain_path / "fee_estimates.dat"
|
||||
|
||||
# Stop the node and backdate the fee_estimates.dat file more than MAX_FILE_AGE
|
||||
# If only the legacy fee_estimates.dat file exists, it is migrated to
|
||||
# the new block policy estimator path.
|
||||
self.stop_node(0)
|
||||
last_modified_time = time.time() - (MAX_FILE_AGE + 1) * SECONDS_PER_HOUR
|
||||
os.utime(fee_dat, (last_modified_time, last_modified_time))
|
||||
os.rename(block_policy_fee_dat, legacy_fee_dat)
|
||||
self.start_node(0)
|
||||
assert_equal(self.nodes[0].estimatesmartfee(1, "economical", {"fee_rate_estimator": "block_policy"})["feerate"], fee_rate)
|
||||
self.stop_node(0)
|
||||
assert_equal(os.path.isfile(block_policy_fee_dat), True)
|
||||
assert_equal(os.path.isfile(legacy_fee_dat), False)
|
||||
|
||||
# Start node and ensure the fee_estimates.dat file was not read
|
||||
# If both files exist, the new block policy estimator path is used and
|
||||
# the obsolete legacy file is removed.
|
||||
with open(legacy_fee_dat, "wb") as f:
|
||||
f.write(b"ignored legacy fee estimates")
|
||||
self.start_node(0)
|
||||
assert_equal(self.nodes[0].estimatesmartfee(1, "economical", {"fee_rate_estimator": "block_policy"})["feerate"], fee_rate)
|
||||
self.stop_node(0)
|
||||
assert_equal(os.path.isfile(legacy_fee_dat), False)
|
||||
|
||||
# Stop the node and backdate the block policy estimator file more than MAX_FILE_AGE
|
||||
last_modified_time = time.time() - (MAX_FILE_AGE + 1) * SECONDS_PER_HOUR
|
||||
os.utime(block_policy_fee_dat, (last_modified_time, last_modified_time))
|
||||
|
||||
# Start node and ensure the block policy estimator file was not read
|
||||
self.start_node(0)
|
||||
assert_equal(self.nodes[0].estimatesmartfee(1, "economical", {"fee_rate_estimator": "block_policy"})["errors"], [BLOCK_POLICY_ESTIMATOR_ERROR])
|
||||
|
||||
|
||||
def test_estimate_dat_is_flushed_periodically(self):
|
||||
fee_dat = self.nodes[0].chain_path / "fee_estimates.dat"
|
||||
os.remove(fee_dat) if os.path.exists(fee_dat) else None
|
||||
block_policy_fees_dat = self.nodes[0].chain_path / BLOCK_POLICY_ESTIMATOR_FILE_PATH
|
||||
os.remove(block_policy_fees_dat) if os.path.exists(block_policy_fees_dat) else None
|
||||
if os.path.isdir(block_policy_fees_dat.parent):
|
||||
os.rmdir(block_policy_fees_dat.parent)
|
||||
|
||||
# Verify that fee_estimates.dat does not exist
|
||||
assert_equal(os.path.isfile(fee_dat), False)
|
||||
|
||||
# Verify if the string "Flushed fee estimates to fee_estimates.dat." is present in the debug log file.
|
||||
# Verify that block policy estimator file and its parent directory do not exist
|
||||
assert_equal(os.path.isfile(block_policy_fees_dat), False)
|
||||
assert_equal(os.path.isdir(block_policy_fees_dat.parent), False)
|
||||
# Verify if the string "Flushed fee estimates to block_policy_estimates.dat." is present in the debug log file.
|
||||
# If present, it indicates that fee estimates have been successfully flushed to disk.
|
||||
expected_messages = [f"Flushed fee estimates to {fee_dat}."]
|
||||
expected_messages = [f"Flushed fee estimates to {block_policy_fees_dat}."]
|
||||
with self.nodes[0].assert_debug_log(expected_msgs=expected_messages, timeout=1):
|
||||
# Mock the scheduler for an hour to flush fee estimates to fee_estimates.dat
|
||||
# Mock the scheduler for an hour to flush fee estimates to block_policy_estimates.dat
|
||||
self.nodes[0].mockscheduler(SECONDS_PER_HOUR)
|
||||
|
||||
# Verify that fee estimates were flushed and fee_estimates.dat file is created
|
||||
assert_equal(os.path.isfile(fee_dat), True)
|
||||
# Verify that fee estimates were flushed and block policy estimator directory and file are created
|
||||
assert_equal(os.path.isdir(block_policy_fees_dat.parent), True)
|
||||
assert_equal(os.path.isfile(block_policy_fees_dat), True)
|
||||
|
||||
# Verify that the estimates remain the same if there are no blocks in the flush interval
|
||||
block_hash_before = self.nodes[0].getbestblockhash()
|
||||
fee_dat_initial_content = open(fee_dat, "rb").read()
|
||||
block_policy_dat_initial_content = open(block_policy_fees_dat, "rb").read()
|
||||
with self.nodes[0].assert_debug_log(expected_msgs=expected_messages, timeout=1):
|
||||
# Mock the scheduler for an hour to flush fee estimates to fee_estimates.dat
|
||||
# Mock the scheduler for an hour to flush fee estimates to the block policy estimator file
|
||||
self.nodes[0].mockscheduler(SECONDS_PER_HOUR)
|
||||
|
||||
# Verify that there were no blocks in between the flush interval
|
||||
assert_equal(block_hash_before, self.nodes[0].getbestblockhash())
|
||||
|
||||
fee_dat_current_content = open(fee_dat, "rb").read()
|
||||
assert_equal(fee_dat_current_content, fee_dat_initial_content)
|
||||
block_policy_fee_dat_current_content = open(block_policy_fees_dat, "rb").read()
|
||||
assert_equal(block_policy_dat_initial_content, block_policy_fee_dat_current_content)
|
||||
|
||||
# Verify that the estimates remain the same after shutdown with no blocks before shutdown
|
||||
self.restart_node(0)
|
||||
fee_dat_current_content = open(fee_dat, "rb").read()
|
||||
assert_equal(fee_dat_current_content, fee_dat_initial_content)
|
||||
block_policy_fee_dat_current_content = open(block_policy_fees_dat, "rb").read()
|
||||
assert_equal(block_policy_dat_initial_content, block_policy_fee_dat_current_content)
|
||||
|
||||
# Verify that the estimates are not the same if new blocks were produced in the flush interval
|
||||
with self.nodes[0].assert_debug_log(expected_msgs=expected_messages, timeout=1):
|
||||
# Mock the scheduler for an hour to flush fee estimates to fee_estimates.dat
|
||||
# Mock the scheduler for an hour to flush fee estimates to block_policy_estimates.dat
|
||||
self.generate(self.nodes[0], 5, sync_fun=self.no_op)
|
||||
self.nodes[0].mockscheduler(SECONDS_PER_HOUR)
|
||||
|
||||
fee_dat_current_content = open(fee_dat, "rb").read()
|
||||
assert_not_equal(fee_dat_current_content, fee_dat_initial_content)
|
||||
|
||||
fee_dat_initial_content = fee_dat_current_content
|
||||
block_policy_fee_dat_current_content = open(block_policy_fees_dat, "rb").read()
|
||||
assert_not_equal(block_policy_fee_dat_current_content, block_policy_dat_initial_content)
|
||||
block_policy_dat_initial_content = block_policy_fee_dat_current_content
|
||||
|
||||
# Generate blocks before shutdown and verify that the fee estimates are not the same
|
||||
self.generate(self.nodes[0], 5, sync_fun=self.no_op)
|
||||
self.restart_node(0)
|
||||
fee_dat_current_content = open(fee_dat, "rb").read()
|
||||
assert_not_equal(fee_dat_current_content, fee_dat_initial_content)
|
||||
|
||||
block_policy_fee_dat_current_content = open(block_policy_fees_dat, "rb").read()
|
||||
assert_not_equal(block_policy_dat_initial_content, block_policy_fee_dat_current_content)
|
||||
|
||||
|
||||
def test_acceptstalefeeestimates_option(self):
|
||||
@@ -404,20 +427,20 @@ class EstimateFeeTest(BitcoinTestFramework):
|
||||
|
||||
self.stop_node(0)
|
||||
|
||||
fee_dat = self.nodes[0].chain_path / "fee_estimates.dat"
|
||||
fee_dat = self.nodes[0].chain_path / BLOCK_POLICY_ESTIMATOR_FILE_PATH
|
||||
|
||||
# Stop the node and backdate the fee_estimates.dat file more than MAX_FILE_AGE
|
||||
# Stop the node and backdate the block policy estimator file more than MAX_FILE_AGE
|
||||
last_modified_time = time.time() - (MAX_FILE_AGE + 1) * SECONDS_PER_HOUR
|
||||
os.utime(fee_dat, (last_modified_time, last_modified_time))
|
||||
|
||||
# Restart node with -acceptstalefeeestimates option to ensure fee_estimate.dat file is read
|
||||
# Restart node with -acceptstalefeeestimates option to ensure block policy estimator file is read
|
||||
self.start_node(0,extra_args=["-acceptstalefeeestimates"])
|
||||
assert_equal(self.nodes[0].estimatesmartfee(1, "economical", {"fee_rate_estimator": "block_policy"})["feerate"], fee_rate)
|
||||
|
||||
def clear_estimates(self):
|
||||
self.log.info("Restarting node with fresh estimation")
|
||||
self.stop_node(0)
|
||||
fee_dat = self.nodes[0].chain_path / "fee_estimates.dat"
|
||||
fee_dat = self.nodes[0].chain_path / BLOCK_POLICY_ESTIMATOR_FILE_PATH
|
||||
os.remove(fee_dat)
|
||||
self.start_node(0)
|
||||
self.connect_nodes(0, 1)
|
||||
@@ -552,7 +575,7 @@ class EstimateFeeTest(BitcoinTestFramework):
|
||||
self.log.info("Testing estimates with single transactions.")
|
||||
self.sanity_check_estimates_range()
|
||||
|
||||
self.log.info("Test fee_estimates.dat is flushed periodically")
|
||||
self.log.info("Test fees data is flushed periodically")
|
||||
self.test_estimate_dat_is_flushed_periodically()
|
||||
|
||||
# check that estimatesmartfee feerate is greater than or equal to maximum of mempoolminfee and minrelaytxfee
|
||||
@@ -564,7 +587,7 @@ class EstimateFeeTest(BitcoinTestFramework):
|
||||
self.log.info("Test acceptstalefeeestimates option")
|
||||
self.test_acceptstalefeeestimates_option()
|
||||
|
||||
self.log.info("Test reading old fee_estimates.dat")
|
||||
self.log.info("Test reading old block policy estimator file")
|
||||
self.test_old_fee_estimate_file()
|
||||
|
||||
self.clear_estimates()
|
||||
|
||||
@@ -965,6 +965,7 @@ class BitcoinTestFramework(metaclass=BitcoinTestMetaClass):
|
||||
return os.path.join(cache_node_dir, self.chain, *paths)
|
||||
|
||||
os.rmdir(cache_path('wallets')) # Remove empty wallets dir
|
||||
shutil.rmtree(cache_path('fees'), ignore_errors=True)
|
||||
for entry in os.listdir(cache_path()):
|
||||
if entry not in ['chainstate', 'blocks', 'indexes']: # Only indexes, chainstate and blocks folders
|
||||
os.remove(cache_path(entry))
|
||||
|
||||
Reference in New Issue
Block a user