Inside Bitcoin
Opening the selected file…
Inside Bitcoin
Opening the selected file…
The code behind the network, with room to understand it.
Release published 2026-10-28 · Snapshot fetched 2026-11-01. Latest stable release at fetch time; development branches and Git history are excluded. Only the selected code window and visible folders load here.
251for (int txhash = 0; txhash < MAX_TXHASHES; ++txhash) {252// Mark any expired REQUESTED announcements as COMPLETED.253for (int peer2 = 0; peer2 < MAX_PEERS; ++peer2) {254Announcement& ann2 = m_announcements[txhash][peer2];255if (ann2.m_state == State::REQUESTED && ann2.m_time <= m_now) {256auto gtxid = ann2.m_is_wtxid ? GenTxid{Wtxid::FromUint256(TXHASHES[txhash])} : GenTxid{Txid::FromUint256(TXHASHES[txhash])};257expected_expired.emplace_back(peer2, gtxid);258ann2.m_state = State::COMPLETED;259break;260}261}262// And delete txids with only COMPLETED announcements left.263Cleanup(txhash);264// CANDIDATEs for which this announcement has the highest priority get returned.265const Announcement& ann = m_announcements[txhash][peer];266if (ann.m_state == State::CANDIDATE && GetSelected(txhash) == peer) {267result.emplace_back(ann.m_sequence, txhash, ann.m_is_wtxid);268}269}270// Sort the results by sequence number.271std::sort(result.begin(), result.end());272std::sort(expected_expired.begin(), expected_expired.end());274// Compare with TxRequestTracker's implementation.275std::vector<std::pair<NodeId, GenTxid>> expired;276const auto actual = m_tracker.GetRequestable(peer, m_now, &expired);277std::sort(expired.begin(), expired.end());278assert(expired == expected_expired);280m_tracker.PostGetRequestableSanityCheck(m_now);281assert(result.size() == actual.size());282for (size_t pos = 0; pos < actual.size(); ++pos) {283assert(TXHASHES[std::get<1>(result[pos])] == actual[pos].ToUint256());284assert(std::get<2>(result[pos]) == actual[pos].IsWtxid());285}286}288void Check()289{290// Compare CountTracked and CountLoad with naive structure.291size_t total = 0;292for (int peer = 0; peer < MAX_PEERS; ++peer) {293size_t tracked = 0;294size_t inflight = 0;295size_t candidates = 0;296for (int txhash = 0; txhash < MAX_TXHASHES; ++txhash) {297tracked += m_announcements[txhash][peer].m_state != State::NOTHING;298inflight += m_announcements[txhash][peer].m_state == State::REQUESTED;299candidates += m_announcements[txhash][peer].m_state == State::CANDIDATE;301std::bitset<MAX_PEERS> expected_announcers;302for (int peer = 0; peer < MAX_PEERS; ++peer) {303if (m_announcements[txhash][peer].m_state == State::CANDIDATE || m_announcements[txhash][peer].m_state == State::REQUESTED) {304expected_announcers[peer] = true;305}306}307std::vector<NodeId> candidate_peers;308m_tracker.GetCandidatePeers(TXHASHES[txhash], candidate_peers);309assert(expected_announcers.count() == candidate_peers.size());310for (const auto& peer : candidate_peers) {311assert(expected_announcers[peer]);312}313}314assert(m_tracker.Count(peer) == tracked);315assert(m_tracker.CountInFlight(peer) == inflight);316assert(m_tracker.CountCandidates(peer) == candidates);317total += tracked;318}319// Compare Size.320assert(m_tracker.Size() == total);322// Invoke internal consistency check of TxRequestTracker object.323m_tracker.SanityCheck();324}325};326} // namespace328FUZZ_TARGET(txrequest)329{330// Tester object (which encapsulates a TxRequestTracker).331Tester tester;333// Decode the input as a sequence of instructions with parameters334auto it = buffer.begin();335while (it != buffer.end()) {336int cmd = *(it++) % 11;337int peer, txidnum, delaynum;338switch (cmd) {339case 0: // Make time jump to the next event (m_time of CANDIDATE or REQUESTED)340tester.AdvanceToEvent();341break;342case 1: // Change time343delaynum = it == buffer.end() ? 0 : *(it++);344tester.AdvanceTime(DELAYS[delaynum]);345break;346case 2: // Query for requestable txs347peer = it == buffer.end() ? 0 : *(it++) % MAX_PEERS;348tester.GetRequestable(peer);349break;350case 3: // Peer went offline351peer = it == buffer.end() ? 0 : *(it++) % MAX_PEERS;352tester.DisconnectedPeer(peer);353break;354case 4: // No longer need tx355txidnum = it == buffer.end() ? 0 : *(it++);356tester.ForgetTxHash(txidnum % MAX_TXHASHES);357break;358case 5: // Received immediate preferred inv359case 6: // Same, but non-preferred.360peer = it == buffer.end() ? 0 : *(it++) % MAX_PEERS;361txidnum = it == buffer.end() ? 0 : *(it++);362tester.ReceivedInv(peer, txidnum % MAX_TXHASHES, (txidnum / MAX_TXHASHES) & 1, cmd & 1,363std::chrono::microseconds::min());364break;365case 7: // Received delayed preferred inv366case 8: // Same, but non-preferred.367peer = it == buffer.end() ? 0 : *(it++) % MAX_PEERS;368txidnum = it == buffer.end() ? 0 : *(it++);369delaynum = it == buffer.end() ? 0 : *(it++);370tester.ReceivedInv(peer, txidnum % MAX_TXHASHES, (txidnum / MAX_TXHASHES) & 1, cmd & 1,371tester.Now() + DELAYS[delaynum]);372break;373case 9: // Requested tx from peer374peer = it == buffer.end() ? 0 : *(it++) % MAX_PEERS;375txidnum = it == buffer.end() ? 0 : *(it++);376delaynum = it == buffer.end() ? 0 : *(it++);377tester.RequestedTx(peer, txidnum % MAX_TXHASHES, tester.Now() + DELAYS[delaynum]);378break;379case 10: // Received response380peer = it == buffer.end() ? 0 : *(it++) % MAX_PEERS;381txidnum = it == buffer.end() ? 0 : *(it++);382tester.ReceivedResponse(peer, txidnum % MAX_TXHASHES);383break;384default:385assert(false);386}387}388tester.Check();389}
Independent explanations by MyBitcoinExplorer. Not affiliated with or endorsed by Bitcoin Core. Guides are educational and do not replace the source or its tests.
Bitcoin Core source © its contributors, distributed under the MIT license. Original notices and bundled third-party licenses are retained in the source tree.