@@ -5657,6 +5657,11 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
56575657 CBlockHeaderAndShortTxIDs cmpctblock;
56585658 vRecv >> cmpctblock;
56595659
5660+ // Keep a CBlock for "optimistic" compactblock reconstructions (see
5661+ // below)
5662+ CBlock block;
5663+ bool fBlockReconstructed = false ;
5664+
56605665 LOCK (cs_main);
56615666
56625667 if (mapBlockIndex.find (cmpctblock.header .hashPrevBlock ) == mapBlockIndex.end ()) {
@@ -5765,6 +5770,23 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
57655770 req.blockhash = pindex->GetBlockHash ();
57665771 pfrom->PushMessage (NetMsgType::GETBLOCKTXN, req);
57675772 }
5773+ } else {
5774+ // This block is either already in flight from a different
5775+ // peer, or this peer has too many blocks outstanding to
5776+ // download from.
5777+ // Optimistically try to reconstruct anyway since we might be
5778+ // able to without any round trips.
5779+ PartiallyDownloadedBlock tempBlock (&mempool);
5780+ ReadStatus status = tempBlock.InitData (cmpctblock);
5781+ if (status != READ_STATUS_OK) {
5782+ // TODO: don't ignore failures
5783+ return true ;
5784+ }
5785+ std::vector<CTransaction> dummy;
5786+ status = tempBlock.FillBlock (block, dummy);
5787+ if (status == READ_STATUS_OK) {
5788+ fBlockReconstructed = true ;
5789+ }
57685790 }
57695791 } else {
57705792 if (fAlreadyInFlight ) {
@@ -5785,6 +5807,33 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
57855807 }
57865808 }
57875809
5810+ if (fBlockReconstructed ) {
5811+ // If we got here, we were able to optimistically reconstruct a
5812+ // block that is in flight from some other peer. However, this
5813+ // cmpctblock may be invalid. In particular, while we've checked
5814+ // that the block merkle root commits to the transaction ids, we
5815+ // haven't yet checked that tx witnesses are properly committed to
5816+ // in the coinbase witness commitment.
5817+ //
5818+ // ProcessNewBlock will call MarkBlockAsReceived(), which will
5819+ // clear any in-flight compact block state that might be present
5820+ // from some other peer. We don't want a malleated compact block
5821+ // request to interfere with block relay, so we don't want to call
5822+ // ProcessNewBlock until we've already checked that the witness
5823+ // commitment is correct.
5824+ {
5825+ LOCK (cs_main);
5826+ CValidationState dummy;
5827+ if (!ContextualCheckBlock (block, dummy, pindex->pprev )) {
5828+ // TODO: could send reject message to peer?
5829+ return true ;
5830+ }
5831+ }
5832+ CValidationState state;
5833+ ProcessNewBlock (state, chainparams, pfrom, &block, true , NULL , false );
5834+ // TODO: could send reject message if block is invalid?
5835+ }
5836+
57885837 CheckBlockIndex (chainparams.GetConsensus ());
57895838 }
57905839
0 commit comments