@@ -289,10 +289,21 @@ struct CNodeState {
289
289
bool fPreferHeaders ;
290
290
// ! Whether this peer wants invs or cmpctblocks (when possible) for block announcements.
291
291
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
+ */
293
297
bool fProvidesHeaderAndIDs ;
294
298
// ! Whether this peer can give us witnesses
295
299
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 ;
296
307
297
308
CNodeState () {
298
309
fCurrentlyConnected = false ;
@@ -313,6 +324,8 @@ struct CNodeState {
313
324
fPreferHeaderAndIDs = false ;
314
325
fProvidesHeaderAndIDs = false ;
315
326
fHaveWitness = false ;
327
+ fWantsCmpctWitness = false ;
328
+ fSupportsDesiredCmpctVersion = false ;
316
329
}
317
330
};
318
331
@@ -467,16 +480,16 @@ void UpdateBlockAvailability(NodeId nodeid, const uint256 &hash) {
467
480
}
468
481
469
482
void 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 .
472
485
return ;
473
486
}
474
487
if (nodestate->fProvidesHeaderAndIDs ) {
475
488
BOOST_FOREACH (const NodeId nodeid, lNodesAnnouncingHeaderAndIDs)
476
489
if (nodeid == pfrom->GetId ())
477
490
return ;
478
491
bool fAnnounceUsingCMPCTBLOCK = false ;
479
- uint64_t nCMPCTBLOCKVersion = 1 ;
492
+ uint64_t nCMPCTBLOCKVersion = (pfrom-> GetLocalServices () & NODE_WITNESS) ? 2 : 1 ;
480
493
if (lNodesAnnouncingHeaderAndIDs.size () >= 3 ) {
481
494
// As per BIP152, we only get 3 of our peers to announce
482
495
// blocks using compact encodings.
@@ -4856,11 +4869,12 @@ void static ProcessGetData(CNode* pfrom, const Consensus::Params& consensusParam
4856
4869
// they wont have a useful mempool to match against a compact block,
4857
4870
// and we don't feel like constructing the object for them, so
4858
4871
// instead we respond with the full, non-compact block.
4872
+ bool fPeerWantsWitness = State (pfrom->GetId ())->fWantsCmpctWitness ;
4859
4873
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);
4862
4876
} else
4863
- pfrom->PushMessageWithFlag (SERIALIZE_TRANSACTION_NO_WITNESS, NetMsgType::BLOCK, block);
4877
+ pfrom->PushMessageWithFlag (fPeerWantsWitness ? 0 : SERIALIZE_TRANSACTION_NO_WITNESS, NetMsgType::BLOCK, block);
4864
4878
}
4865
4879
4866
4880
// 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,
5128
5142
pfrom->PushMessage (NetMsgType::SENDHEADERS);
5129
5143
}
5130
5144
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
5132
5146
// However, we do not request new block announcements using
5133
5147
// cmpctblock messages.
5134
5148
// We send this to non-NODE NETWORK peers as well, because
5135
5149
// they may wish to request compact blocks from us
5136
5150
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 ;
5138
5155
pfrom->PushMessage (NetMsgType::SENDCMPCT, fAnnounceUsingCMPCTBLOCK , nCMPCTBLOCKVersion);
5139
5156
}
5140
5157
}
@@ -5195,12 +5212,23 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
5195
5212
else if (strCommand == NetMsgType::SENDCMPCT)
5196
5213
{
5197
5214
bool fAnnounceUsingCMPCTBLOCK = false ;
5198
- uint64_t nCMPCTBLOCKVersion = 1 ;
5215
+ uint64_t nCMPCTBLOCKVersion = 0 ;
5199
5216
vRecv >> fAnnounceUsingCMPCTBLOCK >> nCMPCTBLOCKVersion;
5200
- if (nCMPCTBLOCKVersion == 1 ) {
5217
+ if (nCMPCTBLOCKVersion == 1 || ((pfrom-> GetLocalServices () & NODE_WITNESS) && nCMPCTBLOCKVersion == 2 ) ) {
5201
5218
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
+ }
5204
5232
}
5205
5233
}
5206
5234
@@ -5258,7 +5286,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
5258
5286
nodestate->nBlocksInFlight < MAX_BLOCKS_IN_TRANSIT_PER_PEER &&
5259
5287
(!IsWitnessEnabled (chainActive.Tip (), chainparams.GetConsensus ()) || State (pfrom->GetId ())->fHaveWitness )) {
5260
5288
inv.type |= nFetchFlags;
5261
- if (nodestate->fProvidesHeaderAndIDs && !(pfrom-> GetLocalServices () & NODE_WITNESS) )
5289
+ if (nodestate->fSupportsDesiredCmpctVersion )
5262
5290
vToFetch.push_back (CInv (MSG_CMPCT_BLOCK, inv.hash ));
5263
5291
else
5264
5292
vToFetch.push_back (inv);
@@ -5386,7 +5414,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
5386
5414
}
5387
5415
resp.txn [i] = block.vtx [req.indexes [i]];
5388
5416
}
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);
5390
5418
}
5391
5419
5392
5420
@@ -5650,7 +5678,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
5650
5678
// We requested this block for some reason, but our mempool will probably be useless
5651
5679
// so we just grab the block via normal getdata
5652
5680
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 ());
5654
5682
pfrom->PushMessage (NetMsgType::GETDATA, vInv);
5655
5683
}
5656
5684
return true ;
@@ -5662,6 +5690,12 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
5662
5690
5663
5691
CNodeState *nodestate = State (pfrom->GetId ());
5664
5692
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
+
5665
5699
// We want to be a bit conservative just to be extra careful about DoS
5666
5700
// possibilities in compact block processing...
5667
5701
if (pindex->nHeight <= chainActive.Height () + 2 ) {
@@ -5688,7 +5722,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
5688
5722
} else if (status == READ_STATUS_FAILED) {
5689
5723
// Duplicate txindexes, the block is now in-flight, so just request it
5690
5724
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 ());
5692
5726
pfrom->PushMessage (NetMsgType::GETDATA, vInv);
5693
5727
return true ;
5694
5728
}
@@ -5715,7 +5749,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
5715
5749
// We requested this block, but its far into the future, so our
5716
5750
// mempool will probably be useless - request the block normally
5717
5751
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 ());
5719
5753
pfrom->PushMessage (NetMsgType::GETDATA, vInv);
5720
5754
return true ;
5721
5755
} else {
@@ -5757,7 +5791,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
5757
5791
} else if (status == READ_STATUS_FAILED) {
5758
5792
// Might have collided, fall back to getdata now :(
5759
5793
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 ));
5761
5795
pfrom->PushMessage (NetMsgType::GETDATA, invs);
5762
5796
} else {
5763
5797
CValidationState state;
@@ -5906,7 +5940,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
5906
5940
pindexLast->GetBlockHash ().ToString (), pindexLast->nHeight );
5907
5941
}
5908
5942
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)) {
5910
5944
// We seem to be rather well-synced, so it appears pfrom was the first to provide us
5911
5945
// with this block! Let's get them to announce using compact blocks in the future.
5912
5946
MaybeSetPeerAsAnnouncingHeaderAndIDs (nodestate, pfrom, connman);
@@ -6536,8 +6570,8 @@ bool SendMessages(CNode* pto, CConnman& connman)
6536
6570
// TODO: Shouldn't need to reload block from disk, but requires refactor
6537
6571
CBlock block;
6538
6572
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);
6541
6575
state.pindexBestHeaderSent = pBestIndex;
6542
6576
} else if (state.fPreferHeaders ) {
6543
6577
if (vHeaders.size () > 1 ) {
0 commit comments