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.
[policy, fees]: add last 6 blocks fee estimate forecaster
- Loading branch information
1 parent
061b6da
commit a15cffd
Showing
4 changed files
with
126 additions
and
1 deletion.
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,72 @@ | ||
// Copyright (c) 2024 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 <kernel/mempool_entry.h> | ||
#include <logging.h> | ||
#include <policy/block_fees.h> | ||
#include <policy/estimator.h> | ||
#include <policy/policy.h> | ||
#include <queue> | ||
|
||
void BlockFees::MempoolTransactionsRemovedForBlock(const std::vector<RemovedMempoolTransactionInfo>& txs_removed_for_block, unsigned int /*unused*/) | ||
{ | ||
unsigned int block_weight = 0; | ||
BlockPercentiles percentiles; | ||
|
||
for (const auto& tx : txs_removed_for_block) { | ||
block_weight += tx.info.m_virtual_transaction_size * WITNESS_SCALE_FACTOR; | ||
auto fee_rate = CFeeRate(tx.info.m_fee, tx.info.m_virtual_transaction_size); | ||
if (block_weight >= static_cast<unsigned int>(0.05 * DEFAULT_BLOCK_MAX_WEIGHT) && percentiles.p5 == CFeeRate(0)) { | ||
percentiles.p5 = fee_rate; | ||
} | ||
if (block_weight >= static_cast<unsigned int>(0.25 * DEFAULT_BLOCK_MAX_WEIGHT) && percentiles.p25 == CFeeRate(0)) { | ||
percentiles.p25 = fee_rate; | ||
} | ||
if (block_weight >= static_cast<unsigned int>(0.5 * DEFAULT_BLOCK_MAX_WEIGHT) && percentiles.p50 == CFeeRate(0)) { | ||
percentiles.p50 = fee_rate; | ||
} | ||
if (block_weight >= static_cast<unsigned int>(0.75 * DEFAULT_BLOCK_MAX_WEIGHT) && percentiles.p75 == CFeeRate(0)) { | ||
percentiles.p75 = fee_rate; | ||
} | ||
} | ||
|
||
if (blocks_percentiles.size() == MAX_NUMBER_OF_BLOCKS) { | ||
blocks_percentiles.pop(); | ||
} | ||
blocks_percentiles.push(percentiles); | ||
} | ||
|
||
ForecastResult BlockFees::EstimateFee(const unsigned int& targetBlocks) | ||
{ | ||
BlockPercentiles percentiles_average; | ||
|
||
if (targetBlocks > BLOCK_MAX_CONF_TARGET) { | ||
return ForecastResult(strprintf("Block Forecast: Confirmation target %u is above the maximum limit of %u. Mempool conditions might change, and estimates above %u are unreliable.", | ||
targetBlocks, BLOCK_MAX_CONF_TARGET, BLOCK_MAX_CONF_TARGET)); | ||
} | ||
|
||
if (blocks_percentiles.size() < MAX_NUMBER_OF_BLOCKS) { | ||
return ForecastResult("Block Forecast: Insufficient block data to perform an estimate"); | ||
} | ||
|
||
std::queue<BlockPercentiles> blocks_percentiles_cp = blocks_percentiles; | ||
while (!blocks_percentiles_cp.empty()) { | ||
const auto& curr_percentile = blocks_percentiles_cp.front(); | ||
blocks_percentiles_cp.pop(); | ||
percentiles_average.p5 += curr_percentile.p5; | ||
percentiles_average.p25 += curr_percentile.p25; | ||
percentiles_average.p50 += curr_percentile.p50; | ||
percentiles_average.p75 += curr_percentile.p75; | ||
} | ||
|
||
percentiles_average.p5 = CFeeRate(percentiles_average.p5.GetFeePerK() / MAX_NUMBER_OF_BLOCKS); | ||
percentiles_average.p25 = CFeeRate(percentiles_average.p25.GetFeePerK() / MAX_NUMBER_OF_BLOCKS); | ||
percentiles_average.p50 = CFeeRate(percentiles_average.p50.GetFeePerK() / MAX_NUMBER_OF_BLOCKS); | ||
percentiles_average.p75 = CFeeRate(percentiles_average.p75.GetFeePerK() / MAX_NUMBER_OF_BLOCKS); | ||
|
||
LogInfo("Block Forecast: Next block 75th percentile fee rate %s %s/kvB, 50th percentile fee rate %s %s/kvB, 25th percentile fee rate %s %s/kvB, 5th percentile fee rate %s %s/kvB \n", | ||
percentiles_average.p75.GetFeePerK(), CURRENCY_ATOM, percentiles_average.p50.GetFeePerK(), CURRENCY_ATOM, percentiles_average.p25.GetFeePerK(), CURRENCY_ATOM, percentiles_average.p5.GetFeePerK(), CURRENCY_ATOM); | ||
|
||
return ForecastResult(percentiles_average.p25, percentiles_average.p50, "Block Forecast"); | ||
} |
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,48 @@ | ||
// Copyright (c) 2024 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_BLOCK_FEES_H | ||
#define BITCOIN_POLICY_BLOCK_FEES_H | ||
|
||
#include <policy/forecaster.h> | ||
#include <queue> | ||
#include <validationinterface.h> | ||
|
||
struct RemovedMempoolTransactionInfo; | ||
class Forecaster; | ||
class CValidationInterface; | ||
struct ForecastResult; | ||
|
||
static const int MAX_NUMBER_OF_BLOCKS = 6; | ||
static const unsigned int BLOCK_MAX_CONF_TARGET{1}; | ||
|
||
/** | ||
* BlockFees estimates the fee rate that a transaction will pay | ||
* to be included in a block as soon as possible. | ||
* BlockFees uses the fee rate of transactions that were confirmed in | ||
* the last MAX_NUMBER_OF_BLOCKS blocks to calculate their percentiles | ||
* and takes the average as the fee rate estimate. | ||
* TODO: Don't just take individual fee rates; consider selecting the mining score when selecting | ||
* percentile fee rates. | ||
* TODO: Persist this data to disk and use it upon a quick restart where the last mined block is | ||
* less than one. | ||
*/ | ||
class BlockFees : public CValidationInterface, public Forecaster | ||
{ | ||
private: | ||
std::queue<BlockPercentiles> blocks_percentiles; | ||
|
||
protected: | ||
void MempoolTransactionsRemovedForBlock(const std::vector<RemovedMempoolTransactionInfo>& txs_removed_for_block, unsigned int /*unused*/) override; | ||
|
||
public: | ||
BlockFees(){}; | ||
|
||
ForecastResult EstimateFee(const unsigned int& targetBlocks) override; | ||
unsigned int MaxTarget() override | ||
{ | ||
return BLOCK_MAX_CONF_TARGET; | ||
} | ||
}; | ||
#endif // BITCOIN_POLICY_BLOCK_FEES_H |