Line data Source code
1 : // Copyright (c) 2011-2015 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/feerate.h" 6 : #include "policy/fees.h" 7 : #include "txmempool.h" 8 : #include "uint256.h" 9 : #include "util/system.h" 10 : 11 : #include "test/test_pivx.h" 12 : 13 : #include <boost/test/unit_test.hpp> 14 : 15 : BOOST_FIXTURE_TEST_SUITE(policyestimator_tests, TestingSetup) 16 : 17 2 : BOOST_AUTO_TEST_CASE(BlockPolicyEstimates) 18 : { 19 1 : CTxMemPool mpool(CFeeRate(1000)); 20 1 : TestMemPoolEntryHelper entry; 21 1 : CAmount basefee(2000); 22 1 : CAmount deltaFee(100); 23 2 : std::vector<CAmount> feeV; 24 : 25 : // Populate vectors of increasing fees 26 11 : for (int j = 0; j < 10; j++) { 27 10 : feeV.push_back(basefee * (j+1)); 28 : } 29 : 30 : // Store the hashes of transactions that have been 31 : // added to the mempool by their associate fee 32 : // txHashes[j] is populated with transactions either of 33 : // fee = basefee * (j+1) 34 22 : std::vector<uint256> txHashes[10]; 35 : 36 : // Create a transaction template 37 2 : CScript garbage; 38 129 : for (unsigned int i = 0; i < 128; i++) 39 128 : garbage.push_back('X'); 40 2 : CMutableTransaction tx; 41 1 : tx.vin.resize(1); 42 1 : tx.vin[0].scriptSig = garbage; 43 1 : tx.vout.resize(1); 44 1 : tx.vout[0].nValue=0LL; 45 1 : CFeeRate baseRate(basefee, ::GetSerializeSize(tx, PROTOCOL_VERSION)); 46 : 47 : // Create a fake block 48 1 : std::vector<CTransactionRef> block; 49 1 : int blocknum = 0; 50 : 51 : // 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 54 201 : while (blocknum < 200) { 55 2200 : for (int j = 0; j < 10; j++) { // For each fee 56 10000 : for (int k = 0; k < 4; k++) { // add 4 fee txs 57 8000 : tx.vin[0].prevout.n = 10000*blocknum+100*j+k; // make transaction unique 58 8000 : uint256 hash = tx.GetHash(); 59 8000 : mpool.addUnchecked(hash, entry.Fee(feeV[j]).Time(GetTime()).Height(blocknum).FromTx(tx)); 60 8000 : txHashes[j].push_back(hash); 61 : } 62 : } 63 : //Create blocks where higher fee txs are included more often 64 1300 : for (int h = 0; h <= blocknum%10; h++) { 65 : // 10/10 blocks add highest fee transactions 66 : // 9/10 blocks add 2nd highest and so on until ... 67 : // 1/10 blocks add lowest fee transactions 68 9100 : while (txHashes[9-h].size()) { 69 16000 : CTransactionRef ptx = mpool.get(txHashes[9-h].back()); 70 8000 : if (ptx) 71 8000 : block.emplace_back(ptx); 72 8000 : txHashes[9-h].pop_back(); 73 : } 74 : } 75 200 : mpool.removeForBlock(block, ++blocknum); 76 200 : block.clear(); 77 200 : 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 2 : BOOST_CHECK(mpool.estimateFee(1) == CFeeRate(0)); 82 2 : BOOST_CHECK(mpool.estimateFee(2) == CFeeRate(0)); 83 2 : BOOST_CHECK(mpool.estimateFee(3) == CFeeRate(0)); 84 3 : BOOST_CHECK(mpool.estimateFee(4).GetFeePerK() < 8*baseRate.GetFeePerK() + deltaFee); 85 3 : BOOST_CHECK(mpool.estimateFee(4).GetFeePerK() > 8*baseRate.GetFeePerK() - deltaFee); 86 1 : int answerFound; 87 2 : BOOST_CHECK(mpool.estimateSmartFee(1, &answerFound) == mpool.estimateFee(4) && answerFound == 4); 88 2 : BOOST_CHECK(mpool.estimateSmartFee(3, &answerFound) == mpool.estimateFee(4) && answerFound == 4); 89 2 : BOOST_CHECK(mpool.estimateSmartFee(4, &answerFound) == mpool.estimateFee(4) && answerFound == 4); 90 2 : BOOST_CHECK(mpool.estimateSmartFee(8, &answerFound) == mpool.estimateFee(8) && answerFound == 8); 91 : } 92 : } 93 : 94 2 : std::vector<CAmount> origFeeEst; 95 : // Highest feerate is 10*baseRate and gets in all blocks, 96 : // second highest feerate is 9*baseRate and gets in 9/10 blocks = 90%, 97 : // third highest feerate is 8*base rate, and gets in 8/10 blocks = 80%, 98 : // so estimateFee(1) should return 10*baseRate. 99 : // Second highest feerate has 100% chance of being included by 2 blocks, 100 : // so estimateFee(2) should return 9*baseRate etc... 101 10 : for (int i = 1; i < 10;i++) { 102 18 : origFeeEst.push_back(mpool.estimateFee(i).GetFeePerK()); 103 9 : if (i > 1) { // Fee estimates should be monotonically decreasing 104 16 : BOOST_CHECK(origFeeEst[i-1] <= origFeeEst[i-2]); 105 : } 106 9 : int mult = 11-i; 107 18 : BOOST_CHECK(origFeeEst[i-1] < mult*baseRate.GetFeePerK() + deltaFee); 108 18 : BOOST_CHECK(origFeeEst[i-1] > mult*baseRate.GetFeePerK() - deltaFee); 109 : } 110 : 111 : // Mine 50 more blocks with no transactions happening, estimates shouldn't change 112 : // We haven't decayed the moving average enough so we still have enough data points in every bucket 113 51 : while (blocknum < 250) 114 50 : mpool.removeForBlock(block, ++blocknum); 115 : 116 10 : for (int i = 1; i < 10;i++) { 117 27 : BOOST_CHECK(mpool.estimateFee(i).GetFeePerK() < origFeeEst[i-1] + deltaFee); 118 27 : BOOST_CHECK(mpool.estimateFee(i).GetFeePerK() > origFeeEst[i-1] - deltaFee); 119 : } 120 : 121 : 122 : // Mine 15 more blocks with lots of transactions happening and not getting mined 123 : // Estimates should go up 124 16 : while (blocknum < 265) { 125 165 : for (int j = 0; j < 10; j++) { // For each fee multiple 126 750 : for (int k = 0; k < 4; k++) { // add 4 fee txs 127 600 : tx.vin[0].prevout.n = 10000*blocknum+100*j+k; 128 600 : uint256 hash = tx.GetHash(); 129 600 : mpool.addUnchecked(hash, entry.Fee(feeV[j]).Time(GetTime()).Height(blocknum).FromTx(tx)); 130 600 : txHashes[j].push_back(hash); 131 : } 132 : } 133 15 : mpool.removeForBlock(block, ++blocknum); 134 : } 135 : 136 : int answerFound; 137 10 : for (int i = 1; i < 10;i++) { 138 20 : BOOST_CHECK(mpool.estimateFee(i) == CFeeRate(0) || mpool.estimateFee(i).GetFeePerK() > origFeeEst[i-1] - deltaFee); 139 27 : BOOST_CHECK(mpool.estimateSmartFee(i, &answerFound).GetFeePerK() > origFeeEst[answerFound-1] - deltaFee); 140 : } 141 : 142 : // Mine all those transactions 143 : // Estimates should still not be below original 144 11 : for (int j = 0; j < 10; j++) { 145 610 : while(txHashes[j].size()) { 146 1200 : CTransactionRef ptx = mpool.get(txHashes[j].back()); 147 600 : if (ptx) 148 600 : block.emplace_back(ptx); 149 600 : txHashes[j].pop_back(); 150 : } 151 : } 152 1 : mpool.removeForBlock(block, 265); 153 1 : block.clear(); 154 10 : for (int i = 1; i < 10;i++) { 155 27 : BOOST_CHECK(mpool.estimateFee(i).GetFeePerK() > origFeeEst[i-1] - deltaFee); 156 : } 157 : 158 : // Mine 200 more blocks where everything is mined every block 159 : // Estimates should be below original estimates 160 201 : while (blocknum < 465) { 161 2200 : for (int j = 0; j < 10; j++) { // For each fee multiple 162 10000 : for (int k = 0; k < 4; k++) { // add 4 fee txs 163 8000 : tx.vin[0].prevout.n = 10000*blocknum+100*j+k; 164 8000 : uint256 hash = tx.GetHash(); 165 8000 : mpool.addUnchecked(hash, entry.Fee(feeV[j]).Time(GetTime()).Height(blocknum).FromTx(tx)); 166 16000 : CTransactionRef ptx = mpool.get(hash); 167 8000 : if (ptx) 168 8000 : block.emplace_back(ptx); 169 : } 170 : } 171 200 : mpool.removeForBlock(block, ++blocknum); 172 201 : block.clear(); 173 : } 174 10 : for (int i = 1; i < 10; i++) { 175 27 : BOOST_CHECK(mpool.estimateFee(i).GetFeePerK() < origFeeEst[i-1] - deltaFee); 176 : } 177 : 178 : // Test that if the mempool is limited, estimateSmartFee won't return a value below the mempool min fee 179 1 : mpool.addUnchecked(tx.GetHash(), entry.Fee(feeV[5]).Time(GetTime()).Height(blocknum).FromTx(tx)); 180 : // evict that transaction which should set a mempool min fee of minRelayTxFee + feeV[5] 181 1 : mpool.TrimToSize(1); 182 3 : BOOST_CHECK(mpool.GetMinFee(1).GetFeePerK() > feeV[5]); 183 10 : for (int i = 1; i < 10; i++) { 184 36 : BOOST_CHECK(mpool.estimateSmartFee(i).GetFeePerK() >= mpool.estimateFee(i).GetFeePerK()); 185 36 : BOOST_CHECK(mpool.estimateSmartFee(i).GetFeePerK() >= mpool.GetMinFee(1).GetFeePerK()); 186 : } 187 1 : } 188 : 189 : BOOST_AUTO_TEST_SUITE_END()