aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/net_processing.cpp45
1 files changed, 45 insertions, 0 deletions
diff --git a/src/net_processing.cpp b/src/net_processing.cpp
index 74da788ca8..8a18c886e9 100644
--- a/src/net_processing.cpp
+++ b/src/net_processing.cpp
@@ -1782,6 +1782,11 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
}
}
+ // Keep a CBlock for "optimistic" compactblock reconstructions (see
+ // below)
+ std::shared_ptr<CBlock> pblock = std::make_shared<CBlock>();
+ bool fBlockReconstructed = false;
+
LOCK(cs_main);
// If AcceptBlockHeader returned true, it set pindex
assert(pindex);
@@ -1870,6 +1875,23 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
req.blockhash = pindex->GetBlockHash();
connman.PushMessage(pfrom, msgMaker.Make(NetMsgType::GETBLOCKTXN, req));
}
+ } else {
+ // This block is either already in flight from a different
+ // peer, or this peer has too many blocks outstanding to
+ // download from.
+ // Optimistically try to reconstruct anyway since we might be
+ // able to without any round trips.
+ PartiallyDownloadedBlock tempBlock(&mempool);
+ ReadStatus status = tempBlock.InitData(cmpctblock);
+ if (status != READ_STATUS_OK) {
+ // TODO: don't ignore failures
+ return true;
+ }
+ std::vector<CTransactionRef> dummy;
+ status = tempBlock.FillBlock(*pblock, dummy);
+ if (status == READ_STATUS_OK) {
+ fBlockReconstructed = true;
+ }
}
} else {
if (fAlreadyInFlight) {
@@ -1889,6 +1911,29 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
return ProcessMessage(pfrom, NetMsgType::HEADERS, vHeadersMsg, nTimeReceived, chainparams, connman);
}
}
+
+ if (fBlockReconstructed) {
+ // If we got here, we were able to optimistically reconstruct a
+ // block that is in flight from some other peer.
+ {
+ LOCK(cs_main);
+ mapBlockSource.emplace(pblock->GetHash(), std::make_pair(pfrom->GetId(), false));
+ }
+ bool fNewBlock = false;
+ ProcessNewBlock(chainparams, pblock, true, &fNewBlock);
+ if (fNewBlock)
+ pfrom->nLastBlockTime = GetTime();
+
+ LOCK(cs_main); // hold cs_main for CBlockIndex::IsValid()
+ if (pindex->IsValid(BLOCK_VALID_TRANSACTIONS)) {
+ // Clear download state for this block, which is in
+ // process from some other peer. We do this after calling
+ // ProcessNewBlock so that a malleated cmpctblock announcement
+ // can't be used to interfere with block relay.
+ MarkBlockAsReceived(pblock->GetHash());
+ }
+ }
+
}
else if (strCommand == NetMsgType::BLOCKTXN && !fImporting && !fReindex) // Ignore blocks received while importing