forked from bitcoin/bitcoin
-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[tx fees, policy]: create a mempool fee estimator.
Calculate the fee rate estimate for a given confirmation target using the mempool unconfirmed transactions.
- Loading branch information
1 parent
5e249b8
commit 61d97c0
Showing
6 changed files
with
176 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,91 @@ | ||
// Copyright (c) 2009-2010 Satoshi Nakamoto | ||
// Copyright (c) 2009-2023 The Bitcoin Core developers | ||
// Distributed under the MIT software license, see the accompanying | ||
// file COPYING or http://www.opensource.org/licenses/mit-license.php. | ||
|
||
#include <logging.h> | ||
|
||
#include <node/miner.h> | ||
#include <policy/mempool_fees.h> | ||
#include <policy/policy.h> | ||
|
||
using node::GetCustomBlockFeeRateHistogram; | ||
|
||
MemPoolPolicyEstimator::MemPoolPolicyEstimator() {} | ||
|
||
CFeeRate MemPoolPolicyEstimator::EstimateFeeWithMemPool(Chainstate& chainstate, const CTxMemPool& mempool, unsigned int confTarget, std::string& err_message) const | ||
{ | ||
|
||
if (confTarget > MAX_CONF_TARGET) { | ||
err_message = strprintf("Confirmation target %s is above maximum limit of %s, mempool conditions might change and estimates above %s are unreliable.\n", confTarget, MAX_CONF_TARGET, MAX_CONF_TARGET); | ||
return CFeeRate(0); | ||
} | ||
|
||
if (!mempool.GetLoadTried()) { | ||
err_message = "Mempool did not finish loading, can't get accurate fee rate estimate."; | ||
return CFeeRate(0); | ||
} | ||
|
||
std::map<CFeeRate, uint64_t> mempool_fee_stats; | ||
size_t target_weight = confTarget * DEFAULT_BLOCK_MAX_WEIGHT; | ||
{ | ||
mempool_fee_stats = GetCustomBlockFeeRateHistogram(chainstate, &mempool, target_weight); | ||
} | ||
|
||
if (mempool_fee_stats.empty()) { | ||
err_message = "No transactions available in the mempool yet."; | ||
return CFeeRate(0); // Return an appropriate default value (no txs in the mempool) | ||
} | ||
auto fee_rate = EstimateBlockFeeRate(mempool_fee_stats, confTarget, target_weight); | ||
|
||
if (fee_rate == CFeeRate(0)) { | ||
err_message = "Insufficient mempool transactions to perform an estimate."; | ||
} | ||
return fee_rate; // Return the estimated fee rate or a default value if transactions aren't | ||
} | ||
|
||
CFeeRate MemPoolPolicyEstimator::EstimateBlockFeeRate( | ||
std::map<CFeeRate, uint64_t>& mempool_fee_stats, unsigned int confTarget, size_t target_weight) const | ||
{ | ||
auto it = mempool_fee_stats.begin(); | ||
auto end = mempool_fee_stats.end(); | ||
if (confTarget == 1) { | ||
return CalculateMedianFeeRate(it, end); | ||
} | ||
size_t total_weight{0}; | ||
while (total_weight < (target_weight - DEFAULT_BLOCK_MAX_WEIGHT)) { | ||
total_weight += it->second * WITNESS_SCALE_FACTOR; | ||
++it; | ||
} | ||
return CalculateMedianFeeRate(it, end); | ||
} | ||
|
||
CFeeRate MemPoolPolicyEstimator::CalculateMedianFeeRate( | ||
std::map<CFeeRate, uint64_t>::iterator& start_it, | ||
std::map<CFeeRate, uint64_t>::iterator& end_it) const | ||
{ | ||
// Ensure we have enough txs in the target block template. | ||
auto curr = start_it; | ||
unsigned int block_weight{0}; | ||
while (curr != end_it) { | ||
block_weight = curr->second * WITNESS_SCALE_FACTOR; | ||
++curr; | ||
} | ||
if (block_weight < (DEFAULT_BLOCK_MAX_WEIGHT / 2)) { | ||
return CFeeRate(0); | ||
} | ||
|
||
std::size_t size = std::distance(start_it, end_it); | ||
if (size % 2 == 0) { | ||
// If the number of txs is even, average the two middle fee rates | ||
auto first_mid_it = std::next(start_it, size / 2); | ||
auto second_mid_it = std::next(start_it, (size / 2) + 1); | ||
auto mid_fee = (first_mid_it->first.GetFeePerK() + second_mid_it->first.GetFeePerK()) / 2; | ||
return CFeeRate(mid_fee); | ||
} else { | ||
// If the number of txs is odd, return the fee rate of the middle tx | ||
auto mid_it = std::next(start_it, (size / 2) + 1); | ||
return mid_it->first; | ||
} | ||
} | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,71 @@ | ||
// Copyright (c) 2009-2010 Satoshi Nakamoto | ||
// Copyright (c) 2009-2023 The Bitcoin Core developers | ||
// Distributed under the MIT software license, see the accompanying | ||
// file COPYING or http://www.opensource.org/licenses/mit-license.php. | ||
|
||
#ifndef BITCOIN_POLICY_MEMPOOL_FEES_H | ||
#define BITCOIN_POLICY_MEMPOOL_FEES_H | ||
|
||
#include <map> | ||
#include <optional> | ||
#include <string> | ||
|
||
#include <policy/feerate.h> | ||
|
||
class Chainstate; | ||
class CTxMemPool; | ||
|
||
// Fee rate estimates above this confirmation target are not reliable, | ||
// mempool condition might likely change. | ||
static const unsigned int MAX_CONF_TARGET{3}; | ||
|
||
/** | ||
* MemPoolPolicyEstimator estimates the fee rate that a tx should pay | ||
* to be included in a confirmation target based on the mempool | ||
* txs and their fee rates. | ||
* | ||
* The estimator works by generating template block up to a given confirmation target and then calculate the median | ||
* fee rate of the txs in the confirmation target block as the approximate fee rate that a tx will pay to | ||
* likely be included in the block. | ||
*/ | ||
class MemPoolPolicyEstimator | ||
{ | ||
public: | ||
|
||
MemPoolPolicyEstimator(); | ||
|
||
~MemPoolPolicyEstimator() = default; | ||
|
||
/** | ||
* Estimate the fee rate from mempool txs data given a confirmation target. | ||
* | ||
* @param[in] chainstate The reference to the active chainstate. | ||
* @param[in] mempool The reference to the mempool from which we will estimate the fee rate. | ||
* @param[in] confTarget The confirmation target of transactions. | ||
* @param[out] err_message optional error message. | ||
* @return The estimated fee rate. | ||
*/ | ||
CFeeRate EstimateFeeWithMemPool(Chainstate& chainstate, const CTxMemPool& mempool, unsigned int confTarget, std::string& err_message) const; | ||
|
||
private: | ||
/** | ||
* Calculate the fee rate estimate for a block of txs. | ||
* | ||
* @param[in] mempool_fee_stats The mempool fee statistics (fee rate and size). | ||
* @param[in] confTarget The next block we wish to a tx to be included in. | ||
* @param[in] target_weight Calculated of the histogram. | ||
* @return The fee rate estimate in satoshis per kilobyte. | ||
*/ | ||
CFeeRate EstimateBlockFeeRate(std::map<CFeeRate, uint64_t>& mempool_fee_stats, unsigned int confTarget, size_t target_weight) const; | ||
|
||
/** | ||
* Calculate the median fee rate for a range of txs in the mempool. | ||
* | ||
* @param[in] start_it The iterator pointing to the beginning of the range. | ||
* @param[in] end_it The iterator pointing to the end of the range. | ||
* @return The median fee rate. | ||
*/ | ||
CFeeRate CalculateMedianFeeRate(std::map<CFeeRate, uint64_t>::iterator& start_it, std::map<CFeeRate, uint64_t>::iterator& end_it) const; | ||
|
||
}; | ||
#endif // BITCOIN_POLICY_MEMPOOL_FEES_H |