LCOV - code coverage report
Current view: top level - src/test - policyestimator_tests.cpp (source / functions) Hit Total Coverage
Test: total_coverage.info Lines: 100 100 100.0 %
Date: 2025-02-23 09:33:43 Functions: 2 2 100.0 %

          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()

Generated by: LCOV version 1.14