Changeset View
Changeset View
Standalone View
Standalone View
src/txrequest.cpp
Show First 20 Lines • Show All 345 Lines • ▼ Show 20 Lines | for (const Announcement &ann : index) { | ||||
} | } | ||||
// Also keep track of which peers this txid has an announcement for | // Also keep track of which peers this txid has an announcement for | ||||
// (so we can detect duplicates). | // (so we can detect duplicates). | ||||
info.m_peers.push_back(ann.m_peer); | info.m_peers.push_back(ann.m_peer); | ||||
} | } | ||||
return ret; | return ret; | ||||
} | } | ||||
using clearExpiredFun = const std::function<void()> &; | |||||
using emplaceExpiredFun = | |||||
const std::function<void(const NodeId &, const uint256 &)> &; | |||||
} // namespace | } // namespace | ||||
/** Actual implementation for TxRequestTracker's data structure. */ | /** Actual implementation for TxRequestTracker's data structure. */ | ||||
class TxRequestTracker::Impl { | class InvRequestTrackerImpl : public InvRequestTrackerImplInterface { | ||||
//! The current sequence number. Increases for every announcement. This is | //! The current sequence number. Increases for every announcement. This is | ||||
//! used to sort txid returned by GetRequestable in announcement order. | //! used to sort txid returned by GetRequestable in announcement order. | ||||
SequenceNumber m_current_sequence{0}; | SequenceNumber m_current_sequence{0}; | ||||
//! This tracker's priority computer. | //! This tracker's priority computer. | ||||
const PriorityComputer m_computer; | const PriorityComputer m_computer; | ||||
//! This tracker's main data structure. See SanityCheck() for the invariants | //! This tracker's main data structure. See SanityCheck() for the invariants | ||||
▲ Show 20 Lines • Show All 212 Lines • ▼ Show 20 Lines | private: | ||||
//! Make the data structure consistent with a given point in time: | //! Make the data structure consistent with a given point in time: | ||||
//! - REQUESTED annoucements with expiry <= now are turned into COMPLETED. | //! - REQUESTED annoucements with expiry <= now are turned into COMPLETED. | ||||
//! - CANDIDATE_DELAYED announcements with reqtime <= now are turned into | //! - CANDIDATE_DELAYED announcements with reqtime <= now are turned into | ||||
//! CANDIDATE_{READY,BEST}. | //! CANDIDATE_{READY,BEST}. | ||||
//! - CANDIDATE_{READY,BEST} announcements with reqtime > now are turned | //! - CANDIDATE_{READY,BEST} announcements with reqtime > now are turned | ||||
//! into CANDIDATE_DELAYED. | //! into CANDIDATE_DELAYED. | ||||
void SetTimePoint(std::chrono::microseconds now, | void SetTimePoint(std::chrono::microseconds now, | ||||
clearExpiredFun clearExpired, | ClearExpiredFun clearExpired, | ||||
emplaceExpiredFun emplaceExpired) { | EmplaceExpiredFun emplaceExpired) { | ||||
clearExpired(); | clearExpired(); | ||||
// Iterate over all CANDIDATE_DELAYED and REQUESTED from old to new, as | // Iterate over all CANDIDATE_DELAYED and REQUESTED from old to new, as | ||||
// long as they're in the past, and convert them to CANDIDATE_READY and | // long as they're in the past, and convert them to CANDIDATE_READY and | ||||
// COMPLETED respectively. | // COMPLETED respectively. | ||||
while (!m_index.empty()) { | while (!m_index.empty()) { | ||||
auto it = m_index.get<ByTime>().begin(); | auto it = m_index.get<ByTime>().begin(); | ||||
if (it->GetState() == State::CANDIDATE_DELAYED && | if (it->GetState() == State::CANDIDATE_DELAYED && | ||||
it->m_time <= now) { | it->m_time <= now) { | ||||
Show All 19 Lines | void SetTimePoint(std::chrono::microseconds now, | ||||
State::CANDIDATE_DELAYED); | State::CANDIDATE_DELAYED); | ||||
} else { | } else { | ||||
break; | break; | ||||
} | } | ||||
} | } | ||||
} | } | ||||
public: | public: | ||||
Impl(bool deterministic) | InvRequestTrackerImpl(bool deterministic) | ||||
: m_computer(deterministic), | : m_computer(deterministic), | ||||
// Explicitly initialize m_index as we need to pass a reference to | // Explicitly initialize m_index as we need to pass a reference to | ||||
// m_computer to ByTxHashViewExtractor. | // m_computer to ByTxHashViewExtractor. | ||||
m_index(boost::make_tuple( | m_index(boost::make_tuple( | ||||
boost::make_tuple(ByPeerViewExtractor(), std::less<ByPeerView>()), | boost::make_tuple(ByPeerViewExtractor(), std::less<ByPeerView>()), | ||||
boost::make_tuple(ByTxIdViewExtractor(m_computer), | boost::make_tuple(ByTxIdViewExtractor(m_computer), | ||||
std::less<ByTxIdView>()), | std::less<ByTxIdView>()), | ||||
boost::make_tuple(ByTimeViewExtractor(), | boost::make_tuple(ByTimeViewExtractor(), | ||||
std::less<ByTimeView>()))) {} | std::less<ByTimeView>()))) {} | ||||
// Disable copying and assigning (a default copy won't work due the stateful | // Disable copying and assigning (a default copy won't work due the stateful | ||||
// ByTxIdViewExtractor). | // ByTxIdViewExtractor). | ||||
Impl(const Impl &) = delete; | InvRequestTrackerImpl(const InvRequestTrackerImpl &) = delete; | ||||
Impl &operator=(const Impl &) = delete; | InvRequestTrackerImpl &operator=(const InvRequestTrackerImpl &) = delete; | ||||
~InvRequestTrackerImpl() = default; | |||||
void DisconnectedPeer(NodeId peer) { | void DisconnectedPeer(NodeId peer) { | ||||
auto &index = m_index.get<ByPeer>(); | auto &index = m_index.get<ByPeer>(); | ||||
auto it = | auto it = | ||||
index.lower_bound(ByPeerView{peer, false, uint256(uint256::ZERO)}); | index.lower_bound(ByPeerView{peer, false, uint256(uint256::ZERO)}); | ||||
while (it != index.end() && it->m_peer == peer) { | while (it != index.end() && it->m_peer == peer) { | ||||
// Check what to continue with after this iteration. 'it' will be | // Check what to continue with after this iteration. 'it' will be | ||||
// deleted in what follows, so we need to decide what to continue | // deleted in what follows, so we need to decide what to continue | ||||
▲ Show 20 Lines • Show All 64 Lines • ▼ Show 20 Lines | void ReceivedInv(NodeId peer, const uint256 &txid, bool preferred, | ||||
// Update accounting metadata. | // Update accounting metadata. | ||||
++m_peerinfo[peer].m_total; | ++m_peerinfo[peer].m_total; | ||||
++m_current_sequence; | ++m_current_sequence; | ||||
} | } | ||||
//! Find the TxIds to request now from peer. | //! Find the TxIds to request now from peer. | ||||
std::vector<uint256> GetRequestable(NodeId peer, | std::vector<uint256> GetRequestable(NodeId peer, | ||||
std::chrono::microseconds now, | std::chrono::microseconds now, | ||||
clearExpiredFun clearExpired, | ClearExpiredFun clearExpired, | ||||
emplaceExpiredFun emplaceExpired) { | EmplaceExpiredFun emplaceExpired) { | ||||
// Move time. | // Move time. | ||||
SetTimePoint(now, clearExpired, emplaceExpired); | SetTimePoint(now, clearExpired, emplaceExpired); | ||||
// Find all CANDIDATE_BEST announcements for this peer. | // Find all CANDIDATE_BEST announcements for this peer. | ||||
std::vector<const Announcement *> selected; | std::vector<const Announcement *> selected; | ||||
auto it_peer = m_index.get<ByPeer>().lower_bound( | auto it_peer = m_index.get<ByPeer>().lower_bound( | ||||
ByPeerView{peer, true, uint256(uint256::ZERO)}); | ByPeerView{peer, true, uint256(uint256::ZERO)}); | ||||
while (it_peer != m_index.get<ByPeer>().end() && | while (it_peer != m_index.get<ByPeer>().end() && | ||||
▲ Show 20 Lines • Show All 124 Lines • ▼ Show 20 Lines | public: | ||||
uint64_t ComputePriority(const uint256 &txid, NodeId peer, | uint64_t ComputePriority(const uint256 &txid, NodeId peer, | ||||
bool preferred) const { | bool preferred) const { | ||||
// Return Priority as a uint64_t as Priority is internal. | // Return Priority as a uint64_t as Priority is internal. | ||||
return uint64_t{m_computer(txid, peer, preferred)}; | return uint64_t{m_computer(txid, peer, preferred)}; | ||||
} | } | ||||
}; | }; | ||||
std::unique_ptr<InvRequestTrackerImplInterface> | |||||
InvRequestTrackerImplInterface::BuildImpl(bool deterministic) { | |||||
return std::make_unique<InvRequestTrackerImpl>(deterministic); | |||||
} | |||||
TxRequestTracker::TxRequestTracker(bool deterministic) | TxRequestTracker::TxRequestTracker(bool deterministic) | ||||
: m_impl{std::make_unique<TxRequestTracker::Impl>(deterministic)} {} | : m_impl{InvRequestTrackerImplInterface::BuildImpl(deterministic)} {} | ||||
TxRequestTracker::~TxRequestTracker() = default; | TxRequestTracker::~TxRequestTracker() = default; | ||||
void TxRequestTracker::ForgetTxId(const TxId &txid) { | void TxRequestTracker::ForgetTxId(const TxId &txid) { | ||||
m_impl->ForgetTxId(txid); | m_impl->ForgetTxId(txid); | ||||
} | } | ||||
void TxRequestTracker::DisconnectedPeer(NodeId peer) { | void TxRequestTracker::DisconnectedPeer(NodeId peer) { | ||||
m_impl->DisconnectedPeer(peer); | m_impl->DisconnectedPeer(peer); | ||||
Show All 32 Lines | |||||
void TxRequestTracker::ReceivedResponse(NodeId peer, const TxId &txid) { | void TxRequestTracker::ReceivedResponse(NodeId peer, const TxId &txid) { | ||||
m_impl->ReceivedResponse(peer, txid); | m_impl->ReceivedResponse(peer, txid); | ||||
} | } | ||||
std::vector<TxId> TxRequestTracker::GetRequestable( | std::vector<TxId> TxRequestTracker::GetRequestable( | ||||
NodeId peer, std::chrono::microseconds now, | NodeId peer, std::chrono::microseconds now, | ||||
std::vector<std::pair<NodeId, TxId>> *expired) { | std::vector<std::pair<NodeId, TxId>> *expired) { | ||||
clearExpiredFun clearExpired = [expired]() { | InvRequestTrackerImplInterface::ClearExpiredFun clearExpired = [expired]() { | ||||
if (expired) { | if (expired) { | ||||
expired->clear(); | expired->clear(); | ||||
} | } | ||||
}; | }; | ||||
emplaceExpiredFun emplaceExpired = [expired](const NodeId &nodeid, | InvRequestTrackerImplInterface::EmplaceExpiredFun emplaceExpired = | ||||
const uint256 &txid) { | [expired](const NodeId &nodeid, const uint256 &txid) { | ||||
if (expired) { | if (expired) { | ||||
expired->emplace_back(nodeid, TxId(txid)); | expired->emplace_back(nodeid, TxId(txid)); | ||||
} | } | ||||
}; | }; | ||||
std::vector<uint256> hashes = | std::vector<uint256> hashes = | ||||
m_impl->GetRequestable(peer, now, clearExpired, emplaceExpired); | m_impl->GetRequestable(peer, now, clearExpired, emplaceExpired); | ||||
return std::vector<TxId>(hashes.begin(), hashes.end()); | return std::vector<TxId>(hashes.begin(), hashes.end()); | ||||
} | } | ||||
uint64_t TxRequestTracker::ComputePriority(const TxId &txid, NodeId peer, | uint64_t TxRequestTracker::ComputePriority(const TxId &txid, NodeId peer, | ||||
bool preferred) const { | bool preferred) const { | ||||
return m_impl->ComputePriority(txid, peer, preferred); | return m_impl->ComputePriority(txid, peer, preferred); | ||||
} | } |