Bitcoin Core 28.99.0
P2P Digital Currency
ephemeral_policy.cpp
Go to the documentation of this file.
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
7#include <policy/feerate.h>
8#include <policy/packages.h>
9#include <policy/policy.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
23bool 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 if ((base_fee != 0 || mod_fee != 0) && !GetDust(tx, dust_relay_rate).empty()) {
27 return state.Invalid(TxValidationResult::TX_NOT_STANDARD, "dust", "tx with dust output must be 0-fee");
28 }
29
30 return true;
31}
32
33bool CheckEphemeralSpends(const Package& package, CFeeRate dust_relay_rate, const CTxMemPool& tx_pool, TxValidationState& out_child_state, Txid& out_child_txid)
34{
35 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 std::map<Txid, CTransactionRef> map_txid_ref;
41 for (const auto& tx : package) {
42 map_txid_ref[tx->GetHash()] = tx;
43 }
44
45 for (const auto& tx : package) {
46 std::unordered_set<Txid, SaltedTxidHasher> processed_parent_set;
47 std::unordered_set<COutPoint, SaltedOutpointHasher> unspent_parent_dust;
48
49 for (const auto& tx_input : tx->vin) {
50 const Txid& parent_txid{tx_input.prevout.hash};
51 // Skip parents we've already checked dust for
52 if (processed_parent_set.contains(parent_txid)) continue;
53
54 // We look for an in-package or in-mempool dependency
55 CTransactionRef parent_ref = nullptr;
56 if (auto it = map_txid_ref.find(parent_txid); it != map_txid_ref.end()) {
57 parent_ref = it->second;
58 } else {
59 parent_ref = tx_pool.get(parent_txid);
60 }
61
62 // Check for dust on parents
63 if (parent_ref) {
64 for (uint32_t out_index = 0; out_index < parent_ref->vout.size(); out_index++) {
65 const auto& tx_output = parent_ref->vout[out_index];
66 if (IsDust(tx_output, dust_relay_rate)) {
67 unspent_parent_dust.insert(COutPoint(parent_txid, out_index));
68 }
69 }
70 }
71
72 processed_parent_set.insert(parent_txid);
73 }
74
75 if (unspent_parent_dust.empty()) {
76 continue;
77 }
78
79 // Now that we have gathered parents' dust, make sure it's spent
80 // by the child
81 for (const auto& tx_input : tx->vin) {
82 unspent_parent_dust.erase(tx_input.prevout);
83 }
84
85 if (!unspent_parent_dust.empty()) {
86 out_child_txid = tx->GetHash();
87 out_child_state.Invalid(TxValidationResult::TX_MEMPOOL_POLICY, "missing-ephemeral-spends",
88 strprintf("tx %s did not spend parent's ephemeral dust", out_child_txid.ToString()));
89 return false;
90 }
91 }
92
93 return true;
94}
int64_t CAmount
Amount in satoshis (Can be negative)
Definition: amount.h:12
#define Assume(val)
Assume is the identity function.
Definition: check.h:97
Fee rate in satoshis per kilovirtualbyte: CAmount / kvB.
Definition: feerate.h:33
An outpoint - a combination of a transaction hash and an index n into its vout.
Definition: transaction.h:29
The basic transaction that is broadcasted on the network and contained in blocks.
Definition: transaction.h:296
CTxMemPool stores valid-according-to-the-current-best-chain transactions that may be included in the ...
Definition: txmempool.h:304
CTransactionRef get(const uint256 &hash) const
Definition: txmempool.cpp:884
bool Invalid(Result result, const std::string &reject_reason="", const std::string &debug_message="")
Definition: validation.h:89
std::string ToString() const
@ TX_MEMPOOL_POLICY
violated mempool's fee/size/descendant/RBF/etc limits
@ TX_NOT_STANDARD
otherwise didn't meet our local policy rules
bool CheckEphemeralSpends(const Package &package, CFeeRate dust_relay_rate, const CTxMemPool &tx_pool, TxValidationState &out_child_state, Txid &out_child_txid)
Must be called for each transaction(package) if any dust is in the package.
bool PreCheckEphemeralTx(const CTransaction &tx, CFeeRate dust_relay_rate, CAmount base_fee, CAmount mod_fee, TxValidationState &state)
These utility functions ensure that ephemeral dust is safely created and spent without unduly risking...
std::vector< CTransactionRef > Package
A package is an ordered list of transactions.
Definition: packages.h:50
bool IsDust(const CTxOut &txout, const CFeeRate &dustRelayFeeIn)
Definition: policy.cpp:65
std::vector< uint32_t > GetDust(const CTransaction &tx, CFeeRate dust_relay_rate)
Get the vout index numbers of all dust outputs.
Definition: policy.cpp:70
std::shared_ptr< const CTransaction > CTransactionRef
Definition: transaction.h:423
#define strprintf
Format arguments and return the string or write to given std::ostream (see tinyformat::format doc for...
Definition: tinyformat.h:1172