Bitcoin Core 28.99.0
P2P Digital Currency
|
Data structure to keep track of, and schedule, transaction downloads from peers. More...
#include <txrequest.h>
Classes | |
class | Impl |
Actual implementation for TxRequestTracker's data structure. More... | |
Public Member Functions | |
TxRequestTracker (bool deterministic=false) | |
Construct a TxRequestTracker. More... | |
~TxRequestTracker () | |
void | ReceivedInv (NodeId peer, const GenTxid >xid, bool preferred, std::chrono::microseconds reqtime) |
Adds a new CANDIDATE announcement. More... | |
void | DisconnectedPeer (NodeId peer) |
Deletes all announcements for a given peer. More... | |
void | ForgetTxHash (const uint256 &txhash) |
Deletes all announcements for a given txhash (both txid and wtxid ones). More... | |
std::vector< GenTxid > | GetRequestable (NodeId peer, std::chrono::microseconds now, std::vector< std::pair< NodeId, GenTxid > > *expired=nullptr) |
Find the txids to request now from peer. More... | |
void | RequestedTx (NodeId peer, const uint256 &txhash, std::chrono::microseconds expiry) |
Marks a transaction as requested, with a specified expiry. More... | |
void | ReceivedResponse (NodeId peer, const uint256 &txhash) |
Converts a CANDIDATE or REQUESTED announcement to a COMPLETED one. More... | |
size_t | CountInFlight (NodeId peer) const |
Count how many REQUESTED announcements a peer has. More... | |
size_t | CountCandidates (NodeId peer) const |
Count how many CANDIDATE announcements a peer has. More... | |
size_t | Count (NodeId peer) const |
Count how many announcements a peer has (REQUESTED, CANDIDATE, and COMPLETED combined). More... | |
size_t | Size () const |
Count how many announcements are being tracked in total across all peers and transaction hashes. More... | |
uint64_t | ComputePriority (const uint256 &txhash, NodeId peer, bool preferred) const |
Access to the internal priority computation (testing only) More... | |
void | SanityCheck () const |
Run internal consistency check (testing only). More... | |
void | PostGetRequestableSanityCheck (std::chrono::microseconds now) const |
Run a time-dependent internal consistency check (testing only). More... | |
Private Attributes | |
const std::unique_ptr< Impl > | m_impl |
Data structure to keep track of, and schedule, transaction downloads from peers.
=== Specification ===
We keep track of which peers have announced which transactions, and use that to determine which requests should go to which peer, when, and in what order.
The following information is tracked per peer/tx combination ("announcement"):
Transaction requests are then assigned to peers, following these rules:
No transaction is requested as long as another request for the same txhash is outstanding (it needs to fail first by passing expiry, or a NOTFOUND or invalid transaction has to be received for it).
Rationale: to avoid wasting bandwidth on multiple copies of the same transaction. Note that this only works per txhash, so if the same transaction is announced both through txid and wtxid, we have no means to prevent fetching both (the caller can however mitigate this by delaying one, see further).
The same transaction is never requested twice from the same peer, unless the announcement was forgotten in between, and re-announced. Announcements are forgotten only:
Rationale: giving a peer multiple chances to announce a transaction would allow them to bias requests in their favor, worsening transaction censoring attacks. The flip side is that as long as an attacker manages to prevent us from receiving a transaction, failed announcements (including those from honest peers) will linger longer, increasing memory usage somewhat. The impact of this is limited by imposing a cap on the number of tracked announcements per peer. As failed requests in response to announcements from honest peers should be rare, this almost solely hinders attackers. Transaction censoring attacks can be done by announcing transactions quickly while not answering requests for them. See https://allquantor.at/blockchainbib/pdf/miller2015topology.pdf for more information.
Transactions are not requested from a peer until its reqtime has passed.
Rationale: enable the calling code to define a delay for less-than-ideal peers, so that (presumed) better peers have a chance to give their announcement first.
If any preferred peers are available, non-preferred peers are not considered for what follows.
Rationale: preferred peers are more trusted by us, so are less likely to be under attacker control.
Pick a uniformly random peer among the candidates.
Rationale: random assignments are hard to influence for attackers.
Together these rules strike a balance between being fast in non-adverserial conditions and minimizing susceptibility to censorship attacks. An attacker that races the network:
Complexity:
Definition at line 96 of file txrequest.h.
|
explicit |
Construct a TxRequestTracker.
Definition at line 713 of file txrequest.cpp.
|
default |
uint64_t TxRequestTracker::ComputePriority | ( | const uint256 & | txhash, |
NodeId | peer, | ||
bool | preferred | ||
) | const |
Access to the internal priority computation (testing only)
Definition at line 753 of file txrequest.cpp.
size_t TxRequestTracker::Count | ( | NodeId | peer | ) | const |
Count how many announcements a peer has (REQUESTED, CANDIDATE, and COMPLETED combined).
Definition at line 722 of file txrequest.cpp.
size_t TxRequestTracker::CountCandidates | ( | NodeId | peer | ) | const |
Count how many CANDIDATE announcements a peer has.
Definition at line 721 of file txrequest.cpp.
size_t TxRequestTracker::CountInFlight | ( | NodeId | peer | ) | const |
Count how many REQUESTED announcements a peer has.
Definition at line 720 of file txrequest.cpp.
void TxRequestTracker::DisconnectedPeer | ( | NodeId | peer | ) |
Deletes all announcements for a given peer.
It should be called when a peer goes offline.
Definition at line 719 of file txrequest.cpp.
void TxRequestTracker::ForgetTxHash | ( | const uint256 & | txhash | ) |
Deletes all announcements for a given txhash (both txid and wtxid ones).
This should be called when a transaction is no longer needed. The caller should ensure that new announcements for the same txhash will not trigger new ReceivedInv calls, at least in the short term after this call.
Definition at line 718 of file txrequest.cpp.
std::vector< GenTxid > TxRequestTracker::GetRequestable | ( | NodeId | peer, |
std::chrono::microseconds | now, | ||
std::vector< std::pair< NodeId, GenTxid > > * | expired = nullptr |
||
) |
Find the txids to request now from peer.
It does the following:
Definition at line 747 of file txrequest.cpp.
void TxRequestTracker::PostGetRequestableSanityCheck | ( | std::chrono::microseconds | now | ) | const |
Run a time-dependent internal consistency check (testing only).
This can only be called immediately after GetRequestable, with the same 'now' parameter.
Definition at line 726 of file txrequest.cpp.
void TxRequestTracker::ReceivedInv | ( | NodeId | peer, |
const GenTxid & | gtxid, | ||
bool | preferred, | ||
std::chrono::microseconds | reqtime | ||
) |
Adds a new CANDIDATE announcement.
Does nothing if one already exists for that (txhash, peer) combination (whether it's CANDIDATE, REQUESTED, or COMPLETED). Note that the txid/wtxid property is ignored for determining uniqueness, so if an announcement is added for a wtxid H, while one for txid H from the same peer already exists, it will be ignored. This is harmless as the txhashes being equal implies it is a non-segwit transaction, so it doesn't matter how it is fetched. The new announcement is given the specified preferred and reqtime values, and takes its is_wtxid from the specified gtxid.
Definition at line 731 of file txrequest.cpp.
Converts a CANDIDATE or REQUESTED announcement to a COMPLETED one.
If no such announcement exists for the provided peer and txhash, nothing happens.
It should be called whenever a transaction or NOTFOUND was received from a peer. When the transaction is not needed entirely anymore, ForgetTxhash should be called instead of, or in addition to, this call.
Definition at line 742 of file txrequest.cpp.
void TxRequestTracker::RequestedTx | ( | NodeId | peer, |
const uint256 & | txhash, | ||
std::chrono::microseconds | expiry | ||
) |
Marks a transaction as requested, with a specified expiry.
If no CANDIDATE announcement for the provided peer and txhash exists, this call has no effect. Otherwise:
Definition at line 737 of file txrequest.cpp.
void TxRequestTracker::SanityCheck | ( | ) | const |
Run internal consistency check (testing only).
Definition at line 724 of file txrequest.cpp.
size_t TxRequestTracker::Size | ( | ) | const |
Count how many announcements are being tracked in total across all peers and transaction hashes.
Definition at line 723 of file txrequest.cpp.
|
private |
Definition at line 99 of file txrequest.h.