Defer inserting into maprelay until just before relaying.

This reduces the rate of not founds by better matching the far
 end expectations, it also improves privacy by removing the
 ability to use getdata to probe for a node having a txn before
 it has been relayed.
This commit is contained in:
Gregory Maxwell 2016-05-21 09:45:32 +00:00
parent 862fd24b40
commit 4d8993b346
3 changed files with 30 additions and 31 deletions

View file

@ -80,6 +80,10 @@ uint64_t nPruneTarget = 0;
int64_t nMaxTipAge = DEFAULT_MAX_TIP_AGE;
bool fEnableReplacement = DEFAULT_ENABLE_REPLACEMENT;
std::map<uint256, CTransaction> mapRelay;
std::deque<std::pair<int64_t, uint256> > vRelayExpiration;
CCriticalSection cs_mapRelay;
CFeeRate minRelayTxFee = CFeeRate(DEFAULT_MIN_RELAY_TX_FEE);
CAmount maxTxFee = DEFAULT_TRANSACTION_MAXFEE;
@ -4501,27 +4505,28 @@ void static ProcessGetData(CNode* pfrom, const Consensus::Params& consensusParam
}
else if (inv.IsKnownType())
{
CTransaction tx;
// Send stream from relay memory
bool pushed = false;
bool push = false;
{
LOCK(cs_mapRelay);
map<uint256, CTransaction>::iterator mi = mapRelay.find(inv.hash);
if (mi != mapRelay.end()) {
pfrom->PushMessage(inv.GetCommand(), (*mi).second);
pushed = true;
tx = (*mi).second;
push = true;
}
}
if (!pushed && inv.type == MSG_TX) {
CTransaction tx;
if (!push && inv.type == MSG_TX) {
int64_t txtime;
// To protect privacy, do not answer getdata using the mempool when
// that TX couldn't have been INVed in reply to a MEMPOOL request.
if (mempool.lookup(inv.hash, tx, txtime) && txtime <= pfrom->timeLastMempoolReq) {
pfrom->PushMessage(NetMsgType::TX, tx);
pushed = true;
push = true;
}
}
if (!pushed) {
if (push) {
pfrom->PushMessage(inv.GetCommand(), tx);
} else {
vNotFound.push_back(inv);
}
}
@ -5958,14 +5963,26 @@ bool SendMessages(CNode* pto)
if (filterrate && feeRate.GetFeePerK() < filterrate) {
continue;
}
if (pto->pfilter) {
CTransaction tx;
if (!mempool.lookup(hash, tx)) continue;
if (!pto->pfilter->IsRelevantAndUpdate(tx)) continue;
}
CTransaction tx;
if (!mempool.lookup(hash, tx)) continue;
if (pto->pfilter && !pto->pfilter->IsRelevantAndUpdate(tx)) continue;
// Send
vInv.push_back(CInv(MSG_TX, hash));
nRelayedTransactions++;
{
LOCK(cs_mapRelay);
// Expire old relay messages
while (!vRelayExpiration.empty() && vRelayExpiration.front().first < GetTime())
{
mapRelay.erase(vRelayExpiration.front().second);
vRelayExpiration.pop_front();
}
auto ret = mapRelay.insert(std::make_pair(hash, tx));
if (ret.second) {
vRelayExpiration.push_back(std::make_pair(GetTime() + 15 * 60, hash));
}
}
if (vInv.size() == MAX_INV_SZ) {
pto->PushMessage(NetMsgType::INV, vInv);
vInv.clear();

View file

@ -90,9 +90,6 @@ std::string strSubVersion;
std::vector<CNode*> vNodes;
CCriticalSection cs_vNodes;
std::map<uint256, CTransaction> mapRelay;
std::deque<std::pair<int64_t, uint256> > vRelayExpiration;
CCriticalSection cs_mapRelay;
limitedmap<uint256, int64_t> mapAlreadyAskedFor(MAX_INV_SZ);
static std::deque<std::string> vOneShots;
@ -2081,18 +2078,6 @@ instance_of_cnetcleanup;
void RelayTransaction(const CTransaction& tx)
{
CInv inv(MSG_TX, tx.GetHash());
{
LOCK(cs_mapRelay);
// Expire old relay messages
while (!vRelayExpiration.empty() && vRelayExpiration.front().first < GetTime())
{
mapRelay.erase(vRelayExpiration.front().second);
vRelayExpiration.pop_front();
}
mapRelay.insert(std::make_pair(inv.hash, tx));
vRelayExpiration.push_back(std::make_pair(GetTime() + 15 * 60, inv.hash));
}
LOCK(cs_vNodes);
BOOST_FOREACH(CNode* pnode, vNodes)
{

View file

@ -162,9 +162,6 @@ extern int nMaxConnections;
extern std::vector<CNode*> vNodes;
extern CCriticalSection cs_vNodes;
extern std::map<uint256, CTransaction> mapRelay;
extern std::deque<std::pair<int64_t, uint256> > vRelayExpiration;
extern CCriticalSection cs_mapRelay;
extern limitedmap<uint256, int64_t> mapAlreadyAskedFor;
extern std::vector<std::string> vAddedNodes;