LCOV - code coverage report
Current view: top level - src/test - policyestimator_tests.cpp (source / functions) Hit Total Coverage
Test: bitcoincash_test.info Lines: 120 120 100.0 %
Date: 2018-04-13 15:12:50 Functions: 4 4 100.0 %

          Line data    Source code
       1             : // Copyright (c) 2011-2016 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.h"
      10             : 
      11             : #include "test/test_bitcoin.h"
      12             : 
      13             : #include <boost/test/unit_test.hpp>
      14             : 
      15           1 : BOOST_FIXTURE_TEST_SUITE(policyestimator_tests, BasicTestingSetup)
      16             : 
      17           6 : BOOST_AUTO_TEST_CASE(BlockPolicyEstimates) {
      18           3 :     CTxMemPool mpool(CFeeRate(Amount(1000)));
      19           1 :     TestMemPoolEntryHelper entry;
      20           1 :     Amount basefee(2000);
      21           1 :     Amount deltaFee(100);
      22           2 :     std::vector<Amount> feeV;
      23             : 
      24             :     // Populate vectors of increasing fees
      25          11 :     for (int j = 0; j < 10; j++) {
      26          30 :         feeV.push_back((j + 1) * basefee);
      27             :     }
      28             : 
      29             :     // Store the hashes of transactions that have been added to the mempool by
      30             :     // their associate fee txHashes[j] is populated with transactions either of
      31             :     // fee = basefee * (j+1)
      32          32 :     std::vector<uint256> txHashes[10];
      33             : 
      34             :     // Create a transaction template
      35           2 :     CScript garbage;
      36         129 :     for (unsigned int i = 0; i < 128; i++)
      37         128 :         garbage.push_back('X');
      38           2 :     CMutableTransaction tx;
      39           1 :     tx.vin.resize(1);
      40           2 :     tx.vin[0].scriptSig = garbage;
      41           1 :     tx.vout.resize(1);
      42           1 :     tx.vout[0].nValue = Amount(0);
      43           3 :     CFeeRate baseRate(basefee, CTransaction(tx).GetTotalSize());
      44             : 
      45             :     // Create a fake block
      46           2 :     std::vector<CTransactionRef> block;
      47           1 :     int blocknum = 0;
      48             : 
      49             :     // Loop through 200 blocks
      50             :     // At a decay .998 and 4 fee transactions per block
      51             :     // This makes the tx count about 1.33 per bucket, above the 1 threshold
      52         201 :     while (blocknum < 200) {
      53             :         // For each fee
      54        4200 :         for (int j = 0; j < 10; j++) {
      55             :             // add 4 fee txs
      56       18000 :             for (int k = 0; k < 4; k++) {
      57             :                 // make transaction unique
      58        8000 :                 tx.vin[0].prevout.n = 10000 * blocknum + 100 * j + k;
      59        8000 :                 uint256 hash = tx.GetId();
      60             :                 mpool.addUnchecked(hash,
      61       32000 :                                    entry.Fee(feeV[j])
      62       16000 :                                        .Time(GetTime())
      63        8000 :                                        .Priority(0)
      64       16000 :                                        .Height(blocknum)
      65       16000 :                                        .FromTx(tx, &mpool));
      66        8000 :                 txHashes[j].push_back(hash);
      67             :             }
      68             :         }
      69             :         // Create blocks where higher fee txs are included more often
      70        2400 :         for (int h = 0; h <= blocknum % 10; h++) {
      71             :             // 10/10 blocks add highest fee transactions
      72             :             // 9/10 blocks add 2nd highest and so on until ...
      73             :             // 1/10 blocks add lowest fee transactions
      74       26200 :             while (txHashes[9 - h].size()) {
      75       24000 :                 CTransactionRef ptx = mpool.get(txHashes[9 - h].back());
      76        8000 :                 if (ptx) block.push_back(ptx);
      77       16000 :                 txHashes[9 - h].pop_back();
      78             :             }
      79             :         }
      80         200 :         mpool.removeForBlock(block, ++blocknum);
      81         200 :         block.clear();
      82         200 :         if (blocknum == 30) {
      83             :             // At this point we should need to combine 5 buckets to get enough
      84             :             // data points. So estimateFee(1,2,3) should fail and estimateFee(4)
      85             :             // should return somewhere around 8*baserate.  estimateFee(4) %'s
      86             :             // are 100,100,100,100,90 = average 98%
      87          10 :             BOOST_CHECK(mpool.estimateFee(1) == CFeeRate(Amount(0)));
      88           9 :             BOOST_CHECK(mpool.estimateFee(2) == CFeeRate(Amount(0)));
      89          10 :             BOOST_CHECK(mpool.estimateFee(3) == CFeeRate(Amount(0)));
      90          13 :             BOOST_CHECK(mpool.estimateFee(4).GetFeePerK() <
      91             :                         8 * baseRate.GetFeePerK() + deltaFee);
      92          13 :             BOOST_CHECK(mpool.estimateFee(4).GetFeePerK() >
      93             :                         8 * baseRate.GetFeePerK() - deltaFee);
      94             :             int answerFound;
      95           9 :             BOOST_CHECK(mpool.estimateSmartFee(1, &answerFound) ==
      96             :                             mpool.estimateFee(4) &&
      97             :                         answerFound == 4);
      98           9 :             BOOST_CHECK(mpool.estimateSmartFee(3, &answerFound) ==
      99             :                             mpool.estimateFee(4) &&
     100             :                         answerFound == 4);
     101           9 :             BOOST_CHECK(mpool.estimateSmartFee(4, &answerFound) ==
     102             :                             mpool.estimateFee(4) &&
     103             :                         answerFound == 4);
     104           9 :             BOOST_CHECK(mpool.estimateSmartFee(8, &answerFound) ==
     105             :                             mpool.estimateFee(8) &&
     106             :                         answerFound == 8);
     107             :         }
     108             :     }
     109             : 
     110           2 :     std::vector<Amount> origFeeEst;
     111             :     // Highest feerate is 10*baseRate and gets in all blocks, second highest
     112             :     // feerate is 9*baseRate and gets in 9/10 blocks = 90%, third highest
     113             :     // feerate is 8*base rate, and gets in 8/10 blocks = 80%, so estimateFee(1)
     114             :     // would return 10*baseRate but is hardcoded to return failure. Second
     115             :     // highest feerate has 100% chance of being included by 2 blocks, so
     116             :     // estimateFee(2) should return 9*baseRate etc...
     117          10 :     for (int i = 1; i < 10; i++) {
     118          27 :         origFeeEst.push_back(mpool.estimateFee(i).GetFeePerK());
     119             :         // Fee estimates should be monotonically decreasing
     120           9 :         if (i > 2) {
     121          91 :             BOOST_CHECK(origFeeEst[i - 1] <= origFeeEst[i - 2]);
     122             :         }
     123           9 :         int mult = 11 - i;
     124           9 :         if (i > 1) {
     125         112 :             BOOST_CHECK(origFeeEst[i - 1] <
     126             :                         mult * baseRate.GetFeePerK() + deltaFee);
     127         112 :             BOOST_CHECK(origFeeEst[i - 1] >
     128             :                         mult * baseRate.GetFeePerK() - deltaFee);
     129             :         } else {
     130          13 :             BOOST_CHECK(origFeeEst[i - 1] == CFeeRate(Amount(0)).GetFeePerK());
     131             :         }
     132             :     }
     133             : 
     134             :     // Mine 50 more blocks with no transactions happening, estimates shouldn't
     135             :     // change. We haven't decayed the moving average enough so we still have
     136             :     // enough data points in every bucket
     137          51 :     while (blocknum < 250)
     138          50 :         mpool.removeForBlock(block, ++blocknum);
     139             : 
     140          10 :     BOOST_CHECK(mpool.estimateFee(1) == CFeeRate(Amount(0)));
     141          17 :     for (int i = 2; i < 10; i++) {
     142         104 :         BOOST_CHECK(mpool.estimateFee(i).GetFeePerK() <
     143             :                     origFeeEst[i - 1] + deltaFee);
     144         104 :         BOOST_CHECK(mpool.estimateFee(i).GetFeePerK() >
     145             :                     origFeeEst[i - 1] - deltaFee);
     146             :     }
     147             : 
     148             :     // Mine 15 more blocks with lots of transactions happening and not getting
     149             :     // mined. Estimates should go up
     150          16 :     while (blocknum < 265) {
     151             :         // For each fee multiple
     152         315 :         for (int j = 0; j < 10; j++) {
     153             :             // add 4 fee txs
     154        1350 :             for (int k = 0; k < 4; k++) {
     155         600 :                 tx.vin[0].prevout.n = 10000 * blocknum + 100 * j + k;
     156         600 :                 uint256 txid = tx.GetId();
     157             :                 mpool.addUnchecked(txid,
     158        2400 :                                    entry.Fee(feeV[j])
     159        1200 :                                        .Time(GetTime())
     160         600 :                                        .Priority(0)
     161        1200 :                                        .Height(blocknum)
     162        1200 :                                        .FromTx(tx, &mpool));
     163         600 :                 txHashes[j].push_back(txid);
     164             :             }
     165             :         }
     166          15 :         mpool.removeForBlock(block, ++blocknum);
     167             :     }
     168             : 
     169             :     int answerFound;
     170          19 :     for (int i = 1; i < 10; i++) {
     171          95 :         BOOST_CHECK(mpool.estimateFee(i) == CFeeRate(Amount(0)) ||
     172             :                     mpool.estimateFee(i).GetFeePerK() >
     173             :                         origFeeEst[i - 1] - deltaFee);
     174          18 :         Amount a1 = mpool.estimateSmartFee(i, &answerFound).GetFeePerK();
     175          36 :         Amount a2 = origFeeEst[answerFound - 1] - deltaFee;
     176          90 :         BOOST_CHECK(a1 > a2);
     177             :     }
     178             : 
     179             :     // Mine all those transactions
     180             :     // Estimates should still not be below original
     181          21 :     for (int j = 0; j < 10; j++) {
     182        1820 :         while (txHashes[j].size()) {
     183        1800 :             CTransactionRef ptx = mpool.get(txHashes[j].back());
     184         600 :             if (ptx) block.push_back(ptx);
     185        1200 :             txHashes[j].pop_back();
     186             :         }
     187             :     }
     188           1 :     mpool.removeForBlock(block, 265);
     189           1 :     block.clear();
     190          10 :     BOOST_CHECK(mpool.estimateFee(1) == CFeeRate(Amount(0)));
     191          17 :     for (int i = 2; i < 10; i++) {
     192         104 :         BOOST_CHECK(mpool.estimateFee(i).GetFeePerK() >
     193             :                     origFeeEst[i - 1] - deltaFee);
     194             :     }
     195             : 
     196             :     // Mine 200 more blocks where everything is mined every block
     197             :     // Estimates should be below original estimates
     198         200 :     while (blocknum < 465) {
     199             :         // For each fee multiple
     200        4200 :         for (int j = 0; j < 10; j++) {
     201             :             // add 4 fee txs
     202       18000 :             for (int k = 0; k < 4; k++) {
     203        8000 :                 tx.vin[0].prevout.n = 10000 * blocknum + 100 * j + k;
     204        8000 :                 uint256 txid = tx.GetId();
     205             :                 mpool.addUnchecked(txid,
     206       32000 :                                    entry.Fee(feeV[j])
     207       16000 :                                        .Time(GetTime())
     208        8000 :                                        .Priority(0)
     209       16000 :                                        .Height(blocknum)
     210       16000 :                                        .FromTx(tx, &mpool));
     211       16000 :                 CTransactionRef ptx = mpool.get(txid);
     212        8000 :                 if (ptx) block.push_back(ptx);
     213             :             }
     214             :         }
     215         200 :         mpool.removeForBlock(block, ++blocknum);
     216         200 :         block.clear();
     217             :     }
     218          10 :     BOOST_CHECK(mpool.estimateFee(1) == CFeeRate(Amount(0)));
     219          17 :     for (int i = 2; i < 10; i++) {
     220         104 :         BOOST_CHECK(mpool.estimateFee(i).GetFeePerK() <
     221             :                     origFeeEst[i - 1] - deltaFee);
     222             :     }
     223             : 
     224             :     // Test that if the mempool is limited, estimateSmartFee won't return a
     225             :     // value below the mempool min fee and that estimateSmartPriority returns
     226             :     // essentially an infinite value
     227             :     mpool.addUnchecked(
     228           2 :         tx.GetId(),
     229           7 :         entry.Fee(feeV[5]).Time(GetTime()).Priority(0).Height(blocknum).FromTx(
     230           1 :             tx, &mpool));
     231             :     // evict that transaction which should set a mempool min fee of
     232             :     // minRelayTxFee + feeV[5]
     233           1 :     mpool.TrimToSize(1);
     234          11 :     BOOST_CHECK(mpool.GetMinFee(1).GetFeePerK() > feeV[5]);
     235          19 :     for (int i = 1; i < 10; i++) {
     236          99 :         BOOST_CHECK(mpool.estimateSmartFee(i).GetFeePerK() >=
     237             :                     mpool.estimateFee(i).GetFeePerK());
     238          99 :         BOOST_CHECK(mpool.estimateSmartFee(i).GetFeePerK() >=
     239             :                     mpool.GetMinFee(1).GetFeePerK());
     240          81 :         BOOST_CHECK(mpool.estimateSmartPriority(i) ==
     241             :                     double(INF_PRIORITY.GetSatoshis()));
     242             :     }
     243           1 : }
     244             : 
     245           3 : BOOST_AUTO_TEST_SUITE_END()

Generated by: LCOV version 1.12