From b02ddbedcba4f9d86b1aabeb71fe18ec03f9a41a Mon Sep 17 00:00:00 2001 From: Matt Corallo Date: Sat, 18 Aug 2012 23:45:19 -0400 Subject: [PATCH] Relay CMerkleBlocks when asked for MSG_FILTERED_BLOCK --- src/main.cpp | 26 ++++++++++++++++++++++++-- src/protocol.cpp | 1 + src/protocol.h | 3 +++ 3 files changed, 28 insertions(+), 2 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index bd5b2408..abb0174e 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -3068,7 +3068,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv) if (fDebugNet || (vInv.size() == 1)) printf("received getdata for: %s\n", inv.ToString().c_str()); - if (inv.type == MSG_BLOCK) + if (inv.type == MSG_BLOCK || inv.type == MSG_FILTERED_BLOCK) { // Send block from disk map::iterator mi = mapBlockIndex.find(inv.hash); @@ -3076,7 +3076,29 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv) { CBlock block; block.ReadFromDisk((*mi).second); - pfrom->PushMessage("block", block); + if (inv.type == MSG_BLOCK) + pfrom->PushMessage("block", block); + else // MSG_FILTERED_BLOCK) + { + LOCK(pfrom->cs_filter); + if (pfrom->pfilter) + { + CMerkleBlock merkleBlock(block, *pfrom->pfilter); + typedef boost::tuple > TupleType; + // CMerkleBlock just contains hashes, so also push any transactions in the block the client did not see + // This avoids hurting performance by pointlessly requiring a round-trip + // Note that there is currently no way for a node to request any single transactions we didnt send here - + // they must either disconnect and retry or request the full block. + // Thus, the protocol spec specified allows for us to provide duplicate txn here, + // however we MUST always provide at least what the remote peer needs + BOOST_FOREACH(TupleType& tuple, merkleBlock.vtx) + if (!pfrom->setInventoryKnown.count(CInv(MSG_TX, get<1>(tuple)))) + pfrom->PushMessage("tx", block.vtx[get<0>(tuple)]); + pfrom->PushMessage("merkleblock", merkleBlock); + } + // else + // no response + } // Trigger them to send a getblocks request for the next batch of inventory if (inv.hash == pfrom->hashContinue) diff --git a/src/protocol.cpp b/src/protocol.cpp index 23969e5b..7b42f527 100644 --- a/src/protocol.cpp +++ b/src/protocol.cpp @@ -17,6 +17,7 @@ static const char* ppszTypeName[] = "ERROR", "tx", "block", + "filtered block" }; CMessageHeader::CMessageHeader() diff --git a/src/protocol.h b/src/protocol.h index 96fd197e..f5c16205 100644 --- a/src/protocol.h +++ b/src/protocol.h @@ -138,6 +138,9 @@ enum { MSG_TX = 1, MSG_BLOCK, + // Nodes may always request a MSG_FILTERED_BLOCK in a getdata, however, + // MSG_FILTERED_BLOCK should not appear in any invs except as a part of getdata. + MSG_FILTERED_BLOCK, }; #endif // __INCLUDED_PROTOCOL_H__