39 std::set<uint256> orphan_work_set;
40 std::vector<COutPoint> outpoints;
42 for (uint8_t i = 0; i < 4; i++) {
43 outpoints.emplace_back(
uint256{i}, 0);
46 const bool duplicate_input = fuzzed_data_provider.ConsumeBool();
48 LIMITED_WHILE(outpoints.size() < 200
'000 && fuzzed_data_provider.ConsumeBool(), 10 * DEFAULT_MAX_ORPHAN_TRANSACTIONS) 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()); 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{}); 69 // restore previously popped outpoints 70 for (auto& in : tx_mut.vin) { 71 outpoints.push_back(in.prevout); 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); 81 // trigger orphanage functions 82 LIMITED_WHILE(fuzzed_data_provider.ConsumeBool(), 10 * DEFAULT_MAX_ORPHAN_TRANSACTIONS) 84 NodeId peer_id = fuzzed_data_provider.ConsumeIntegral<NodeId>(); 90 orphanage.AddChildrenToWorkSet(*tx, orphan_work_set); 93 bool have_tx = orphanage.HaveTx(GenTxid::Txid(tx->GetHash())) || orphanage.HaveTx(GenTxid::Wtxid(tx->GetHash())); 96 bool get_tx = orphanage.GetTx(tx->GetHash()).first != nullptr; 97 Assert(have_tx == get_tx); 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 106 bool add_tx = orphanage.AddTx(tx, peer_id); 107 // have_tx == true -> add_tx == false 108 Assert(!have_tx || !add_tx); 110 have_tx = orphanage.HaveTx(GenTxid::Txid(tx->GetHash())) || orphanage.HaveTx(GenTxid::Wtxid(tx->GetHash())); 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); 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
135 orphanage.EraseForPeer(peer_id);
140 auto limit = fuzzed_data_provider.ConsumeIntegral<
unsigned int>();
142 Assert(orphanage.Size() <= limit);
RecursiveMutex g_cs_orphans
Guards orphan transactions and extra txs for compact blocks.
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.
static GenTxid Wtxid(const uint256 &hash)
FUZZ_TARGET_INIT(txorphan, initialize_orphanage)
void initialize_orphanage()
A class to track orphan transactions (failed on TX_MISSING_INPUTS) Since we cannot distinguish orphan...
#define LIMITED_WHILE(condition, limit)
Can be used to limit a theoretically unbounded loop.
int EraseTx(const uint256 &txid) EXCLUSIVE_LOCKS_REQUIRED(g_cs_orphans)
Erase an orphan by txid.
void SetMockTime(int64_t nMockTimeIn)
DEPRECATED Use SetMockTime with chrono type.
#define WITH_LOCK(cs, code)
Run code while locking a mutex.
int64_t ConsumeTime(FuzzedDataProvider &fuzzed_data_provider, const std::optional< int64_t > &min, const std::optional< int64_t > &max) noexcept
static GenTxid Txid(const uint256 &hash)
#define Assert(val)
Identity function.