Changeset View
Changeset View
Standalone View
Standalone View
src/test/fuzz/txrequest.cpp
Show First 20 Lines • Show All 48 Lines • ▼ Show 20 Lines | Initializer() { | ||||
// as N=0..127. | // as N=0..127. | ||||
for (; i < 256; ++i) { | for (; i < 256; ++i) { | ||||
DELAYS[i] = -DELAYS[255 - i]; | DELAYS[i] = -DELAYS[255 - i]; | ||||
} | } | ||||
} | } | ||||
} g_initializer; | } g_initializer; | ||||
/** | /** | ||||
* Tester class for TxRequestTracker | * Tester class for InvRequestTracker | ||||
* | * | ||||
* It includes a naive reimplementation of its behavior, for a limited set | * It includes a naive reimplementation of its behavior, for a limited set | ||||
* of MAX_TXIDS distinct txids, and MAX_PEERS peer identifiers. | * of MAX_TXIDS distinct txids, and MAX_PEERS peer identifiers. | ||||
* | * | ||||
* All of the public member functions perform the same operation on | * All of the public member functions perform the same operation on | ||||
* an actual TxRequestTracker and on the state of the reimplementation. | * an actual InvRequestTracker and on the state of the reimplementation. | ||||
* The output of GetRequestable is compared with the expected value | * The output of GetRequestable is compared with the expected value | ||||
* as well. | * as well. | ||||
* | * | ||||
* Check() calls the TxRequestTracker's sanity check, plus compares the | * Check() calls the InvRequestTracker's sanity check, plus compares the | ||||
* output of the constant accessors (Size(), CountLoad(), CountTracked()) | * output of the constant accessors (Size(), CountLoad(), CountTracked()) | ||||
* with expected values. | * with expected values. | ||||
*/ | */ | ||||
class Tester { | class Tester { | ||||
//! TxRequestTracker object being tested. | //! InvRequestTracker object being tested. | ||||
TxRequestTracker m_tracker; | InvRequestTracker m_tracker; | ||||
//! States for txid/peer combinations in the naive data structure. | //! States for txid/peer combinations in the naive data structure. | ||||
enum class State { | enum class State { | ||||
//! Absence of this txid/peer combination | //! Absence of this txid/peer combination | ||||
NOTHING, | NOTHING, | ||||
// Note that this implementation does not distinguish between | // Note that this implementation does not distinguish between | ||||
// DELAYED/READY/BEST variants of CANDIDATE. | // DELAYED/READY/BEST variants of CANDIDATE. | ||||
▲ Show 20 Lines • Show All 96 Lines • ▼ Show 20 Lines | void DisconnectedPeer(int peer) { | ||||
// Apply to naive structure: all announcements for that peer are wiped. | // Apply to naive structure: all announcements for that peer are wiped. | ||||
for (int txid = 0; txid < MAX_TXIDS; ++txid) { | for (int txid = 0; txid < MAX_TXIDS; ++txid) { | ||||
if (m_announcements[txid][peer].m_state != State::NOTHING) { | if (m_announcements[txid][peer].m_state != State::NOTHING) { | ||||
m_announcements[txid][peer].m_state = State::NOTHING; | m_announcements[txid][peer].m_state = State::NOTHING; | ||||
Cleanup(txid); | Cleanup(txid); | ||||
} | } | ||||
} | } | ||||
// Call TxRequestTracker's implementation. | // Call InvRequestTracker's implementation. | ||||
m_tracker.DisconnectedPeer(peer); | m_tracker.DisconnectedPeer(peer); | ||||
} | } | ||||
void ForgetTxId(int txid) { | void ForgetTxId(int txid) { | ||||
// Apply to naive structure: all announcements for that txid are wiped. | // Apply to naive structure: all announcements for that txid are wiped. | ||||
for (int peer = 0; peer < MAX_PEERS; ++peer) { | for (int peer = 0; peer < MAX_PEERS; ++peer) { | ||||
m_announcements[txid][peer].m_state = State::NOTHING; | m_announcements[txid][peer].m_state = State::NOTHING; | ||||
} | } | ||||
Cleanup(txid); | Cleanup(txid); | ||||
// Call TxRequestTracker's implementation. | // Call InvRequestTracker's implementation. | ||||
m_tracker.ForgetTxId(TXIDS[txid]); | m_tracker.ForgetInvId(TXIDS[txid]); | ||||
} | } | ||||
void ReceivedInv(int peer, int txid, bool is_wtxid, bool preferred, | void ReceivedInv(int peer, int txid, bool is_wtxid, bool preferred, | ||||
std::chrono::microseconds reqtime) { | std::chrono::microseconds reqtime) { | ||||
// Apply to naive structure: if no announcement for txidnum/peer | // Apply to naive structure: if no announcement for txidnum/peer | ||||
// combination already, create a new CANDIDATE; otherwise do nothing. | // combination already, create a new CANDIDATE; otherwise do nothing. | ||||
Announcement &ann = m_announcements[txid][peer]; | Announcement &ann = m_announcements[txid][peer]; | ||||
if (ann.m_state == State::NOTHING) { | if (ann.m_state == State::NOTHING) { | ||||
ann.m_preferred = preferred; | ann.m_preferred = preferred; | ||||
ann.m_state = State::CANDIDATE; | ann.m_state = State::CANDIDATE; | ||||
ann.m_time = reqtime; | ann.m_time = reqtime; | ||||
ann.m_sequence = m_current_sequence++; | ann.m_sequence = m_current_sequence++; | ||||
ann.m_priority = | ann.m_priority = | ||||
m_tracker.ComputePriority(TXIDS[txid], peer, ann.m_preferred); | m_tracker.ComputePriority(TXIDS[txid], peer, ann.m_preferred); | ||||
// Add event so that AdvanceToEvent can quickly jump to the point | // Add event so that AdvanceToEvent can quickly jump to the point | ||||
// where its reqtime passes. | // where its reqtime passes. | ||||
if (reqtime > m_now) { | if (reqtime > m_now) { | ||||
m_events.push(reqtime); | m_events.push(reqtime); | ||||
} | } | ||||
} | } | ||||
// Call TxRequestTracker's implementation. | // Call InvRequestTracker's implementation. | ||||
m_tracker.ReceivedInv(peer, TXIDS[txid], preferred, reqtime); | m_tracker.ReceivedInv(peer, TXIDS[txid], preferred, reqtime); | ||||
} | } | ||||
void RequestedTx(int peer, int txid, std::chrono::microseconds exptime) { | void RequestedTx(int peer, int txid, std::chrono::microseconds exptime) { | ||||
// Apply to naive structure: if a CANDIDATE announcement exists for | // Apply to naive structure: if a CANDIDATE announcement exists for | ||||
// peer/txid, convert it to REQUESTED, and change any existing REQUESTED | // peer/txid, convert it to REQUESTED, and change any existing REQUESTED | ||||
// announcement for the same txid to COMPLETED. | // announcement for the same txid to COMPLETED. | ||||
if (m_announcements[txid][peer].m_state == State::CANDIDATE) { | if (m_announcements[txid][peer].m_state == State::CANDIDATE) { | ||||
for (int peer2 = 0; peer2 < MAX_PEERS; ++peer2) { | for (int peer2 = 0; peer2 < MAX_PEERS; ++peer2) { | ||||
if (m_announcements[txid][peer2].m_state == State::REQUESTED) { | if (m_announcements[txid][peer2].m_state == State::REQUESTED) { | ||||
m_announcements[txid][peer2].m_state = State::COMPLETED; | m_announcements[txid][peer2].m_state = State::COMPLETED; | ||||
} | } | ||||
} | } | ||||
m_announcements[txid][peer].m_state = State::REQUESTED; | m_announcements[txid][peer].m_state = State::REQUESTED; | ||||
m_announcements[txid][peer].m_time = exptime; | m_announcements[txid][peer].m_time = exptime; | ||||
} | } | ||||
// Add event so that AdvanceToEvent can quickly jump to the point where | // Add event so that AdvanceToEvent can quickly jump to the point where | ||||
// its exptime passes. | // its exptime passes. | ||||
if (exptime > m_now) { | if (exptime > m_now) { | ||||
m_events.push(exptime); | m_events.push(exptime); | ||||
} | } | ||||
// Call TxRequestTracker's implementation. | // Call InvRequestTracker's implementation. | ||||
m_tracker.RequestedTx(peer, TXIDS[txid], exptime); | m_tracker.RequestedData(peer, TXIDS[txid], exptime); | ||||
} | } | ||||
void ReceivedResponse(int peer, int txid) { | void ReceivedResponse(int peer, int txid) { | ||||
// Apply to naive structure: convert anything to COMPLETED. | // Apply to naive structure: convert anything to COMPLETED. | ||||
if (m_announcements[txid][peer].m_state != State::NOTHING) { | if (m_announcements[txid][peer].m_state != State::NOTHING) { | ||||
m_announcements[txid][peer].m_state = State::COMPLETED; | m_announcements[txid][peer].m_state = State::COMPLETED; | ||||
Cleanup(txid); | Cleanup(txid); | ||||
} | } | ||||
// Call TxRequestTracker's implementation. | // Call InvRequestTracker's implementation. | ||||
m_tracker.ReceivedResponse(peer, TXIDS[txid]); | m_tracker.ReceivedResponse(peer, TXIDS[txid]); | ||||
} | } | ||||
void GetRequestable(int peer) { | void GetRequestable(int peer) { | ||||
// Implement using naive structure: | // Implement using naive structure: | ||||
//! list of (sequence number, txid) tuples. | //! list of (sequence number, txid) tuples. | ||||
std::vector<std::tuple<uint64_t, int>> result; | std::vector<std::tuple<uint64_t, int>> result; | ||||
Show All 16 Lines | void GetRequestable(int peer) { | ||||
if (ann.m_state == State::CANDIDATE && GetSelected(txid) == peer) { | if (ann.m_state == State::CANDIDATE && GetSelected(txid) == peer) { | ||||
result.emplace_back(ann.m_sequence, txid); | result.emplace_back(ann.m_sequence, txid); | ||||
} | } | ||||
} | } | ||||
// Sort the results by sequence number. | // Sort the results by sequence number. | ||||
std::sort(result.begin(), result.end()); | std::sort(result.begin(), result.end()); | ||||
std::sort(expected_expired.begin(), expected_expired.end()); | std::sort(expected_expired.begin(), expected_expired.end()); | ||||
// Compare with TxRequestTracker's implementation. | // Compare with InvRequestTracker's implementation. | ||||
std::vector<std::pair<NodeId, TxId>> expired; | std::vector<std::pair<NodeId, TxId>> expired; | ||||
const auto actual = m_tracker.GetRequestable(peer, m_now, &expired); | const auto actual = m_tracker.GetRequestable(peer, m_now, &expired); | ||||
std::sort(expired.begin(), expired.end()); | std::sort(expired.begin(), expired.end()); | ||||
assert(expired == expected_expired); | assert(expired == expected_expired); | ||||
m_tracker.PostGetRequestableSanityCheck(m_now); | m_tracker.PostGetRequestableSanityCheck(m_now); | ||||
assert(result.size() == actual.size()); | assert(result.size() == actual.size()); | ||||
for (size_t pos = 0; pos < actual.size(); ++pos) { | for (size_t pos = 0; pos < actual.size(); ++pos) { | ||||
Show All 19 Lines | void Check() { | ||||
assert(m_tracker.Count(peer) == tracked); | assert(m_tracker.Count(peer) == tracked); | ||||
assert(m_tracker.CountInFlight(peer) == inflight); | assert(m_tracker.CountInFlight(peer) == inflight); | ||||
assert(m_tracker.CountCandidates(peer) == candidates); | assert(m_tracker.CountCandidates(peer) == candidates); | ||||
total += tracked; | total += tracked; | ||||
} | } | ||||
// Compare Size. | // Compare Size. | ||||
assert(m_tracker.Size() == total); | assert(m_tracker.Size() == total); | ||||
// Invoke internal consistency check of TxRequestTracker object. | // Invoke internal consistency check of InvRequestTracker object. | ||||
m_tracker.SanityCheck(); | m_tracker.SanityCheck(); | ||||
} | } | ||||
}; | }; | ||||
} // namespace | } // namespace | ||||
void test_one_input(const std::vector<uint8_t> &buffer) { | void test_one_input(const std::vector<uint8_t> &buffer) { | ||||
// Tester object (which encapsulates a TxRequestTracker). | // Tester object (which encapsulates a InvRequestTracker). | ||||
Tester tester; | Tester tester; | ||||
// Decode the input as a sequence of instructions with parameters | // Decode the input as a sequence of instructions with parameters | ||||
auto it = buffer.begin(); | auto it = buffer.begin(); | ||||
while (it != buffer.end()) { | while (it != buffer.end()) { | ||||
int cmd = *(it++) % 11; | int cmd = *(it++) % 11; | ||||
int peer, txidnum, delaynum; | int peer, txidnum, delaynum; | ||||
switch (cmd) { | switch (cmd) { | ||||
▲ Show 20 Lines • Show All 66 Lines • Show Last 20 Lines |