Bitcoin Core  29.1.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 
5 #include <consensus/validation.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 {
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 
33 bool CheckEphemeralSpends(const Package& package, CFeeRate dust_relay_rate, const CTxMemPool& tx_pool, TxValidationState& out_child_state, Wtxid& out_child_wtxid)
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  const Txid& out_child_txid = tx->GetHash();
87  out_child_wtxid = tx->GetWitnessHash();
88  out_child_state.Invalid(TxValidationResult::TX_MEMPOOL_POLICY, "missing-ephemeral-spends",
89  strprintf("tx %s (wtxid=%s) did not spend parent's ephemeral dust", out_child_txid.ToString(), out_child_wtxid.ToString()));
90  return false;
91  }
92  }
93 
94  return true;
95 }
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
std::vector< CTransactionRef > Package
A package is an ordered list of transactions.
Definition: packages.h:50
violated mempool&#39;s fee/size/descendant/RBF/etc limits
int64_t CAmount
Amount in satoshis (Can be negative)
Definition: amount.h:12
bool Invalid(Result result, const std::string &reject_reason="", const std::string &debug_message="")
Definition: validation.h:89
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::string ToString() const
An outpoint - a combination of a transaction hash and an index n into its vout.
Definition: transaction.h:28
bool CheckEphemeralSpends(const Package &package, CFeeRate dust_relay_rate, const CTxMemPool &tx_pool, TxValidationState &out_child_state, Wtxid &out_child_wtxid)
Must be called for each transaction(package) if any dust is in the package.
#define Assume(val)
Assume is the identity function.
Definition: check.h:97
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
CTxMemPool stores valid-according-to-the-current-best-chain transactions that may be included in the ...
Definition: txmempool.h:303
Fee rate in satoshis per kilovirtualbyte: CAmount / kvB.
Definition: feerate.h:32
bool IsDust(const CTxOut &txout, const CFeeRate &dustRelayFeeIn)
Definition: policy.cpp:65
CTransactionRef get(const uint256 &hash) const
Definition: txmempool.cpp:884
The basic transaction that is broadcasted on the network and contained in blocks. ...
Definition: transaction.h:295
otherwise didn&#39;t meet our local policy rules
transaction_identifier represents the two canonical transaction identifier types (txid, wtxid).