Bitcoin Core  24.99.0
P2P Digital Currency
txorphan.cpp
Go to the documentation of this file.
1 // Copyright (c) 2022 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/amount.h>
6 #include <consensus/validation.h>
7 #include <net_processing.h>
8 #include <node/eviction.h>
9 #include <policy/policy.h>
10 #include <primitives/transaction.h>
11 #include <script/script.h>
12 #include <sync.h>
14 #include <test/fuzz/fuzz.h>
15 #include <test/fuzz/util.h>
16 #include <test/util/setup_common.h>
17 #include <txorphanage.h>
18 #include <uint256.h>
19 #include <util/check.h>
20 #include <util/time.h>
21 
22 #include <cstdint>
23 #include <memory>
24 #include <set>
25 #include <utility>
26 #include <vector>
27 
29 {
30  static const auto testing_setup = MakeNoLogFileContext();
31 }
32 
34 {
35  FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size());
36  SetMockTime(ConsumeTime(fuzzed_data_provider));
37 
38  TxOrphanage orphanage;
39  std::set<uint256> orphan_work_set;
40  std::vector<COutPoint> outpoints;
41  // initial outpoints used to construct transactions later
42  for (uint8_t i = 0; i < 4; i++) {
43  outpoints.emplace_back(uint256{i}, 0);
44  }
45  // if true, allow duplicate input when constructing tx
46  const bool duplicate_input = fuzzed_data_provider.ConsumeBool();
47 
48  LIMITED_WHILE(fuzzed_data_provider.ConsumeBool(), 10 * DEFAULT_MAX_ORPHAN_TRANSACTIONS)
49  {
50  // construct transaction
51  const CTransactionRef tx = [&] {
52  CMutableTransaction tx_mut;
53  const auto num_in = fuzzed_data_provider.ConsumeIntegralInRange<uint32_t>(1, outpoints.size());
54  const auto num_out = fuzzed_data_provider.ConsumeIntegralInRange<uint32_t>(1, outpoints.size());
55  // pick unique outpoints from outpoints as input
56  for (uint32_t i = 0; i < num_in; i++) {
57  auto& prevout = PickValue(fuzzed_data_provider, outpoints);
58  tx_mut.vin.emplace_back(prevout);
59  // pop the picked outpoint if duplicate input is not allowed
60  if (!duplicate_input) {
61  std::swap(prevout, outpoints.back());
62  outpoints.pop_back();
63  }
64  }
65  // output amount will not affect txorphanage
66  for (uint32_t i = 0; i < num_out; i++) {
67  tx_mut.vout.emplace_back(CAmount{0}, CScript{});
68  }
69  // restore previously popped outpoints
70  for (auto& in : tx_mut.vin) {
71  outpoints.push_back(in.prevout);
72  }
73  const auto new_tx = MakeTransactionRef(tx_mut);
74  // add newly constructed transaction to outpoints
75  for (uint32_t i = 0; i < num_out; i++) {
76  outpoints.emplace_back(new_tx->GetHash(), i);
77  }
78  return new_tx;
79  }();
80 
81  // trigger orphanage functions
82  LIMITED_WHILE(fuzzed_data_provider.ConsumeBool(), 10 * DEFAULT_MAX_ORPHAN_TRANSACTIONS)
83  {
84  NodeId peer_id = fuzzed_data_provider.ConsumeIntegral<NodeId>();
85 
86  CallOneOf(
87  fuzzed_data_provider,
88  [&] {
90  orphanage.AddChildrenToWorkSet(*tx, orphan_work_set);
91  },
92  [&] {
93  bool have_tx = orphanage.HaveTx(GenTxid::Txid(tx->GetHash())) || orphanage.HaveTx(GenTxid::Wtxid(tx->GetHash()));
94  {
96  bool get_tx = orphanage.GetTx(tx->GetHash()).first != nullptr;
97  Assert(have_tx == get_tx);
98  }
99  },
100  [&] {
101  bool have_tx = orphanage.HaveTx(GenTxid::Txid(tx->GetHash())) || orphanage.HaveTx(GenTxid::Wtxid(tx->GetHash()));
102  // AddTx should return false if tx is too big or already have it
103  // tx weight is unknown, we only check when tx is already in orphanage
104  {
106  bool add_tx = orphanage.AddTx(tx, peer_id);
107  // have_tx == true -> add_tx == false
108  Assert(!have_tx || !add_tx);
109  }
110  have_tx = orphanage.HaveTx(GenTxid::Txid(tx->GetHash())) || orphanage.HaveTx(GenTxid::Wtxid(tx->GetHash()));
111  {
113  bool add_tx = orphanage.AddTx(tx, peer_id);
114  // if have_tx is still false, it must be too big
115  Assert(!have_tx == (GetTransactionWeight(*tx) > MAX_STANDARD_TX_WEIGHT));
116  Assert(!have_tx || !add_tx);
117  }
118  },
119  [&] {
120  bool have_tx = orphanage.HaveTx(GenTxid::Txid(tx->GetHash())) || orphanage.HaveTx(GenTxid::Wtxid(tx->GetHash()));
121  // EraseTx should return 0 if m_orphans doesn't have the tx
122  {
124  Assert(have_tx == orphanage.EraseTx(tx->GetHash()));
125  }
126  have_tx = orphanage.HaveTx(GenTxid::Txid(tx->GetHash())) || orphanage.HaveTx(GenTxid::Wtxid(tx->GetHash()));
127  // have_tx should be false and EraseTx should fail
128  {
130  Assert(!have_tx && !orphanage.EraseTx(tx->GetHash()));
131  }
132  },
133  [&] {
135  orphanage.EraseForPeer(peer_id);
136  },
137  [&] {
138  // test mocktime and expiry
139  SetMockTime(ConsumeTime(fuzzed_data_provider));
140  auto limit = fuzzed_data_provider.ConsumeIntegral<unsigned int>();
141  WITH_LOCK(g_cs_orphans, orphanage.LimitOrphans(limit));
142  Assert(orphanage.Size() <= limit);
143  });
144  }
145  }
146 }
int64_t CAmount
Amount in satoshis (Can be negative)
Definition: amount.h:12
#define Assert(val)
Identity function.
Definition: check.h:74
Serialized script, used inside transaction inputs and outputs.
Definition: script.h:411
T ConsumeIntegralInRange(T min, T max)
static GenTxid Wtxid(const uint256 &hash)
Definition: transaction.h:426
static GenTxid Txid(const uint256 &hash)
Definition: transaction.h:425
A class to track orphan transactions (failed on TX_MISSING_INPUTS) Since we cannot distinguish orphan...
Definition: txorphanage.h:21
void EraseForBlock(const CBlock &block) LOCKS_EXCLUDED(void LimitOrphans(unsigned int max_orphans) EXCLUSIVE_LOCKS_REQUIRED(g_cs_orphans)
Erase all orphans included in or invalidated by a new block.
Definition: txorphanage.h:44
int EraseTx(const uint256 &txid) EXCLUSIVE_LOCKS_REQUIRED(g_cs_orphans)
Erase an orphan by txid.
Definition: txorphanage.cpp:56
bool HaveTx(const GenTxid &gtxid) const LOCKS_EXCLUDED(std::pair< CTransactionRef, NodeId > GetTx(const uint256 &txid) const EXCLUSIVE_LOCKS_REQUIRED(g_cs_orphans)
Check if we already have an orphan transaction (by txid or wtxid)
Definition: txorphanage.h:32
size_t Size() LOCKS_EXCLUDED(
Return how many entries exist in the orphange.
Definition: txorphanage.h:51
void AddChildrenToWorkSet(const CTransaction &tx, std::set< uint256 > &orphan_work_set) const EXCLUSIVE_LOCKS_REQUIRED(g_cs_orphans)
Add any orphans that list a particular tx as a parent into a peer's work set (ie orphans that may hav...
void EraseForPeer(NodeId peer) EXCLUSIVE_LOCKS_REQUIRED(g_cs_orphans)
Erase all orphans announced by a peer (eg, after that peer disconnects)
Definition: txorphanage.cpp:88
bool AddTx(const CTransactionRef &tx, NodeId peer) EXCLUSIVE_LOCKS_REQUIRED(g_cs_orphans)
Add a new orphan transaction.
Definition: txorphanage.cpp:20
256-bit opaque blob.
Definition: uint256.h:119
static int64_t GetTransactionWeight(const CTransaction &tx)
Definition: validation.h:148
#define LIMITED_WHILE(condition, limit)
Can be used to limit a theoretically unbounded loop.
Definition: fuzz.h:18
int64_t NodeId
Definition: net.h:92
static const unsigned int DEFAULT_MAX_ORPHAN_TRANSACTIONS
Default for -maxorphantx, maximum number of orphan transactions kept in memory.
static constexpr unsigned int MAX_STANDARD_TX_WEIGHT
The maximum weight for transactions we're willing to relay/mine.
Definition: policy.h:27
static CTransactionRef MakeTransactionRef(Tx &&txIn)
Definition: transaction.h:415
std::shared_ptr< const CTransaction > CTransactionRef
Definition: transaction.h:414
std::unique_ptr< T > MakeNoLogFileContext(const std::string &chain_name=CBaseChainParams::REGTEST, const std::vector< const char * > &extra_args={})
Make a test setup that has disk access to the debug.log file disabled.
Definition: setup_common.h:192
A mutable version of CTransaction.
Definition: transaction.h:373
std::vector< CTxOut > vout
Definition: transaction.h:375
std::vector< CTxIn > vin
Definition: transaction.h:374
#define LOCK(cs)
Definition: sync.h:261
#define WITH_LOCK(cs, code)
Run code while locking a mutex.
Definition: sync.h:305
int64_t ConsumeTime(FuzzedDataProvider &fuzzed_data_provider, const std::optional< int64_t > &min, const std::optional< int64_t > &max) noexcept
Definition: util.cpp:307
auto & PickValue(FuzzedDataProvider &fuzzed_data_provider, Collection &col)
Definition: util.h:101
size_t CallOneOf(FuzzedDataProvider &fuzzed_data_provider, Callables... callables)
Definition: util.h:89
void SetMockTime(int64_t nMockTimeIn)
DEPRECATED Use SetMockTime with chrono type.
Definition: time.cpp:91
FUZZ_TARGET_INIT(txorphan, initialize_orphanage)
Definition: txorphan.cpp:33
void initialize_orphanage()
Definition: txorphan.cpp:28
RecursiveMutex g_cs_orphans
Guards orphan transactions and extra txs for compact blocks.
Definition: txorphanage.cpp:18