Branch data Line data Source code
# 1 : : // Copyright (c) 2011-2020 The Bitcoin Core developers # 2 : : // Distributed under the MIT software license, see the accompanying # 3 : : // file COPYING or http://www.opensource.org/licenses/mit-license.php. # 4 : : # 5 : : #include <policy/fees.h> # 6 : : #include <policy/policy.h> # 7 : : #include <txmempool.h> # 8 : : #include <uint256.h> # 9 : : #include <util/time.h> # 10 : : # 11 : : #include <test/util/setup_common.h> # 12 : : # 13 : : #include <boost/test/unit_test.hpp> # 14 : : # 15 : : BOOST_FIXTURE_TEST_SUITE(policyestimator_tests, BasicTestingSetup) # 16 : : # 17 : : BOOST_AUTO_TEST_CASE(BlockPolicyEstimates) # 18 : 2 : { # 19 : 2 : CBlockPolicyEstimator feeEst; # 20 : 2 : CTxMemPool mpool(&feeEst); # 21 : 2 : LOCK2(cs_main, mpool.cs); # 22 : 2 : TestMemPoolEntryHelper entry; # 23 : 2 : CAmount basefee(2000); # 24 : 2 : CAmount deltaFee(100); # 25 : 2 : std::vector<CAmount> feeV; # 26 : : # 27 : : // Populate vectors of increasing fees # 28 [ + + ]: 22 : for (int j = 0; j < 10; j++) { # 29 : 20 : feeV.push_back(basefee * (j+1)); # 30 : 20 : } # 31 : : # 32 : : // Store the hashes of transactions that have been # 33 : : // added to the mempool by their associate fee # 34 : : // txHashes[j] is populated with transactions either of # 35 : : // fee = basefee * (j+1) # 36 : 2 : std::vector<uint256> txHashes[10]; # 37 : : # 38 : : // Create a transaction template # 39 : 2 : CScript garbage; # 40 [ + + ]: 258 : for (unsigned int i = 0; i < 128; i++) # 41 : 256 : garbage.push_back('X'); # 42 : 2 : CMutableTransaction tx; # 43 : 2 : tx.vin.resize(1); # 44 : 2 : tx.vin[0].scriptSig = garbage; # 45 : 2 : tx.vout.resize(1); # 46 : 2 : tx.vout[0].nValue=0LL; # 47 : 2 : CFeeRate baseRate(basefee, GetVirtualTransactionSize(CTransaction(tx))); # 48 : : # 49 : : // Create a fake block # 50 : 2 : std::vector<CTransactionRef> block; # 51 : 2 : int blocknum = 0; # 52 : : # 53 : : // Loop through 200 blocks # 54 : : // At a decay .9952 and 4 fee transactions per block # 55 : : // This makes the tx count about 2.5 per bucket, well above the 0.1 threshold # 56 [ + + ]: 402 : while (blocknum < 200) { # 57 [ + + ]: 4400 : for (int j = 0; j < 10; j++) { // For each fee # 58 [ + + ]: 20000 : for (int k = 0; k < 4; k++) { // add 4 fee txs # 59 : 16000 : tx.vin[0].prevout.n = 10000*blocknum+100*j+k; // make transaction unique # 60 : 16000 : uint256 hash = tx.GetHash(); # 61 : 16000 : mpool.addUnchecked(entry.Fee(feeV[j]).Time(GetTime()).Height(blocknum).FromTx(tx)); # 62 : 16000 : txHashes[j].push_back(hash); # 63 : 16000 : } # 64 : 4000 : } # 65 : : //Create blocks where higher fee txs are included more often # 66 [ + + ]: 2600 : for (int h = 0; h <= blocknum%10; h++) { # 67 : : // 10/10 blocks add highest fee transactions # 68 : : // 9/10 blocks add 2nd highest and so on until ... # 69 : : // 1/10 blocks add lowest fee transactions # 70 [ + + ]: 18200 : while (txHashes[9-h].size()) { # 71 : 16000 : CTransactionRef ptx = mpool.get(txHashes[9-h].back()); # 72 [ + - ]: 16000 : if (ptx) # 73 : 16000 : block.push_back(ptx); # 74 : 16000 : txHashes[9-h].pop_back(); # 75 : 16000 : } # 76 : 2200 : } # 77 : 400 : mpool.removeForBlock(block, ++blocknum); # 78 : 400 : block.clear(); # 79 : : // Check after just a few txs that combining buckets works as expected # 80 [ + + ]: 400 : if (blocknum == 3) { # 81 : : // At this point we should need to combine 3 buckets to get enough data points # 82 : : // So estimateFee(1) should fail and estimateFee(2) should return somewhere around # 83 : : // 9*baserate. estimateFee(2) %'s are 100,100,90 = average 97% # 84 : 2 : BOOST_CHECK(feeEst.estimateFee(1) == CFeeRate(0)); # 85 : 2 : BOOST_CHECK(feeEst.estimateFee(2).GetFeePerK() < 9*baseRate.GetFeePerK() + deltaFee); # 86 : 2 : BOOST_CHECK(feeEst.estimateFee(2).GetFeePerK() > 9*baseRate.GetFeePerK() - deltaFee); # 87 : 2 : } # 88 : 400 : } # 89 : : # 90 : 2 : std::vector<CAmount> origFeeEst; # 91 : : // Highest feerate is 10*baseRate and gets in all blocks, # 92 : : // second highest feerate is 9*baseRate and gets in 9/10 blocks = 90%, # 93 : : // third highest feerate is 8*base rate, and gets in 8/10 blocks = 80%, # 94 : : // so estimateFee(1) would return 10*baseRate but is hardcoded to return failure # 95 : : // Second highest feerate has 100% chance of being included by 2 blocks, # 96 : : // so estimateFee(2) should return 9*baseRate etc... # 97 [ + + ]: 20 : for (int i = 1; i < 10;i++) { # 98 : 18 : origFeeEst.push_back(feeEst.estimateFee(i).GetFeePerK()); # 99 [ + + ]: 18 : if (i > 2) { // Fee estimates should be monotonically decreasing # 100 : 14 : BOOST_CHECK(origFeeEst[i-1] <= origFeeEst[i-2]); # 101 : 14 : } # 102 : 18 : int mult = 11-i; # 103 [ + + ]: 18 : if (i % 2 == 0) { //At scale 2, test logic is only correct for even targets # 104 : 8 : BOOST_CHECK(origFeeEst[i-1] < mult*baseRate.GetFeePerK() + deltaFee); # 105 : 8 : BOOST_CHECK(origFeeEst[i-1] > mult*baseRate.GetFeePerK() - deltaFee); # 106 : 8 : } # 107 : 18 : } # 108 : : // Fill out rest of the original estimates # 109 [ + + ]: 80 : for (int i = 10; i <= 48; i++) { # 110 : 78 : origFeeEst.push_back(feeEst.estimateFee(i).GetFeePerK()); # 111 : 78 : } # 112 : : # 113 : : // Mine 50 more blocks with no transactions happening, estimates shouldn't change # 114 : : // We haven't decayed the moving average enough so we still have enough data points in every bucket # 115 [ + + ]: 102 : while (blocknum < 250) # 116 : 100 : mpool.removeForBlock(block, ++blocknum); # 117 : : # 118 : 2 : BOOST_CHECK(feeEst.estimateFee(1) == CFeeRate(0)); # 119 [ + + ]: 18 : for (int i = 2; i < 10;i++) { # 120 : 16 : BOOST_CHECK(feeEst.estimateFee(i).GetFeePerK() < origFeeEst[i-1] + deltaFee); # 121 : 16 : BOOST_CHECK(feeEst.estimateFee(i).GetFeePerK() > origFeeEst[i-1] - deltaFee); # 122 : 16 : } # 123 : : # 124 : : # 125 : : // Mine 15 more blocks with lots of transactions happening and not getting mined # 126 : : // Estimates should go up # 127 [ + + ]: 32 : while (blocknum < 265) { # 128 [ + + ]: 330 : for (int j = 0; j < 10; j++) { // For each fee multiple # 129 [ + + ]: 1500 : for (int k = 0; k < 4; k++) { // add 4 fee txs # 130 : 1200 : tx.vin[0].prevout.n = 10000*blocknum+100*j+k; # 131 : 1200 : uint256 hash = tx.GetHash(); # 132 : 1200 : mpool.addUnchecked(entry.Fee(feeV[j]).Time(GetTime()).Height(blocknum).FromTx(tx)); # 133 : 1200 : txHashes[j].push_back(hash); # 134 : 1200 : } # 135 : 300 : } # 136 : 30 : mpool.removeForBlock(block, ++blocknum); # 137 : 30 : } # 138 : : # 139 [ + + ]: 20 : for (int i = 1; i < 10;i++) { # 140 : 18 : BOOST_CHECK(feeEst.estimateFee(i) == CFeeRate(0) || feeEst.estimateFee(i).GetFeePerK() > origFeeEst[i-1] - deltaFee); # 141 : 18 : } # 142 : : # 143 : : // Mine all those transactions # 144 : : // Estimates should still not be below original # 145 [ + + ]: 22 : for (int j = 0; j < 10; j++) { # 146 [ + + ]: 1220 : while(txHashes[j].size()) { # 147 : 1200 : CTransactionRef ptx = mpool.get(txHashes[j].back()); # 148 [ + - ]: 1200 : if (ptx) # 149 : 1200 : block.push_back(ptx); # 150 : 1200 : txHashes[j].pop_back(); # 151 : 1200 : } # 152 : 20 : } # 153 : 2 : mpool.removeForBlock(block, 266); # 154 : 2 : block.clear(); # 155 : 2 : BOOST_CHECK(feeEst.estimateFee(1) == CFeeRate(0)); # 156 [ + + ]: 18 : for (int i = 2; i < 10;i++) { # 157 : 16 : BOOST_CHECK(feeEst.estimateFee(i) == CFeeRate(0) || feeEst.estimateFee(i).GetFeePerK() > origFeeEst[i-1] - deltaFee); # 158 : 16 : } # 159 : : # 160 : : // Mine 400 more blocks where everything is mined every block # 161 : : // Estimates should be below original estimates # 162 [ + + ]: 802 : while (blocknum < 665) { # 163 [ + + ]: 8800 : for (int j = 0; j < 10; j++) { // For each fee multiple # 164 [ + + ]: 40000 : for (int k = 0; k < 4; k++) { // add 4 fee txs # 165 : 32000 : tx.vin[0].prevout.n = 10000*blocknum+100*j+k; # 166 : 32000 : uint256 hash = tx.GetHash(); # 167 : 32000 : mpool.addUnchecked(entry.Fee(feeV[j]).Time(GetTime()).Height(blocknum).FromTx(tx)); # 168 : 32000 : CTransactionRef ptx = mpool.get(hash); # 169 [ + - ]: 32000 : if (ptx) # 170 : 32000 : block.push_back(ptx); # 171 : : # 172 : 32000 : } # 173 : 8000 : } # 174 : 800 : mpool.removeForBlock(block, ++blocknum); # 175 : 800 : block.clear(); # 176 : 800 : } # 177 : 2 : BOOST_CHECK(feeEst.estimateFee(1) == CFeeRate(0)); # 178 [ + + ]: 16 : for (int i = 2; i < 9; i++) { // At 9, the original estimate was already at the bottom (b/c scale = 2) # 179 : 14 : BOOST_CHECK(feeEst.estimateFee(i).GetFeePerK() < origFeeEst[i-1] - deltaFee); # 180 : 14 : } # 181 : 2 : } # 182 : : # 183 : : BOOST_AUTO_TEST_SUITE_END()