LCOV - code coverage report
Current view: top level - src/policy - ephemeral_policy.cpp (source / functions) Coverage Total Hit
Test: total_coverage.info Lines: 100.0 % 36 36
Test Date: 2025-01-19 05:08:01 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                 :       30116 : 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   [ +  +  +  +  :       60118 :     if ((base_fee != 0 || mod_fee != 0) && !GetDust(tx, dust_relay_rate).empty()) {
                   +  + ]
      27   [ +  -  +  - ]:          87 :         return state.Invalid(TxValidationResult::TX_NOT_STANDARD, "dust", "tx with dust output must be 0-fee");
      28                 :             :     }
      29                 :             : 
      30                 :             :     return true;
      31                 :             : }
      32                 :             : 
      33                 :       29210 : bool CheckEphemeralSpends(const Package& package, CFeeRate dust_relay_rate, const CTxMemPool& tx_pool, TxValidationState& out_child_state, Txid& out_child_txid)
      34                 :             : {
      35   [ +  -  +  - ]:       58969 :     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                 :       29210 :     std::map<Txid, CTransactionRef> map_txid_ref;
      41         [ +  + ]:       58969 :     for (const auto& tx : package) {
      42         [ +  - ]:       29759 :         map_txid_ref[tx->GetHash()] = tx;
      43                 :             :     }
      44                 :             : 
      45         [ +  + ]:       58957 :     for (const auto& tx : package) {
      46         [ +  - ]:       29758 :         std::unordered_set<Txid, SaltedTxidHasher> processed_parent_set;
      47         [ +  - ]:       29758 :         std::unordered_set<COutPoint, SaltedOutpointHasher> unspent_parent_dust;
      48                 :             : 
      49         [ +  + ]:       82241 :         for (const auto& tx_input : tx->vin) {
      50                 :       52483 :             const Txid& parent_txid{tx_input.prevout.hash};
      51                 :             :             // Skip parents we've already checked dust for
      52   [ +  -  +  + ]:       52483 :             if (processed_parent_set.contains(parent_txid)) continue;
      53                 :             : 
      54                 :             :             // We look for an in-package or in-mempool dependency
      55                 :       49596 :             CTransactionRef parent_ref = nullptr;
      56         [ +  + ]:       49596 :             if (auto it = map_txid_ref.find(parent_txid); it != map_txid_ref.end()) {
      57                 :         534 :                 parent_ref = it->second;
      58                 :             :             } else {
      59   [ +  -  -  + ]:       98124 :                 parent_ref = tx_pool.get(parent_txid);
      60                 :             :             }
      61                 :             : 
      62                 :             :             // Check for dust on parents
      63         [ +  + ]:       49596 :             if (parent_ref) {
      64         [ +  + ]:      151451 :                 for (uint32_t out_index = 0; out_index < parent_ref->vout.size(); out_index++) {
      65         [ +  - ]:      145155 :                     const auto& tx_output = parent_ref->vout[out_index];
      66   [ +  -  +  + ]:      145155 :                     if (IsDust(tx_output, dust_relay_rate)) {
      67         [ +  - ]:         193 :                         unspent_parent_dust.insert(COutPoint(parent_txid, out_index));
      68                 :             :                     }
      69                 :             :                 }
      70                 :             :             }
      71                 :             : 
      72   [ +  -  +  + ]:       49596 :             processed_parent_set.insert(parent_txid);
      73                 :       49596 :         }
      74                 :             : 
      75         [ +  + ]:       29758 :         if (unspent_parent_dust.empty()) {
      76                 :       29711 :             continue;
      77                 :             :         }
      78                 :             : 
      79                 :             :         // Now that we have gathered parents' dust, make sure it's spent
      80                 :             :         // by the child
      81         [ +  + ]:         406 :         for (const auto& tx_input : tx->vin) {
      82                 :         359 :             unspent_parent_dust.erase(tx_input.prevout);
      83                 :             :         }
      84                 :             : 
      85         [ +  + ]:          47 :         if (!unspent_parent_dust.empty()) {
      86         [ +  - ]:          11 :             out_child_txid = tx->GetHash();
      87   [ +  -  +  -  :          33 :             out_child_state.Invalid(TxValidationResult::TX_MEMPOOL_POLICY, "missing-ephemeral-spends",
                   +  - ]
      88         [ +  - ]:          22 :                                 strprintf("tx %s did not spend parent's ephemeral dust", out_child_txid.ToString()));
      89                 :          11 :             return false;
      90                 :             :         }
      91                 :       29758 :     }
      92                 :             : 
      93                 :             :     return true;
      94                 :       29210 : }
        

Generated by: LCOV version 2.0-1