@@ -180,8 +180,10 @@ namespace {
180
180
* Sources of received blocks, saved to be able to send them reject
181
181
* messages or ban them when processing happens afterwards. Protected by
182
182
* cs_main.
183
+ * Set mapBlockSource[hash].second to false if the node should not be
184
+ * punished if the block is invalid.
183
185
*/
184
- map<uint256, NodeId> mapBlockSource;
186
+ map<uint256, std::pair< NodeId, bool > > mapBlockSource;
185
187
186
188
/* *
187
189
* Filter for transactions that were recently rejected by
@@ -3785,7 +3787,7 @@ static bool AcceptBlock(const CBlock& block, CValidationState& state, const CCha
3785
3787
return true ;
3786
3788
}
3787
3789
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 )
3789
3791
{
3790
3792
{
3791
3793
LOCK (cs_main);
@@ -3795,7 +3797,7 @@ bool ProcessNewBlock(CValidationState& state, const CChainParams& chainparams, C
3795
3797
bool fNewBlock = false ;
3796
3798
bool ret = AcceptBlock (*pblock, state, chainparams, &pindex, fForceProcessing , dbp, &fNewBlock );
3797
3799
if (pindex && pfrom) {
3798
- mapBlockSource[pindex->GetBlockHash ()] = pfrom->GetId ();
3800
+ mapBlockSource[pindex->GetBlockHash ()] = std::make_pair ( pfrom->GetId (), fMayBanPeerIfInvalid );
3799
3801
if (fNewBlock ) pfrom->nLastBlockTime = GetTime ();
3800
3802
}
3801
3803
CheckBlockIndex (chainparams.GetConsensus ());
@@ -4775,16 +4777,16 @@ void PeerLogicValidation::BlockChecked(const CBlock& block, const CValidationSta
4775
4777
LOCK (cs_main);
4776
4778
4777
4779
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);
4779
4781
4780
4782
int nDoS = 0 ;
4781
4783
if (state.IsInvalid (nDoS)) {
4782
- if (it != mapBlockSource.end () && State (it->second )) {
4784
+ if (it != mapBlockSource.end () && State (it->second . first )) {
4783
4785
assert (state.GetRejectCode () < REJECT_INTERNAL); // Blocks are never rejected with internal reject codes
4784
4786
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);
4788
4790
}
4789
4791
}
4790
4792
if (it != mapBlockSource.end ())
@@ -5893,6 +5895,23 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
5893
5895
invs.push_back (CInv (MSG_BLOCK | GetFetchFlags (pfrom, chainActive.Tip (), chainparams.GetConsensus ()), resp.blockhash ));
5894
5896
connman.PushMessage (pfrom, NetMsgType::GETDATA, invs);
5895
5897
} 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.
5896
5915
MarkBlockAsReceived (resp.blockhash ); // it is now an empty pointer
5897
5916
fBlockRead = true ;
5898
5917
}
@@ -5901,16 +5920,15 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
5901
5920
CValidationState state;
5902
5921
// Since we requested this block (it was in mapBlocksInFlight), force it to be processed,
5903
5922
// 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 );
5905
5927
int nDoS;
5906
5928
if (state.IsInvalid (nDoS)) {
5907
5929
assert (state.GetRejectCode () < REJECT_INTERNAL); // Blocks are never rejected with internal reject codes
5908
5930
connman.PushMessage (pfrom, NetMsgType::REJECT, strCommand, (unsigned char )state.GetRejectCode (),
5909
5931
state.GetRejectReason ().substr (0 , MAX_REJECT_MESSAGE_LENGTH), block.GetHash ());
5910
- if (nDoS > 0 ) {
5911
- LOCK (cs_main);
5912
- Misbehaving (pfrom->GetId (), nDoS);
5913
- }
5914
5932
}
5915
5933
}
5916
5934
}
@@ -6081,7 +6099,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
6081
6099
// need it even though it is not a candidate for a new best tip.
6082
6100
forceProcessing |= MarkBlockAsReceived (block.GetHash ());
6083
6101
}
6084
- ProcessNewBlock (state, chainparams, pfrom, &block, forceProcessing, NULL );
6102
+ ProcessNewBlock (state, chainparams, pfrom, &block, forceProcessing, NULL , true );
6085
6103
int nDoS;
6086
6104
if (state.IsInvalid (nDoS)) {
6087
6105
assert (state.GetRejectCode () < REJECT_INTERNAL); // Blocks are never rejected with internal reject codes
0 commit comments