Repository: bitcoin/bitcoin
File: test/functional/feature_fee_estimation.py (Python)

Code before:
        high_feerate = Decimal("0.005")
        tx_count = 24
        # Broadcast and mine high fee transactions for the first 12 blocks.
        for _ in range(12):
            self.broadcast_and_mine(self.nodes[1], self.nodes[2], high_feerate, tx_count)
        check_fee_estimates_btw_modes(self.nodes[0], high_feerate, high_feerate)

        # We now track 12 blocks; short horizon stats will start decaying.
        # Broadcast and mine low fee transactions for the next 4 blocks.
        for _ in range(4):
            self.broadcast_and_mine(self.nodes[1], self.nodes[2], low_feerate, tx_count)
        # conservative mode will consider longer time horizons while economical mode does not
        # Check the fee estimates for both modes after mining low fee transactions.
        check_fee_estimates_btw_modes(self.nodes[0], high_feerate, low_feerate)


    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")

        # Split two coinbases into many small utxos
        self.start_node(0)
        self.wallet = MiniWallet(self.nodes[0])
        self.initial_split(self.nodes[0])
        self.log.info("Finished splitting")

        # Now we can connect the other nodes, didn't want to connect them earlier
        # so the estimates would not be affected by the splitting transactions
        self.start_node(1)
        self.start_node(2)
        self.connect_nodes(1, 0)
        self.connect_nodes(0, 2)
        self.connect_nodes(2, 1)
        self.sync_all()

        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 estimatesmartfee feerate is greater than or equal to maximum of mempoolminfee and minrelaytxfee
        self.log.info(
            "Test fee rate estimation after restarting node with high minrelaytxfee"
        )
        self.test_estimates_with_highminrelaytxfee()

        self.log.info("Test acceptstalefeeestimates option")
        self.test_acceptstalefeeestimates_option()

        self.log.info("Test reading old fee_estimates.dat")

Review comment (suggestion):
I was wondering if the new test could be avoided by defining `low_feerate` as MINIMUM_RELAY_FEE_RATE in the previous test `test_estimation_modes`.

Code after:
        """Broadcast and maybe mine some number of transactions with a specified fee rate."""
        for _ in range(count):
            tx = self.wallet.send_self_transfer(from_node=broadcaster, fee_rate=feerate, confirmed_only=True, utxo_to_spend=self.confutxo.pop(0))
            self.memutxo.append(tx["new_utxo"])
        self.sync_mempools(wait=0.1, nodes=[self.nodes[0], self.nodes[1], self.nodes[2]])
        if miner:
            mined = miner.getblock(self.generate(miner, 1)[0], True)["tx"]
            self.update_utxo(mined)

    def test_estimation_modes(self):
        low_feerate = Decimal("0.001")
        high_feerate = Decimal("0.005")
        # Broadcast and mine high fee transactions for the first 12 blocks.
        for _ in range(12):
            self.broadcast_many(self.nodes[1], high_feerate, TXS_COUNT, self.nodes[2])
        check_fee_estimates_btw_modes(self.nodes[0], high_feerate, high_feerate)

        # We now track 12 blocks; short horizon stats will start decaying.
        # Broadcast and mine low fee transactions for the next 4 blocks.
        for _ in range(4):
            self.broadcast_many(self.nodes[1], low_feerate, TXS_COUNT, self.nodes[2])
        # conservative mode will consider longer time horizons while economical mode does not
        # Check the fee estimates for both modes after mining low fee transactions.
        check_fee_estimates_btw_modes(self.nodes[0], high_feerate, low_feerate)

    def test_sub_1s_per_vb_estimates(self):
        feerate_0_5_s_per_vb = MIN_BUCKET_FEERATE * 5
        feerate_1_s_per_vb = Decimal(1000) / Decimal(COIN)
        for i in range(6):
            self.broadcast_many(self.nodes[1], feerate_0_5_s_per_vb, TXS_COUNT)
            self.broadcast_many(self.nodes[1], feerate_1_s_per_vb, TXS_COUNT, self.nodes[2])
        assert_equal(feerate_0_5_s_per_vb, self.nodes[0].estimatesmartfee(1)["feerate"])


    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")

        # Split two coinbases into many small utxos
        self.start_node(0)
        self.wallet = MiniWallet(self.nodes[0])
        self.initial_split(self.nodes[0])
        self.log.info("Finished splitting")

        # Now we can connect the other nodes, didn't want to connect them earlier
        # so the estimates would not be affected by the splitting transactions
        self.start_node(1)
        self.start_node(2)
        self.connect_nodes(1, 0)
        self.connect_nodes(0, 2)
        self.connect_nodes(2, 1)