Skip to content

Commit fc128f3

Browse files
authored
Merge pull request dogecoin#3389 from patricklodder/1.14.7-rework-smartfee-params
policy: tune feerate estimator parameters
2 parents e0b6a51 + 35c2910 commit fc128f3

File tree

2 files changed

+77
-41
lines changed

2 files changed

+77
-41
lines changed

src/policy/fees.h

Lines changed: 58 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -169,26 +169,70 @@ class TxConfirmStats
169169
/** Track confirm delays up to 25 blocks, can't estimate beyond that */
170170
static const unsigned int MAX_BLOCK_CONFIRMS = 25;
171171

172-
/** Decay of .998 is a half-life of 346 blocks or about 2.4 days */
173-
static const double DEFAULT_DECAY = .998;
172+
/** Inverse rate of decay of statistical history
173+
* Reduces all historical block stats by this multiplier, for each new block
174+
*
175+
* A value of 0.98845 corresponds to a half-life of 60 blocks or about 1 hour
176+
*
177+
* The calculation involves the rate constant for first order reactions, "ln 2",
178+
* which is approximately 0.693: 1 - ( ln(2) / <t0.5> )
179+
*
180+
* Rationale: The mempool from hours ago should have only a light effect
181+
* on estimates, to better deal with volatility.
182+
*/
183+
static const double DEFAULT_DECAY = 1.0 - (0.693 / 60.0); // 0.98845
184+
185+
/** Historical confidence level
186+
* Determines validity of results based on the historical inclusion rate of
187+
* transactions of this feerate
188+
*
189+
* Require greater than 80% of X feerate transactions to be confirmed within
190+
* Y blocks for X to be big enough
191+
*
192+
* Rationale: More conservative than Bitcoin Core's 60% for "half" confidence,
193+
* but less conservative than the 85% for "normal" confidence, because the
194+
* Dogecoin miners have a hightened incentive to not orphan blocks while the
195+
* impact of not being included in a block is only ~1/10th of Bitcoin's when
196+
* expressed in time expired.
197+
*/
198+
static const double MIN_SUCCESS_PCT = .8;
174199

175-
/** Require greater than 95% of X feerate transactions to be confirmed within Y blocks for X to be big enough */
176-
static const double MIN_SUCCESS_PCT = .95;
200+
/** Bucket significance in transactions per bucket
201+
* Filters which ranges of feerates are significant enough to consider
202+
*
203+
* Require an avg of 1 tx in the combined feerate bucket per 10 blocks to have
204+
* stat significance
205+
*
206+
* Rationale: Reduced this from 1 tx per feerate per block as lower values make
207+
* more buckets relevant during periods of low transaction volume, uniform fee
208+
* transaction surges (i.e. spam) or miners rapidly finding successive blocks
209+
* while there are no transactions matching their feefilter
210+
*
211+
* Copied from Bitcoin Core 0.15-25.0
212+
*/
213+
static const double SUFFICIENT_FEETXS = 0.1;
177214

178-
/** Require an avg of 1 tx in the combined feerate bucket per block to have stat significance */
179-
static const double SUFFICIENT_FEETXS = 1;
215+
// Minimum and Maximum values for tracking feerates, in koinu per kB
216+
static constexpr double MIN_FEERATE = COIN / 1000.0; //!< 100,000 - equals 100 koinu per byte
217+
static const double MAX_FEERATE = COIN * 10.0; //!< 1000,000,000 koinu - equals 10 DOGE/kb
180218

181-
// Minimum and Maximum values for tracking feerates
182-
static constexpr double MIN_FEERATE = 10;
183-
static const double MAX_FEERATE = 1e7;
219+
// Feerate and priority for the upper border of the highest bucket, in koinu per kB
184220
static const double INF_FEERATE = MAX_MONEY;
185221
static const double INF_PRIORITY = 1e9 * MAX_MONEY;
186222

