/root/bitcoin/src/policy/ephemeral_policy.cpp
Line | Count | Source (jump to first uncovered line) |
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 <policy/ephemeral_policy.h> |
6 | | #include <policy/policy.h> |
7 | | |
8 | | bool HasDust(const CTransactionRef& tx, CFeeRate dust_relay_rate) |
9 | 0 | { |
10 | 0 | return std::any_of(tx->vout.cbegin(), tx->vout.cend(), [&](const auto& output) { return IsDust(output, dust_relay_rate); }); |
11 | 0 | } |
12 | | |
13 | | bool CheckValidEphemeralTx(const CTransactionRef& tx, CFeeRate dust_relay_rate, CAmount base_fee, CAmount mod_fee, TxValidationState& state) |
14 | 0 | { |
15 | | // We never want to give incentives to mine this transaction alone |
16 | 0 | if ((base_fee != 0 || mod_fee != 0) && HasDust(tx, dust_relay_rate)) { |
17 | 0 | return state.Invalid(TxValidationResult::TX_NOT_STANDARD, "dust", "tx with dust output must be 0-fee"); |
18 | 0 | } |
19 | | |
20 | 0 | return true; |
21 | 0 | } |
22 | | |
23 | | std::optional<Txid> CheckEphemeralSpends(const Package& package, CFeeRate dust_relay_rate, const CTxMemPool& tx_pool) |
24 | 0 | { |
25 | 0 | if (!Assume(std::all_of(package.cbegin(), package.cend(), [](const auto& tx){return tx != nullptr;}))) { |
26 | | // Bail out of spend checks if caller gave us an invalid package |
27 | 0 | return std::nullopt; |
28 | 0 | } |
29 | | |
30 | 0 | std::map<Txid, CTransactionRef> map_txid_ref; |
31 | 0 | for (const auto& tx : package) { |
32 | 0 | map_txid_ref[tx->GetHash()] = tx; |
33 | 0 | } |
34 | |
|
35 | 0 | for (const auto& tx : package) { |
36 | 0 | Txid txid = tx->GetHash(); |
37 | 0 | std::unordered_set<Txid, SaltedTxidHasher> processed_parent_set; |
38 | 0 | std::unordered_set<COutPoint, SaltedOutpointHasher> unspent_parent_dust; |
39 | |
|
40 | 0 | for (const auto& tx_input : tx->vin) { |
41 | 0 | const Txid& parent_txid{tx_input.prevout.hash}; |
42 | | // Skip parents we've already checked dust for |
43 | 0 | if (processed_parent_set.contains(parent_txid)) continue; |
44 | | |
45 | | // We look for an in-package or in-mempool dependency |
46 | 0 | CTransactionRef parent_ref = nullptr; |
47 | 0 | if (auto it = map_txid_ref.find(parent_txid); it != map_txid_ref.end()) { |
48 | 0 | parent_ref = it->second; |
49 | 0 | } else { |
50 | 0 | parent_ref = tx_pool.get(parent_txid); |
51 | 0 | } |
52 | | |
53 | | // Check for dust on parents |
54 | 0 | if (parent_ref) { |
55 | 0 | for (uint32_t out_index = 0; out_index < parent_ref->vout.size(); out_index++) { |
56 | 0 | const auto& tx_output = parent_ref->vout[out_index]; |
57 | 0 | if (IsDust(tx_output, dust_relay_rate)) { |
58 | 0 | unspent_parent_dust.insert(COutPoint(parent_txid, out_index)); |
59 | 0 | } |
60 | 0 | } |
61 | 0 | } |
62 | |
|
63 | 0 | processed_parent_set.insert(parent_txid); |
64 | 0 | } |
65 | | |
66 | | // Now that we have gathered parents' dust, make sure it's spent |
67 | | // by the child |
68 | 0 | for (const auto& tx_input : tx->vin) { |
69 | 0 | unspent_parent_dust.erase(tx_input.prevout); |
70 | 0 | } |
71 | |
|
72 | 0 | if (!unspent_parent_dust.empty()) { |
73 | 0 | return txid; |
74 | 0 | } |
75 | 0 | } |
76 | | |
77 | 0 | return std::nullopt; |
78 | 0 | } |