aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMatt Corallo <git@bluematt.me>2016-04-11 01:00:17 -0700
committerMatt Corallo <git@bluematt.me>2016-06-19 01:34:58 -0700
commit9c837d5468063917009aef8569ce6ce9ddd340d2 (patch)
tree935370a1ac9367b167fe91a95650062c696b53a9
parent00c40784fe737ca67122fdec6538c450d2a516f3 (diff)
Add sender-side protocol implementation for CMPCTBLOCK stuff
-rw-r--r--src/main.cpp110
1 files changed, 95 insertions, 15 deletions
diff --git a/src/main.cpp b/src/main.cpp
index 7d267bef7d..911c0a648b 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -274,6 +274,10 @@ struct CNodeState {
bool fPreferredDownload;
//! Whether this peer wants invs or headers (when possible) for block announcements.
bool fPreferHeaders;
+ //! Whether this peer wants invs or cmpctblocks (when possible) for block announcements.
+ bool fPreferHeaderAndIDs;
+ //! Whether this peer will send us cmpctblocks if we request them
+ bool fProvidesHeaderAndIDs;
CNodeState() {
fCurrentlyConnected = false;
@@ -290,6 +294,8 @@ struct CNodeState {
nBlocksInFlightValidHeaders = 0;
fPreferredDownload = false;
fPreferHeaders = false;
+ fPreferHeaderAndIDs = false;
+ fProvidesHeaderAndIDs = false;
}
};
@@ -4454,7 +4460,7 @@ void static ProcessGetData(CNode* pfrom, const Consensus::Params& consensusParam
boost::this_thread::interruption_point();
it++;
- if (inv.type == MSG_BLOCK || inv.type == MSG_FILTERED_BLOCK)
+ if (inv.type == MSG_BLOCK || inv.type == MSG_FILTERED_BLOCK || inv.type == MSG_CMPCT_BLOCK)
{
bool send = false;
BlockMap::iterator mi = mapBlockIndex.find(inv.hash);
@@ -4496,7 +4502,7 @@ void static ProcessGetData(CNode* pfrom, const Consensus::Params& consensusParam
assert(!"cannot load block from disk");
if (inv.type == MSG_BLOCK)
pfrom->PushMessage(NetMsgType::BLOCK, block);
- else // MSG_FILTERED_BLOCK)
+ else if (inv.type == MSG_FILTERED_BLOCK)
{
LOCK(pfrom->cs_filter);
if (pfrom->pfilter)
@@ -4516,6 +4522,18 @@ void static ProcessGetData(CNode* pfrom, const Consensus::Params& consensusParam
// else
// no response
}
+ else if (inv.type == MSG_CMPCT_BLOCK)
+ {
+ // If a peer is asking for old blocks, we're almost guaranteed
+ // they wont have a useful mempool to match against a compact block,
+ // and we dont feel like constructing the object for them, so
+ // instead we respond with the full, non-compact block.
+ if (mi->second->nHeight >= chainActive.Height() - 10) {
+ CBlockHeaderAndShortTxIDs cmpctblock(block);
+ pfrom->PushMessage(NetMsgType::CMPCTBLOCK, cmpctblock);
+ } else
+ pfrom->PushMessage(NetMsgType::BLOCK, block);
+ }
// Trigger the peer node to send a getblocks request for the next batch of inventory
if (inv.hash == pfrom->hashContinue)
@@ -4839,6 +4857,18 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
State(pfrom->GetId())->fPreferHeaders = true;
}
+ else if (strCommand == NetMsgType::SENDCMPCT)
+ {
+ bool fAnnounceUsingCMPCTBLOCK = false;
+ uint64_t nCMPCTBLOCKVersion = 1;
+ vRecv >> fAnnounceUsingCMPCTBLOCK >> nCMPCTBLOCKVersion;
+ if (nCMPCTBLOCKVersion == 1) {
+ LOCK(cs_main);
+ State(pfrom->GetId())->fProvidesHeaderAndIDs = true;
+ State(pfrom->GetId())->fPreferHeaderAndIDs = fAnnounceUsingCMPCTBLOCK;
+ }
+ }
+
else if (strCommand == NetMsgType::INV)
{
@@ -4982,6 +5012,39 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
}
+ else if (strCommand == NetMsgType::GETBLOCKTXN)
+ {
+ BlockTransactionsRequest req;
+ vRecv >> req;
+
+ BlockMap::iterator it = mapBlockIndex.find(req.blockhash);
+ if (it == mapBlockIndex.end() || !(it->second->nStatus & BLOCK_HAVE_DATA)) {
+ Misbehaving(pfrom->GetId(), 100);
+ LogPrintf("Peer %d sent us a getblocktxn for a block we don't have", pfrom->id);
+ return true;
+ }
+
+ if (it->second->nHeight < chainActive.Height() - 10) {
+ LogPrint("net", "Peer %d sent us a getblocktxn for a block > 10 deep", pfrom->id);
+ return true;
+ }
+
+ CBlock block;
+ assert(ReadBlockFromDisk(block, it->second, chainparams.GetConsensus()));
+
+ BlockTransactions resp(req);
+ for (size_t i = 0; i < req.indexes.size(); i++) {
+ if (req.indexes[i] >= block.vtx.size()) {
+ Misbehaving(pfrom->GetId(), 100);
+ LogPrintf("Peer %d sent us a getblocktxn with out-of-bounds tx indices", pfrom->id);
+ return true;
+ }
+ resp.txn[i] = block.vtx[req.indexes[i]];
+ }
+ pfrom->PushMessage(NetMsgType::BLOCKTXN, resp);
+ }
+
+
else if (strCommand == NetMsgType::GETHEADERS)
{
CBlockLocator locator;
@@ -5824,7 +5887,9 @@ bool SendMessages(CNode* pto)
// add all to the inv queue.
LOCK(pto->cs_inventory);
vector<CBlock> vHeaders;
- bool fRevertToInv = (!state.fPreferHeaders || pto->vBlockHashesToAnnounce.size() > MAX_BLOCKS_TO_ANNOUNCE);
+ bool fRevertToInv = ((!state.fPreferHeaders &&
+ (!state.fPreferHeaderAndIDs || pto->vBlockHashesToAnnounce.size() > 1)) ||
+ pto->vBlockHashesToAnnounce.size() > MAX_BLOCKS_TO_ANNOUNCE);
CBlockIndex *pBestIndex = NULL; // last header queued for delivery
ProcessBlockAvailability(pto->id); // ensure pindexBestKnownBlock is up-to-date
@@ -5876,6 +5941,33 @@ bool SendMessages(CNode* pto)
}
}
}
+ if (!fRevertToInv && !vHeaders.empty()) {
+ if (vHeaders.size() == 1 && state.fPreferHeaderAndIDs) {
+ // We only send up to 1 block as header-and-ids, as otherwise
+ // probably means we're doing an initial-ish-sync or they're slow
+ LogPrint("net", "%s sending header-and-ids %s to peer %d\n", __func__,
+ vHeaders.front().GetHash().ToString(), pto->id);
+ //TODO: Shouldn't need to reload block from disk, but requires refactor
+ CBlock block;
+ assert(ReadBlockFromDisk(block, pBestIndex, consensusParams));
+ CBlockHeaderAndShortTxIDs cmpctblock(block);
+ pto->PushMessage(NetMsgType::CMPCTBLOCK, cmpctblock);
+ state.pindexBestHeaderSent = pBestIndex;
+ } else if (state.fPreferHeaders) {
+ if (vHeaders.size() > 1) {
+ LogPrint("net", "%s: %u headers, range (%s, %s), to peer=%d\n", __func__,
+ vHeaders.size(),
+ vHeaders.front().GetHash().ToString(),
+ vHeaders.back().GetHash().ToString(), pto->id);
+ } else {
+ LogPrint("net", "%s: sending header %s to peer=%d\n", __func__,
+ vHeaders.front().GetHash().ToString(), pto->id);
+ }
+ pto->PushMessage(NetMsgType::HEADERS, vHeaders);
+ state.pindexBestHeaderSent = pBestIndex;
+ } else
+ fRevertToInv = true;
+ }
if (fRevertToInv) {
// If falling back to using an inv, just try to inv the tip.
// The last entry in vBlockHashesToAnnounce was our tip at some point
@@ -5901,18 +5993,6 @@ bool SendMessages(CNode* pto)
pto->id, hashToAnnounce.ToString());
}
}
- } else if (!vHeaders.empty()) {
- if (vHeaders.size() > 1) {
- LogPrint("net", "%s: %u headers, range (%s, %s), to peer=%d\n", __func__,
- vHeaders.size(),
- vHeaders.front().GetHash().ToString(),
- vHeaders.back().GetHash().ToString(), pto->id);
- } else {
- LogPrint("net", "%s: sending header %s to peer=%d\n", __func__,
- vHeaders.front().GetHash().ToString(), pto->id);
- }
- pto->PushMessage(NetMsgType::HEADERS, vHeaders);
- state.pindexBestHeaderSent = pBestIndex;
}
pto->vBlockHashesToAnnounce.clear();
}