LCOV - code coverage report
Current view: top level - src/test - txvalidation_tests.cpp (source / functions) Coverage Total Hit
Test: test_bitcoin_coverage.info Lines: 99.2 % 256 254
Test Date: 2024-11-04 04:45:35 Functions: 100.0 % 7 7
Branches: 49.7 % 1130 562

             Branch data     Line data    Source code
       1                 :             : // Copyright (c) 2017-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 <consensus/validation.h>
       6                 :             : #include <key_io.h>
       7                 :             : #include <policy/packages.h>
       8                 :             : #include <policy/policy.h>
       9                 :             : #include <policy/truc_policy.h>
      10                 :             : #include <primitives/transaction.h>
      11                 :             : #include <random.h>
      12                 :             : #include <script/script.h>
      13                 :             : #include <test/util/setup_common.h>
      14                 :             : #include <test/util/txmempool.h>
      15                 :             : #include <validation.h>
      16                 :             : 
      17                 :             : #include <boost/test/unit_test.hpp>
      18                 :             : 
      19                 :             : 
      20                 :             : BOOST_AUTO_TEST_SUITE(txvalidation_tests)
      21                 :             : 
      22                 :             : /**
      23                 :             :  * Ensure that the mempool won't accept coinbase transactions.
      24                 :             :  */
      25   [ +  -  +  -  :           7 : BOOST_FIXTURE_TEST_CASE(tx_mempool_reject_coinbase, TestChain100Setup)
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
                      - ]
      26                 :             : {
      27   [ +  -  +  -  :           1 :     CScript scriptPubKey = CScript() << ToByteVector(coinbaseKey.GetPubKey()) << OP_CHECKSIG;
                   +  - ]
      28         [ +  - ]:           1 :     CMutableTransaction coinbaseTx;
      29                 :             : 
      30                 :           1 :     coinbaseTx.version = 1;
      31         [ +  - ]:           1 :     coinbaseTx.vin.resize(1);
      32         [ +  - ]:           1 :     coinbaseTx.vout.resize(1);
      33   [ +  -  +  - ]:           1 :     coinbaseTx.vin[0].scriptSig = CScript() << OP_11 << OP_EQUAL;
      34                 :           1 :     coinbaseTx.vout[0].nValue = 1 * CENT;
      35                 :           1 :     coinbaseTx.vout[0].scriptPubKey = scriptPubKey;
      36                 :             : 
      37   [ +  -  +  -  :           3 :     BOOST_CHECK(CTransaction(coinbaseTx).IsCoinBase());
             +  -  +  - ]
      38                 :             : 
      39         [ +  - ]:           1 :     LOCK(cs_main);
      40                 :             : 
      41         [ +  - ]:           1 :     unsigned int initialPoolSize = m_node.mempool->size();
      42   [ +  -  +  - ]:           2 :     const MempoolAcceptResult result = m_node.chainman->ProcessTransaction(MakeTransactionRef(coinbaseTx));
      43                 :             : 
      44   [ +  -  +  -  :           2 :     BOOST_CHECK(result.m_result_type == MempoolAcceptResult::ResultType::INVALID);
                   +  - ]
      45                 :             : 
      46                 :             :     // Check that the transaction hasn't been added to mempool.
      47   [ +  -  +  -  :           1 :     BOOST_CHECK_EQUAL(m_node.mempool->size(), initialPoolSize);
                   +  - ]
      48                 :             : 
      49                 :             :     // Check that the validation state reflects the unsuccessful attempt.
      50   [ +  -  +  -  :           2 :     BOOST_CHECK(result.m_state.IsInvalid());
                   +  - ]
      51   [ +  -  +  -  :           1 :     BOOST_CHECK_EQUAL(result.m_state.GetRejectReason(), "coinbase");
                   +  - ]
      52   [ +  -  +  - ]:           2 :     BOOST_CHECK(result.m_state.GetResult() == TxValidationResult::TX_CONSENSUS);
      53         [ +  - ]:           3 : }
      54                 :             : 
      55                 :             : // Generate a number of random, nonexistent outpoints.
      56                 :           8 : static inline std::vector<COutPoint> random_outpoints(size_t num_outpoints) {
      57                 :           8 :     std::vector<COutPoint> outpoints;
      58         [ +  + ]:         125 :     for (size_t i{0}; i < num_outpoints; ++i) {
      59         [ +  - ]:         117 :         outpoints.emplace_back(Txid::FromUint256(GetRandHash()), 0);
      60                 :             :     }
      61                 :           8 :     return outpoints;
      62                 :           0 : }
      63                 :             : 
      64                 :           1 : static inline std::vector<CPubKey> random_keys(size_t num_keys) {
      65                 :           1 :     std::vector<CPubKey> keys;
      66         [ +  - ]:           1 :     keys.reserve(num_keys);
      67         [ +  + ]:           3 :     for (size_t i{0}; i < num_keys; ++i) {
      68                 :           2 :         CKey key;
      69         [ +  - ]:           2 :         key.MakeNewKey(true);
      70   [ +  -  +  - ]:           2 :         keys.emplace_back(key.GetPubKey());
      71                 :           2 :     }
      72                 :           1 :     return keys;
      73                 :           0 : }
      74                 :             : 
      75                 :             : // Creates a placeholder tx (not valid) with 25 outputs. Specify the version and the inputs.
      76                 :          22 : static inline CTransactionRef make_tx(const std::vector<COutPoint>& inputs, int32_t version)
      77                 :             : {
      78                 :          22 :     CMutableTransaction mtx = CMutableTransaction{};
      79                 :          22 :     mtx.version = version;
      80         [ +  - ]:          22 :     mtx.vin.resize(inputs.size());
      81         [ +  - ]:          22 :     mtx.vout.resize(25);
      82         [ +  + ]:         149 :     for (size_t i{0}; i < inputs.size(); ++i) {
      83                 :         127 :         mtx.vin[i].prevout = inputs[i];
      84                 :             :     }
      85         [ +  + ]:         572 :     for (auto i{0}; i < 25; ++i) {
      86         [ +  - ]:         550 :         mtx.vout[i].scriptPubKey = CScript() << OP_TRUE;
      87                 :         550 :         mtx.vout[i].nValue = 10000;
      88                 :             :     }
      89         [ +  - ]:          44 :     return MakeTransactionRef(mtx);
      90                 :          22 : }
      91                 :             : 
      92   [ +  -  +  -  :           7 : BOOST_FIXTURE_TEST_CASE(version3_tests, RegTestingSetup)
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
          -  +  -  +  -  
          +  -  +  -  +  
                      - ]
      93                 :             : {
      94                 :             :     // Test TRUC policy helper functions
      95                 :           1 :     CTxMemPool& pool = *Assert(m_node.mempool);
      96         [ +  - ]:           1 :     LOCK2(cs_main, pool.cs);
      97                 :           1 :     TestMemPoolEntryHelper entry;
      98         [ +  - ]:           1 :     std::set<Txid> empty_conflicts_set;
      99                 :           1 :     CTxMemPool::setEntries empty_ancestors;
     100                 :             : 
     101   [ +  -  +  - ]:           1 :     auto mempool_tx_v3 = make_tx(random_outpoints(1), /*version=*/3);
     102   [ +  -  +  - ]:           1 :     pool.addUnchecked(entry.FromTx(mempool_tx_v3));
     103   [ +  -  +  - ]:           1 :     auto mempool_tx_v2 = make_tx(random_outpoints(1), /*version=*/2);
     104   [ +  -  +  - ]:           1 :     pool.addUnchecked(entry.FromTx(mempool_tx_v2));
     105                 :             :     // Default values.
     106                 :           1 :     CTxMemPool::Limits m_limits{};
     107                 :             : 
     108                 :             :     // Cannot spend from an unconfirmed TRUC transaction unless this tx is also TRUC.
     109                 :           1 :     {
     110                 :             :         // mempool_tx_v3
     111                 :             :         //      ^
     112                 :             :         // tx_v2_from_v3
     113   [ +  -  +  -  :           2 :         auto tx_v2_from_v3 = make_tx({COutPoint{mempool_tx_v3->GetHash(), 0}}, /*version=*/2);
                   +  - ]
     114   [ +  -  +  - ]:           1 :         auto ancestors_v2_from_v3{pool.CalculateMemPoolAncestors(entry.FromTx(tx_v2_from_v3), m_limits)};
     115         [ +  - ]:           1 :         const auto expected_error_str{strprintf("non-version=3 tx %s (wtxid=%s) cannot spend from version=3 tx %s (wtxid=%s)",
     116   [ +  -  +  - ]:           2 :             tx_v2_from_v3->GetHash().ToString(), tx_v2_from_v3->GetWitnessHash().ToString(),
     117   [ +  -  +  -  :           3 :             mempool_tx_v3->GetHash().ToString(), mempool_tx_v3->GetWitnessHash().ToString())};
             +  -  +  - ]
     118   [ +  -  +  - ]:           1 :         auto result_v2_from_v3{SingleTRUCChecks(tx_v2_from_v3, *ancestors_v2_from_v3, empty_conflicts_set, GetVirtualTransactionSize(*tx_v2_from_v3))};
     119   [ +  -  +  - ]:           1 :         BOOST_CHECK_EQUAL(result_v2_from_v3->first, expected_error_str);
     120   [ +  -  +  - ]:           1 :         BOOST_CHECK_EQUAL(result_v2_from_v3->second, nullptr);
     121                 :             : 
     122   [ +  +  +  -  :           3 :         Package package_v3_v2{mempool_tx_v3, tx_v2_from_v3};
             -  -  -  - ]
     123   [ +  -  +  -  :           1 :         BOOST_CHECK_EQUAL(*PackageTRUCChecks(tx_v2_from_v3, GetVirtualTransactionSize(*tx_v2_from_v3), package_v3_v2, empty_ancestors), expected_error_str);
             +  -  +  - ]
     124   [ +  -  +  - ]:           2 :         CTxMemPool::setEntries entries_mempool_v3{pool.GetIter(mempool_tx_v3->GetHash().ToUint256()).value()};
     125   [ +  -  +  -  :           3 :         BOOST_CHECK_EQUAL(*PackageTRUCChecks(tx_v2_from_v3, GetVirtualTransactionSize(*tx_v2_from_v3), {tx_v2_from_v3}, entries_mempool_v3), expected_error_str);
          +  -  +  -  +  
          +  +  -  -  -  
                   -  - ]
     126                 :             : 
     127                 :             :         // mempool_tx_v3  mempool_tx_v2
     128                 :             :         //            ^    ^
     129                 :             :         //    tx_v2_from_v2_and_v3
     130   [ +  -  +  -  :           2 :         auto tx_v2_from_v2_and_v3 = make_tx({COutPoint{mempool_tx_v3->GetHash(), 0}, COutPoint{mempool_tx_v2->GetHash(), 0}}, /*version=*/2);
                   +  - ]
     131   [ +  -  +  - ]:           1 :         auto ancestors_v2_from_both{pool.CalculateMemPoolAncestors(entry.FromTx(tx_v2_from_v2_and_v3), m_limits)};
     132         [ +  - ]:           1 :         const auto expected_error_str_2{strprintf("non-version=3 tx %s (wtxid=%s) cannot spend from version=3 tx %s (wtxid=%s)",
     133   [ +  -  +  - ]:           2 :             tx_v2_from_v2_and_v3->GetHash().ToString(), tx_v2_from_v2_and_v3->GetWitnessHash().ToString(),
     134   [ +  -  +  -  :           3 :             mempool_tx_v3->GetHash().ToString(), mempool_tx_v3->GetWitnessHash().ToString())};
             +  -  +  - ]
     135   [ +  -  +  - ]:           1 :         auto result_v2_from_both{SingleTRUCChecks(tx_v2_from_v2_and_v3, *ancestors_v2_from_both, empty_conflicts_set, GetVirtualTransactionSize(*tx_v2_from_v2_and_v3))};
     136   [ +  -  +  - ]:           1 :         BOOST_CHECK_EQUAL(result_v2_from_both->first, expected_error_str_2);
     137   [ +  -  +  - ]:           1 :         BOOST_CHECK_EQUAL(result_v2_from_both->second, nullptr);
     138                 :             : 
     139   [ +  +  +  -  :           4 :         Package package_v3_v2_v2{mempool_tx_v3, mempool_tx_v2, tx_v2_from_v2_and_v3};
             -  -  -  - ]
     140   [ +  -  +  -  :           1 :         BOOST_CHECK_EQUAL(*PackageTRUCChecks(tx_v2_from_v2_and_v3, GetVirtualTransactionSize(*tx_v2_from_v2_and_v3), package_v3_v2_v2, empty_ancestors), expected_error_str_2);
             +  -  +  - ]
     141   [ +  -  +  - ]:           2 :     }
     142                 :             : 
     143                 :             :     // TRUC cannot spend from an unconfirmed non-TRUC transaction.
     144                 :           1 :     {
     145                 :             :         // mempool_tx_v2
     146                 :             :         //      ^
     147                 :             :         // tx_v3_from_v2
     148   [ +  -  +  -  :           2 :         auto tx_v3_from_v2 = make_tx({COutPoint{mempool_tx_v2->GetHash(), 0}}, /*version=*/3);
                   +  - ]
     149   [ +  -  +  - ]:           1 :         auto ancestors_v3_from_v2{pool.CalculateMemPoolAncestors(entry.FromTx(tx_v3_from_v2), m_limits)};
     150         [ +  - ]:           1 :         const auto expected_error_str{strprintf("version=3 tx %s (wtxid=%s) cannot spend from non-version=3 tx %s (wtxid=%s)",
     151   [ +  -  +  - ]:           2 :             tx_v3_from_v2->GetHash().ToString(), tx_v3_from_v2->GetWitnessHash().ToString(),
     152   [ +  -  +  -  :           3 :             mempool_tx_v2->GetHash().ToString(), mempool_tx_v2->GetWitnessHash().ToString())};
             +  -  +  - ]
     153   [ +  -  +  - ]:           1 :         auto result_v3_from_v2{SingleTRUCChecks(tx_v3_from_v2, *ancestors_v3_from_v2,  empty_conflicts_set, GetVirtualTransactionSize(*tx_v3_from_v2))};
     154   [ +  -  +  - ]:           1 :         BOOST_CHECK_EQUAL(result_v3_from_v2->first, expected_error_str);
     155   [ +  -  +  - ]:           1 :         BOOST_CHECK_EQUAL(result_v3_from_v2->second, nullptr);
     156                 :             : 
     157   [ +  +  +  -  :           3 :         Package package_v2_v3{mempool_tx_v2, tx_v3_from_v2};
             -  -  -  - ]
     158   [ +  -  +  -  :           1 :         BOOST_CHECK_EQUAL(*PackageTRUCChecks(tx_v3_from_v2, GetVirtualTransactionSize(*tx_v3_from_v2), package_v2_v3, empty_ancestors), expected_error_str);
             +  -  +  - ]
     159   [ +  -  +  - ]:           2 :         CTxMemPool::setEntries entries_mempool_v2{pool.GetIter(mempool_tx_v2->GetHash().ToUint256()).value()};
     160   [ +  -  +  -  :           3 :         BOOST_CHECK_EQUAL(*PackageTRUCChecks(tx_v3_from_v2, GetVirtualTransactionSize(*tx_v3_from_v2), {tx_v3_from_v2}, entries_mempool_v2), expected_error_str);
          +  -  +  -  +  
          +  +  -  -  -  
                   -  - ]
     161                 :             : 
     162                 :             :         // mempool_tx_v3  mempool_tx_v2
     163                 :             :         //            ^    ^
     164                 :             :         //    tx_v3_from_v2_and_v3
     165   [ +  -  +  -  :           2 :         auto tx_v3_from_v2_and_v3 = make_tx({COutPoint{mempool_tx_v3->GetHash(), 0}, COutPoint{mempool_tx_v2->GetHash(), 0}}, /*version=*/3);
                   +  - ]
     166   [ +  -  +  - ]:           1 :         auto ancestors_v3_from_both{pool.CalculateMemPoolAncestors(entry.FromTx(tx_v3_from_v2_and_v3), m_limits)};
     167         [ +  - ]:           1 :         const auto expected_error_str_2{strprintf("version=3 tx %s (wtxid=%s) cannot spend from non-version=3 tx %s (wtxid=%s)",
     168   [ +  -  +  - ]:           2 :             tx_v3_from_v2_and_v3->GetHash().ToString(), tx_v3_from_v2_and_v3->GetWitnessHash().ToString(),
     169   [ +  -  +  -  :           3 :             mempool_tx_v2->GetHash().ToString(), mempool_tx_v2->GetWitnessHash().ToString())};
             +  -  +  - ]
     170   [ +  -  +  - ]:           1 :         auto result_v3_from_both{SingleTRUCChecks(tx_v3_from_v2_and_v3, *ancestors_v3_from_both, empty_conflicts_set, GetVirtualTransactionSize(*tx_v3_from_v2_and_v3))};
     171   [ +  -  +  - ]:           1 :         BOOST_CHECK_EQUAL(result_v3_from_both->first, expected_error_str_2);
     172   [ +  -  +  - ]:           1 :         BOOST_CHECK_EQUAL(result_v3_from_both->second, nullptr);
     173                 :             : 
     174                 :             :         // tx_v3_from_v2_and_v3 also violates TRUC_ANCESTOR_LIMIT.
     175         [ +  - ]:           1 :         const auto expected_error_str_3{strprintf("tx %s (wtxid=%s) would have too many ancestors",
     176   [ +  -  +  -  :           2 :             tx_v3_from_v2_and_v3->GetHash().ToString(), tx_v3_from_v2_and_v3->GetWitnessHash().ToString())};
                   +  - ]
     177   [ +  +  +  -  :           4 :         Package package_v3_v2_v3{mempool_tx_v3, mempool_tx_v2, tx_v3_from_v2_and_v3};
             -  -  -  - ]
     178   [ +  -  +  -  :           1 :         BOOST_CHECK_EQUAL(*PackageTRUCChecks(tx_v3_from_v2_and_v3, GetVirtualTransactionSize(*tx_v3_from_v2_and_v3), package_v3_v2_v3, empty_ancestors), expected_error_str_3);
             +  -  +  - ]
     179   [ +  -  +  - ]:           2 :     }
     180                 :             :     // V3 from V3 is ok, and non-V3 from non-V3 is ok.
     181                 :           1 :     {
     182                 :             :         // mempool_tx_v3
     183                 :             :         //      ^
     184                 :             :         // tx_v3_from_v3
     185   [ +  -  +  -  :           2 :         auto tx_v3_from_v3 = make_tx({COutPoint{mempool_tx_v3->GetHash(), 0}}, /*version=*/3);
                   +  - ]
     186   [ +  -  +  - ]:           1 :         auto ancestors_v3{pool.CalculateMemPoolAncestors(entry.FromTx(tx_v3_from_v3), m_limits)};
     187   [ +  -  +  -  :           2 :         BOOST_CHECK(SingleTRUCChecks(tx_v3_from_v3, *ancestors_v3, empty_conflicts_set, GetVirtualTransactionSize(*tx_v3_from_v3))
          +  -  +  -  +  
                      - ]
     188                 :             :                     == std::nullopt);
     189                 :             : 
     190   [ +  +  +  -  :           3 :         Package package_v3_v3{mempool_tx_v3, tx_v3_from_v3};
             -  -  -  - ]
     191   [ +  -  +  -  :           2 :         BOOST_CHECK(PackageTRUCChecks(tx_v3_from_v3, GetVirtualTransactionSize(*tx_v3_from_v3), package_v3_v3, empty_ancestors) == std::nullopt);
          +  -  +  -  +  
                      - ]
     192                 :             : 
     193                 :             :         // mempool_tx_v2
     194                 :             :         //      ^
     195                 :             :         // tx_v2_from_v2
     196   [ +  -  +  -  :           2 :         auto tx_v2_from_v2 = make_tx({COutPoint{mempool_tx_v2->GetHash(), 0}}, /*version=*/2);
                   +  - ]
     197   [ +  -  +  - ]:           1 :         auto ancestors_v2{pool.CalculateMemPoolAncestors(entry.FromTx(tx_v2_from_v2), m_limits)};
     198   [ +  -  +  -  :           2 :         BOOST_CHECK(SingleTRUCChecks(tx_v2_from_v2, *ancestors_v2, empty_conflicts_set, GetVirtualTransactionSize(*tx_v2_from_v2))
          +  -  +  -  +  
                      - ]
     199                 :             :                     == std::nullopt);
     200                 :             : 
     201   [ +  +  +  -  :           3 :         Package package_v2_v2{mempool_tx_v2, tx_v2_from_v2};
             -  -  -  - ]
     202   [ +  -  +  -  :           2 :         BOOST_CHECK(PackageTRUCChecks(tx_v2_from_v2, GetVirtualTransactionSize(*tx_v2_from_v2), package_v2_v2, empty_ancestors) == std::nullopt);
             +  -  +  - ]
     203   [ +  -  +  - ]:           2 :     }
     204                 :             : 
     205                 :             :     // Tx spending TRUC cannot have too many mempool ancestors
     206                 :             :     // Configuration where the tx has multiple direct parents.
     207                 :           1 :     {
     208                 :           1 :         Package package_multi_parents;
     209                 :           1 :         std::vector<COutPoint> mempool_outpoints;
     210         [ +  - ]:           1 :         mempool_outpoints.emplace_back(mempool_tx_v3->GetHash(), 0);
     211         [ +  - ]:           1 :         package_multi_parents.emplace_back(mempool_tx_v3);
     212         [ +  + ]:           3 :         for (size_t i{0}; i < 2; ++i) {
     213   [ +  -  +  - ]:           2 :             auto mempool_tx = make_tx(random_outpoints(i + 1), /*version=*/3);
     214   [ +  -  +  - ]:           2 :             pool.addUnchecked(entry.FromTx(mempool_tx));
     215         [ +  - ]:           2 :             mempool_outpoints.emplace_back(mempool_tx->GetHash(), 0);
     216         [ +  - ]:           2 :             package_multi_parents.emplace_back(mempool_tx);
     217                 :           2 :         }
     218         [ +  - ]:           1 :         auto tx_v3_multi_parent = make_tx(mempool_outpoints, /*version=*/3);
     219         [ +  - ]:           1 :         package_multi_parents.emplace_back(tx_v3_multi_parent);
     220   [ +  -  +  - ]:           1 :         auto ancestors{pool.CalculateMemPoolAncestors(entry.FromTx(tx_v3_multi_parent), m_limits)};
     221   [ +  -  +  - ]:           1 :         BOOST_CHECK_EQUAL(ancestors->size(), 3);
     222         [ +  - ]:           1 :         const auto expected_error_str{strprintf("tx %s (wtxid=%s) would have too many ancestors",
     223   [ +  -  +  -  :           2 :             tx_v3_multi_parent->GetHash().ToString(), tx_v3_multi_parent->GetWitnessHash().ToString())};
                   +  - ]
     224   [ +  -  +  - ]:           1 :         auto result{SingleTRUCChecks(tx_v3_multi_parent, *ancestors, empty_conflicts_set, GetVirtualTransactionSize(*tx_v3_multi_parent))};
     225   [ +  -  +  - ]:           1 :         BOOST_CHECK_EQUAL(result->first, expected_error_str);
     226   [ +  -  +  - ]:           1 :         BOOST_CHECK_EQUAL(result->second, nullptr);
     227                 :             : 
     228   [ +  -  +  -  :           1 :         BOOST_CHECK_EQUAL(*PackageTRUCChecks(tx_v3_multi_parent, GetVirtualTransactionSize(*tx_v3_multi_parent), package_multi_parents, empty_ancestors),
             +  -  +  - ]
     229                 :             :                           expected_error_str);
     230         [ +  - ]:           2 :     }
     231                 :             : 
     232                 :             :     // Configuration where the tx is in a multi-generation chain.
     233                 :           1 :     {
     234                 :           1 :         Package package_multi_gen;
     235                 :           1 :         CTransactionRef middle_tx;
     236         [ +  - ]:           1 :         auto last_outpoint{random_outpoints(1)[0]};
     237         [ +  + ]:           3 :         for (size_t i{0}; i < 2; ++i) {
     238   [ +  -  +  -  :           4 :             auto mempool_tx = make_tx({last_outpoint}, /*version=*/3);
                   +  - ]
     239   [ +  -  +  - ]:           2 :             pool.addUnchecked(entry.FromTx(mempool_tx));
     240         [ +  - ]:           2 :             last_outpoint = COutPoint{mempool_tx->GetHash(), 0};
     241         [ +  - ]:           2 :             package_multi_gen.emplace_back(mempool_tx);
     242         [ +  + ]:           2 :             if (i == 1) middle_tx = mempool_tx;
     243                 :           2 :         }
     244   [ +  -  +  -  :           2 :         auto tx_v3_multi_gen = make_tx({last_outpoint}, /*version=*/3);
                   +  - ]
     245         [ +  - ]:           1 :         package_multi_gen.emplace_back(tx_v3_multi_gen);
     246   [ +  -  +  - ]:           1 :         auto ancestors{pool.CalculateMemPoolAncestors(entry.FromTx(tx_v3_multi_gen), m_limits)};
     247         [ +  - ]:           1 :         const auto expected_error_str{strprintf("tx %s (wtxid=%s) would have too many ancestors",
     248   [ +  -  +  -  :           2 :             tx_v3_multi_gen->GetHash().ToString(), tx_v3_multi_gen->GetWitnessHash().ToString())};
                   +  - ]
     249   [ +  -  +  - ]:           1 :         auto result{SingleTRUCChecks(tx_v3_multi_gen, *ancestors, empty_conflicts_set, GetVirtualTransactionSize(*tx_v3_multi_gen))};
     250   [ +  -  +  - ]:           1 :         BOOST_CHECK_EQUAL(result->first, expected_error_str);
     251   [ +  -  +  - ]:           1 :         BOOST_CHECK_EQUAL(result->second, nullptr);
     252                 :             : 
     253                 :             :         // Middle tx is what triggers a failure for the grandchild:
     254   [ +  -  +  -  :           1 :         BOOST_CHECK_EQUAL(*PackageTRUCChecks(middle_tx, GetVirtualTransactionSize(*middle_tx), package_multi_gen, empty_ancestors), expected_error_str);
             +  -  +  - ]
     255   [ +  -  +  -  :           2 :         BOOST_CHECK(PackageTRUCChecks(tx_v3_multi_gen, GetVirtualTransactionSize(*tx_v3_multi_gen), package_multi_gen, empty_ancestors) == std::nullopt);
             +  -  +  - ]
     256   [ +  -  +  - ]:           3 :     }
     257                 :             : 
     258                 :             :     // Tx spending TRUC cannot be too large in virtual size.
     259         [ +  - ]:           1 :     auto many_inputs{random_outpoints(100)};
     260         [ +  - ]:           1 :     many_inputs.emplace_back(mempool_tx_v3->GetHash(), 0);
     261                 :           1 :     {
     262         [ +  - ]:           1 :         auto tx_v3_child_big = make_tx(many_inputs, /*version=*/3);
     263         [ +  - ]:           1 :         const auto vsize{GetVirtualTransactionSize(*tx_v3_child_big)};
     264   [ +  -  +  - ]:           1 :         auto ancestors{pool.CalculateMemPoolAncestors(entry.FromTx(tx_v3_child_big), m_limits)};
     265         [ +  - ]:           1 :         const auto expected_error_str{strprintf("version=3 child tx %s (wtxid=%s) is too big: %u > %u virtual bytes",
     266   [ +  -  +  -  :           2 :             tx_v3_child_big->GetHash().ToString(), tx_v3_child_big->GetWitnessHash().ToString(), vsize, TRUC_CHILD_MAX_VSIZE)};
                   +  - ]
     267   [ +  -  +  - ]:           1 :         auto result{SingleTRUCChecks(tx_v3_child_big, *ancestors, empty_conflicts_set, GetVirtualTransactionSize(*tx_v3_child_big))};
     268   [ +  -  +  - ]:           1 :         BOOST_CHECK_EQUAL(result->first, expected_error_str);
     269   [ +  -  +  - ]:           1 :         BOOST_CHECK_EQUAL(result->second, nullptr);
     270                 :             : 
     271   [ +  +  +  -  :           3 :         Package package_child_big{mempool_tx_v3, tx_v3_child_big};
             -  -  -  - ]
     272   [ +  -  +  -  :           1 :         BOOST_CHECK_EQUAL(*PackageTRUCChecks(tx_v3_child_big, GetVirtualTransactionSize(*tx_v3_child_big), package_child_big, empty_ancestors),
             +  -  +  - ]
     273                 :             :                           expected_error_str);
     274         [ +  - ]:           1 :     }
     275                 :             : 
     276                 :             :     // Tx spending TRUC cannot have too many sigops.
     277                 :             :     // This child has 10 P2WSH multisig inputs.
     278         [ +  - ]:           1 :     auto multisig_outpoints{random_outpoints(10)};
     279         [ +  - ]:           1 :     multisig_outpoints.emplace_back(mempool_tx_v3->GetHash(), 0);
     280         [ +  - ]:           1 :     auto keys{random_keys(2)};
     281                 :           1 :     CScript script_multisig;
     282         [ +  - ]:           1 :     script_multisig << OP_1;
     283         [ +  + ]:           3 :     for (const auto& key : keys) {
     284         [ +  - ]:           2 :         script_multisig << ToByteVector(key);
     285                 :             :     }
     286   [ +  -  +  - ]:           1 :     script_multisig << OP_2 << OP_CHECKMULTISIG;
     287                 :           1 :     {
     288         [ +  - ]:           1 :         CMutableTransaction mtx_many_sigops = CMutableTransaction{};
     289                 :           1 :         mtx_many_sigops.version = TRUC_VERSION;
     290         [ +  + ]:          12 :         for (const auto& outpoint : multisig_outpoints) {
     291         [ +  - ]:          11 :             mtx_many_sigops.vin.emplace_back(outpoint);
     292   [ +  -  +  - ]:          22 :             mtx_many_sigops.vin.back().scriptWitness.stack.emplace_back(script_multisig.begin(), script_multisig.end());
     293                 :             :         }
     294         [ +  - ]:           1 :         mtx_many_sigops.vout.resize(1);
     295         [ +  - ]:           1 :         mtx_many_sigops.vout.back().scriptPubKey = CScript() << OP_TRUE;
     296                 :           1 :         mtx_many_sigops.vout.back().nValue = 10000;
     297         [ +  - ]:           1 :         auto tx_many_sigops{MakeTransactionRef(mtx_many_sigops)};
     298                 :             : 
     299   [ +  -  +  - ]:           1 :         auto ancestors{pool.CalculateMemPoolAncestors(entry.FromTx(tx_many_sigops), m_limits)};
     300                 :             :         // legacy uses fAccurate = false, and the maximum number of multisig keys is used
     301         [ +  - ]:           1 :         const int64_t total_sigops{static_cast<int64_t>(tx_many_sigops->vin.size()) * static_cast<int64_t>(script_multisig.GetSigOpCount(/*fAccurate=*/false))};
     302   [ +  -  +  - ]:           1 :         BOOST_CHECK_EQUAL(total_sigops, tx_many_sigops->vin.size() * MAX_PUBKEYS_PER_MULTISIG);
     303         [ +  - ]:           1 :         const int64_t bip141_vsize{GetVirtualTransactionSize(*tx_many_sigops)};
     304                 :             :         // Weight limit is not reached...
     305   [ +  -  +  -  :           2 :         BOOST_CHECK(SingleTRUCChecks(tx_many_sigops, *ancestors, empty_conflicts_set, bip141_vsize) == std::nullopt);
             +  -  +  - ]
     306                 :             :         // ...but sigop limit is.
     307                 :           1 :         const auto expected_error_str{strprintf("version=3 child tx %s (wtxid=%s) is too big: %u > %u virtual bytes",
     308   [ +  -  +  - ]:           2 :             tx_many_sigops->GetHash().ToString(), tx_many_sigops->GetWitnessHash().ToString(),
     309   [ +  -  +  - ]:           2 :             total_sigops * DEFAULT_BYTES_PER_SIGOP / WITNESS_SCALE_FACTOR, TRUC_CHILD_MAX_VSIZE)};
     310                 :           2 :         auto result{SingleTRUCChecks(tx_many_sigops, *ancestors, empty_conflicts_set,
     311   [ +  -  +  - ]:           1 :                                         GetVirtualTransactionSize(*tx_many_sigops, /*nSigOpCost=*/total_sigops, /*bytes_per_sigop=*/ DEFAULT_BYTES_PER_SIGOP))};
     312   [ +  -  +  - ]:           1 :         BOOST_CHECK_EQUAL(result->first, expected_error_str);
     313   [ +  -  +  - ]:           1 :         BOOST_CHECK_EQUAL(result->second, nullptr);
     314                 :             : 
     315   [ +  +  +  -  :           3 :         Package package_child_sigops{mempool_tx_v3, tx_many_sigops};
             -  -  -  - ]
     316   [ +  -  +  -  :           1 :         BOOST_CHECK_EQUAL(*PackageTRUCChecks(tx_many_sigops, total_sigops * DEFAULT_BYTES_PER_SIGOP / WITNESS_SCALE_FACTOR, package_child_sigops, empty_ancestors),
                   +  - ]
     317                 :             :                           expected_error_str);
     318         [ +  - ]:           2 :     }
     319                 :             : 
     320                 :             :     // Parent + child with TRUC in the mempool. Child is allowed as long as it is under TRUC_CHILD_MAX_VSIZE.
     321   [ +  -  +  -  :           2 :     auto tx_mempool_v3_child = make_tx({COutPoint{mempool_tx_v3->GetHash(), 0}}, /*version=*/3);
                   +  - ]
     322                 :           1 :     {
     323   [ +  -  +  -  :           2 :         BOOST_CHECK(GetTransactionWeight(*tx_mempool_v3_child) <= TRUC_CHILD_MAX_VSIZE * WITNESS_SCALE_FACTOR);
                   +  - ]
     324   [ +  -  +  - ]:           1 :         auto ancestors{pool.CalculateMemPoolAncestors(entry.FromTx(tx_mempool_v3_child), m_limits)};
     325   [ +  -  +  -  :           2 :         BOOST_CHECK(SingleTRUCChecks(tx_mempool_v3_child, *ancestors, empty_conflicts_set, GetVirtualTransactionSize(*tx_mempool_v3_child)) == std::nullopt);
          +  -  +  -  +  
                      - ]
     326   [ +  -  +  - ]:           1 :         pool.addUnchecked(entry.FromTx(tx_mempool_v3_child));
     327                 :             : 
     328   [ +  +  +  -  :           3 :         Package package_v3_1p1c{mempool_tx_v3, tx_mempool_v3_child};
             -  -  -  - ]
     329   [ +  -  +  -  :           2 :         BOOST_CHECK(PackageTRUCChecks(tx_mempool_v3_child, GetVirtualTransactionSize(*tx_mempool_v3_child), package_v3_1p1c, empty_ancestors) == std::nullopt);
             +  -  +  - ]
     330                 :           1 :     }
     331                 :             : 
     332                 :             :     // A TRUC transaction cannot have more than 1 descendant. Sibling is returned when exactly 1 exists.
     333                 :           1 :     {
     334   [ +  -  +  -  :           2 :         auto tx_v3_child2 = make_tx({COutPoint{mempool_tx_v3->GetHash(), 1}}, /*version=*/3);
                   +  - ]
     335                 :             : 
     336                 :             :         // Configuration where parent already has 1 other child in mempool
     337   [ +  -  +  - ]:           1 :         auto ancestors_1sibling{pool.CalculateMemPoolAncestors(entry.FromTx(tx_v3_child2), m_limits)};
     338         [ +  - ]:           1 :         const auto expected_error_str{strprintf("tx %s (wtxid=%s) would exceed descendant count limit",
     339   [ +  -  +  -  :           2 :             mempool_tx_v3->GetHash().ToString(), mempool_tx_v3->GetWitnessHash().ToString())};
                   +  - ]
     340   [ +  -  +  - ]:           1 :         auto result_with_sibling_eviction{SingleTRUCChecks(tx_v3_child2, *ancestors_1sibling, empty_conflicts_set, GetVirtualTransactionSize(*tx_v3_child2))};
     341   [ +  -  +  - ]:           1 :         BOOST_CHECK_EQUAL(result_with_sibling_eviction->first, expected_error_str);
     342                 :             :         // The other mempool child is returned to allow for sibling eviction.
     343   [ +  -  +  - ]:           1 :         BOOST_CHECK_EQUAL(result_with_sibling_eviction->second, tx_mempool_v3_child);
     344                 :             : 
     345                 :             :         // If directly replacing the child, make sure there is no double-counting.
     346   [ +  -  +  -  :           3 :         BOOST_CHECK(SingleTRUCChecks(tx_v3_child2, *ancestors_1sibling, {tx_mempool_v3_child->GetHash()}, GetVirtualTransactionSize(*tx_v3_child2))
          +  -  +  -  +  
                -  +  - ]
     347                 :             :                     == std::nullopt);
     348                 :             : 
     349   [ +  +  +  -  :           4 :         Package package_v3_1p2c{mempool_tx_v3, tx_mempool_v3_child, tx_v3_child2};
             -  -  -  - ]
     350   [ +  -  +  -  :           1 :         BOOST_CHECK_EQUAL(*PackageTRUCChecks(tx_v3_child2, GetVirtualTransactionSize(*tx_v3_child2), package_v3_1p2c, empty_ancestors),
             +  -  +  - ]
     351                 :             :                           expected_error_str);
     352                 :             : 
     353                 :             :         // Configuration where parent already has 2 other children in mempool (no sibling eviction allowed). This may happen as the result of a reorg.
     354   [ +  -  +  - ]:           1 :         pool.addUnchecked(entry.FromTx(tx_v3_child2));
     355   [ +  -  +  -  :           2 :         auto tx_v3_child3 = make_tx({COutPoint{mempool_tx_v3->GetHash(), 24}}, /*version=*/3);
                   +  - ]
     356         [ +  - ]:           1 :         auto entry_mempool_parent = pool.GetIter(mempool_tx_v3->GetHash().ToUint256()).value();
     357   [ +  -  +  - ]:           1 :         BOOST_CHECK_EQUAL(entry_mempool_parent->GetCountWithDescendants(), 3);
     358   [ +  -  +  - ]:           1 :         auto ancestors_2siblings{pool.CalculateMemPoolAncestors(entry.FromTx(tx_v3_child3), m_limits)};
     359                 :             : 
     360   [ +  -  +  - ]:           1 :         auto result_2children{SingleTRUCChecks(tx_v3_child3, *ancestors_2siblings, empty_conflicts_set, GetVirtualTransactionSize(*tx_v3_child3))};
     361   [ +  -  +  - ]:           1 :         BOOST_CHECK_EQUAL(result_2children->first, expected_error_str);
     362                 :             :         // The other mempool child is not returned because sibling eviction is not allowed.
     363   [ +  -  +  - ]:           1 :         BOOST_CHECK_EQUAL(result_2children->second, nullptr);
     364   [ +  -  +  - ]:           2 :     }
     365                 :             : 
     366                 :             :     // Sibling eviction: parent already has 1 other child, which also has its own child (no sibling eviction allowed). This may happen as the result of a reorg.
     367                 :           1 :     {
     368   [ +  -  +  - ]:           1 :         auto tx_mempool_grandparent = make_tx(random_outpoints(1), /*version=*/3);
     369   [ +  -  +  -  :           2 :         auto tx_mempool_sibling = make_tx({COutPoint{tx_mempool_grandparent->GetHash(), 0}}, /*version=*/3);
                   +  - ]
     370   [ +  -  +  -  :           2 :         auto tx_mempool_nibling = make_tx({COutPoint{tx_mempool_sibling->GetHash(), 0}}, /*version=*/3);
                   +  - ]
     371   [ +  -  +  -  :           2 :         auto tx_to_submit = make_tx({COutPoint{tx_mempool_grandparent->GetHash(), 1}}, /*version=*/3);
                   +  - ]
     372                 :             : 
     373   [ +  -  +  - ]:           1 :         pool.addUnchecked(entry.FromTx(tx_mempool_grandparent));
     374   [ +  -  +  - ]:           1 :         pool.addUnchecked(entry.FromTx(tx_mempool_sibling));
     375   [ +  -  +  - ]:           1 :         pool.addUnchecked(entry.FromTx(tx_mempool_nibling));
     376                 :             : 
     377   [ +  -  +  - ]:           1 :         auto ancestors_3gen{pool.CalculateMemPoolAncestors(entry.FromTx(tx_to_submit), m_limits)};
     378         [ +  - ]:           1 :         const auto expected_error_str{strprintf("tx %s (wtxid=%s) would exceed descendant count limit",
     379   [ +  -  +  -  :           2 :             tx_mempool_grandparent->GetHash().ToString(), tx_mempool_grandparent->GetWitnessHash().ToString())};
                   +  - ]
     380   [ +  -  +  - ]:           1 :         auto result_3gen{SingleTRUCChecks(tx_to_submit, *ancestors_3gen, empty_conflicts_set, GetVirtualTransactionSize(*tx_to_submit))};
     381   [ +  -  +  - ]:           1 :         BOOST_CHECK_EQUAL(result_3gen->first, expected_error_str);
     382                 :             :         // The other mempool child is not returned because sibling eviction is not allowed.
     383   [ +  -  +  - ]:           1 :         BOOST_CHECK_EQUAL(result_3gen->second, nullptr);
     384   [ +  -  +  -  :           5 :     }
          +  -  +  -  +  
                      - ]
     385                 :             : 
     386                 :             :     // Configuration where tx has multiple generations of descendants is not tested because that is
     387                 :             :     // equivalent to the tx with multiple generations of ancestors.
     388   [ +  -  +  -  :          42 : }
          -  +  +  -  +  
          -  +  -  +  -  
          +  -  -  +  +  
          -  +  -  -  +  
          +  -  +  -  +  
          -  +  -  +  -  
          -  +  +  -  +  
          -  -  +  +  -  
          +  -  -  +  +  
          -  +  -  -  +  
          +  -  +  -  -  
          +  +  -  +  -  
          -  +  +  -  +  
          -  +  -  -  +  
          +  -  +  -  +  
                -  +  - ]
     389                 :             : 
     390                 :             : BOOST_AUTO_TEST_SUITE_END()
        

Generated by: LCOV version 2.0-1