187-
// We have to lump transactions into buckets based on feerate, but we want to be able
188-
// to give accurate estimates over a large range of potential feerates
189-
// Therefore it makes sense to exponentially space the buckets
190-
/** Spacing of FeeRate buckets */
191-
static const double FEE_SPACING = 1.1;
223+
/** Spacing of FeeRate buckets
224+
* Determines the (exponential) granularity of the fee buckets
225+
*
226+
* We have to lump transactions into buckets based on feerate, but we want to be
227+
* able to give accurate estimates over a large range of potential feerates
228+
* Therefore it makes sense to exponentially space the buckets
229+
*
230+
* Rationale: previously, spacing was 1.1; we reduce this to 1.05 to have finer
231+
* grained buckets
232+
*
233+
* Copied from Bitcoin Core 0.15-25.0
234+
*/
235+
static const double FEE_SPACING = 1.05;
192236

193237
/**
194238
* We want to be able to estimate feerates that are needed on tx's to be included in

src/test/policyestimator_tests.cpp

Lines changed: 19 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,10 @@ BOOST_FIXTURE_TEST_SUITE(policyestimator_tests, BasicTestingSetup)
1616

1717
BOOST_AUTO_TEST_CASE(BlockPolicyEstimates)
1818
{
19-
CTxMemPool mpool(CFeeRate(1000));
19+
CTxMemPool mpool(CFeeRate(100000));
2020
TestMemPoolEntryHelper entry;
21-
CAmount basefee(2000);
22-
CAmount deltaFee(100);
21+
CAmount basefee(200000);
22+
CAmount deltaFee(100); // error margin for feerate tests
2323
std::vector<CAmount> feeV;
2424

2525
// Populate vectors of increasing fees
@@ -49,8 +49,8 @@ BOOST_AUTO_TEST_CASE(BlockPolicyEstimates)
4949
int blocknum = 0;
5050

5151
// Loop through 200 blocks
52-
// At a decay .998 and 4 fee transactions per block
53-
// This makes the tx count about 1.33 per bucket, above the 1 threshold
52+
// At a decay .98845 and 4 fee transactions per block
53+
// This makes the tx count about 0.39 per bucket, above the 0.1 threshold
5454
while (blocknum < 200) {
5555
for (int j = 0; j < 10; j++) { // For each fee
5656
for (int k = 0; k < 4; k++) { // add 4 fee txs
@@ -74,20 +74,12 @@ BOOST_AUTO_TEST_CASE(BlockPolicyEstimates)
7474
}
7575
mpool.removeForBlock(block, ++blocknum);
7676
block.clear();
77-
if (blocknum == 30) {
78-
// At this point we should need to combine 5 buckets to get enough data points
79-
// So estimateFee(1,2,3) should fail and estimateFee(4) should return somewhere around
80-
// 8*baserate. estimateFee(4) %'s are 100,100,100,100,90 = average 98%
81-
BOOST_CHECK(mpool.estimateFee(1) == CFeeRate(0));
82-
BOOST_CHECK(mpool.estimateFee(2) == CFeeRate(0));
83-
BOOST_CHECK(mpool.estimateFee(3) == CFeeRate(0));
84-
BOOST_CHECK(mpool.estimateFee(4).GetFeePerK() < 8*baseRate.GetFeePerK() + deltaFee);
85-
BOOST_CHECK(mpool.estimateFee(4).GetFeePerK() > 8*baseRate.GetFeePerK() - deltaFee);
86-
int answerFound;
87-
BOOST_CHECK(mpool.estimateSmartFee(1, &answerFound) == mpool.estimateFee(4) && answerFound == 4);
88-
BOOST_CHECK(mpool.estimateSmartFee(3, &answerFound) == mpool.estimateFee(4) && answerFound == 4);
89-
BOOST_CHECK(mpool.estimateSmartFee(4, &answerFound) == mpool.estimateFee(4) && answerFound == 4);
90-
BOOST_CHECK(mpool.estimateSmartFee(8, &answerFound) == mpool.estimateFee(8) && answerFound == 8);
77+
if (blocknum == 3) {
78+
// At this point we should need to combine 2 buckets to get enough data points
79+
// So estimateFee(2) should return somewhere around 9*baserate.
80+
// estimateFee(2) %'s are 100,100,90 = average 97%
81+
BOOST_CHECK(mpool.estimateFee(2).GetFeePerK() < 9*baseRate.GetFeePerK() + deltaFee);
82+
BOOST_CHECK(mpool.estimateFee(2).GetFeePerK() > 9*baseRate.GetFeePerK() - deltaFee);
9183
}
9284
}
9385

@@ -97,14 +89,14 @@ BOOST_AUTO_TEST_CASE(BlockPolicyEstimates)
9789
// third highest feerate is 8*base rate, and gets in 8/10 blocks = 80%,
9890
// so estimateFee(1) would return 10*baseRate but is hardcoded to return failure
9991
// Second highest feerate has 100% chance of being included by 2 blocks,
100-
// so estimateFee(2) should return 9*baseRate etc...
101-
for (int i = 1; i < 10;i++) {
92+
// thus at 80% confidence, estimateFee(2) should return 8*baseRate etc...
93+
for (int i = 1; i < 8;i++) {
10294
origFeeEst.push_back(mpool.estimateFee(i).GetFeePerK());
10395
if (i > 2) { // Fee estimates should be monotonically decreasing
10496
BOOST_CHECK(origFeeEst[i-1] <= origFeeEst[i-2]);
10597
}
106-
int mult = 11-i;
107-
if (i > 1) {
98+
int mult = 9-i;
99+
if (i > 1 && i < 8) {
108100
BOOST_CHECK(origFeeEst[i-1] < mult*baseRate.GetFeePerK() + deltaFee);
109101
BOOST_CHECK(origFeeEst[i-1] > mult*baseRate.GetFeePerK() - deltaFee);
110102
}
@@ -119,7 +111,7 @@ BOOST_AUTO_TEST_CASE(BlockPolicyEstimates)
119111
mpool.removeForBlock(block, ++blocknum);
120112

121113
BOOST_CHECK(mpool.estimateFee(1) == CFeeRate(0));
122-
for (int i = 2; i < 10;i++) {
114+
for (int i = 2; i < 8;i++) {
123115
BOOST_CHECK(mpool.estimateFee(i).GetFeePerK() < origFeeEst[i-1] + deltaFee);
124116
BOOST_CHECK(mpool.estimateFee(i).GetFeePerK() > origFeeEst[i-1] - deltaFee);
125117
}
@@ -140,7 +132,7 @@ BOOST_AUTO_TEST_CASE(BlockPolicyEstimates)
140132
}
141133

142134
int answerFound;
143-
for (int i = 1; i < 10;i++) {
135+
for (int i = 1; i < 8;i++) {
144136
BOOST_CHECK(mpool.estimateFee(i) == CFeeRate(0) || mpool.estimateFee(i).GetFeePerK() > origFeeEst[i-1] - deltaFee);
145137
BOOST_CHECK(mpool.estimateSmartFee(i, &answerFound).GetFeePerK() > origFeeEst[answerFound-1] - deltaFee);
146138
}
@@ -158,7 +150,7 @@ BOOST_AUTO_TEST_CASE(BlockPolicyEstimates)
158150
mpool.removeForBlock(block, 265);
159151
block.clear();
160152
BOOST_CHECK(mpool.estimateFee(1) == CFeeRate(0));
161-
for (int i = 2; i < 10;i++) {
153+
for (int i = 2; i < 8;i++) {
162154
BOOST_CHECK(mpool.estimateFee(i).GetFeePerK() > origFeeEst[i-1] - deltaFee);
163155
}
164156

@@ -180,7 +172,7 @@ BOOST_AUTO_TEST_CASE(BlockPolicyEstimates)
180172
block.clear();
181173
}
182174
BOOST_CHECK(mpool.estimateFee(1) == CFeeRate(0));
183-
for (int i = 2; i < 10; i++) {
175+
for (int i = 2; i < 8; i++) {
184176
BOOST_CHECK(mpool.estimateFee(i).GetFeePerK() < origFeeEst[i-1] - deltaFee);
185177
}
186178

0 commit comments

Comments
 (0)