/root/bitcoin/src/policy/ephemeral_policy.cpp
| Line | Count | Source | 
| 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 |  | bool PreCheckEphemeralTx(const CTransaction& tx, CFeeRate dust_relay_rate, CAmount base_fee, CAmount mod_fee, TxValidationState& state) | 
| 24 | 26.4k | { | 
| 25 |  |     // We never want to give incentives to mine this transaction alone | 
| 26 | 26.4k |     if ((base_fee != 0 || mod_fee != 0) && !GetDust(tx, dust_relay_rate).empty()) { | 
| 27 | 31 |         return state.Invalid(TxValidationResult::TX_NOT_STANDARD, "dust", "tx with dust output must be 0-fee"); | 
| 28 | 31 |     } | 
| 29 |  |  | 
| 30 | 26.3k |     return true; | 
| 31 | 26.4k | } | 
| 32 |  |  | 
| 33 |  | bool CheckEphemeralSpends(const Package& package, CFeeRate dust_relay_rate, const CTxMemPool& tx_pool, TxValidationState& out_child_state, Wtxid& out_child_wtxid) | 
| 34 | 17.4k | { | 
| 35 | 17.4k |     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 | 0 |         return true; | 
| 38 | 0 |     } | 
| 39 |  |  | 
| 40 | 17.4k |     std::map<Txid, CTransactionRef> map_txid_ref; | 
| 41 | 17.4k |     for (const auto& tx : package) { | 
| 42 | 17.4k |         map_txid_ref[tx->GetHash()] = tx; | 
| 43 | 17.4k |     } | 
| 44 |  |  | 
| 45 | 17.4k |     for (const auto& tx : package) { | 
| 46 | 17.4k |         std::unordered_set<Txid, SaltedTxidHasher> processed_parent_set; | 
| 47 | 17.4k |         std::unordered_set<COutPoint, SaltedOutpointHasher> unspent_parent_dust; | 
| 48 |  |  | 
| 49 | 68.8k |         for (const auto& tx_input : tx->vin) { | 
| 50 | 68.8k |             const Txid& parent_txid{tx_input.prevout.hash}; | 
| 51 |  |             // Skip parents we've already checked dust for | 
| 52 | 68.8k |             if (processed_parent_set.contains(parent_txid)) continue; | 
| 53 |  |  | 
| 54 |  |             // We look for an in-package or in-mempool dependency | 
| 55 | 64.0k |             CTransactionRef parent_ref = nullptr; | 
| 56 | 64.0k |             if (auto it = map_txid_ref.find(parent_txid); it != map_txid_ref.end()) { | 
| 57 | 0 |                 parent_ref = it->second; | 
| 58 | 64.0k |             } else { | 
| 59 | 64.0k |                 parent_ref = tx_pool.get(parent_txid); | 
| 60 | 64.0k |             } | 
| 61 |  |  | 
| 62 |  |             // Check for dust on parents | 
| 63 | 64.0k |             if (parent_ref) { | 
| 64 | 208k |                 for (uint32_t out_index = 0; out_index < parent_ref->vout.size(); out_index++) { | 
| 65 | 204k |                     const auto& tx_output = parent_ref->vout[out_index]; | 
| 66 | 204k |                     if (IsDust(tx_output, dust_relay_rate)) { | 
| 67 | 0 |                         unspent_parent_dust.insert(COutPoint(parent_txid, out_index)); | 
| 68 | 0 |                     } | 
| 69 | 204k |                 } | 
| 70 | 4.62k |             } | 
| 71 |  |  | 
| 72 | 64.0k |             processed_parent_set.insert(parent_txid); | 
| 73 | 64.0k |         } | 
| 74 |  |  | 
| 75 | 17.4k |         if (unspent_parent_dust.empty()) { | 
| 76 | 17.4k |             continue; | 
| 77 | 17.4k |         } | 
| 78 |  |  | 
| 79 |  |         // Now that we have gathered parents' dust, make sure it's spent | 
| 80 |  |         // by the child | 
| 81 | 0 |         for (const auto& tx_input : tx->vin) { | 
| 82 | 0 |             unspent_parent_dust.erase(tx_input.prevout); | 
| 83 | 0 |         } | 
| 84 |  | 
 | 
| 85 | 0 |         if (!unspent_parent_dust.empty()) { | 
| 86 | 0 |             const Txid& out_child_txid = tx->GetHash(); | 
| 87 | 0 |             out_child_wtxid = tx->GetWitnessHash(); | 
| 88 | 0 |             out_child_state.Invalid(TxValidationResult::TX_MEMPOOL_POLICY, "missing-ephemeral-spends", | 
| 89 | 0 |                                 strprintf("tx %s (wtxid=%s) did not spend parent's ephemeral dust", out_child_txid.ToString(), out_child_wtxid.ToString())); | 
| 90 | 0 |             return false; | 
| 91 | 0 |         } | 
| 92 | 0 |     } | 
| 93 |  |  | 
| 94 | 17.4k |     return true; | 
| 95 | 17.4k | } |