LCOV - code coverage report
Current view: top level - src/policy - ephemeral_policy.cpp (source / functions) Coverage Total Hit
Test: fuzz_coverage.info Lines: 100.0 % 36 36
Test Date: 2024-12-04 04:00:22 Functions: 100.0 % 2 2
Branches: 72.1 % 68 49

             Branch data     Line data    Source code
       1                 :             : // Copyright (c) 2024-present 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 <policy/ephemeral_policy.h>
       7                 :             : #include <policy/feerate.h>
       8                 :             : #include <policy/packages.h>
       9                 :             : #include <policy/policy.h>
      10                 :             : #include <primitives/transaction.h>
      11                 :             : #include <txmempool.h>
      12                 :             : #include <util/check.h>
      13                 :             : #include <util/hasher.h>
      14                 :             : 
      15                 :             : #include <algorithm>
      16                 :             : #include <cstdint>
      17                 :             : #include <map>
      18                 :             : #include <memory>
      19                 :             : #include <unordered_set>
      20                 :             : #include <utility>
      21                 :             : #include <vector>
      22                 :             : 
      23                 :      202659 : bool PreCheckEphemeralTx(const CTransaction& tx, CFeeRate dust_relay_rate, CAmount base_fee, CAmount mod_fee, TxValidationState& state)
      24                 :             : {
      25                 :             :     // We never want to give incentives to mine this transaction alone
      26   [ +  +  +  +  :      391067 :     if ((base_fee != 0 || mod_fee != 0) && !GetDust(tx, dust_relay_rate).empty()) {
                   +  + ]
      27   [ +  -  +  - ]:       37489 :         return state.Invalid(TxValidationResult::TX_NOT_STANDARD, "dust", "tx with dust output must be 0-fee");
      28                 :             :     }
      29                 :             : 
      30                 :             :     return true;
      31                 :             : }
      32                 :             : 
      33                 :      110429 : bool CheckEphemeralSpends(const Package& package, CFeeRate dust_relay_rate, const CTxMemPool& tx_pool, TxValidationState& out_child_state, Txid& out_child_txid)
      34                 :             : {
      35   [ +  -  +  - ]:      221228 :     if (!Assume(std::ranges::all_of(package, [](const auto& tx){return tx != nullptr;}))) {
      36                 :             :         // Bail out of spend checks if caller gave us an invalid package
      37                 :             :         return true;
      38                 :             :     }
      39                 :             : 
      40                 :      110429 :     std::map<Txid, CTransactionRef> map_txid_ref;
      41         [ +  + ]:      221228 :     for (const auto& tx : package) {
      42         [ +  - ]:      110799 :         map_txid_ref[tx->GetHash()] = tx;
      43                 :             :     }
      44                 :             : 
      45         [ +  + ]:      219467 :     for (const auto& tx : package) {
      46         [ +  - ]:      110799 :         std::unordered_set<Txid, SaltedTxidHasher> processed_parent_set;
      47         [ +  - ]:      110799 :         std::unordered_set<COutPoint, SaltedOutpointHasher> unspent_parent_dust;
      48                 :             : 
      49         [ +  + ]:      330016 :         for (const auto& tx_input : tx->vin) {
      50                 :      219217 :             const Txid& parent_txid{tx_input.prevout.hash};
      51                 :             :             // Skip parents we've already checked dust for
      52   [ +  -  +  + ]:      219217 :             if (processed_parent_set.contains(parent_txid)) continue;
      53                 :             : 
      54                 :             :             // We look for an in-package or in-mempool dependency
      55                 :      209880 :             CTransactionRef parent_ref = nullptr;
      56         [ +  + ]:      209880 :             if (auto it = map_txid_ref.find(parent_txid); it != map_txid_ref.end()) {
      57                 :         370 :                 parent_ref = it->second;
      58                 :             :             } else {
      59   [ +  -  -  + ]:      419020 :                 parent_ref = tx_pool.get(parent_txid);
      60                 :             :             }
      61                 :             : 
      62                 :             :             // Check for dust on parents
      63         [ +  + ]:      209880 :             if (parent_ref) {
      64         [ +  + ]:      881944 :                 for (uint32_t out_index = 0; out_index < parent_ref->vout.size(); out_index++) {
      65         [ +  - ]:      830555 :                     const auto& tx_output = parent_ref->vout[out_index];
      66   [ +  -  +  + ]:      830555 :                     if (IsDust(tx_output, dust_relay_rate)) {
      67         [ +  - ]:        3195 :                         unspent_parent_dust.insert(COutPoint(parent_txid, out_index));
      68                 :             :                     }
      69                 :             :                 }
      70                 :             :             }
      71                 :             : 
      72   [ +  -  +  + ]:      209880 :             processed_parent_set.insert(parent_txid);
      73                 :      209880 :         }
      74                 :             : 
      75         [ +  + ]:      110799 :         if (unspent_parent_dust.empty()) {
      76                 :      108213 :             continue;
      77                 :             :         }
      78                 :             : 
      79                 :             :         // Now that we have gathered parents' dust, make sure it's spent
      80                 :             :         // by the child
      81         [ +  + ]:        7247 :         for (const auto& tx_input : tx->vin) {
      82                 :        4661 :             unspent_parent_dust.erase(tx_input.prevout);
      83                 :             :         }
      84                 :             : 
      85         [ +  + ]:        2586 :         if (!unspent_parent_dust.empty()) {
      86         [ +  - ]:        1761 :             out_child_txid = tx->GetHash();
      87   [ +  -  +  -  :        5283 :             out_child_state.Invalid(TxValidationResult::TX_MEMPOOL_POLICY, "missing-ephemeral-spends",
                   +  - ]
      88         [ +  - ]:        3522 :                                 strprintf("tx %s did not spend parent's ephemeral dust", out_child_txid.ToString()));
      89                 :        1761 :             return false;
      90                 :             :         }
      91                 :      110799 :     }
      92                 :             : 
      93                 :             :     return true;
      94                 :      110429 : }
        

Generated by: LCOV version 2.0-1