Coverage Report

Created: 2024-11-15 12:18

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