@@ -289,10 +289,21 @@ struct CNodeState {
289289 bool fPreferHeaders ;
290290 // ! Whether this peer wants invs or cmpctblocks (when possible) for block announcements.
291291 bool fPreferHeaderAndIDs ;
292- // ! Whether this peer will send us cmpctblocks if we request them
292+ /* *
293+ * Whether this peer will send us cmpctblocks if we request them.
294+ * This is not used to gate request logic, as we really only care about fSupportsDesiredCmpctVersion,
295+ * but is used as a flag to "lock in" the version of compact blocks (fWantsCmpctWitness) we send.
296+ */
293297 bool fProvidesHeaderAndIDs ;
294298 // ! Whether this peer can give us witnesses
295299 bool fHaveWitness ;
300+ // ! Whether this peer wants witnesses in cmpctblocks/blocktxns
301+ bool fWantsCmpctWitness ;
302+ /* *
303+ * If we've announced NODE_WITNESS to this peer: whether the peer sends witnesses in cmpctblocks/blocktxns,
304+ * otherwise: whether this peer sends non-witnesses in cmpctblocks/blocktxns.
305+ */
306+ bool fSupportsDesiredCmpctVersion ;
296307
297308 CNodeState () {
298309 fCurrentlyConnected = false ;
@@ -313,6 +324,8 @@ struct CNodeState {
313324 fPreferHeaderAndIDs = false ;
314325 fProvidesHeaderAndIDs = false ;
315326 fHaveWitness = false ;
327+ fWantsCmpctWitness = false ;
328+ fSupportsDesiredCmpctVersion = false ;
316329 }
317330};
318331
@@ -467,16 +480,16 @@ void UpdateBlockAvailability(NodeId nodeid, const uint256 &hash) {
467480}
468481
469482void MaybeSetPeerAsAnnouncingHeaderAndIDs (const CNodeState* nodestate, CNode* pfrom, CConnman& connman) {
470- if (pfrom-> GetLocalServices () & NODE_WITNESS ) {
471- // Don't ever request compact blocks when segwit is enabled .
483+ if (!nodestate-> fSupportsDesiredCmpctVersion ) {
484+ // Never ask from peers who can't provide witnesses .
472485 return ;
473486 }
474487 if (nodestate->fProvidesHeaderAndIDs ) {
475488 BOOST_FOREACH (const NodeId nodeid, lNodesAnnouncingHeaderAndIDs)
476489 if (nodeid == pfrom->GetId ())
477490 return ;
478491 bool fAnnounceUsingCMPCTBLOCK = false ;
479- uint64_t nCMPCTBLOCKVersion = 1 ;
492+ uint64_t nCMPCTBLOCKVersion = (pfrom-> GetLocalServices () & NODE_WITNESS) ? 2 : 1 ;
480493 if (lNodesAnnouncingHeaderAndIDs.size () >= 3 ) {
481494 // As per BIP152, we only get 3 of our peers to announce
482495 // blocks using compact encodings.
@@ -4856,11 +4869,12 @@ void static ProcessGetData(CNode* pfrom, const Consensus::Params& consensusParam
48564869 // they wont have a useful mempool to match against a compact block,
48574870 // and we don't feel like constructing the object for them, so
48584871 // instead we respond with the full, non-compact block.
4872+ bool fPeerWantsWitness = State (pfrom->GetId ())->fWantsCmpctWitness ;
48594873 if (mi->second ->nHeight >= chainActive.Height () - 10 ) {
4860- CBlockHeaderAndShortTxIDs cmpctblock (block);
4861- pfrom->PushMessageWithFlag (SERIALIZE_TRANSACTION_NO_WITNESS, NetMsgType::CMPCTBLOCK, cmpctblock);
4874+ CBlockHeaderAndShortTxIDs cmpctblock (block, fPeerWantsWitness );
4875+ pfrom->PushMessageWithFlag (fPeerWantsWitness ? 0 : SERIALIZE_TRANSACTION_NO_WITNESS, NetMsgType::CMPCTBLOCK, cmpctblock);
48624876 } else
4863- pfrom->PushMessageWithFlag (SERIALIZE_TRANSACTION_NO_WITNESS, NetMsgType::BLOCK, block);
4877+ pfrom->PushMessageWithFlag (fPeerWantsWitness ? 0 : SERIALIZE_TRANSACTION_NO_WITNESS, NetMsgType::BLOCK, block);
48644878 }
48654879
48664880 // Trigger the peer node to send a getblocks request for the next batch of inventory
@@ -5128,13 +5142,16 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
51285142 pfrom->PushMessage (NetMsgType::SENDHEADERS);
51295143 }
51305144 if (pfrom->nVersion >= SHORT_IDS_BLOCKS_VERSION) {
5131- // Tell our peer we are willing to provide version-1 cmpctblocks
5145+ // Tell our peer we are willing to provide version 1 or 2 cmpctblocks
51325146 // However, we do not request new block announcements using
51335147 // cmpctblock messages.
51345148 // We send this to non-NODE NETWORK peers as well, because
51355149 // they may wish to request compact blocks from us
51365150 bool fAnnounceUsingCMPCTBLOCK = false ;
5137- uint64_t nCMPCTBLOCKVersion = 1 ;
5151+ uint64_t nCMPCTBLOCKVersion = 2 ;
5152+ if (pfrom->GetLocalServices () & NODE_WITNESS)
5153+ pfrom->PushMessage (NetMsgType::SENDCMPCT, fAnnounceUsingCMPCTBLOCK , nCMPCTBLOCKVersion);
5154+ nCMPCTBLOCKVersion = 1 ;
51385155 pfrom->PushMessage (NetMsgType::SENDCMPCT, fAnnounceUsingCMPCTBLOCK , nCMPCTBLOCKVersion);
51395156 }
51405157 }
@@ -5195,12 +5212,23 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
51955212 else if (strCommand == NetMsgType::SENDCMPCT)
51965213 {
51975214 bool fAnnounceUsingCMPCTBLOCK = false ;
5198- uint64_t nCMPCTBLOCKVersion = 1 ;
5215+ uint64_t nCMPCTBLOCKVersion = 0 ;
51995216 vRecv >> fAnnounceUsingCMPCTBLOCK >> nCMPCTBLOCKVersion;
5200- if (nCMPCTBLOCKVersion == 1 ) {
5217+ if (nCMPCTBLOCKVersion == 1 || ((pfrom-> GetLocalServices () & NODE_WITNESS) && nCMPCTBLOCKVersion == 2 ) ) {
52015218 LOCK (cs_main);
5202- State (pfrom->GetId ())->fProvidesHeaderAndIDs = true ;
5203- State (pfrom->GetId ())->fPreferHeaderAndIDs = fAnnounceUsingCMPCTBLOCK ;
5219+ // fProvidesHeaderAndIDs is used to "lock in" version of compact blocks we send (fWantsCmpctWitness)
5220+ if (!State (pfrom->GetId ())->fProvidesHeaderAndIDs ) {
5221+ State (pfrom->GetId ())->fProvidesHeaderAndIDs = true ;
5222+ State (pfrom->GetId ())->fWantsCmpctWitness = nCMPCTBLOCKVersion == 2 ;
5223+ }
5224+ if (State (pfrom->GetId ())->fWantsCmpctWitness == (nCMPCTBLOCKVersion == 2 )) // ignore later version announces
5225+ State (pfrom->GetId ())->fPreferHeaderAndIDs = fAnnounceUsingCMPCTBLOCK ;
5226+ if (!State (pfrom->GetId ())->fSupportsDesiredCmpctVersion ) {
5227+ if (pfrom->GetLocalServices () & NODE_WITNESS)
5228+ State (pfrom->GetId ())->fSupportsDesiredCmpctVersion = (nCMPCTBLOCKVersion == 2 );
5229+ else
5230+ State (pfrom->GetId ())->fSupportsDesiredCmpctVersion = (nCMPCTBLOCKVersion == 1 );
5231+ }
52045232 }
52055233 }
52065234
@@ -5258,7 +5286,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
52585286 nodestate->nBlocksInFlight < MAX_BLOCKS_IN_TRANSIT_PER_PEER &&
52595287 (!IsWitnessEnabled (chainActive.Tip (), chainparams.GetConsensus ()) || State (pfrom->GetId ())->fHaveWitness )) {
52605288 inv.type |= nFetchFlags;
5261- if (nodestate->fProvidesHeaderAndIDs && !(pfrom-> GetLocalServices () & NODE_WITNESS) )
5289+ if (nodestate->fSupportsDesiredCmpctVersion )
52625290 vToFetch.push_back (CInv (MSG_CMPCT_BLOCK, inv.hash ));
52635291 else
52645292 vToFetch.push_back (inv);
@@ -5386,7 +5414,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
53865414 }
53875415 resp.txn [i] = block.vtx [req.indexes [i]];
53885416 }
5389- pfrom->PushMessageWithFlag (SERIALIZE_TRANSACTION_NO_WITNESS, NetMsgType::BLOCKTXN, resp);
5417+ pfrom->PushMessageWithFlag (State (pfrom-> GetId ())-> fWantsCmpctWitness ? 0 : SERIALIZE_TRANSACTION_NO_WITNESS, NetMsgType::BLOCKTXN, resp);
53905418 }
53915419
53925420
@@ -5650,7 +5678,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
56505678 // We requested this block for some reason, but our mempool will probably be useless
56515679 // so we just grab the block via normal getdata
56525680 std::vector<CInv> vInv (1 );
5653- vInv[0 ] = CInv (MSG_BLOCK, cmpctblock.header .GetHash ());
5681+ vInv[0 ] = CInv (MSG_BLOCK | GetFetchFlags (pfrom, pindex-> pprev , chainparams. GetConsensus ()) , cmpctblock.header .GetHash ());
56545682 pfrom->PushMessage (NetMsgType::GETDATA, vInv);
56555683 }
56565684 return true ;
@@ -5662,6 +5690,12 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
56625690
56635691 CNodeState *nodestate = State (pfrom->GetId ());
56645692
5693+ if (IsWitnessEnabled (pindex->pprev , chainparams.GetConsensus ()) && !nodestate->fSupportsDesiredCmpctVersion ) {
5694+ // Don't bother trying to process compact blocks from v1 peers
5695+ // after segwit activates.
5696+ return true ;
5697+ }
5698+
56655699 // We want to be a bit conservative just to be extra careful about DoS
56665700 // possibilities in compact block processing...
56675701 if (pindex->nHeight <= chainActive.Height () + 2 ) {
@@ -5688,7 +5722,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
56885722 } else if (status == READ_STATUS_FAILED) {
56895723 // Duplicate txindexes, the block is now in-flight, so just request it
56905724 std::vector<CInv> vInv (1 );
5691- vInv[0 ] = CInv (MSG_BLOCK, cmpctblock.header .GetHash ());
5725+ vInv[0 ] = CInv (MSG_BLOCK | GetFetchFlags (pfrom, pindex-> pprev , chainparams. GetConsensus ()) , cmpctblock.header .GetHash ());
56925726 pfrom->PushMessage (NetMsgType::GETDATA, vInv);
56935727 return true ;
56945728 }
@@ -5715,7 +5749,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
57155749 // We requested this block, but its far into the future, so our
57165750 // mempool will probably be useless - request the block normally
57175751 std::vector<CInv> vInv (1 );
5718- vInv[0 ] = CInv (MSG_BLOCK, cmpctblock.header .GetHash ());
5752+ vInv[0 ] = CInv (MSG_BLOCK | GetFetchFlags (pfrom, pindex-> pprev , chainparams. GetConsensus ()) , cmpctblock.header .GetHash ());
57195753 pfrom->PushMessage (NetMsgType::GETDATA, vInv);
57205754 return true ;
57215755 } else {
@@ -5757,7 +5791,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
57575791 } else if (status == READ_STATUS_FAILED) {
57585792 // Might have collided, fall back to getdata now :(
57595793 std::vector<CInv> invs;
5760- invs.push_back (CInv (MSG_BLOCK, resp.blockhash ));
5794+ invs.push_back (CInv (MSG_BLOCK | GetFetchFlags (pfrom, chainActive. Tip (), chainparams. GetConsensus ()) , resp.blockhash ));
57615795 pfrom->PushMessage (NetMsgType::GETDATA, invs);
57625796 } else {
57635797 CValidationState state;
@@ -5906,7 +5940,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
59065940 pindexLast->GetBlockHash ().ToString (), pindexLast->nHeight );
59075941 }
59085942 if (vGetData.size () > 0 ) {
5909- if (nodestate->fProvidesHeaderAndIDs && vGetData.size () == 1 && mapBlocksInFlight.size () == 1 && pindexLast->pprev ->IsValid (BLOCK_VALID_CHAIN) && !(pfrom-> GetLocalServices () & NODE_WITNESS )) {
5943+ if (nodestate->fSupportsDesiredCmpctVersion && vGetData.size () == 1 && mapBlocksInFlight.size () == 1 && pindexLast->pprev ->IsValid (BLOCK_VALID_CHAIN)) {
59105944 // We seem to be rather well-synced, so it appears pfrom was the first to provide us
59115945 // with this block! Let's get them to announce using compact blocks in the future.
59125946 MaybeSetPeerAsAnnouncingHeaderAndIDs (nodestate, pfrom, connman);
@@ -6536,8 +6570,8 @@ bool SendMessages(CNode* pto, CConnman& connman)
65366570 // TODO: Shouldn't need to reload block from disk, but requires refactor
65376571 CBlock block;
65386572 assert (ReadBlockFromDisk (block, pBestIndex, consensusParams));
6539- CBlockHeaderAndShortTxIDs cmpctblock (block);
6540- pto->PushMessageWithFlag (SERIALIZE_TRANSACTION_NO_WITNESS, NetMsgType::CMPCTBLOCK, cmpctblock);
6573+ CBlockHeaderAndShortTxIDs cmpctblock (block, state. fWantsCmpctWitness );
6574+ pto->PushMessageWithFlag (state. fWantsCmpctWitness ? 0 : SERIALIZE_TRANSACTION_NO_WITNESS, NetMsgType::CMPCTBLOCK, cmpctblock);
65416575 state.pindexBestHeaderSent = pBestIndex;
65426576 } else if (state.fPreferHeaders ) {
65436577 if (vHeaders.size () > 1 ) {
0 commit comments