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