@@ -179,8 +179,10 @@ namespace {
179
179
* Sources of received blocks, saved to be able to send them reject
180
180
* messages or ban them when processing happens afterwards. Protected by
181
181
* cs_main.
182
+ * Set mapBlockSource[hash].second to false if the node should not be
183
+ * punished if the block is invalid.
182
184
*/
183
- map<uint256, NodeId> mapBlockSource;
185
+ map<uint256, std::pair< NodeId, bool > > mapBlockSource;
184
186
185
187
/* *
186
188
* Filter for transactions that were recently rejected by
@@ -3759,7 +3761,7 @@ static bool AcceptBlock(const CBlock& block, CValidationState& state, const CCha
3759
3761
return true ;
3760
3762
}
3761
3763
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 )
3763
3765
{
3764
3766
{
3765
3767
LOCK (cs_main);
@@ -3769,7 +3771,7 @@ bool ProcessNewBlock(CValidationState& state, const CChainParams& chainparams, C
3769
3771
bool fNewBlock = false ;
3770
3772
bool ret = AcceptBlock (*pblock, state, chainparams, &pindex, fForceProcessing , dbp, &fNewBlock );
3771
3773
if (pindex && pfrom) {
3772
- mapBlockSource[pindex->GetBlockHash ()] = pfrom->GetId ();
3774
+ mapBlockSource[pindex->GetBlockHash ()] = std::make_pair ( pfrom->GetId (), fMayBanPeerIfInvalid );
3773
3775
if (fNewBlock ) pfrom->nLastBlockTime = GetTime ();
3774
3776
}
3775
3777
CheckBlockIndex (chainparams.GetConsensus ());
@@ -4749,16 +4751,16 @@ void PeerLogicValidation::BlockChecked(const CBlock& block, const CValidationSta
4749
4751
LOCK (cs_main);
4750
4752
4751
4753
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);
4753
4755
4754
4756
int nDoS = 0 ;
4755
4757
if (state.IsInvalid (nDoS)) {
4756
- if (it != mapBlockSource.end () && State (it->second )) {
4758
+ if (it != mapBlockSource.end () && State (it->second . first )) {
4757
4759
assert (state.GetRejectCode () < REJECT_INTERNAL); // Blocks are never rejected with internal reject codes
4758
4760
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);
4762
4764
}
4763
4765
}
4764
4766
if (it != mapBlockSource.end ())
@@ -5868,6 +5870,23 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
5868
5870
invs.push_back (CInv (MSG_BLOCK | GetFetchFlags (pfrom, chainActive.Tip (), chainparams.GetConsensus ()), resp.blockhash ));
5869
5871
pfrom->PushMessage (NetMsgType::GETDATA, invs);
5870
5872
} 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.
5871
5890
MarkBlockAsReceived (resp.blockhash ); // it is now an empty pointer
5872
5891
fBlockRead = true ;
5873
5892
}
@@ -5876,16 +5895,15 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
5876
5895
CValidationState state;
5877
5896
// Since we requested this block (it was in mapBlocksInFlight), force it to be processed,
5878
5897
// 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 );
5880
5902
int nDoS;
5881
5903
if (state.IsInvalid (nDoS)) {
5882
5904
assert (state.GetRejectCode () < REJECT_INTERNAL); // Blocks are never rejected with internal reject codes
5883
5905
pfrom->PushMessage (NetMsgType::REJECT, strCommand, (unsigned char )state.GetRejectCode (),
5884
5906
state.GetRejectReason ().substr (0 , MAX_REJECT_MESSAGE_LENGTH), block.GetHash ());
5885
- if (nDoS > 0 ) {
5886
- LOCK (cs_main);
5887
- Misbehaving (pfrom->GetId (), nDoS);
5888
- }
5889
5907
}
5890
5908
}
5891
5909
}
@@ -6056,7 +6074,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
6056
6074
// need it even though it is not a candidate for a new best tip.
6057
6075
forceProcessing |= MarkBlockAsReceived (block.GetHash ());
6058
6076
}
6059
- ProcessNewBlock (state, chainparams, pfrom, &block, forceProcessing, NULL );
6077
+ ProcessNewBlock (state, chainparams, pfrom, &block, forceProcessing, NULL , true );
6060
6078
int nDoS;
6061
6079
if (state.IsInvalid (nDoS)) {
6062
6080
assert (state.GetRejectCode () < REJECT_INTERNAL); // Blocks are never rejected with internal reject codes
0 commit comments