LCOV - code coverage report
Current view: top level - src/test - mempool_tests.cpp (source / functions) Coverage Total Hit
Test: test_bitcoin_coverage.info Lines: 98.8 % 521 515
Test Date: 2024-11-04 04:45:35 Functions: 100.0 % 15 15
Branches: 50.0 % 2154 1077

             Branch data     Line data    Source code
       1                 :             : // Copyright (c) 2011-2022 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 <common/system.h>
       6                 :             : #include <policy/policy.h>
       7                 :             : #include <test/util/txmempool.h>
       8                 :             : #include <txmempool.h>
       9                 :             : #include <util/time.h>
      10                 :             : 
      11                 :             : #include <test/util/setup_common.h>
      12                 :             : 
      13                 :             : #include <boost/test/unit_test.hpp>
      14                 :             : #include <vector>
      15                 :             : 
      16                 :             : BOOST_FIXTURE_TEST_SUITE(mempool_tests, TestingSetup)
      17                 :             : 
      18                 :             : static constexpr auto REMOVAL_REASON_DUMMY = MemPoolRemovalReason::REPLACED;
      19                 :             : 
      20                 :             : class MemPoolTest final : public CTxMemPool
      21                 :             : {
      22                 :             : public:
      23                 :             :     using CTxMemPool::GetMinFee;
      24                 :             : };
      25                 :             : 
      26   [ +  -  +  -  :           7 : BOOST_AUTO_TEST_CASE(MempoolRemoveTest)
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
                      - ]
      27                 :             : {
      28                 :             :     // Test CTxMemPool::remove functionality
      29                 :             : 
      30                 :           1 :     TestMemPoolEntryHelper entry;
      31                 :             :     // Parent transaction with three children,
      32                 :             :     // and three grand-children:
      33                 :           1 :     CMutableTransaction txParent;
      34         [ +  - ]:           1 :     txParent.vin.resize(1);
      35         [ +  - ]:           1 :     txParent.vin[0].scriptSig = CScript() << OP_11;
      36         [ +  - ]:           1 :     txParent.vout.resize(3);
      37         [ +  + ]:           4 :     for (int i = 0; i < 3; i++)
      38                 :             :     {
      39   [ +  -  +  - ]:           3 :         txParent.vout[i].scriptPubKey = CScript() << OP_11 << OP_EQUAL;
      40                 :           3 :         txParent.vout[i].nValue = 33000LL;
      41                 :             :     }
      42   [ +  -  +  +  :          10 :     CMutableTransaction txChild[3];
                   -  - ]
      43         [ +  + ]:           4 :     for (int i = 0; i < 3; i++)
      44                 :             :     {
      45         [ +  - ]:           3 :         txChild[i].vin.resize(1);
      46         [ +  - ]:           3 :         txChild[i].vin[0].scriptSig = CScript() << OP_11;
      47   [ +  -  +  - ]:           3 :         txChild[i].vin[0].prevout.hash = txParent.GetHash();
      48                 :           3 :         txChild[i].vin[0].prevout.n = i;
      49         [ +  - ]:           3 :         txChild[i].vout.resize(1);
      50   [ +  -  +  - ]:           3 :         txChild[i].vout[0].scriptPubKey = CScript() << OP_11 << OP_EQUAL;
      51                 :           3 :         txChild[i].vout[0].nValue = 11000LL;
      52                 :             :     }
      53   [ +  -  +  +  :          11 :     CMutableTransaction txGrandChild[3];
                   -  - ]
      54         [ +  + ]:           4 :     for (int i = 0; i < 3; i++)
      55                 :             :     {
      56         [ +  - ]:           3 :         txGrandChild[i].vin.resize(1);
      57         [ +  - ]:           3 :         txGrandChild[i].vin[0].scriptSig = CScript() << OP_11;
      58   [ +  -  +  - ]:           3 :         txGrandChild[i].vin[0].prevout.hash = txChild[i].GetHash();
      59                 :           3 :         txGrandChild[i].vin[0].prevout.n = 0;
      60         [ +  - ]:           3 :         txGrandChild[i].vout.resize(1);
      61   [ +  -  +  - ]:           3 :         txGrandChild[i].vout[0].scriptPubKey = CScript() << OP_11 << OP_EQUAL;
      62                 :           3 :         txGrandChild[i].vout[0].nValue = 11000LL;
      63                 :             :     }
      64                 :             : 
      65                 :             : 
      66   [ +  -  +  - ]:           1 :     CTxMemPool& testPool = *Assert(m_node.mempool);
      67   [ +  -  +  - ]:           1 :     LOCK2(::cs_main, testPool.cs);
      68                 :             : 
      69                 :             :     // Nothing in pool, remove should do nothing:
      70         [ +  - ]:           1 :     unsigned int poolSize = testPool.size();
      71   [ +  -  +  - ]:           1 :     testPool.removeRecursive(CTransaction(txParent), REMOVAL_REASON_DUMMY);
      72   [ +  -  +  -  :           1 :     BOOST_CHECK_EQUAL(testPool.size(), poolSize);
                   +  - ]
      73                 :             : 
      74                 :             :     // Just the parent:
      75   [ +  -  +  - ]:           1 :     testPool.addUnchecked(entry.FromTx(txParent));
      76         [ +  - ]:           1 :     poolSize = testPool.size();
      77   [ +  -  +  - ]:           1 :     testPool.removeRecursive(CTransaction(txParent), REMOVAL_REASON_DUMMY);
      78   [ +  -  +  -  :           1 :     BOOST_CHECK_EQUAL(testPool.size(), poolSize - 1);
                   +  - ]
      79                 :             : 
      80                 :             :     // Parent, children, grandchildren:
      81   [ +  -  +  - ]:           1 :     testPool.addUnchecked(entry.FromTx(txParent));
      82         [ +  + ]:           4 :     for (int i = 0; i < 3; i++)
      83                 :             :     {
      84   [ +  -  +  - ]:           3 :         testPool.addUnchecked(entry.FromTx(txChild[i]));
      85   [ +  -  +  - ]:           3 :         testPool.addUnchecked(entry.FromTx(txGrandChild[i]));
      86                 :             :     }
      87                 :             :     // Remove Child[0], GrandChild[0] should be removed:
      88         [ +  - ]:           1 :     poolSize = testPool.size();
      89   [ +  -  +  - ]:           1 :     testPool.removeRecursive(CTransaction(txChild[0]), REMOVAL_REASON_DUMMY);
      90   [ +  -  +  -  :           1 :     BOOST_CHECK_EQUAL(testPool.size(), poolSize - 2);
                   +  - ]
      91                 :             :     // ... make sure grandchild and child are gone:
      92         [ +  - ]:           1 :     poolSize = testPool.size();
      93   [ +  -  +  - ]:           1 :     testPool.removeRecursive(CTransaction(txGrandChild[0]), REMOVAL_REASON_DUMMY);
      94   [ +  -  +  -  :           1 :     BOOST_CHECK_EQUAL(testPool.size(), poolSize);
                   +  - ]
      95         [ +  - ]:           1 :     poolSize = testPool.size();
      96   [ +  -  +  - ]:           1 :     testPool.removeRecursive(CTransaction(txChild[0]), REMOVAL_REASON_DUMMY);
      97   [ +  -  +  -  :           1 :     BOOST_CHECK_EQUAL(testPool.size(), poolSize);
                   +  - ]
      98                 :             :     // Remove parent, all children/grandchildren should go:
      99         [ +  - ]:           1 :     poolSize = testPool.size();
     100   [ +  -  +  - ]:           1 :     testPool.removeRecursive(CTransaction(txParent), REMOVAL_REASON_DUMMY);
     101   [ +  -  +  -  :           1 :     BOOST_CHECK_EQUAL(testPool.size(), poolSize - 5);
                   +  - ]
     102   [ +  -  +  -  :           1 :     BOOST_CHECK_EQUAL(testPool.size(), 0U);
                   +  - ]
     103                 :             : 
     104                 :             :     // Add children and grandchildren, but NOT the parent (simulate the parent being in a block)
     105         [ +  + ]:           4 :     for (int i = 0; i < 3; i++)
     106                 :             :     {
     107   [ +  -  +  - ]:           3 :         testPool.addUnchecked(entry.FromTx(txChild[i]));
     108   [ +  -  +  - ]:           3 :         testPool.addUnchecked(entry.FromTx(txGrandChild[i]));
     109                 :             :     }
     110                 :             :     // Now remove the parent, as might happen if a block-re-org occurs but the parent cannot be
     111                 :             :     // put into the mempool (maybe because it is non-standard):
     112         [ +  - ]:           1 :     poolSize = testPool.size();
     113   [ +  -  +  - ]:           1 :     testPool.removeRecursive(CTransaction(txParent), REMOVAL_REASON_DUMMY);
     114   [ +  -  +  -  :           1 :     BOOST_CHECK_EQUAL(testPool.size(), poolSize - 6);
                   +  - ]
     115   [ +  -  +  -  :           1 :     BOOST_CHECK_EQUAL(testPool.size(), 0U);
             +  -  +  - ]
     116   [ +  -  +  +  :          10 : }
          +  +  -  -  -  
                      - ]
     117                 :             : 
     118                 :             : template <typename name>
     119                 :          12 : static void CheckSort(CTxMemPool& pool, std::vector<std::string>& sortedOrder) EXCLUSIVE_LOCKS_REQUIRED(pool.cs)
     120                 :             : {
     121         [ +  - ]:          12 :     BOOST_CHECK_EQUAL(pool.size(), sortedOrder.size());
     122                 :          12 :     typename CTxMemPool::indexed_transaction_set::index<name>::type::iterator it = pool.mapTx.get<name>().begin();
     123                 :          12 :     int count = 0;
     124         [ +  + ]:          97 :     for (; it != pool.mapTx.get<name>().end(); ++it, ++count) {
     125         [ +  - ]:          85 :         BOOST_CHECK_EQUAL(it->GetTx().GetHash().ToString(), sortedOrder[count]);
     126                 :             :     }
     127                 :          12 : }
     128                 :             : 
     129   [ +  -  +  -  :           7 : BOOST_AUTO_TEST_CASE(MempoolIndexingTest)
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
                      - ]
     130                 :             : {
     131                 :           1 :     CTxMemPool& pool = *Assert(m_node.mempool);
     132         [ +  - ]:           1 :     LOCK2(cs_main, pool.cs);
     133                 :           1 :     TestMemPoolEntryHelper entry;
     134                 :             : 
     135                 :             :     /* 3rd highest fee */
     136         [ +  - ]:           1 :     CMutableTransaction tx1 = CMutableTransaction();
     137         [ +  - ]:           1 :     tx1.vout.resize(1);
     138   [ +  -  +  - ]:           1 :     tx1.vout[0].scriptPubKey = CScript() << OP_11 << OP_EQUAL;
     139         [ +  - ]:           1 :     tx1.vout[0].nValue = 10 * COIN;
     140   [ +  -  +  - ]:           1 :     pool.addUnchecked(entry.Fee(10000LL).FromTx(tx1));
     141                 :             : 
     142                 :             :     /* highest fee */
     143         [ +  - ]:           1 :     CMutableTransaction tx2 = CMutableTransaction();
     144         [ +  - ]:           1 :     tx2.vout.resize(1);
     145   [ +  -  +  - ]:           1 :     tx2.vout[0].scriptPubKey = CScript() << OP_11 << OP_EQUAL;
     146         [ +  - ]:           1 :     tx2.vout[0].nValue = 2 * COIN;
     147   [ +  -  +  - ]:           1 :     pool.addUnchecked(entry.Fee(20000LL).FromTx(tx2));
     148                 :             : 
     149                 :             :     /* lowest fee */
     150         [ +  - ]:           1 :     CMutableTransaction tx3 = CMutableTransaction();
     151         [ +  - ]:           1 :     tx3.vout.resize(1);
     152   [ +  -  +  - ]:           1 :     tx3.vout[0].scriptPubKey = CScript() << OP_11 << OP_EQUAL;
     153         [ +  - ]:           1 :     tx3.vout[0].nValue = 5 * COIN;
     154   [ +  -  +  - ]:           1 :     pool.addUnchecked(entry.Fee(0LL).FromTx(tx3));
     155                 :             : 
     156                 :             :     /* 2nd highest fee */
     157         [ +  - ]:           1 :     CMutableTransaction tx4 = CMutableTransaction();
     158         [ +  - ]:           1 :     tx4.vout.resize(1);
     159   [ +  -  +  - ]:           1 :     tx4.vout[0].scriptPubKey = CScript() << OP_11 << OP_EQUAL;
     160         [ +  - ]:           1 :     tx4.vout[0].nValue = 6 * COIN;
     161   [ +  -  +  - ]:           1 :     pool.addUnchecked(entry.Fee(15000LL).FromTx(tx4));
     162                 :             : 
     163                 :             :     /* equal fee rate to tx1, but newer */
     164         [ +  - ]:           1 :     CMutableTransaction tx5 = CMutableTransaction();
     165         [ +  - ]:           1 :     tx5.vout.resize(1);
     166   [ +  -  +  - ]:           1 :     tx5.vout[0].scriptPubKey = CScript() << OP_11 << OP_EQUAL;
     167         [ +  - ]:           1 :     tx5.vout[0].nValue = 11 * COIN;
     168         [ +  - ]:           1 :     entry.time = NodeSeconds{1s};
     169   [ +  -  +  - ]:           1 :     pool.addUnchecked(entry.Fee(10000LL).FromTx(tx5));
     170   [ +  -  +  -  :           1 :     BOOST_CHECK_EQUAL(pool.size(), 5U);
                   +  - ]
     171                 :             : 
     172                 :           1 :     std::vector<std::string> sortedOrder;
     173         [ +  - ]:           1 :     sortedOrder.resize(5);
     174         [ +  - ]:           2 :     sortedOrder[0] = tx3.GetHash().ToString(); // 0
     175         [ +  - ]:           2 :     sortedOrder[1] = tx5.GetHash().ToString(); // 10000
     176         [ +  - ]:           2 :     sortedOrder[2] = tx1.GetHash().ToString(); // 10000
     177         [ +  - ]:           2 :     sortedOrder[3] = tx4.GetHash().ToString(); // 15000
     178         [ +  - ]:           2 :     sortedOrder[4] = tx2.GetHash().ToString(); // 20000
     179         [ +  - ]:           1 :     CheckSort<descendant_score>(pool, sortedOrder);
     180                 :             : 
     181                 :             :     /* low fee but with high fee child */
     182                 :             :     /* tx6 -> tx7 -> tx8, tx9 -> tx10 */
     183         [ +  - ]:           1 :     CMutableTransaction tx6 = CMutableTransaction();
     184         [ +  - ]:           1 :     tx6.vout.resize(1);
     185   [ +  -  +  - ]:           1 :     tx6.vout[0].scriptPubKey = CScript() << OP_11 << OP_EQUAL;
     186         [ +  - ]:           1 :     tx6.vout[0].nValue = 20 * COIN;
     187   [ +  -  +  - ]:           1 :     pool.addUnchecked(entry.Fee(0LL).FromTx(tx6));
     188   [ +  -  +  -  :           1 :     BOOST_CHECK_EQUAL(pool.size(), 6U);
                   +  - ]
     189                 :             :     // Check that at this point, tx6 is sorted low
     190   [ +  -  +  - ]:           2 :     sortedOrder.insert(sortedOrder.begin(), tx6.GetHash().ToString());
     191         [ +  - ]:           1 :     CheckSort<descendant_score>(pool, sortedOrder);
     192                 :             : 
     193         [ +  - ]:           1 :     CTxMemPool::setEntries setAncestors;
     194   [ +  -  +  -  :           2 :     setAncestors.insert(pool.GetIter(tx6.GetHash()).value());
                   +  - ]
     195         [ +  - ]:           1 :     CMutableTransaction tx7 = CMutableTransaction();
     196         [ +  - ]:           1 :     tx7.vin.resize(1);
     197   [ +  -  +  - ]:           1 :     tx7.vin[0].prevout = COutPoint(tx6.GetHash(), 0);
     198         [ +  - ]:           1 :     tx7.vin[0].scriptSig = CScript() << OP_11;
     199         [ +  - ]:           1 :     tx7.vout.resize(2);
     200   [ +  -  +  - ]:           1 :     tx7.vout[0].scriptPubKey = CScript() << OP_11 << OP_EQUAL;
     201         [ +  - ]:           1 :     tx7.vout[0].nValue = 10 * COIN;
     202   [ +  -  +  - ]:           1 :     tx7.vout[1].scriptPubKey = CScript() << OP_11 << OP_EQUAL;
     203         [ +  - ]:           1 :     tx7.vout[1].nValue = 1 * COIN;
     204                 :             : 
     205                 :           1 :     {
     206   [ +  -  +  - ]:           1 :         auto ancestors_calculated{pool.CalculateMemPoolAncestors(entry.Fee(2000000LL).FromTx(tx7), CTxMemPool::Limits::NoLimits())};
     207   [ +  -  +  -  :           2 :         BOOST_REQUIRE(ancestors_calculated.has_value());
                   +  - ]
     208   [ +  -  +  - ]:           2 :         BOOST_CHECK(*ancestors_calculated == setAncestors);
     209                 :           0 :     }
     210                 :             : 
     211   [ +  -  +  - ]:           1 :     pool.addUnchecked(entry.FromTx(tx7), setAncestors);
     212   [ +  -  +  -  :           1 :     BOOST_CHECK_EQUAL(pool.size(), 7U);
                   +  - ]
     213                 :             : 
     214                 :             :     // Now tx6 should be sorted higher (high fee child): tx7, tx6, tx2, ...
     215                 :           1 :     sortedOrder.erase(sortedOrder.begin());
     216   [ +  -  +  - ]:           2 :     sortedOrder.push_back(tx6.GetHash().ToString());
     217   [ +  -  +  - ]:           2 :     sortedOrder.push_back(tx7.GetHash().ToString());
     218         [ +  - ]:           1 :     CheckSort<descendant_score>(pool, sortedOrder);
     219                 :             : 
     220                 :             :     /* low fee child of tx7 */
     221         [ +  - ]:           1 :     CMutableTransaction tx8 = CMutableTransaction();
     222         [ +  - ]:           1 :     tx8.vin.resize(1);
     223   [ +  -  +  - ]:           1 :     tx8.vin[0].prevout = COutPoint(tx7.GetHash(), 0);
     224         [ +  - ]:           1 :     tx8.vin[0].scriptSig = CScript() << OP_11;
     225         [ +  - ]:           1 :     tx8.vout.resize(1);
     226   [ +  -  +  - ]:           1 :     tx8.vout[0].scriptPubKey = CScript() << OP_11 << OP_EQUAL;
     227         [ +  - ]:           1 :     tx8.vout[0].nValue = 10 * COIN;
     228   [ +  -  +  -  :           2 :     setAncestors.insert(pool.GetIter(tx7.GetHash()).value());
                   +  - ]
     229   [ +  -  +  - ]:           1 :     pool.addUnchecked(entry.Fee(0LL).Time(NodeSeconds{2s}).FromTx(tx8), setAncestors);
     230                 :             : 
     231                 :             :     // Now tx8 should be sorted low, but tx6/tx both high
     232   [ +  -  +  - ]:           2 :     sortedOrder.insert(sortedOrder.begin(), tx8.GetHash().ToString());
     233         [ +  - ]:           1 :     CheckSort<descendant_score>(pool, sortedOrder);
     234                 :             : 
     235                 :             :     /* low fee child of tx7 */
     236         [ +  - ]:           1 :     CMutableTransaction tx9 = CMutableTransaction();
     237         [ +  - ]:           1 :     tx9.vin.resize(1);
     238   [ +  -  +  - ]:           1 :     tx9.vin[0].prevout = COutPoint(tx7.GetHash(), 1);
     239         [ +  - ]:           1 :     tx9.vin[0].scriptSig = CScript() << OP_11;
     240         [ +  - ]:           1 :     tx9.vout.resize(1);
     241   [ +  -  +  - ]:           1 :     tx9.vout[0].scriptPubKey = CScript() << OP_11 << OP_EQUAL;
     242         [ +  - ]:           1 :     tx9.vout[0].nValue = 1 * COIN;
     243   [ +  -  +  - ]:           1 :     pool.addUnchecked(entry.Fee(0LL).Time(NodeSeconds{3s}).FromTx(tx9), setAncestors);
     244                 :             : 
     245                 :             :     // tx9 should be sorted low
     246   [ +  -  +  -  :           1 :     BOOST_CHECK_EQUAL(pool.size(), 9U);
                   +  - ]
     247   [ +  -  +  - ]:           2 :     sortedOrder.insert(sortedOrder.begin(), tx9.GetHash().ToString());
     248         [ +  - ]:           1 :     CheckSort<descendant_score>(pool, sortedOrder);
     249                 :             : 
     250         [ +  - ]:           1 :     std::vector<std::string> snapshotOrder = sortedOrder;
     251                 :             : 
     252   [ +  -  +  -  :           2 :     setAncestors.insert(pool.GetIter(tx8.GetHash()).value());
                   +  - ]
     253   [ +  -  +  -  :           2 :     setAncestors.insert(pool.GetIter(tx9.GetHash()).value());
                   +  - ]
     254                 :             :     /* tx10 depends on tx8 and tx9 and has a high fee*/
     255         [ +  - ]:           1 :     CMutableTransaction tx10 = CMutableTransaction();
     256         [ +  - ]:           1 :     tx10.vin.resize(2);
     257   [ +  -  +  - ]:           1 :     tx10.vin[0].prevout = COutPoint(tx8.GetHash(), 0);
     258         [ +  - ]:           1 :     tx10.vin[0].scriptSig = CScript() << OP_11;
     259   [ +  -  +  - ]:           1 :     tx10.vin[1].prevout = COutPoint(tx9.GetHash(), 0);
     260         [ +  - ]:           1 :     tx10.vin[1].scriptSig = CScript() << OP_11;
     261         [ +  - ]:           1 :     tx10.vout.resize(1);
     262   [ +  -  +  - ]:           1 :     tx10.vout[0].scriptPubKey = CScript() << OP_11 << OP_EQUAL;
     263         [ +  - ]:           1 :     tx10.vout[0].nValue = 10 * COIN;
     264                 :             : 
     265                 :           1 :     {
     266   [ +  -  +  - ]:           1 :         auto ancestors_calculated{pool.CalculateMemPoolAncestors(entry.Fee(200000LL).Time(NodeSeconds{4s}).FromTx(tx10), CTxMemPool::Limits::NoLimits())};
     267   [ +  -  +  -  :           2 :         BOOST_REQUIRE(ancestors_calculated);
                   +  - ]
     268   [ +  -  +  - ]:           2 :         BOOST_CHECK(*ancestors_calculated == setAncestors);
     269                 :           0 :     }
     270                 :             : 
     271   [ +  -  +  - ]:           1 :     pool.addUnchecked(entry.FromTx(tx10), setAncestors);
     272                 :             : 
     273                 :             :     /**
     274                 :             :      *  tx8 and tx9 should both now be sorted higher
     275                 :             :      *  Final order after tx10 is added:
     276                 :             :      *
     277                 :             :      *  tx3 = 0 (1)
     278                 :             :      *  tx5 = 10000 (1)
     279                 :             :      *  tx1 = 10000 (1)
     280                 :             :      *  tx4 = 15000 (1)
     281                 :             :      *  tx2 = 20000 (1)
     282                 :             :      *  tx9 = 200k (2 txs)
     283                 :             :      *  tx8 = 200k (2 txs)
     284                 :             :      *  tx10 = 200k (1 tx)
     285                 :             :      *  tx6 = 2.2M (5 txs)
     286                 :             :      *  tx7 = 2.2M (4 txs)
     287                 :             :      */
     288                 :           1 :     sortedOrder.erase(sortedOrder.begin(), sortedOrder.begin()+2); // take out tx9, tx8 from the beginning
     289   [ +  -  +  - ]:           2 :     sortedOrder.insert(sortedOrder.begin()+5, tx9.GetHash().ToString());
     290   [ +  -  +  - ]:           2 :     sortedOrder.insert(sortedOrder.begin()+6, tx8.GetHash().ToString());
     291   [ +  -  +  - ]:           2 :     sortedOrder.insert(sortedOrder.begin()+7, tx10.GetHash().ToString()); // tx10 is just before tx6
     292         [ +  - ]:           1 :     CheckSort<descendant_score>(pool, sortedOrder);
     293                 :             : 
     294                 :             :     // there should be 10 transactions in the mempool
     295   [ +  -  +  -  :           1 :     BOOST_CHECK_EQUAL(pool.size(), 10U);
                   +  - ]
     296                 :             : 
     297                 :             :     // Now try removing tx10 and verify the sort order returns to normal
     298   [ +  -  +  -  :           1 :     pool.removeRecursive(*Assert(pool.get(tx10.GetHash())), REMOVAL_REASON_DUMMY);
             +  -  +  - ]
     299         [ +  - ]:           1 :     CheckSort<descendant_score>(pool, snapshotOrder);
     300                 :             : 
     301   [ +  -  +  -  :           1 :     pool.removeRecursive(*Assert(pool.get(tx9.GetHash())), REMOVAL_REASON_DUMMY);
             +  -  +  - ]
     302   [ +  -  +  -  :           2 :     pool.removeRecursive(*Assert(pool.get(tx8.GetHash())), REMOVAL_REASON_DUMMY);
             +  -  +  - ]
     303   [ +  -  +  - ]:          12 : }
     304                 :             : 
     305   [ +  -  +  -  :           7 : BOOST_AUTO_TEST_CASE(MempoolAncestorIndexingTest)
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
                      - ]
     306                 :             : {
     307                 :           1 :     CTxMemPool& pool = *Assert(m_node.mempool);
     308         [ +  - ]:           1 :     LOCK2(cs_main, pool.cs);
     309                 :           1 :     TestMemPoolEntryHelper entry;
     310                 :             : 
     311                 :             :     /* 3rd highest fee */
     312         [ +  - ]:           1 :     CMutableTransaction tx1 = CMutableTransaction();
     313         [ +  - ]:           1 :     tx1.vout.resize(1);
     314   [ +  -  +  - ]:           1 :     tx1.vout[0].scriptPubKey = CScript() << OP_11 << OP_EQUAL;
     315         [ +  - ]:           1 :     tx1.vout[0].nValue = 10 * COIN;
     316   [ +  -  +  - ]:           1 :     pool.addUnchecked(entry.Fee(10000LL).FromTx(tx1));
     317                 :             : 
     318                 :             :     /* highest fee */
     319         [ +  - ]:           1 :     CMutableTransaction tx2 = CMutableTransaction();
     320         [ +  - ]:           1 :     tx2.vout.resize(1);
     321   [ +  -  +  - ]:           1 :     tx2.vout[0].scriptPubKey = CScript() << OP_11 << OP_EQUAL;
     322         [ +  - ]:           1 :     tx2.vout[0].nValue = 2 * COIN;
     323   [ +  -  +  - ]:           1 :     pool.addUnchecked(entry.Fee(20000LL).FromTx(tx2));
     324         [ +  - ]:           2 :     uint64_t tx2Size = GetVirtualTransactionSize(CTransaction(tx2));
     325                 :             : 
     326                 :             :     /* lowest fee */
     327         [ +  - ]:           1 :     CMutableTransaction tx3 = CMutableTransaction();
     328         [ +  - ]:           1 :     tx3.vout.resize(1);
     329   [ +  -  +  - ]:           1 :     tx3.vout[0].scriptPubKey = CScript() << OP_11 << OP_EQUAL;
     330         [ +  - ]:           1 :     tx3.vout[0].nValue = 5 * COIN;
     331   [ +  -  +  - ]:           1 :     pool.addUnchecked(entry.Fee(0LL).FromTx(tx3));
     332                 :             : 
     333                 :             :     /* 2nd highest fee */
     334         [ +  - ]:           1 :     CMutableTransaction tx4 = CMutableTransaction();
     335         [ +  - ]:           1 :     tx4.vout.resize(1);
     336   [ +  -  +  - ]:           1 :     tx4.vout[0].scriptPubKey = CScript() << OP_11 << OP_EQUAL;
     337         [ +  - ]:           1 :     tx4.vout[0].nValue = 6 * COIN;
     338   [ +  -  +  - ]:           1 :     pool.addUnchecked(entry.Fee(15000LL).FromTx(tx4));
     339                 :             : 
     340                 :             :     /* equal fee rate to tx1, but newer */
     341         [ +  - ]:           1 :     CMutableTransaction tx5 = CMutableTransaction();
     342         [ +  - ]:           1 :     tx5.vout.resize(1);
     343   [ +  -  +  - ]:           1 :     tx5.vout[0].scriptPubKey = CScript() << OP_11 << OP_EQUAL;
     344         [ +  - ]:           1 :     tx5.vout[0].nValue = 11 * COIN;
     345   [ +  -  +  - ]:           1 :     pool.addUnchecked(entry.Fee(10000LL).FromTx(tx5));
     346   [ +  -  +  -  :           1 :     BOOST_CHECK_EQUAL(pool.size(), 5U);
                   +  - ]
     347                 :             : 
     348                 :           1 :     std::vector<std::string> sortedOrder;
     349         [ +  - ]:           1 :     sortedOrder.resize(5);
     350         [ +  - ]:           2 :     sortedOrder[0] = tx2.GetHash().ToString(); // 20000
     351         [ +  - ]:           2 :     sortedOrder[1] = tx4.GetHash().ToString(); // 15000
     352                 :             :     // tx1 and tx5 are both 10000
     353                 :             :     // Ties are broken by hash, not timestamp, so determine which
     354                 :             :     // hash comes first.
     355   [ +  -  +  -  :           1 :     if (tx1.GetHash() < tx5.GetHash()) {
                   +  - ]
     356         [ +  - ]:           2 :         sortedOrder[2] = tx1.GetHash().ToString();
     357         [ +  - ]:           2 :         sortedOrder[3] = tx5.GetHash().ToString();
     358                 :             :     } else {
     359         [ #  # ]:           0 :         sortedOrder[2] = tx5.GetHash().ToString();
     360         [ #  # ]:           0 :         sortedOrder[3] = tx1.GetHash().ToString();
     361                 :             :     }
     362         [ +  - ]:           2 :     sortedOrder[4] = tx3.GetHash().ToString(); // 0
     363                 :             : 
     364         [ +  - ]:           1 :     CheckSort<ancestor_score>(pool, sortedOrder);
     365                 :             : 
     366                 :             :     /* low fee parent with high fee child */
     367                 :             :     /* tx6 (0) -> tx7 (high) */
     368         [ +  - ]:           1 :     CMutableTransaction tx6 = CMutableTransaction();
     369         [ +  - ]:           1 :     tx6.vout.resize(1);
     370   [ +  -  +  - ]:           1 :     tx6.vout[0].scriptPubKey = CScript() << OP_11 << OP_EQUAL;
     371         [ +  - ]:           1 :     tx6.vout[0].nValue = 20 * COIN;
     372         [ +  - ]:           2 :     uint64_t tx6Size = GetVirtualTransactionSize(CTransaction(tx6));
     373                 :             : 
     374   [ +  -  +  - ]:           1 :     pool.addUnchecked(entry.Fee(0LL).FromTx(tx6));
     375   [ +  -  +  -  :           1 :     BOOST_CHECK_EQUAL(pool.size(), 6U);
                   +  - ]
     376                 :             :     // Ties are broken by hash
     377   [ +  -  +  -  :           1 :     if (tx3.GetHash() < tx6.GetHash())
                   -  + ]
     378   [ #  #  #  # ]:           0 :         sortedOrder.push_back(tx6.GetHash().ToString());
     379                 :             :     else
     380   [ +  -  +  - ]:           2 :         sortedOrder.insert(sortedOrder.end()-1,tx6.GetHash().ToString());
     381                 :             : 
     382         [ +  - ]:           1 :     CheckSort<ancestor_score>(pool, sortedOrder);
     383                 :             : 
     384         [ +  - ]:           1 :     CMutableTransaction tx7 = CMutableTransaction();
     385         [ +  - ]:           1 :     tx7.vin.resize(1);
     386   [ +  -  +  - ]:           1 :     tx7.vin[0].prevout = COutPoint(tx6.GetHash(), 0);
     387         [ +  - ]:           1 :     tx7.vin[0].scriptSig = CScript() << OP_11;
     388         [ +  - ]:           1 :     tx7.vout.resize(1);
     389   [ +  -  +  - ]:           1 :     tx7.vout[0].scriptPubKey = CScript() << OP_11 << OP_EQUAL;
     390         [ +  - ]:           1 :     tx7.vout[0].nValue = 10 * COIN;
     391         [ +  - ]:           2 :     uint64_t tx7Size = GetVirtualTransactionSize(CTransaction(tx7));
     392                 :             : 
     393                 :             :     /* set the fee to just below tx2's feerate when including ancestor */
     394                 :           1 :     CAmount fee = (20000/tx2Size)*(tx7Size + tx6Size) - 1;
     395                 :             : 
     396   [ +  -  +  - ]:           1 :     pool.addUnchecked(entry.Fee(fee).FromTx(tx7));
     397   [ +  -  +  -  :           1 :     BOOST_CHECK_EQUAL(pool.size(), 7U);
                   +  - ]
     398   [ +  -  +  - ]:           2 :     sortedOrder.insert(sortedOrder.begin()+1, tx7.GetHash().ToString());
     399         [ +  - ]:           1 :     CheckSort<ancestor_score>(pool, sortedOrder);
     400                 :             : 
     401                 :             :     /* after tx6 is mined, tx7 should move up in the sort */
     402                 :           1 :     std::vector<CTransactionRef> vtx;
     403   [ +  -  +  -  :           2 :     vtx.push_back(MakeTransactionRef(tx6));
                   -  + ]
     404         [ +  - ]:           1 :     pool.removeForBlock(vtx, 1);
     405                 :             : 
     406                 :           1 :     sortedOrder.erase(sortedOrder.begin()+1);
     407                 :             :     // Ties are broken by hash
     408   [ +  -  +  -  :           1 :     if (tx3.GetHash() < tx6.GetHash())
                   -  + ]
     409                 :           0 :         sortedOrder.pop_back();
     410                 :             :     else
     411                 :           1 :         sortedOrder.erase(sortedOrder.end()-2);
     412   [ +  -  +  - ]:           2 :     sortedOrder.insert(sortedOrder.begin(), tx7.GetHash().ToString());
     413         [ +  - ]:           1 :     CheckSort<ancestor_score>(pool, sortedOrder);
     414                 :             : 
     415                 :             :     // High-fee parent, low-fee child
     416                 :             :     // tx7 -> tx8
     417         [ +  - ]:           1 :     CMutableTransaction tx8 = CMutableTransaction();
     418         [ +  - ]:           1 :     tx8.vin.resize(1);
     419   [ +  -  +  - ]:           1 :     tx8.vin[0].prevout  = COutPoint(tx7.GetHash(), 0);
     420         [ +  - ]:           1 :     tx8.vin[0].scriptSig = CScript() << OP_11;
     421         [ +  - ]:           1 :     tx8.vout.resize(1);
     422   [ +  -  +  - ]:           1 :     tx8.vout[0].scriptPubKey = CScript() << OP_11 << OP_EQUAL;
     423         [ +  - ]:           1 :     tx8.vout[0].nValue = 10*COIN;
     424                 :             : 
     425                 :             :     // Check that we sort by min(feerate, ancestor_feerate):
     426                 :             :     // set the fee so that the ancestor feerate is above tx1/5,
     427                 :             :     // but the transaction's own feerate is lower
     428   [ +  -  +  - ]:           1 :     pool.addUnchecked(entry.Fee(5000LL).FromTx(tx8));
     429   [ +  -  +  - ]:           2 :     sortedOrder.insert(sortedOrder.end()-1, tx8.GetHash().ToString());
     430         [ +  - ]:           1 :     CheckSort<ancestor_score>(pool, sortedOrder);
     431   [ +  -  +  - ]:          10 : }
     432                 :             : 
     433                 :             : 
     434   [ +  -  +  -  :           7 : BOOST_AUTO_TEST_CASE(MempoolSizeLimitTest)
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
                      - ]
     435                 :             : {
     436                 :           1 :     auto& pool = static_cast<MemPoolTest&>(*Assert(m_node.mempool));
     437         [ +  - ]:           1 :     LOCK2(cs_main, pool.cs);
     438                 :           1 :     TestMemPoolEntryHelper entry;
     439                 :             : 
     440         [ +  - ]:           1 :     CMutableTransaction tx1 = CMutableTransaction();
     441         [ +  - ]:           1 :     tx1.vin.resize(1);
     442         [ +  - ]:           1 :     tx1.vin[0].scriptSig = CScript() << OP_1;
     443         [ +  - ]:           1 :     tx1.vout.resize(1);
     444   [ +  -  +  - ]:           1 :     tx1.vout[0].scriptPubKey = CScript() << OP_1 << OP_EQUAL;
     445         [ +  - ]:           1 :     tx1.vout[0].nValue = 10 * COIN;
     446   [ +  -  +  - ]:           1 :     pool.addUnchecked(entry.Fee(10000LL).FromTx(tx1));
     447                 :             : 
     448         [ +  - ]:           1 :     CMutableTransaction tx2 = CMutableTransaction();
     449         [ +  - ]:           1 :     tx2.vin.resize(1);
     450         [ +  - ]:           1 :     tx2.vin[0].scriptSig = CScript() << OP_2;
     451         [ +  - ]:           1 :     tx2.vout.resize(1);
     452   [ +  -  +  - ]:           1 :     tx2.vout[0].scriptPubKey = CScript() << OP_2 << OP_EQUAL;
     453         [ +  - ]:           1 :     tx2.vout[0].nValue = 10 * COIN;
     454   [ +  -  +  - ]:           1 :     pool.addUnchecked(entry.Fee(5000LL).FromTx(tx2));
     455                 :             : 
     456   [ +  -  +  - ]:           1 :     pool.TrimToSize(pool.DynamicMemoryUsage()); // should do nothing
     457   [ +  -  +  -  :           2 :     BOOST_CHECK(pool.exists(GenTxid::Txid(tx1.GetHash())));
          +  -  +  -  +  
                      - ]
     458   [ +  -  +  -  :           2 :     BOOST_CHECK(pool.exists(GenTxid::Txid(tx2.GetHash())));
          +  -  +  -  +  
                      - ]
     459                 :             : 
     460   [ +  -  +  - ]:           1 :     pool.TrimToSize(pool.DynamicMemoryUsage() * 3 / 4); // should remove the lower-feerate transaction
     461   [ +  -  +  -  :           2 :     BOOST_CHECK(pool.exists(GenTxid::Txid(tx1.GetHash())));
          +  -  +  -  +  
                      - ]
     462   [ +  -  +  -  :           2 :     BOOST_CHECK(!pool.exists(GenTxid::Txid(tx2.GetHash())));
          +  -  +  -  +  
                      - ]
     463                 :             : 
     464   [ +  -  +  - ]:           1 :     pool.addUnchecked(entry.FromTx(tx2));
     465         [ +  - ]:           1 :     CMutableTransaction tx3 = CMutableTransaction();
     466         [ +  - ]:           1 :     tx3.vin.resize(1);
     467   [ +  -  +  - ]:           1 :     tx3.vin[0].prevout = COutPoint(tx2.GetHash(), 0);
     468         [ +  - ]:           1 :     tx3.vin[0].scriptSig = CScript() << OP_2;
     469         [ +  - ]:           1 :     tx3.vout.resize(1);
     470   [ +  -  +  - ]:           1 :     tx3.vout[0].scriptPubKey = CScript() << OP_3 << OP_EQUAL;
     471         [ +  - ]:           1 :     tx3.vout[0].nValue = 10 * COIN;
     472   [ +  -  +  - ]:           1 :     pool.addUnchecked(entry.Fee(20000LL).FromTx(tx3));
     473                 :             : 
     474   [ +  -  +  - ]:           1 :     pool.TrimToSize(pool.DynamicMemoryUsage() * 3 / 4); // tx3 should pay for tx2 (CPFP)
     475   [ +  -  +  -  :           2 :     BOOST_CHECK(!pool.exists(GenTxid::Txid(tx1.GetHash())));
          +  -  +  -  +  
                      - ]
     476   [ +  -  +  -  :           2 :     BOOST_CHECK(pool.exists(GenTxid::Txid(tx2.GetHash())));
          +  -  +  -  +  
                      - ]
     477   [ +  -  +  -  :           2 :     BOOST_CHECK(pool.exists(GenTxid::Txid(tx3.GetHash())));
          +  -  +  -  +  
                      - ]
     478                 :             : 
     479   [ +  -  +  - ]:           2 :     pool.TrimToSize(GetVirtualTransactionSize(CTransaction(tx1))); // mempool is limited to tx1's size in memory usage, so nothing fits
     480   [ +  -  +  -  :           2 :     BOOST_CHECK(!pool.exists(GenTxid::Txid(tx1.GetHash())));
          +  -  +  -  +  
                      - ]
     481   [ +  -  +  -  :           2 :     BOOST_CHECK(!pool.exists(GenTxid::Txid(tx2.GetHash())));
          +  -  +  -  +  
                      - ]
     482   [ +  -  +  -  :           2 :     BOOST_CHECK(!pool.exists(GenTxid::Txid(tx3.GetHash())));
          +  -  +  -  +  
                      - ]
     483                 :             : 
     484   [ +  -  +  -  :           4 :     CFeeRate maxFeeRateRemoved(25000, GetVirtualTransactionSize(CTransaction(tx3)) + GetVirtualTransactionSize(CTransaction(tx2)));
                   +  - ]
     485   [ +  -  +  -  :           1 :     BOOST_CHECK_EQUAL(pool.GetMinFee(1).GetFeePerK(), maxFeeRateRemoved.GetFeePerK() + 1000);
                   +  - ]
     486                 :             : 
     487         [ +  - ]:           1 :     CMutableTransaction tx4 = CMutableTransaction();
     488         [ +  - ]:           1 :     tx4.vin.resize(2);
     489                 :           1 :     tx4.vin[0].prevout.SetNull();
     490         [ +  - ]:           1 :     tx4.vin[0].scriptSig = CScript() << OP_4;
     491                 :           1 :     tx4.vin[1].prevout.SetNull();
     492         [ +  - ]:           1 :     tx4.vin[1].scriptSig = CScript() << OP_4;
     493         [ +  - ]:           1 :     tx4.vout.resize(2);
     494   [ +  -  +  - ]:           1 :     tx4.vout[0].scriptPubKey = CScript() << OP_4 << OP_EQUAL;
     495         [ +  - ]:           1 :     tx4.vout[0].nValue = 10 * COIN;
     496   [ +  -  +  - ]:           1 :     tx4.vout[1].scriptPubKey = CScript() << OP_4 << OP_EQUAL;
     497         [ +  - ]:           1 :     tx4.vout[1].nValue = 10 * COIN;
     498                 :             : 
     499         [ +  - ]:           1 :     CMutableTransaction tx5 = CMutableTransaction();
     500         [ +  - ]:           1 :     tx5.vin.resize(2);
     501   [ +  -  +  - ]:           1 :     tx5.vin[0].prevout = COutPoint(tx4.GetHash(), 0);
     502         [ +  - ]:           1 :     tx5.vin[0].scriptSig = CScript() << OP_4;
     503                 :           1 :     tx5.vin[1].prevout.SetNull();
     504         [ +  - ]:           1 :     tx5.vin[1].scriptSig = CScript() << OP_5;
     505         [ +  - ]:           1 :     tx5.vout.resize(2);
     506   [ +  -  +  - ]:           1 :     tx5.vout[0].scriptPubKey = CScript() << OP_5 << OP_EQUAL;
     507         [ +  - ]:           1 :     tx5.vout[0].nValue = 10 * COIN;
     508   [ +  -  +  - ]:           1 :     tx5.vout[1].scriptPubKey = CScript() << OP_5 << OP_EQUAL;
     509         [ +  - ]:           1 :     tx5.vout[1].nValue = 10 * COIN;
     510                 :             : 
     511         [ +  - ]:           1 :     CMutableTransaction tx6 = CMutableTransaction();
     512         [ +  - ]:           1 :     tx6.vin.resize(2);
     513   [ +  -  +  - ]:           1 :     tx6.vin[0].prevout = COutPoint(tx4.GetHash(), 1);
     514         [ +  - ]:           1 :     tx6.vin[0].scriptSig = CScript() << OP_4;
     515                 :           1 :     tx6.vin[1].prevout.SetNull();
     516         [ +  - ]:           1 :     tx6.vin[1].scriptSig = CScript() << OP_6;
     517         [ +  - ]:           1 :     tx6.vout.resize(2);
     518   [ +  -  +  - ]:           1 :     tx6.vout[0].scriptPubKey = CScript() << OP_6 << OP_EQUAL;
     519         [ +  - ]:           1 :     tx6.vout[0].nValue = 10 * COIN;
     520   [ +  -  +  - ]:           1 :     tx6.vout[1].scriptPubKey = CScript() << OP_6 << OP_EQUAL;
     521         [ +  - ]:           1 :     tx6.vout[1].nValue = 10 * COIN;
     522                 :             : 
     523         [ +  - ]:           1 :     CMutableTransaction tx7 = CMutableTransaction();
     524         [ +  - ]:           1 :     tx7.vin.resize(2);
     525   [ +  -  +  - ]:           1 :     tx7.vin[0].prevout = COutPoint(tx5.GetHash(), 0);
     526         [ +  - ]:           1 :     tx7.vin[0].scriptSig = CScript() << OP_5;
     527   [ +  -  +  - ]:           1 :     tx7.vin[1].prevout = COutPoint(tx6.GetHash(), 0);
     528         [ +  - ]:           1 :     tx7.vin[1].scriptSig = CScript() << OP_6;
     529         [ +  - ]:           1 :     tx7.vout.resize(2);
     530   [ +  -  +  - ]:           1 :     tx7.vout[0].scriptPubKey = CScript() << OP_7 << OP_EQUAL;
     531         [ +  - ]:           1 :     tx7.vout[0].nValue = 10 * COIN;
     532   [ +  -  +  - ]:           1 :     tx7.vout[1].scriptPubKey = CScript() << OP_7 << OP_EQUAL;
     533         [ +  - ]:           1 :     tx7.vout[1].nValue = 10 * COIN;
     534                 :             : 
     535   [ +  -  +  - ]:           1 :     pool.addUnchecked(entry.Fee(7000LL).FromTx(tx4));
     536   [ +  -  +  - ]:           1 :     pool.addUnchecked(entry.Fee(1000LL).FromTx(tx5));
     537   [ +  -  +  - ]:           1 :     pool.addUnchecked(entry.Fee(1100LL).FromTx(tx6));
     538   [ +  -  +  - ]:           1 :     pool.addUnchecked(entry.Fee(9000LL).FromTx(tx7));
     539                 :             : 
     540                 :             :     // we only require this to remove, at max, 2 txn, because it's not clear what we're really optimizing for aside from that
     541   [ +  -  +  - ]:           1 :     pool.TrimToSize(pool.DynamicMemoryUsage() - 1);
     542   [ +  -  +  -  :           2 :     BOOST_CHECK(pool.exists(GenTxid::Txid(tx4.GetHash())));
          +  -  +  -  +  
                      - ]
     543   [ +  -  +  -  :           2 :     BOOST_CHECK(pool.exists(GenTxid::Txid(tx6.GetHash())));
          +  -  +  -  +  
                      - ]
     544   [ +  -  +  -  :           2 :     BOOST_CHECK(!pool.exists(GenTxid::Txid(tx7.GetHash())));
          +  -  +  -  +  
                      - ]
     545                 :             : 
     546   [ +  -  +  -  :           1 :     if (!pool.exists(GenTxid::Txid(tx5.GetHash())))
                   +  - ]
     547   [ +  -  +  - ]:           1 :         pool.addUnchecked(entry.Fee(1000LL).FromTx(tx5));
     548   [ +  -  +  - ]:           1 :     pool.addUnchecked(entry.Fee(9000LL).FromTx(tx7));
     549                 :             : 
     550   [ +  -  +  - ]:           1 :     pool.TrimToSize(pool.DynamicMemoryUsage() / 2); // should maximize mempool size by only removing 5/7
     551   [ +  -  +  -  :           2 :     BOOST_CHECK(pool.exists(GenTxid::Txid(tx4.GetHash())));
          +  -  +  -  +  
                      - ]
     552   [ +  -  +  -  :           2 :     BOOST_CHECK(!pool.exists(GenTxid::Txid(tx5.GetHash())));
          +  -  +  -  +  
                      - ]
     553   [ +  -  +  -  :           2 :     BOOST_CHECK(pool.exists(GenTxid::Txid(tx6.GetHash())));
          +  -  +  -  +  
                      - ]
     554   [ +  -  +  -  :           2 :     BOOST_CHECK(!pool.exists(GenTxid::Txid(tx7.GetHash())));
          +  -  +  -  +  
                      - ]
     555                 :             : 
     556   [ +  -  +  - ]:           1 :     pool.addUnchecked(entry.Fee(1000LL).FromTx(tx5));
     557   [ +  -  +  - ]:           1 :     pool.addUnchecked(entry.Fee(9000LL).FromTx(tx7));
     558                 :             : 
     559                 :           1 :     std::vector<CTransactionRef> vtx;
     560         [ +  - ]:           1 :     SetMockTime(42);
     561         [ +  - ]:           1 :     SetMockTime(42 + CTxMemPool::ROLLING_FEE_HALFLIFE);
     562   [ +  -  +  -  :           1 :     BOOST_CHECK_EQUAL(pool.GetMinFee(1).GetFeePerK(), maxFeeRateRemoved.GetFeePerK() + 1000);
                   +  - ]
     563                 :             :     // ... we should keep the same min fee until we get a block
     564         [ +  - ]:           1 :     pool.removeForBlock(vtx, 1);
     565         [ +  - ]:           1 :     SetMockTime(42 + 2*CTxMemPool::ROLLING_FEE_HALFLIFE);
     566   [ +  -  +  -  :           1 :     BOOST_CHECK_EQUAL(pool.GetMinFee(1).GetFeePerK(), llround((maxFeeRateRemoved.GetFeePerK() + 1000)/2.0));
                   +  - ]
     567                 :             :     // ... then feerate should drop 1/2 each halflife
     568                 :             : 
     569         [ +  - ]:           1 :     SetMockTime(42 + 2*CTxMemPool::ROLLING_FEE_HALFLIFE + CTxMemPool::ROLLING_FEE_HALFLIFE/2);
     570   [ +  -  +  -  :           1 :     BOOST_CHECK_EQUAL(pool.GetMinFee(pool.DynamicMemoryUsage() * 5 / 2).GetFeePerK(), llround((maxFeeRateRemoved.GetFeePerK() + 1000)/4.0));
             +  -  +  - ]
     571                 :             :     // ... with a 1/2 halflife when mempool is < 1/2 its target size
     572                 :             : 
     573         [ +  - ]:           1 :     SetMockTime(42 + 2*CTxMemPool::ROLLING_FEE_HALFLIFE + CTxMemPool::ROLLING_FEE_HALFLIFE/2 + CTxMemPool::ROLLING_FEE_HALFLIFE/4);
     574   [ +  -  +  -  :           1 :     BOOST_CHECK_EQUAL(pool.GetMinFee(pool.DynamicMemoryUsage() * 9 / 2).GetFeePerK(), llround((maxFeeRateRemoved.GetFeePerK() + 1000)/8.0));
             +  -  +  - ]
     575                 :             :     // ... with a 1/4 halflife when mempool is < 1/4 its target size
     576                 :             : 
     577         [ +  - ]:           1 :     SetMockTime(42 + 7*CTxMemPool::ROLLING_FEE_HALFLIFE + CTxMemPool::ROLLING_FEE_HALFLIFE/2 + CTxMemPool::ROLLING_FEE_HALFLIFE/4);
     578   [ +  -  +  -  :           1 :     BOOST_CHECK_EQUAL(pool.GetMinFee(1).GetFeePerK(), 1000);
                   +  - ]
     579                 :             :     // ... but feerate should never drop below 1000
     580                 :             : 
     581         [ +  - ]:           1 :     SetMockTime(42 + 8*CTxMemPool::ROLLING_FEE_HALFLIFE + CTxMemPool::ROLLING_FEE_HALFLIFE/2 + CTxMemPool::ROLLING_FEE_HALFLIFE/4);
     582   [ +  -  +  -  :           1 :     BOOST_CHECK_EQUAL(pool.GetMinFee(1).GetFeePerK(), 0);
                   +  - ]
     583                 :             :     // ... unless it has gone all the way to 0 (after getting past 1000/2)
     584   [ +  -  +  - ]:          10 : }
     585                 :             : 
     586                 :          14 : inline CTransactionRef make_tx(std::vector<CAmount>&& output_values, std::vector<CTransactionRef>&& inputs=std::vector<CTransactionRef>(), std::vector<uint32_t>&& input_indices=std::vector<uint32_t>())
     587                 :             : {
     588                 :          14 :     CMutableTransaction tx = CMutableTransaction();
     589         [ +  - ]:          14 :     tx.vin.resize(inputs.size());
     590         [ +  - ]:          14 :     tx.vout.resize(output_values.size());
     591         [ +  + ]:          27 :     for (size_t i = 0; i < inputs.size(); ++i) {
     592         [ +  + ]:          13 :         tx.vin[i].prevout.hash = inputs[i]->GetHash();
     593         [ +  + ]:          13 :         tx.vin[i].prevout.n = input_indices.size() > i ? input_indices[i] : 0;
     594                 :             :     }
     595         [ +  + ]:          32 :     for (size_t i = 0; i < output_values.size(); ++i) {
     596   [ +  -  +  - ]:          18 :         tx.vout[i].scriptPubKey = CScript() << OP_11 << OP_EQUAL;
     597                 :          18 :         tx.vout[i].nValue = output_values[i];
     598                 :             :     }
     599         [ +  - ]:          28 :     return MakeTransactionRef(tx);
     600                 :          14 : }
     601                 :             : 
     602                 :             : 
     603   [ +  -  +  -  :           7 : BOOST_AUTO_TEST_CASE(MempoolAncestryTests)
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
                      - ]
     604                 :             : {
     605                 :           1 :     size_t ancestors, descendants;
     606                 :             : 
     607                 :           1 :     CTxMemPool& pool = *Assert(m_node.mempool);
     608         [ +  - ]:           1 :     LOCK2(cs_main, pool.cs);
     609                 :           1 :     TestMemPoolEntryHelper entry;
     610                 :             : 
     611                 :             :     /* Base transaction */
     612                 :             :     //
     613                 :             :     // [tx1]
     614                 :             :     //
     615   [ +  -  +  - ]:           2 :     CTransactionRef tx1 = make_tx(/*output_values=*/{10 * COIN});
     616   [ +  -  +  - ]:           1 :     pool.addUnchecked(entry.Fee(10000LL).FromTx(tx1));
     617                 :             : 
     618                 :             :     // Ancestors / descendants should be 1 / 1 (itself / itself)
     619         [ +  - ]:           1 :     pool.GetTransactionAncestry(tx1->GetHash(), ancestors, descendants);
     620   [ +  -  +  - ]:           1 :     BOOST_CHECK_EQUAL(ancestors, 1ULL);
     621   [ +  -  +  - ]:           1 :     BOOST_CHECK_EQUAL(descendants, 1ULL);
     622                 :             : 
     623                 :             :     /* Child transaction */
     624                 :             :     //
     625                 :             :     // [tx1].0 <- [tx2]
     626                 :             :     //
     627   [ +  -  +  -  :           4 :     CTransactionRef tx2 = make_tx(/*output_values=*/{495 * CENT, 5 * COIN}, /*inputs=*/{tx1});
          +  -  +  +  +  
             -  -  -  -  
                      - ]
     628   [ +  -  +  - ]:           1 :     pool.addUnchecked(entry.Fee(10000LL).FromTx(tx2));
     629                 :             : 
     630                 :             :     // Ancestors / descendants should be:
     631                 :             :     // transaction  ancestors   descendants
     632                 :             :     // ============ =========== ===========
     633                 :             :     // tx1          1 (tx1)     2 (tx1,2)
     634                 :             :     // tx2          2 (tx1,2)   2 (tx1,2)
     635         [ +  - ]:           1 :     pool.GetTransactionAncestry(tx1->GetHash(), ancestors, descendants);
     636   [ +  -  +  - ]:           1 :     BOOST_CHECK_EQUAL(ancestors, 1ULL);
     637   [ +  -  +  - ]:           1 :     BOOST_CHECK_EQUAL(descendants, 2ULL);
     638         [ +  - ]:           1 :     pool.GetTransactionAncestry(tx2->GetHash(), ancestors, descendants);
     639   [ +  -  +  - ]:           1 :     BOOST_CHECK_EQUAL(ancestors, 2ULL);
     640   [ +  -  +  - ]:           1 :     BOOST_CHECK_EQUAL(descendants, 2ULL);
     641                 :             : 
     642                 :             :     /* Grand-child 1 */
     643                 :             :     //
     644                 :             :     // [tx1].0 <- [tx2].0 <- [tx3]
     645                 :             :     //
     646   [ +  -  +  -  :           4 :     CTransactionRef tx3 = make_tx(/*output_values=*/{290 * CENT, 200 * CENT}, /*inputs=*/{tx2});
          +  -  +  +  +  
             -  -  -  -  
                      - ]
     647   [ +  -  +  - ]:           1 :     pool.addUnchecked(entry.Fee(10000LL).FromTx(tx3));
     648                 :             : 
     649                 :             :     // Ancestors / descendants should be:
     650                 :             :     // transaction  ancestors   descendants
     651                 :             :     // ============ =========== ===========
     652                 :             :     // tx1          1 (tx1)     3 (tx1,2,3)
     653                 :             :     // tx2          2 (tx1,2)   3 (tx1,2,3)
     654                 :             :     // tx3          3 (tx1,2,3) 3 (tx1,2,3)
     655         [ +  - ]:           1 :     pool.GetTransactionAncestry(tx1->GetHash(), ancestors, descendants);
     656   [ +  -  +  - ]:           1 :     BOOST_CHECK_EQUAL(ancestors, 1ULL);
     657   [ +  -  +  - ]:           1 :     BOOST_CHECK_EQUAL(descendants, 3ULL);
     658         [ +  - ]:           1 :     pool.GetTransactionAncestry(tx2->GetHash(), ancestors, descendants);
     659   [ +  -  +  - ]:           1 :     BOOST_CHECK_EQUAL(ancestors, 2ULL);
     660   [ +  -  +  - ]:           1 :     BOOST_CHECK_EQUAL(descendants, 3ULL);
     661         [ +  - ]:           1 :     pool.GetTransactionAncestry(tx3->GetHash(), ancestors, descendants);
     662   [ +  -  +  - ]:           1 :     BOOST_CHECK_EQUAL(ancestors, 3ULL);
     663   [ +  -  +  - ]:           1 :     BOOST_CHECK_EQUAL(descendants, 3ULL);
     664                 :             : 
     665                 :             :     /* Grand-child 2 */
     666                 :             :     //
     667                 :             :     // [tx1].0 <- [tx2].0 <- [tx3]
     668                 :             :     //              |
     669                 :             :     //              \---1 <- [tx4]
     670                 :             :     //
     671   [ +  -  +  -  :           5 :     CTransactionRef tx4 = make_tx(/*output_values=*/{290 * CENT, 250 * CENT}, /*inputs=*/{tx2}, /*input_indices=*/{1});
          +  -  +  +  +  
          -  +  -  -  -  
                   -  - ]
     672   [ +  -  +  - ]:           1 :     pool.addUnchecked(entry.Fee(10000LL).FromTx(tx4));
     673                 :             : 
     674                 :             :     // Ancestors / descendants should be:
     675                 :             :     // transaction  ancestors   descendants
     676                 :             :     // ============ =========== ===========
     677                 :             :     // tx1          1 (tx1)     4 (tx1,2,3,4)
     678                 :             :     // tx2          2 (tx1,2)   4 (tx1,2,3,4)
     679                 :             :     // tx3          3 (tx1,2,3) 4 (tx1,2,3,4)
     680                 :             :     // tx4          3 (tx1,2,4) 4 (tx1,2,3,4)
     681         [ +  - ]:           1 :     pool.GetTransactionAncestry(tx1->GetHash(), ancestors, descendants);
     682   [ +  -  +  - ]:           1 :     BOOST_CHECK_EQUAL(ancestors, 1ULL);
     683   [ +  -  +  - ]:           1 :     BOOST_CHECK_EQUAL(descendants, 4ULL);
     684         [ +  - ]:           1 :     pool.GetTransactionAncestry(tx2->GetHash(), ancestors, descendants);
     685   [ +  -  +  - ]:           1 :     BOOST_CHECK_EQUAL(ancestors, 2ULL);
     686   [ +  -  +  - ]:           1 :     BOOST_CHECK_EQUAL(descendants, 4ULL);
     687         [ +  - ]:           1 :     pool.GetTransactionAncestry(tx3->GetHash(), ancestors, descendants);
     688   [ +  -  +  - ]:           1 :     BOOST_CHECK_EQUAL(ancestors, 3ULL);
     689   [ +  -  +  - ]:           1 :     BOOST_CHECK_EQUAL(descendants, 4ULL);
     690         [ +  - ]:           1 :     pool.GetTransactionAncestry(tx4->GetHash(), ancestors, descendants);
     691   [ +  -  +  - ]:           1 :     BOOST_CHECK_EQUAL(ancestors, 3ULL);
     692   [ +  -  +  - ]:           1 :     BOOST_CHECK_EQUAL(descendants, 4ULL);
     693                 :             : 
     694                 :             :     /* Make an alternate branch that is longer and connect it to tx3 */
     695                 :             :     //
     696                 :             :     // [ty1].0 <- [ty2].0 <- [ty3].0 <- [ty4].0 <- [ty5].0
     697                 :             :     //                                              |
     698                 :             :     // [tx1].0 <- [tx2].0 <- [tx3].0 <- [ty6] --->--/
     699                 :             :     //              |
     700                 :             :     //              \---1 <- [tx4]
     701                 :             :     //
     702                 :           1 :     CTransactionRef ty1, ty2, ty3, ty4, ty5;
     703                 :           1 :     CTransactionRef* ty[5] = {&ty1, &ty2, &ty3, &ty4, &ty5};
     704                 :           1 :     CAmount v = 5 * COIN;
     705         [ +  + ]:           6 :     for (uint64_t i = 0; i < 5; i++) {
     706                 :           5 :         CTransactionRef& tyi = *ty[i];
     707   [ +  +  +  -  :          22 :         tyi = make_tx(/*output_values=*/{v}, /*inputs=*/i > 0 ? std::vector<CTransactionRef>{*ty[i - 1]} : std::vector<CTransactionRef>{});
          +  -  +  -  -  
          +  +  +  +  +  
          +  -  -  -  -  
                -  -  - ]
     708                 :           5 :         v -= 50 * CENT;
     709   [ +  -  +  - ]:           5 :         pool.addUnchecked(entry.Fee(10000LL).FromTx(tyi));
     710         [ +  - ]:           5 :         pool.GetTransactionAncestry(tyi->GetHash(), ancestors, descendants);
     711   [ +  -  +  - ]:           5 :         BOOST_CHECK_EQUAL(ancestors, i+1);
     712   [ +  -  +  - ]:           5 :         BOOST_CHECK_EQUAL(descendants, i+1);
     713                 :             :     }
     714   [ +  -  +  -  :           5 :     CTransactionRef ty6 = make_tx(/*output_values=*/{5 * COIN}, /*inputs=*/{tx3, ty5});
          +  -  +  +  +  
             -  -  -  -  
                      - ]
     715   [ +  -  +  - ]:           1 :     pool.addUnchecked(entry.Fee(10000LL).FromTx(ty6));
     716                 :             : 
     717                 :             :     // Ancestors / descendants should be:
     718                 :             :     // transaction  ancestors           descendants
     719                 :             :     // ============ =================== ===========
     720                 :             :     // tx1          1 (tx1)             5 (tx1,2,3,4, ty6)
     721                 :             :     // tx2          2 (tx1,2)           5 (tx1,2,3,4, ty6)
     722                 :             :     // tx3          3 (tx1,2,3)         5 (tx1,2,3,4, ty6)
     723                 :             :     // tx4          3 (tx1,2,4)         5 (tx1,2,3,4, ty6)
     724                 :             :     // ty1          1 (ty1)             6 (ty1,2,3,4,5,6)
     725                 :             :     // ty2          2 (ty1,2)           6 (ty1,2,3,4,5,6)
     726                 :             :     // ty3          3 (ty1,2,3)         6 (ty1,2,3,4,5,6)
     727                 :             :     // ty4          4 (y1234)           6 (ty1,2,3,4,5,6)
     728                 :             :     // ty5          5 (y12345)          6 (ty1,2,3,4,5,6)
     729                 :             :     // ty6          9 (tx123, ty123456) 6 (ty1,2,3,4,5,6)
     730         [ +  - ]:           1 :     pool.GetTransactionAncestry(tx1->GetHash(), ancestors, descendants);
     731   [ +  -  +  - ]:           1 :     BOOST_CHECK_EQUAL(ancestors, 1ULL);
     732   [ +  -  +  - ]:           1 :     BOOST_CHECK_EQUAL(descendants, 5ULL);
     733         [ +  - ]:           1 :     pool.GetTransactionAncestry(tx2->GetHash(), ancestors, descendants);
     734   [ +  -  +  - ]:           1 :     BOOST_CHECK_EQUAL(ancestors, 2ULL);
     735   [ +  -  +  - ]:           1 :     BOOST_CHECK_EQUAL(descendants, 5ULL);
     736         [ +  - ]:           1 :     pool.GetTransactionAncestry(tx3->GetHash(), ancestors, descendants);
     737   [ +  -  +  - ]:           1 :     BOOST_CHECK_EQUAL(ancestors, 3ULL);
     738   [ +  -  +  - ]:           1 :     BOOST_CHECK_EQUAL(descendants, 5ULL);
     739         [ +  - ]:           1 :     pool.GetTransactionAncestry(tx4->GetHash(), ancestors, descendants);
     740   [ +  -  +  - ]:           1 :     BOOST_CHECK_EQUAL(ancestors, 3ULL);
     741   [ +  -  +  - ]:           1 :     BOOST_CHECK_EQUAL(descendants, 5ULL);
     742         [ +  - ]:           1 :     pool.GetTransactionAncestry(ty1->GetHash(), ancestors, descendants);
     743   [ +  -  +  - ]:           1 :     BOOST_CHECK_EQUAL(ancestors, 1ULL);
     744   [ +  -  +  - ]:           1 :     BOOST_CHECK_EQUAL(descendants, 6ULL);
     745         [ +  - ]:           1 :     pool.GetTransactionAncestry(ty2->GetHash(), ancestors, descendants);
     746   [ +  -  +  - ]:           1 :     BOOST_CHECK_EQUAL(ancestors, 2ULL);
     747   [ +  -  +  - ]:           1 :     BOOST_CHECK_EQUAL(descendants, 6ULL);
     748         [ +  - ]:           1 :     pool.GetTransactionAncestry(ty3->GetHash(), ancestors, descendants);
     749   [ +  -  +  - ]:           1 :     BOOST_CHECK_EQUAL(ancestors, 3ULL);
     750   [ +  -  +  - ]:           1 :     BOOST_CHECK_EQUAL(descendants, 6ULL);
     751         [ +  - ]:           1 :     pool.GetTransactionAncestry(ty4->GetHash(), ancestors, descendants);
     752   [ +  -  +  - ]:           1 :     BOOST_CHECK_EQUAL(ancestors, 4ULL);
     753   [ +  -  +  - ]:           1 :     BOOST_CHECK_EQUAL(descendants, 6ULL);
     754         [ +  - ]:           1 :     pool.GetTransactionAncestry(ty5->GetHash(), ancestors, descendants);
     755   [ +  -  +  - ]:           1 :     BOOST_CHECK_EQUAL(ancestors, 5ULL);
     756   [ +  -  +  - ]:           1 :     BOOST_CHECK_EQUAL(descendants, 6ULL);
     757         [ +  - ]:           1 :     pool.GetTransactionAncestry(ty6->GetHash(), ancestors, descendants);
     758   [ +  -  +  - ]:           1 :     BOOST_CHECK_EQUAL(ancestors, 9ULL);
     759   [ +  -  +  -  :           1 :     BOOST_CHECK_EQUAL(descendants, 6ULL);
                   +  - ]
     760   [ +  -  +  -  :          25 : }
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
                -  +  - ]
     761                 :             : 
     762   [ +  -  +  -  :           7 : BOOST_AUTO_TEST_CASE(MempoolAncestryTestsDiamond)
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
                      - ]
     763                 :             : {
     764                 :           1 :     size_t ancestors, descendants;
     765                 :             : 
     766                 :           1 :     CTxMemPool& pool = *Assert(m_node.mempool);
     767         [ +  - ]:           1 :     LOCK2(::cs_main, pool.cs);
     768                 :           1 :     TestMemPoolEntryHelper entry;
     769                 :             : 
     770                 :             :     /* Ancestors represented more than once ("diamond") */
     771                 :             :     //
     772                 :             :     // [ta].0 <- [tb].0 -----<------- [td].0
     773                 :             :     //            |                    |
     774                 :             :     //            \---1 <- [tc].0 --<--/
     775                 :             :     //
     776                 :           1 :     CTransactionRef ta, tb, tc, td;
     777   [ +  -  +  -  :           2 :     ta = make_tx(/*output_values=*/{10 * COIN});
                   -  + ]
     778   [ +  -  +  -  :           4 :     tb = make_tx(/*output_values=*/{5 * COIN, 3 * COIN}, /*inputs=*/ {ta});
          +  -  -  +  +  
          +  +  -  -  -  
                   -  - ]
     779   [ +  -  +  -  :           5 :     tc = make_tx(/*output_values=*/{2 * COIN}, /*inputs=*/{tb}, /*input_indices=*/{1});
          +  -  -  +  +  
          +  +  -  +  -  
             -  -  -  - ]
     780   [ +  -  +  -  :           6 :     td = make_tx(/*output_values=*/{6 * COIN}, /*inputs=*/{tb, tc}, /*input_indices=*/{0, 0});
          +  -  -  +  +  
          +  +  -  +  -  
             -  -  -  - ]
     781   [ +  -  +  - ]:           1 :     pool.addUnchecked(entry.Fee(10000LL).FromTx(ta));
     782   [ +  -  +  - ]:           1 :     pool.addUnchecked(entry.Fee(10000LL).FromTx(tb));
     783   [ +  -  +  - ]:           1 :     pool.addUnchecked(entry.Fee(10000LL).FromTx(tc));
     784   [ +  -  +  - ]:           1 :     pool.addUnchecked(entry.Fee(10000LL).FromTx(td));
     785                 :             : 
     786                 :             :     // Ancestors / descendants should be:
     787                 :             :     // transaction  ancestors           descendants
     788                 :             :     // ============ =================== ===========
     789                 :             :     // ta           1 (ta               4 (ta,tb,tc,td)
     790                 :             :     // tb           2 (ta,tb)           4 (ta,tb,tc,td)
     791                 :             :     // tc           3 (ta,tb,tc)        4 (ta,tb,tc,td)
     792                 :             :     // td           4 (ta,tb,tc,td)     4 (ta,tb,tc,td)
     793         [ +  - ]:           1 :     pool.GetTransactionAncestry(ta->GetHash(), ancestors, descendants);
     794   [ +  -  +  - ]:           1 :     BOOST_CHECK_EQUAL(ancestors, 1ULL);
     795   [ +  -  +  - ]:           1 :     BOOST_CHECK_EQUAL(descendants, 4ULL);
     796         [ +  - ]:           1 :     pool.GetTransactionAncestry(tb->GetHash(), ancestors, descendants);
     797   [ +  -  +  - ]:           1 :     BOOST_CHECK_EQUAL(ancestors, 2ULL);
     798   [ +  -  +  - ]:           1 :     BOOST_CHECK_EQUAL(descendants, 4ULL);
     799         [ +  - ]:           1 :     pool.GetTransactionAncestry(tc->GetHash(), ancestors, descendants);
     800   [ +  -  +  - ]:           1 :     BOOST_CHECK_EQUAL(ancestors, 3ULL);
     801   [ +  -  +  - ]:           1 :     BOOST_CHECK_EQUAL(descendants, 4ULL);
     802         [ +  - ]:           1 :     pool.GetTransactionAncestry(td->GetHash(), ancestors, descendants);
     803   [ +  -  +  - ]:           1 :     BOOST_CHECK_EQUAL(ancestors, 4ULL);
     804   [ +  -  +  -  :           1 :     BOOST_CHECK_EQUAL(descendants, 4ULL);
                   +  - ]
     805   [ +  -  +  -  :          13 : }
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
             -  +  -  +  
                      - ]
     806                 :             : 
     807                 :             : BOOST_AUTO_TEST_SUITE_END()
        

Generated by: LCOV version 2.0-1