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

Not modified by patch:
Lines: hit not hit | Branches: + taken - not taken # not executed
Branches: 28 32 87.5 %

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

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