mirror of
https://github.com/bitcoin/bitcoin.git
synced 2025-04-29 14:59:39 -04:00
fees: add ForecastFeeRateFromForecasters
method
- Polls all registered forecasters and selects the lowest fee rate.
This commit is contained in:
parent
7bf7b212a5
commit
75e6bb5ada
3 changed files with 90 additions and 19 deletions
39
src/init.cpp
39
src/init.cpp
|
@ -60,6 +60,7 @@
|
||||||
#include <policy/fees/block_policy_estimator.h>
|
#include <policy/fees/block_policy_estimator.h>
|
||||||
#include <policy/fees/block_policy_estimator_args.h>
|
#include <policy/fees/block_policy_estimator_args.h>
|
||||||
#include <policy/fees/forecaster_man.h>
|
#include <policy/fees/forecaster_man.h>
|
||||||
|
#include <policy/fees/mempool_forecaster.h>
|
||||||
#include <policy/policy.h>
|
#include <policy/policy.h>
|
||||||
#include <policy/settings.h>
|
#include <policy/settings.h>
|
||||||
#include <protocol.h>
|
#include <protocol.h>
|
||||||
|
@ -1494,24 +1495,6 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info)
|
||||||
rng.rand64(),
|
rng.rand64(),
|
||||||
*node.addrman, *node.netgroupman, chainparams, args.GetBoolArg("-networkactive", true));
|
*node.addrman, *node.netgroupman, chainparams, args.GetBoolArg("-networkactive", true));
|
||||||
|
|
||||||
assert(!node.forecasterman);
|
|
||||||
// Don't initialize fee estimation with old data if we don't relay transactions,
|
|
||||||
// as they would never get updated.
|
|
||||||
if (!peerman_opts.ignore_incoming_txs) {
|
|
||||||
bool read_stale_estimates = args.GetBoolArg("-acceptstalefeeestimates", DEFAULT_ACCEPT_STALE_FEE_ESTIMATES);
|
|
||||||
if (read_stale_estimates && (chainparams.GetChainType() != ChainType::REGTEST)) {
|
|
||||||
return InitError(strprintf(_("acceptstalefeeestimates is not supported on %s chain."), chainparams.GetChainTypeString()));
|
|
||||||
}
|
|
||||||
node.forecasterman = std::make_unique<FeeRateForecasterManager>();
|
|
||||||
auto block_policy_estimator = std::make_shared<CBlockPolicyEstimator>(FeeestPath(args), read_stale_estimates);
|
|
||||||
validation_signals.RegisterSharedValidationInterface(block_policy_estimator);
|
|
||||||
// Flush block policy estimates to disk periodically
|
|
||||||
scheduler.scheduleEvery([block_policy_estimator] { block_policy_estimator->FlushFeeEstimates(); }, FEE_FLUSH_INTERVAL);
|
|
||||||
|
|
||||||
// Register block policy estimator to forecaster manager
|
|
||||||
node.forecasterman->RegisterForecaster(block_policy_estimator);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (const std::string& socket_addr : args.GetArgs("-bind")) {
|
for (const std::string& socket_addr : args.GetArgs("-bind")) {
|
||||||
std::string host_out;
|
std::string host_out;
|
||||||
uint16_t port_out{0};
|
uint16_t port_out{0};
|
||||||
|
@ -1726,6 +1709,26 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info)
|
||||||
|
|
||||||
ChainstateManager& chainman = *Assert(node.chainman);
|
ChainstateManager& chainman = *Assert(node.chainman);
|
||||||
|
|
||||||
|
assert(!node.forecasterman);
|
||||||
|
// Don't initialize fee estimation with old data if we don't relay transactions,
|
||||||
|
// as they would never get updated.
|
||||||
|
if (!peerman_opts.ignore_incoming_txs) {
|
||||||
|
bool read_stale_estimates = args.GetBoolArg("-acceptstalefeeestimates", DEFAULT_ACCEPT_STALE_FEE_ESTIMATES);
|
||||||
|
if (read_stale_estimates && (chainparams.GetChainType() != ChainType::REGTEST)) {
|
||||||
|
return InitError(strprintf(_("acceptstalefeeestimates is not supported on %s chain."), chainparams.GetChainTypeString()));
|
||||||
|
}
|
||||||
|
node.forecasterman = std::make_unique<FeeRateForecasterManager>();
|
||||||
|
auto mempool_forecaster = std::make_shared<MemPoolForecaster>(node.mempool.get(), &(chainman.ActiveChainstate()));
|
||||||
|
node.forecasterman->RegisterForecaster(mempool_forecaster);
|
||||||
|
auto block_policy_estimator = std::make_shared<CBlockPolicyEstimator>(FeeestPath(args), read_stale_estimates);
|
||||||
|
validation_signals.RegisterSharedValidationInterface(block_policy_estimator);
|
||||||
|
// Flush block policy estimates to disk periodically
|
||||||
|
scheduler.scheduleEvery([block_policy_estimator] { block_policy_estimator->FlushFeeEstimates(); }, FEE_FLUSH_INTERVAL);
|
||||||
|
|
||||||
|
// Register block policy estimator to forecaster manager
|
||||||
|
node.forecasterman->RegisterForecaster(block_policy_estimator);
|
||||||
|
}
|
||||||
|
|
||||||
assert(!node.peerman);
|
assert(!node.peerman);
|
||||||
node.peerman = PeerManager::make(*node.connman, *node.addrman,
|
node.peerman = PeerManager::make(*node.connman, *node.addrman,
|
||||||
node.banman.get(), chainman,
|
node.banman.get(), chainman,
|
||||||
|
|
|
@ -2,11 +2,13 @@
|
||||||
// Distributed under the MIT software license. See the accompanying
|
// Distributed under the MIT software license. See the accompanying
|
||||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||||
|
|
||||||
|
#include <logging.h>
|
||||||
#include <policy/fees/block_policy_estimator.h>
|
#include <policy/fees/block_policy_estimator.h>
|
||||||
#include <policy/fees/forecaster.h>
|
#include <policy/fees/forecaster.h>
|
||||||
#include <policy/fees/forecaster_man.h>
|
#include <policy/fees/forecaster_man.h>
|
||||||
#include <policy/fees/forecaster_util.h>
|
#include <policy/fees/forecaster_util.h>
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
|
|
||||||
void FeeRateForecasterManager::RegisterForecaster(std::shared_ptr<Forecaster> forecaster)
|
void FeeRateForecasterManager::RegisterForecaster(std::shared_ptr<Forecaster> forecaster)
|
||||||
|
@ -20,3 +22,53 @@ CBlockPolicyEstimator* FeeRateForecasterManager::GetBlockPolicyEstimator()
|
||||||
Forecaster* block_policy_estimator = forecasters.find(ForecastType::BLOCK_POLICY)->second.get();
|
Forecaster* block_policy_estimator = forecasters.find(ForecastType::BLOCK_POLICY)->second.get();
|
||||||
return dynamic_cast<CBlockPolicyEstimator*>(block_policy_estimator);
|
return dynamic_cast<CBlockPolicyEstimator*>(block_policy_estimator);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::pair<ForecastResult, std::vector<std::string>> FeeRateForecasterManager::ForecastFeeRateFromForecasters(
|
||||||
|
int target, bool conservative) const
|
||||||
|
{
|
||||||
|
std::vector<std::string> err_messages;
|
||||||
|
ForecastResult feerate_forecast;
|
||||||
|
|
||||||
|
for (const auto& forecaster : forecasters) {
|
||||||
|
auto curr_forecast = forecaster.second->ForecastFeeRate(target, conservative);
|
||||||
|
|
||||||
|
if (curr_forecast.m_error.has_value()) {
|
||||||
|
err_messages.emplace_back(
|
||||||
|
strprintf("%s: %s", forecastTypeToString(forecaster.first), curr_forecast.m_error.value()));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle case where the block policy forecaster does not have enough data.
|
||||||
|
if (forecaster.first == ForecastType::BLOCK_POLICY && curr_forecast.feerate.IsEmpty()) {
|
||||||
|
return {ForecastResult(), err_messages};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!curr_forecast.feerate.IsEmpty()) {
|
||||||
|
if (feerate_forecast.feerate.IsEmpty()) {
|
||||||
|
// If there's no selected forecast, choose curr_forecast as feerate_forecast.
|
||||||
|
feerate_forecast = curr_forecast;
|
||||||
|
} else {
|
||||||
|
// Otherwise, choose the smaller as feerate_forecast.
|
||||||
|
feerate_forecast = std::min(feerate_forecast, curr_forecast);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!feerate_forecast.feerate.IsEmpty()) {
|
||||||
|
LogInfo("Fee rate Forecaster %s: Block height %s, fee rate %s %s/kvB.\n",
|
||||||
|
forecastTypeToString(feerate_forecast.forecaster),
|
||||||
|
feerate_forecast.current_block_height,
|
||||||
|
CFeeRate(feerate_forecast.feerate.fee, feerate_forecast.feerate.size).GetFeePerK(),
|
||||||
|
CURRENCY_ATOM);
|
||||||
|
}
|
||||||
|
|
||||||
|
return {feerate_forecast, err_messages};
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int FeeRateForecasterManager::MaximumTarget() const
|
||||||
|
{
|
||||||
|
unsigned int maximum_target{0};
|
||||||
|
for (const auto& forecaster : forecasters) {
|
||||||
|
maximum_target = std::max(maximum_target, forecaster.second->MaximumTarget());
|
||||||
|
}
|
||||||
|
return maximum_target;
|
||||||
|
}
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
#define BITCOIN_POLICY_FEES_FORECASTER_MAN_H
|
#define BITCOIN_POLICY_FEES_FORECASTER_MAN_H
|
||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
#include <optional>
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
|
|
||||||
class CBlockPolicyEstimator;
|
class CBlockPolicyEstimator;
|
||||||
|
@ -22,7 +23,6 @@ class FeeRateForecasterManager
|
||||||
private:
|
private:
|
||||||
//! Map of all registered forecasters to their shared pointers.
|
//! Map of all registered forecasters to their shared pointers.
|
||||||
std::unordered_map<ForecastType, std::shared_ptr<Forecaster>> forecasters;
|
std::unordered_map<ForecastType, std::shared_ptr<Forecaster>> forecasters;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
/**
|
/**
|
||||||
* Register a forecaster.
|
* Register a forecaster.
|
||||||
|
@ -34,6 +34,22 @@ public:
|
||||||
* Return the pointer to block policy estimator.
|
* Return the pointer to block policy estimator.
|
||||||
*/
|
*/
|
||||||
CBlockPolicyEstimator* GetBlockPolicyEstimator();
|
CBlockPolicyEstimator* GetBlockPolicyEstimator();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a fee rate forecast from all registered forecasters for a given confirmation target.
|
||||||
|
*
|
||||||
|
* Polls all registered forecasters and selects the lowest fee rate.
|
||||||
|
*
|
||||||
|
* @param[in] target The target within which the transaction should be confirmed.
|
||||||
|
* @param[in] conservative True if the package cannot be fee bumped later.
|
||||||
|
* @return A pair consisting of the forecast result and a vector of forecaster names.
|
||||||
|
*/
|
||||||
|
std::pair<ForecastResult, std::vector<std::string>> ForecastFeeRateFromForecasters(int target, bool conservative) const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Returns the maximum supported confirmation target from all forecasters.
|
||||||
|
*/
|
||||||
|
unsigned int MaximumTarget() const;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // BITCOIN_POLICY_FEES_FORECASTER_MAN_H
|
#endif // BITCOIN_POLICY_FEES_FORECASTER_MAN_H
|
||||||
|
|
Loading…
Add table
Reference in a new issue