/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 | } |