mirror of
https://github.com/bitcoin/bitcoin.git
synced 2025-01-24 10:17:45 -03:00
test: ensure old fee_estimate.dat not read on restart and flushed
This commit adds tests to ensure that old fee_estimates.dat files
are not read and that fee_estimates are periodically flushed to the
fee_estimates.dat file.
Additionaly it tests the -regtestonly option -acceptstalefeeestimates.
Github-Pull: #27622
Rebased-From: d2b39e09bc
This commit is contained in:
parent
01f8ee48ef
commit
cb5512da23
1 changed files with 101 additions and 0 deletions
|
@ -7,6 +7,7 @@ from copy import deepcopy
|
|||
from decimal import Decimal
|
||||
import os
|
||||
import random
|
||||
import time
|
||||
|
||||
from test_framework.messages import (
|
||||
COIN,
|
||||
|
@ -21,6 +22,8 @@ from test_framework.util import (
|
|||
)
|
||||
from test_framework.wallet import MiniWallet
|
||||
|
||||
MAX_FILE_AGE = 60
|
||||
SECONDS_PER_HOUR = 60 * 60
|
||||
|
||||
def small_txpuzzle_randfee(
|
||||
wallet, from_node, conflist, unconflist, amount, min_fee, fee_increment
|
||||
|
@ -273,6 +276,95 @@ class EstimateFeeTest(BitcoinTestFramework):
|
|||
est_feerate = node.estimatesmartfee(2)["feerate"]
|
||||
assert_equal(est_feerate, high_feerate_kvb)
|
||||
|
||||
def test_old_fee_estimate_file(self):
|
||||
# Get the initial fee rate while node is running
|
||||
fee_rate = self.nodes[0].estimatesmartfee(1)["feerate"]
|
||||
|
||||
# Restart node to ensure fee_estimate.dat file is read
|
||||
self.restart_node(0)
|
||||
assert_equal(self.nodes[0].estimatesmartfee(1)["feerate"], fee_rate)
|
||||
|
||||
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
|
||||
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))
|
||||
|
||||
# Start node and ensure the fee_estimates.dat file was not read
|
||||
self.start_node(0)
|
||||
assert_equal(self.nodes[0].estimatesmartfee(1)["errors"], ["Insufficient data or no feerate found"])
|
||||
|
||||
|
||||
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
|
||||
|
||||
# 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.
|
||||
# If present, it indicates that fee estimates have been successfully flushed to disk.
|
||||
with self.nodes[0].assert_debug_log(expected_msgs=["Flushed fee estimates to fee_estimates.dat."], timeout=1):
|
||||
# Mock the scheduler for an hour to flush fee estimates to fee_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 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()
|
||||
with self.nodes[0].assert_debug_log(expected_msgs=["Flushed fee estimates to fee_estimates.dat."], timeout=1):
|
||||
# Mock the scheduler for an hour to flush fee estimates to fee_estimates.dat
|
||||
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)
|
||||
|
||||
# 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)
|
||||
|
||||
# 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=["Flushed fee estimates to fee_estimates.dat."], timeout=1):
|
||||
# Mock the scheduler for an hour to flush fee estimates to fee_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 fee_dat_current_content != fee_dat_initial_content
|
||||
|
||||
fee_dat_initial_content = 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 fee_dat_current_content != fee_dat_initial_content
|
||||
|
||||
|
||||
def test_acceptstalefeeestimates_option(self):
|
||||
# Get the initial fee rate while node is running
|
||||
fee_rate = self.nodes[0].estimatesmartfee(1)["feerate"]
|
||||
|
||||
self.stop_node(0)
|
||||
|
||||
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
|
||||
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
|
||||
self.start_node(0,extra_args=["-acceptstalefeeestimates"])
|
||||
assert_equal(self.nodes[0].estimatesmartfee(1)["feerate"], fee_rate)
|
||||
|
||||
|
||||
def run_test(self):
|
||||
self.log.info("This test is time consuming, please be patient")
|
||||
self.log.info("Splitting inputs so we can generate tx's")
|
||||
|
@ -296,12 +388,21 @@ 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.test_estimate_dat_is_flushed_periodically()
|
||||
|
||||
# check that the effective feerate is greater than or equal to the mempoolminfee even for high mempoolminfee
|
||||
self.log.info(
|
||||
"Test fee rate estimation after restarting node with high MempoolMinFee"
|
||||
)
|
||||
self.test_feerate_mempoolminfee()
|
||||
|
||||
self.log.info("Test acceptstalefeeestimates option")
|
||||
self.test_acceptstalefeeestimates_option()
|
||||
|
||||
self.log.info("Test reading old fee_estimates.dat")
|
||||
self.test_old_fee_estimate_file()
|
||||
|
||||
self.log.info("Restarting node with fresh estimation")
|
||||
self.stop_node(0)
|
||||
fee_dat = os.path.join(self.nodes[0].datadir, self.chain, "fee_estimates.dat")
|
||||
|
|
Loading…
Add table
Reference in a new issue