diff --git a/src/feerate.h b/src/feerate.h --- a/src/feerate.h +++ b/src/feerate.h @@ -84,6 +84,9 @@ nSatoshisPerK += a.nSatoshisPerK; return *this; } + CFeeRate operator+(const CFeeRate &a) { + return CFeeRate(nSatoshisPerK + a.nSatoshisPerK); + } std::string ToString() const; ADD_SERIALIZE_METHODS; diff --git a/src/policy/fees.h b/src/policy/fees.h --- a/src/policy/fees.h +++ b/src/policy/fees.h @@ -14,6 +14,37 @@ #include class CFeeRate; +class CTxMemPoolEntry; +class CTxMemPool; + +/** \class MempoolFeeEstimator + * The MempoolFeeEstimator is used for estimating the feerate needed for a + * transaction to be included in a block within a certain number of blocks. + */ +class MempoolFeeEstimator { +private: + std::vector m_minHeap; + std::vector m_maxHeap; + +public: + MempoolFeeEstimator() {} + + /** + * Clear the state of the curBlock variables to start counting for after a + * block is received. + */ + void clear(); + + /** + * Record a new fee data point in the current block stats + */ + void addFee(CFeeRate fee); + + /** + * Calculate a feerate estimate. + */ + CFeeRate estimateMedian(); +}; // Minimum and Maximum values for tracking feerates static constexpr Amount MIN_FEERATE(10 * SATOSHI); diff --git a/src/policy/fees.cpp b/src/policy/fees.cpp --- a/src/policy/fees.cpp +++ b/src/policy/fees.cpp @@ -8,6 +8,51 @@ #include "amount.h" #include "feerate.h" +#include "primitives/transaction.h" +#include "random.h" +#include "streams.h" +#include "txmempool.h" +#include "util.h" + +#include + +void MempoolFeeEstimator::clear() { + m_maxHeap.resize(0); + m_minHeap.resize(0); +} + +static bool minComparor(const CFeeRate &a, const CFeeRate &b) { + return a < b; +} + +void MempoolFeeEstimator::addFee(CFeeRate fee) { + auto maxHeapSize = m_maxHeap.size(); + auto minHeapSize = m_minHeap.size(); + + if (maxHeapSize == 0 || fee <= m_maxHeap.front()) { + m_maxHeap.push_back(fee); + std::push_heap(m_maxHeap.begin(), m_maxHeap.end()); + } else if (minHeapSize == 0 || fee <= m_minHeap.front()) { + m_minHeap.push_back(fee); + std::push_heap(m_minHeap.begin(), m_minHeap.end(), minComparor); + } else if (maxHeapSize < minHeapSize) { + m_maxHeap.push_back(fee); + std::push_heap(m_maxHeap.begin(), m_maxHeap.end(), minComparor); + } else { + m_minHeap.push_back(fee); + std::push_heap(m_minHeap.begin(), m_minHeap.end(), minComparor); + } +} + +CFeeRate MempoolFeeEstimator::estimateMedian() { + if (m_maxHeap.size() == m_minHeap.size()) { + return CFeeRate( + (m_minHeap.front().GetFeePerK() + m_maxHeap.front().GetFeePerK()) / + 2); + } + std::cout << "interesting" << std::endl; + return m_maxHeap.front(); +} FeeFilterRounder::FeeFilterRounder(const CFeeRate &minIncrementalFee) { Amount minFeeLimit = std::max(SATOSHI, minIncrementalFee.GetFeePerK() / 2); diff --git a/src/test/policyestimator_tests.cpp b/src/test/policyestimator_tests.cpp --- a/src/test/policyestimator_tests.cpp +++ b/src/test/policyestimator_tests.cpp @@ -14,6 +14,25 @@ BOOST_FIXTURE_TEST_SUITE(policyestimator_tests, BasicTestingSetup) +BOOST_AUTO_TEST_CASE(test_MempoolFeeEstimator) { + MempoolFeeEstimator estimator; + estimator.addFee(CFeeRate(5 * SATOSHI)); + estimator.addFee(CFeeRate(4 * SATOSHI)); + estimator.addFee(CFeeRate(1 * SATOSHI)); + estimator.addFee(CFeeRate(2 * SATOSHI)); + estimator.addFee(CFeeRate(3 * SATOSHI)); + BOOST_CHECK_MESSAGE( + estimator.estimateMedian() == CFeeRate(3 * SATOSHI), + "Median is incorrect: " << estimator.estimateMedian().ToString()); + estimator.addFee(CFeeRate(4 * SATOSHI)); + estimator.addFee(CFeeRate(5 * SATOSHI)); + estimator.addFee(CFeeRate(3 * SATOSHI)); + estimator.addFee(CFeeRate(3 * SATOSHI)); + BOOST_CHECK_MESSAGE( + estimator.estimateMedian() == CFeeRate(3 * SATOSHI), + "Median is incorrect: " << estimator.estimateMedian().ToString()); +} + BOOST_AUTO_TEST_CASE(MempoolMinimumFeeEstimate) { CTxMemPool mpool; TestMemPoolEntryHelper entry; diff --git a/src/wallet/fees.h b/src/wallet/fees.h --- a/src/wallet/fees.h +++ b/src/wallet/fees.h @@ -9,7 +9,6 @@ #include "amount.h" -class CBlockPolicyEstimator; class CCoinControl; class CFeeRate; class CTxMemPool;