Skip to content

Commit

Permalink
[fees]: add last block forecaster
Browse files Browse the repository at this point in the history
  • Loading branch information
ismaelsadeeq committed Jun 20, 2024
1 parent fd62684 commit 107f174
Show file tree
Hide file tree
Showing 4 changed files with 111 additions and 0 deletions.
2 changes: 2 additions & 0 deletions src/Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -254,6 +254,7 @@ BITCOIN_CORE_H = \
policy/forecasters/block.h \
policy/forecasters/mempool.h \
policy/forecasters/mempool_last_10_min.h \
policy/forecasters/last_block.h \
policy/policy.h \
policy/rbf.h \
policy/settings.h \
Expand Down Expand Up @@ -461,6 +462,7 @@ libbitcoin_node_a_SOURCES = \
policy/forecasters/block.cpp \
policy/forecasters/mempool.cpp \
policy/forecasters/mempool_last_10_min.cpp \
policy/forecasters/last_block.cpp \
policy/packages.cpp \
policy/rbf.cpp \
policy/settings.cpp \
Expand Down
4 changes: 4 additions & 0 deletions src/init.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@
#include <policy/fees.h>
#include <policy/fees_args.h>
#include <policy/forecasters/block.h>
#include <policy/forecasters/last_block.h>
#include <policy/forecasters/mempool.h>
#include <policy/forecasters/mempool_last_10_min.h>
#include <policy/policy.h>
Expand Down Expand Up @@ -1647,8 +1648,11 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info)
node.fee_estimator->RegisterForecaster(std::make_unique<MemPoolForecaster>(node.mempool.get(), &(chainman.ActiveChainstate())));
node.fee_estimator->RegisterForecaster(std::make_unique<MemPoolLast10MinForecaster>(node.mempool.get(), &(chainman.ActiveChainstate())));
auto block_estimator = std::make_shared<BlockForecaster>();
auto last_block_estimator = std::make_shared<LastBlockForecaster>();
validation_signals.RegisterValidationInterface(block_estimator.get());
validation_signals.RegisterValidationInterface(last_block_estimator.get());
node.fee_estimator->RegisterForecaster(block_estimator);
node.fee_estimator->RegisterForecaster(last_block_estimator);
FeeEstimator* fee_estimator = node.fee_estimator.get();
node.scheduler->scheduleEvery([fee_estimator] { fee_estimator->GetAllEstimates(/*targetBlocks=*/1); }, FEE_ESTIMATE_INTERVAL);
assert(!node.peerman);
Expand Down
56 changes: 56 additions & 0 deletions src/policy/forecasters/last_block.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
// 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/fee_estimator.h>
#include <policy/forecasters/last_block.h>
#include <util/trace.h>


void LastBlockForecaster::MempoolTransactionsRemovedForBlock(const std::vector<RemovedMempoolTransactionInfo>& txs_removed_for_block, unsigned int nBlockHeight)
{
chain_tip_height = nBlockHeight;
const std::vector<std::tuple<CFeeRate, uint64_t>> size_per_feerate = LinearizeTransactions(txs_removed_for_block).size_per_feerate;
BlockPercentiles percentiles = CalculateBlockPercentiles(size_per_feerate);
if (percentiles.p75 != CFeeRate(0)) {
blocks_percentile = percentiles;
}
}

ForecastResult LastBlockForecaster::EstimateFee(unsigned int targetBlocks)
{
ForecastResult::ForecastOptions forecast_options;
forecast_options.m_forecaster = LAST_BLOCK_FORECAST_NAME_STR;
forecast_options.m_block_height = chain_tip_height;
if (targetBlocks <= 0) {
return ForecastResult(forecast_options, strprintf("%s: Confirmation target must be greater than zero", LAST_BLOCK_FORECAST_NAME_STR));
}

if (targetBlocks > LAST_BLOCK_FORECAST_MAX_TARGET) {
return ForecastResult(forecast_options, strprintf("%s: Confirmation target %u is above the maximum limit of %u",
LAST_BLOCK_FORECAST_NAME_STR, targetBlocks, LAST_BLOCK_FORECAST_MAX_TARGET));
}

if (blocks_percentile.empty()) {
return ForecastResult(forecast_options, strprintf("%s: Insufficient block data to perform an estimate", LAST_BLOCK_FORECAST_NAME_STR));
}


LogPrint(BCLog::ESTIMATEFEE, "FeeEst: %s: Block height %s, 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",
LAST_BLOCK_FORECAST_NAME_STR, chain_tip_height, blocks_percentile.p75.GetFeePerK(), CURRENCY_ATOM, blocks_percentile.p50.GetFeePerK(), CURRENCY_ATOM, blocks_percentile.p25.GetFeePerK(), CURRENCY_ATOM, blocks_percentile.p5.GetFeePerK(), CURRENCY_ATOM);

TRACE7(feerate_forecast, forecast_generated,
targetBlocks,
LAST_BLOCK_FORECAST_NAME_STR.c_str(),
chain_tip_height,
blocks_percentile.p5.GetFeePerK(),
blocks_percentile.p25.GetFeePerK(),
blocks_percentile.p50.GetFeePerK(),
blocks_percentile.p75.GetFeePerK());

forecast_options.m_l_priority_estimate = blocks_percentile.p25;
forecast_options.m_h_priority_estimate = blocks_percentile.p50;
return ForecastResult(forecast_options, std::nullopt);
}
49 changes: 49 additions & 0 deletions src/policy/forecasters/last_block.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
// 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_FORECASTERS_LAST_BLOCK_H
#define BITCOIN_POLICY_FORECASTERS_LAST_BLOCK_H

#include <policy/fees_util.h>
#include <policy/forecaster.h>
#include <validationinterface.h>

#include <queue>


struct RemovedMempoolTransactionInfo;
class Forecaster;
class CValidationInterface;
struct ForecastResult;

const std::string LAST_BLOCK_FORECAST_NAME_STR{"Last Block Forecast"};
const unsigned int LAST_BLOCK_FORECAST_MAX_TARGET{2};

/** \class LastBlockForecaster
* LastBlockForecaster fee rate forecaster estimates the fee rate that a transaction will pay
* to be included in a block as soon as possible.
* LastBlockForecaster uses the mining score of the transactions that were confirmed in
* the last block that the node mempool sees.
* LastBlockForecaster calculates the percentiles mining score
* It returns the 25th and 50th percentiles as the fee rate estimate.
*/
class LastBlockForecaster : public CValidationInterface, public Forecaster
{
private:
BlockPercentiles blocks_percentile;
unsigned int chain_tip_height;

protected:
void MempoolTransactionsRemovedForBlock(const std::vector<RemovedMempoolTransactionInfo>& txs_removed_for_block, unsigned int nBlockHeight) override;

public:
LastBlockForecaster(){};

ForecastResult EstimateFee(unsigned int targetBlocks) override;
unsigned int MaxTarget() override
{
return LAST_BLOCK_FORECAST_MAX_TARGET;
}
};
#endif // BITCOIN_POLICY_FORECASTERS_LAST_BLOCK_H

0 comments on commit 107f174

Please sign in to comment.