@@ -180,8 +180,10 @@ namespace {
180180 * Sources of received blocks, saved to be able to send them reject
181181 * messages or ban them when processing happens afterwards. Protected by
182182 * cs_main.
183+ * Set mapBlockSource[hash].second to false if the node should not be
184+ * punished if the block is invalid.
183185 */
184- map<uint256, NodeId> mapBlockSource;
186+ map<uint256, std::pair< NodeId, bool > > mapBlockSource;
185187
186188 /* *
187189 * Filter for transactions that were recently rejected by
@@ -3785,7 +3787,7 @@ static bool AcceptBlock(const CBlock& block, CValidationState& state, const CCha
37853787 return true ;
37863788}
37873789
3788- bool ProcessNewBlock (CValidationState& state, const CChainParams& chainparams, CNode* pfrom, const CBlock* pblock, bool fForceProcessing , const CDiskBlockPos* dbp)
3790+ bool ProcessNewBlock (CValidationState& state, const CChainParams& chainparams, CNode* pfrom, const CBlock* pblock, bool fForceProcessing , const CDiskBlockPos* dbp, bool fMayBanPeerIfInvalid )
37893791{
37903792 {
37913793 LOCK (cs_main);
@@ -3795,7 +3797,7 @@ bool ProcessNewBlock(CValidationState& state, const CChainParams& chainparams, C
37953797 bool fNewBlock = false ;
37963798 bool ret = AcceptBlock (*pblock, state, chainparams, &pindex, fForceProcessing , dbp, &fNewBlock );
37973799 if (pindex && pfrom) {
3798- mapBlockSource[pindex->GetBlockHash ()] = pfrom->GetId ();
3800+ mapBlockSource[pindex->GetBlockHash ()] = std::make_pair ( pfrom->GetId (), fMayBanPeerIfInvalid );
37993801 if (fNewBlock ) pfrom->nLastBlockTime = GetTime ();
38003802 }
38013803 CheckBlockIndex (chainparams.GetConsensus ());
@@ -4775,16 +4777,16 @@ void PeerLogicValidation::BlockChecked(const CBlock& block, const CValidationSta
47754777 LOCK (cs_main);
47764778
47774779 const uint256 hash (block.GetHash ());
4778- std::map<uint256, NodeId>::iterator it = mapBlockSource.find (hash);
4780+ std::map<uint256, std::pair< NodeId, bool > >::iterator it = mapBlockSource.find (hash);
47794781
47804782 int nDoS = 0 ;
47814783 if (state.IsInvalid (nDoS)) {
4782- if (it != mapBlockSource.end () && State (it->second )) {
4784+ if (it != mapBlockSource.end () && State (it->second . first )) {
47834785 assert (state.GetRejectCode () < REJECT_INTERNAL); // Blocks are never rejected with internal reject codes
47844786 CBlockReject reject = {(unsigned char )state.GetRejectCode (), state.GetRejectReason ().substr (0 , MAX_REJECT_MESSAGE_LENGTH), hash};
4785- State (it->second )->rejects .push_back (reject);
4786- if (nDoS > 0 )
4787- Misbehaving (it->second , nDoS);
4787+ State (it->second . first )->rejects .push_back (reject);
4788+ if (nDoS > 0 && it-> second . second )
4789+ Misbehaving (it->second . first , nDoS);
47884790 }
47894791 }
47904792 if (it != mapBlockSource.end ())
@@ -5893,6 +5895,23 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
58935895 invs.push_back (CInv (MSG_BLOCK | GetFetchFlags (pfrom, chainActive.Tip (), chainparams.GetConsensus ()), resp.blockhash ));
58945896 connman.PushMessage (pfrom, NetMsgType::GETDATA, invs);
58955897 } else {
5898+ // Block is either okay, or possibly we received
5899+ // READ_STATUS_CHECKBLOCK_FAILED.
5900+ // Note that CheckBlock can only fail for one of a few reasons:
5901+ // 1. bad-proof-of-work (impossible here, because we've already
5902+ // accepted the header)
5903+ // 2. merkleroot doesn't match the transactions given (already
5904+ // caught in FillBlock with READ_STATUS_FAILED, so
5905+ // impossible here)
5906+ // 3. the block is otherwise invalid (eg invalid coinbase,
5907+ // block is too big, too many legacy sigops, etc).
5908+ // So if CheckBlock failed, #3 is the only possibility.
5909+ // Under BIP 152, we don't DoS-ban unless proof of work is
5910+ // invalid (we don't require all the stateless checks to have
5911+ // been run). This is handled below, so just treat this as
5912+ // though the block was successfully read, and rely on the
5913+ // handling in ProcessNewBlock to ensure the block index is
5914+ // updated, reject messages go out, etc.
58965915 MarkBlockAsReceived (resp.blockhash ); // it is now an empty pointer
58975916 fBlockRead = true ;
58985917 }
@@ -5901,16 +5920,15 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
59015920 CValidationState state;
59025921 // Since we requested this block (it was in mapBlocksInFlight), force it to be processed,
59035922 // even if it would not be a candidate for new tip (missing previous block, chain not long enough, etc)
5904- ProcessNewBlock (state, chainparams, pfrom, &block, true , NULL );
5923+ // BIP 152 permits peers to relay compact blocks after validating
5924+ // the header only; we should not punish peers if the block turns
5925+ // out to be invalid.
5926+ ProcessNewBlock (state, chainparams, pfrom, &block, true , NULL , false );
59055927 int nDoS;
59065928 if (state.IsInvalid (nDoS)) {
59075929 assert (state.GetRejectCode () < REJECT_INTERNAL); // Blocks are never rejected with internal reject codes
59085930 connman.PushMessage (pfrom, NetMsgType::REJECT, strCommand, (unsigned char )state.GetRejectCode (),
59095931 state.GetRejectReason ().substr (0 , MAX_REJECT_MESSAGE_LENGTH), block.GetHash ());
5910- if (nDoS > 0 ) {
5911- LOCK (cs_main);
5912- Misbehaving (pfrom->GetId (), nDoS);
5913- }
59145932 }
59155933 }
59165934 }
@@ -6081,7 +6099,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
60816099 // need it even though it is not a candidate for a new best tip.
60826100 forceProcessing |= MarkBlockAsReceived (block.GetHash ());
60836101 }
6084- ProcessNewBlock (state, chainparams, pfrom, &block, forceProcessing, NULL );
6102+ ProcessNewBlock (state, chainparams, pfrom, &block, forceProcessing, NULL , true );
60856103 int nDoS;
60866104 if (state.IsInvalid (nDoS)) {
60876105 assert (state.GetRejectCode () < REJECT_INTERNAL); // Blocks are never rejected with internal reject codes
0 commit comments