LCOV - code coverage report
Current view: top level - src/test - policyestimator_tests.cpp (source / functions) Hit Total Coverage
Test: coverage.lcov Lines: 117 117 100.0 %
Date: 2022-04-21 14:51:19 Functions: 1 1 100.0 %
Legend: Modified by patch:
Lines: hit not hit | Branches: + taken - not taken # not executed

Not modified by patch:
Lines: hit not hit | Branches: + taken - not taken # not executed
Branches: 53 56 94.6 %

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

Generated by: LCOV version 0-eol-96201-ge66f56f4af6a