LCOV - code coverage report
Current view: top level - src/test - policyestimator_tests.cpp (source / functions) Hit Total Coverage
Test: total_coverage.info Lines: 97 97 100.0 %
Date: 2015-10-12 22:39:14 Functions: 4 6 66.7 %
Legend: Lines: hit not hit

          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/fees.h"
       6             : #include "txmempool.h"
       7             : #include "uint256.h"
       8             : #include "util.h"
       9             : 
      10             : #include "test/test_bitcoin.h"
      11             : 
      12             : #include <boost/test/unit_test.hpp>
      13             : 
      14           1 : BOOST_FIXTURE_TEST_SUITE(policyestimator_tests, BasicTestingSetup)
      15             : 
      16           6 : BOOST_AUTO_TEST_CASE(BlockPolicyEstimates)
      17             : {
      18           2 :     CTxMemPool mpool(CFeeRate(1000));
      19           1 :     CAmount basefee(2000);
      20           1 :     double basepri = 1e6;
      21           1 :     CAmount deltaFee(100);
      22           1 :     double deltaPri=5e5;
      23           6 :     std::vector<CAmount> feeV[2];
      24           5 :     std::vector<double> priV[2];
      25             : 
      26             :     // Populate vectors of increasing fees or priorities
      27          10 :     for (int j = 0; j < 10; j++) {
      28             :         //V[0] is for fee transactions
      29          10 :         feeV[0].push_back(basefee * (j+1));
      30          10 :         priV[0].push_back(0);
      31             :         //V[1] is for priority transactions
      32          10 :         feeV[1].push_back(CAmount(0));
      33          10 :         priV[1].push_back(basepri * pow(10, j+1));
      34             :     }
      35             : 
      36             :     // Store the hashes of transactions that have been
      37             :     // added to the mempool by their associate fee/pri
      38             :     // txHashes[j] is populated with transactions either of
      39             :     // fee = basefee * (j+1)  OR  pri = 10^6 * 10^(j+1)
      40          21 :     std::vector<uint256> txHashes[10];
      41             : 
      42             :     // Create a transaction template
      43             :     CScript garbage;
      44         129 :     for (unsigned int i = 0; i < 128; i++)
      45         128 :         garbage.push_back('X');
      46           1 :     CMutableTransaction tx;
      47             :     std::list<CTransaction> dummyConflicted;
      48           2 :     tx.vin.resize(1);
      49           1 :     tx.vin[0].scriptSig = garbage;
      50           2 :     tx.vout.resize(1);
      51           1 :     tx.vout[0].nValue=0LL;
      52           1 :     CFeeRate baseRate(basefee, ::GetSerializeSize(tx, SER_NETWORK, PROTOCOL_VERSION));
      53             : 
      54             :     // Create a fake block
      55           1 :     std::vector<CTransaction> block;
      56           1 :     int blocknum = 0;
      57             : 
      58             :     // Loop through 200 blocks
      59             :     // At a decay .998 and 4 fee transactions per block
      60             :     // This makes the tx count about 1.33 per bucket, above the 1 threshold
      61         202 :     while (blocknum < 200) {
      62        2000 :         for (int j = 0; j < 10; j++) { // For each fee/pri multiple
      63       10000 :             for (int k = 0; k < 5; k++) { // add 4 fee txs for every priority tx
      64       10000 :                 tx.vin[0].prevout.n = 10000*blocknum+100*j+k; // make transaction unique
      65       10000 :                 uint256 hash = tx.GetHash();
      66       60000 :                 mpool.addUnchecked(hash, CTxMemPoolEntry(tx, feeV[k/4][j], GetTime(), priV[k/4][j], blocknum, mpool.HasNoInputsOf(tx)));
      67       10000 :                 txHashes[j].push_back(hash);
      68             :             }
      69             :         }
      70             :         //Create blocks where higher fee/pri txs are included more often
      71        1100 :         for (int h = 0; h <= blocknum%10; h++) {
      72             :             // 10/10 blocks add highest fee/pri transactions
      73             :             // 9/10 blocks add 2nd highest and so on until ...
      74             :             // 1/10 blocks add lowest fee/pri transactions
      75       22200 :             while (txHashes[9-h].size()) {
      76       10000 :                 CTransaction btx;
      77       20000 :                 if (mpool.lookup(txHashes[9-h].back(), btx))
      78       10000 :                     block.push_back(btx);
      79       10000 :                 txHashes[9-h].pop_back();
      80             :             }
      81             :         }
      82         200 :         mpool.removeForBlock(block, ++blocknum, dummyConflicted);
      83             :         block.clear();
      84         200 :         if (blocknum == 30) {
      85             :             // At this point we should need to combine 5 buckets to get enough data points
      86             :             // So estimateFee(1) should fail and estimateFee(2) should return somewhere around
      87             :             // 8*baserate
      88           9 :             BOOST_CHECK(mpool.estimateFee(1) == CFeeRate(0));
      89          10 :             BOOST_CHECK(mpool.estimateFee(2).GetFeePerK() < 8*baseRate.GetFeePerK() + deltaFee);
      90          10 :             BOOST_CHECK(mpool.estimateFee(2).GetFeePerK() > 8*baseRate.GetFeePerK() - deltaFee);
      91             :         }
      92             :     }
      93             : 
      94             :     std::vector<CAmount> origFeeEst;
      95             :     std::vector<double> origPriEst;
      96             :     // Highest feerate is 10*baseRate and gets in all blocks,
      97             :     // second highest feerate is 9*baseRate and gets in 9/10 blocks = 90%,
      98             :     // third highest feerate is 8*base rate, and gets in 8/10 blocks = 80%,
      99             :     // so estimateFee(1) should return 9*baseRate.
     100             :     // Third highest feerate has 90% chance of being included by 2 blocks,
     101             :     // so estimateFee(2) should return 8*baseRate etc...
     102          10 :     for (int i = 1; i < 10;i++) {
     103          18 :         origFeeEst.push_back(mpool.estimateFee(i).GetFeePerK());
     104           9 :         origPriEst.push_back(mpool.estimatePriority(i));
     105           9 :         if (i > 1) { // Fee estimates should be monotonically decreasing
     106          80 :             BOOST_CHECK(origFeeEst[i-1] <= origFeeEst[i-2]);
     107          80 :             BOOST_CHECK(origPriEst[i-1] <= origPriEst[i-2]);
     108             :         }
     109          90 :         BOOST_CHECK(origFeeEst[i-1] < (10-i)*baseRate.GetFeePerK() + deltaFee);
     110          90 :         BOOST_CHECK(origFeeEst[i-1] > (10-i)*baseRate.GetFeePerK() - deltaFee);
     111          81 :         BOOST_CHECK(origPriEst[i-1] < pow(10,10-i) * basepri + deltaPri);
     112          81 :         BOOST_CHECK(origPriEst[i-1] > pow(10,10-i) * basepri - deltaPri);
     113             :     }
     114             : 
     115             :     // Mine 50 more blocks with no transactions happening, estimates shouldn't change
     116             :     // We haven't decayed the moving average enough so we still have enough data points in every bucket
     117          51 :     while (blocknum < 250)
     118          50 :         mpool.removeForBlock(block, ++blocknum, dummyConflicted);
     119             : 
     120           9 :     for (int i = 1; i < 10;i++) {
     121          90 :         BOOST_CHECK(mpool.estimateFee(i).GetFeePerK() < origFeeEst[i-1] + deltaFee);
     122          90 :         BOOST_CHECK(mpool.estimateFee(i).GetFeePerK() > origFeeEst[i-1] - deltaFee);
     123          81 :         BOOST_CHECK(mpool.estimatePriority(i) < origPriEst[i-1] + deltaPri);
     124          81 :         BOOST_CHECK(mpool.estimatePriority(i) > origPriEst[i-1] - deltaPri);
     125             :     }
     126             : 
     127             : 
     128             :     // Mine 15 more blocks with lots of transactions happening and not getting mined
     129             :     // Estimates should go up
     130          16 :     while (blocknum < 265) {
     131         150 :         for (int j = 0; j < 10; j++) { // For each fee/pri multiple
     132         750 :             for (int k = 0; k < 5; k++) { // add 4 fee txs for every priority tx
     133         750 :                 tx.vin[0].prevout.n = 10000*blocknum+100*j+k;
     134         750 :                 uint256 hash = tx.GetHash();
     135        4500 :                 mpool.addUnchecked(hash, CTxMemPoolEntry(tx, feeV[k/4][j], GetTime(), priV[k/4][j], blocknum, mpool.HasNoInputsOf(tx)));
     136         750 :                 txHashes[j].push_back(hash);
     137             :             }
     138             :         }
     139          15 :         mpool.removeForBlock(block, ++blocknum, dummyConflicted);
     140             :     }
     141             : 
     142           9 :     for (int i = 1; i < 10;i++) {
     143          90 :         BOOST_CHECK(mpool.estimateFee(i).GetFeePerK() > origFeeEst[i-1] - deltaFee);
     144          81 :         BOOST_CHECK(mpool.estimatePriority(i) > origPriEst[i-1] - deltaPri);
     145             :     }
     146             : 
     147             :     // Mine all those transactions
     148             :     // Estimates should still not be below original
     149          10 :     for (int j = 0; j < 10; j++) {
     150        1520 :         while(txHashes[j].size()) {
     151         750 :             CTransaction btx;
     152        1500 :             if (mpool.lookup(txHashes[j].back(), btx))
     153         750 :                 block.push_back(btx);
     154         750 :             txHashes[j].pop_back();
     155             :         }
     156             :     }
     157           1 :     mpool.removeForBlock(block, 265, dummyConflicted);
     158             :     block.clear();
     159          10 :     for (int i = 1; i < 10;i++) {
     160          90 :         BOOST_CHECK(mpool.estimateFee(i).GetFeePerK() > origFeeEst[i-1] - deltaFee);
     161          81 :         BOOST_CHECK(mpool.estimatePriority(i) > origPriEst[i-1] - deltaPri);
     162             :     }
     163             : 
     164             :     // Mine 100 more blocks where everything is mined every block
     165             :     // Estimates should be below original estimates (not possible for last estimate)
     166         101 :     while (blocknum < 365) {
     167        1000 :         for (int j = 0; j < 10; j++) { // For each fee/pri multiple
     168        5000 :             for (int k = 0; k < 5; k++) { // add 4 fee txs for every priority tx
     169        5000 :                 tx.vin[0].prevout.n = 10000*blocknum+100*j+k;
     170        5000 :                 uint256 hash = tx.GetHash();
     171       30000 :                 mpool.addUnchecked(hash, CTxMemPoolEntry(tx, feeV[k/4][j], GetTime(), priV[k/4][j], blocknum, mpool.HasNoInputsOf(tx)));
     172        5000 :                 CTransaction btx;
     173        5000 :                 if (mpool.lookup(hash, btx))
     174        5000 :                     block.push_back(btx);
     175             :             }
     176             :         }
     177         100 :         mpool.removeForBlock(block, ++blocknum, dummyConflicted);
     178             :         block.clear();
     179             :     }
     180           8 :     for (int i = 1; i < 9; i++) {
     181          80 :         BOOST_CHECK(mpool.estimateFee(i).GetFeePerK() < origFeeEst[i-1] - deltaFee);
     182          72 :         BOOST_CHECK(mpool.estimatePriority(i) < origPriEst[i-1] - deltaPri);
     183           1 :     }
     184           1 : }
     185             : 
     186           3 : BOOST_AUTO_TEST_SUITE_END()

Generated by: LCOV version 1.11