@@ -179,8 +179,10 @@ namespace {
179179 * Sources of received blocks, saved to be able to send them reject
180180 * messages or ban them when processing happens afterwards. Protected by
181181 * cs_main.
182+ * Set mapBlockSource[hash].second to false if the node should not be
183+ * punished if the block is invalid.
182184 */
183- map<uint256, NodeId> mapBlockSource;
185+ map<uint256, std::pair< NodeId, bool > > mapBlockSource;
184186
185187 /* *
186188 * Filter for transactions that were recently rejected by
@@ -3759,7 +3761,7 @@ static bool AcceptBlock(const CBlock& block, CValidationState& state, const CCha
37593761 return true ;
37603762}
37613763
3762- bool ProcessNewBlock (CValidationState& state, const CChainParams& chainparams, CNode* pfrom, const CBlock* pblock, bool fForceProcessing , const CDiskBlockPos* dbp)
3764+ bool ProcessNewBlock (CValidationState& state, const CChainParams& chainparams, CNode* pfrom, const CBlock* pblock, bool fForceProcessing , const CDiskBlockPos* dbp, bool fMayBanPeerIfInvalid )
37633765{
37643766 {
37653767 LOCK (cs_main);
@@ -3769,7 +3771,7 @@ bool ProcessNewBlock(CValidationState& state, const CChainParams& chainparams, C
37693771 bool fNewBlock = false ;
37703772 bool ret = AcceptBlock (*pblock, state, chainparams, &pindex, fForceProcessing , dbp, &fNewBlock );
37713773 if (pindex && pfrom) {
3772- mapBlockSource[pindex->GetBlockHash ()] = pfrom->GetId ();
3774+ mapBlockSource[pindex->GetBlockHash ()] = std::make_pair ( pfrom->GetId (), fMayBanPeerIfInvalid );
37733775 if (fNewBlock ) pfrom->nLastBlockTime = GetTime ();
37743776 }
37753777 CheckBlockIndex (chainparams.GetConsensus ());
@@ -4749,16 +4751,16 @@ void PeerLogicValidation::BlockChecked(const CBlock& block, const CValidationSta
47494751 LOCK (cs_main);
47504752
47514753 const uint256 hash (block.GetHash ());
4752- std::map<uint256, NodeId>::iterator it = mapBlockSource.find (hash);
4754+ std::map<uint256, std::pair< NodeId, bool > >::iterator it = mapBlockSource.find (hash);
47534755
47544756 int nDoS = 0 ;
47554757 if (state.IsInvalid (nDoS)) {
4756- if (it != mapBlockSource.end () && State (it->second )) {
4758+ if (it != mapBlockSource.end () && State (it->second . first )) {
47574759 assert (state.GetRejectCode () < REJECT_INTERNAL); // Blocks are never rejected with internal reject codes
47584760 CBlockReject reject = {(unsigned char )state.GetRejectCode (), state.GetRejectReason ().substr (0 , MAX_REJECT_MESSAGE_LENGTH), hash};
4759- State (it->second )->rejects .push_back (reject);
4760- if (nDoS > 0 )
4761- Misbehaving (it->second , nDoS);
4761+ State (it->second . first )->rejects .push_back (reject);
4762+ if (nDoS > 0 && it-> second . second )
4763+ Misbehaving (it->second . first , nDoS);
47624764 }
47634765 }
47644766 if (it != mapBlockSource.end ())
@@ -5868,6 +5870,23 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
58685870 invs.push_back (CInv (MSG_BLOCK | GetFetchFlags (pfrom, chainActive.Tip (), chainparams.GetConsensus ()), resp.blockhash ));
58695871 pfrom->PushMessage (NetMsgType::GETDATA, invs);
58705872 } else {
5873+ // Block is either okay, or possibly we received
5874+ // READ_STATUS_CHECKBLOCK_FAILED.
5875+ // Note that CheckBlock can only fail for one of a few reasons:
5876+ // 1. bad-proof-of-work (impossible here, because we've already
5877+ // accepted the header)
5878+ // 2. merkleroot doesn't match the transactions given (already
5879+ // caught in FillBlock with READ_STATUS_FAILED, so
5880+ // impossible here)
5881+ // 3. the block is otherwise invalid (eg invalid coinbase,
5882+ // block is too big, too many legacy sigops, etc).
5883+ // So if CheckBlock failed, #3 is the only possibility.
5884+ // Under BIP 152, we don't DoS-ban unless proof of work is
5885+ // invalid (we don't require all the stateless checks to have
5886+ // been run). This is handled below, so just treat this as
5887+ // though the block was successfully read, and rely on the
5888+ // handling in ProcessNewBlock to ensure the block index is
5889+ // updated, reject messages go out, etc.
58715890 MarkBlockAsReceived (resp.blockhash ); // it is now an empty pointer
58725891 fBlockRead = true ;
58735892 }
@@ -5876,16 +5895,15 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
58765895 CValidationState state;
58775896 // Since we requested this block (it was in mapBlocksInFlight), force it to be processed,
58785897 // even if it would not be a candidate for new tip (missing previous block, chain not long enough, etc)
5879- ProcessNewBlock (state, chainparams, pfrom, &block, true , NULL );
5898+ // BIP 152 permits peers to relay compact blocks after validating
5899+ // the header only; we should not punish peers if the block turns
5900+ // out to be invalid.
5901+ ProcessNewBlock (state, chainparams, pfrom, &block, true , NULL , false );
58805902 int nDoS;
58815903 if (state.IsInvalid (nDoS)) {
58825904 assert (state.GetRejectCode () < REJECT_INTERNAL); // Blocks are never rejected with internal reject codes
58835905 pfrom->PushMessage (NetMsgType::REJECT, strCommand, (unsigned char )state.GetRejectCode (),
58845906 state.GetRejectReason ().substr (0 , MAX_REJECT_MESSAGE_LENGTH), block.GetHash ());
5885- if (nDoS > 0 ) {
5886- LOCK (cs_main);
5887- Misbehaving (pfrom->GetId (), nDoS);
5888- }
58895907 }
58905908 }
58915909 }
@@ -6056,7 +6074,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
60566074 // need it even though it is not a candidate for a new best tip.
60576075 forceProcessing |= MarkBlockAsReceived (block.GetHash ());
60586076 }
6059- ProcessNewBlock (state, chainparams, pfrom, &block, forceProcessing, NULL );
6077+ ProcessNewBlock (state, chainparams, pfrom, &block, forceProcessing, NULL , true );
60606078 int nDoS;
60616079 if (state.IsInvalid (nDoS)) {
60626080 assert (state.GetRejectCode () < REJECT_INTERNAL); // Blocks are never rejected with internal reject codes
0 commit comments