|
|
@ -179,8 +179,10 @@ namespace { |
|
|
|
* Sources of received blocks, saved to be able to send them reject |
|
|
|
* Sources of received blocks, saved to be able to send them reject |
|
|
|
* messages or ban them when processing happens afterwards. Protected by |
|
|
|
* messages or ban them when processing happens afterwards. Protected by |
|
|
|
* cs_main. |
|
|
|
* cs_main. |
|
|
|
|
|
|
|
* Set mapBlockSource[hash].second to false if the node should not be |
|
|
|
|
|
|
|
* punished if the block is invalid. |
|
|
|
*/ |
|
|
|
*/ |
|
|
|
map<uint256, NodeId> mapBlockSource; |
|
|
|
map<uint256, std::pair<NodeId, bool>> mapBlockSource; |
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
/**
|
|
|
|
* Filter for transactions that were recently rejected by |
|
|
|
* Filter for transactions that were recently rejected by |
|
|
@ -3759,7 +3761,7 @@ static bool AcceptBlock(const CBlock& block, CValidationState& state, const CCha |
|
|
|
return true; |
|
|
|
return true; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
bool ProcessNewBlock(CValidationState& state, const CChainParams& chainparams, CNode* pfrom, const CBlock* pblock, bool fForceProcessing, const CDiskBlockPos* dbp) |
|
|
|
bool ProcessNewBlock(CValidationState& state, const CChainParams& chainparams, CNode* pfrom, const CBlock* pblock, bool fForceProcessing, const CDiskBlockPos* dbp, bool fMayBanPeerIfInvalid) |
|
|
|
{ |
|
|
|
{ |
|
|
|
{ |
|
|
|
{ |
|
|
|
LOCK(cs_main); |
|
|
|
LOCK(cs_main); |
|
|
@ -3769,7 +3771,7 @@ bool ProcessNewBlock(CValidationState& state, const CChainParams& chainparams, C |
|
|
|
bool fNewBlock = false; |
|
|
|
bool fNewBlock = false; |
|
|
|
bool ret = AcceptBlock(*pblock, state, chainparams, &pindex, fForceProcessing, dbp, &fNewBlock); |
|
|
|
bool ret = AcceptBlock(*pblock, state, chainparams, &pindex, fForceProcessing, dbp, &fNewBlock); |
|
|
|
if (pindex && pfrom) { |
|
|
|
if (pindex && pfrom) { |
|
|
|
mapBlockSource[pindex->GetBlockHash()] = pfrom->GetId(); |
|
|
|
mapBlockSource[pindex->GetBlockHash()] = std::make_pair(pfrom->GetId(), fMayBanPeerIfInvalid); |
|
|
|
if (fNewBlock) pfrom->nLastBlockTime = GetTime(); |
|
|
|
if (fNewBlock) pfrom->nLastBlockTime = GetTime(); |
|
|
|
} |
|
|
|
} |
|
|
|
CheckBlockIndex(chainparams.GetConsensus()); |
|
|
|
CheckBlockIndex(chainparams.GetConsensus()); |
|
|
@ -4749,16 +4751,16 @@ void PeerLogicValidation::BlockChecked(const CBlock& block, const CValidationSta |
|
|
|
LOCK(cs_main); |
|
|
|
LOCK(cs_main); |
|
|
|
|
|
|
|
|
|
|
|
const uint256 hash(block.GetHash()); |
|
|
|
const uint256 hash(block.GetHash()); |
|
|
|
std::map<uint256, NodeId>::iterator it = mapBlockSource.find(hash); |
|
|
|
std::map<uint256, std::pair<NodeId, bool>>::iterator it = mapBlockSource.find(hash); |
|
|
|
|
|
|
|
|
|
|
|
int nDoS = 0; |
|
|
|
int nDoS = 0; |
|
|
|
if (state.IsInvalid(nDoS)) { |
|
|
|
if (state.IsInvalid(nDoS)) { |
|
|
|
if (it != mapBlockSource.end() && State(it->second)) { |
|
|
|
if (it != mapBlockSource.end() && State(it->second.first)) { |
|
|
|
assert (state.GetRejectCode() < REJECT_INTERNAL); // Blocks are never rejected with internal reject codes
|
|
|
|
assert (state.GetRejectCode() < REJECT_INTERNAL); // Blocks are never rejected with internal reject codes
|
|
|
|
CBlockReject reject = {(unsigned char)state.GetRejectCode(), state.GetRejectReason().substr(0, MAX_REJECT_MESSAGE_LENGTH), hash}; |
|
|
|
CBlockReject reject = {(unsigned char)state.GetRejectCode(), state.GetRejectReason().substr(0, MAX_REJECT_MESSAGE_LENGTH), hash}; |
|
|
|
State(it->second)->rejects.push_back(reject); |
|
|
|
State(it->second.first)->rejects.push_back(reject); |
|
|
|
if (nDoS > 0) |
|
|
|
if (nDoS > 0 && it->second.second) |
|
|
|
Misbehaving(it->second, nDoS); |
|
|
|
Misbehaving(it->second.first, nDoS); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
if (it != mapBlockSource.end()) |
|
|
|
if (it != mapBlockSource.end()) |
|
|
@ -5868,6 +5870,23 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, |
|
|
|
invs.push_back(CInv(MSG_BLOCK | GetFetchFlags(pfrom, chainActive.Tip(), chainparams.GetConsensus()), resp.blockhash)); |
|
|
|
invs.push_back(CInv(MSG_BLOCK | GetFetchFlags(pfrom, chainActive.Tip(), chainparams.GetConsensus()), resp.blockhash)); |
|
|
|
pfrom->PushMessage(NetMsgType::GETDATA, invs); |
|
|
|
pfrom->PushMessage(NetMsgType::GETDATA, invs); |
|
|
|
} else { |
|
|
|
} else { |
|
|
|
|
|
|
|
// Block is either okay, or possibly we received
|
|
|
|
|
|
|
|
// READ_STATUS_CHECKBLOCK_FAILED.
|
|
|
|
|
|
|
|
// Note that CheckBlock can only fail for one of a few reasons:
|
|
|
|
|
|
|
|
// 1. bad-proof-of-work (impossible here, because we've already
|
|
|
|
|
|
|
|
// accepted the header)
|
|
|
|
|
|
|
|
// 2. merkleroot doesn't match the transactions given (already
|
|
|
|
|
|
|
|
// caught in FillBlock with READ_STATUS_FAILED, so
|
|
|
|
|
|
|
|
// impossible here)
|
|
|
|
|
|
|
|
// 3. the block is otherwise invalid (eg invalid coinbase,
|
|
|
|
|
|
|
|
// block is too big, too many legacy sigops, etc).
|
|
|
|
|
|
|
|
// So if CheckBlock failed, #3 is the only possibility.
|
|
|
|
|
|
|
|
// Under BIP 152, we don't DoS-ban unless proof of work is
|
|
|
|
|
|
|
|
// invalid (we don't require all the stateless checks to have
|
|
|
|
|
|
|
|
// been run). This is handled below, so just treat this as
|
|
|
|
|
|
|
|
// though the block was successfully read, and rely on the
|
|
|
|
|
|
|
|
// handling in ProcessNewBlock to ensure the block index is
|
|
|
|
|
|
|
|
// updated, reject messages go out, etc.
|
|
|
|
MarkBlockAsReceived(resp.blockhash); // it is now an empty pointer
|
|
|
|
MarkBlockAsReceived(resp.blockhash); // it is now an empty pointer
|
|
|
|
fBlockRead = true; |
|
|
|
fBlockRead = true; |
|
|
|
} |
|
|
|
} |
|
|
@ -5876,16 +5895,15 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, |
|
|
|
CValidationState state; |
|
|
|
CValidationState state; |
|
|
|
// Since we requested this block (it was in mapBlocksInFlight), force it to be processed,
|
|
|
|
// Since we requested this block (it was in mapBlocksInFlight), force it to be processed,
|
|
|
|
// even if it would not be a candidate for new tip (missing previous block, chain not long enough, etc)
|
|
|
|
// even if it would not be a candidate for new tip (missing previous block, chain not long enough, etc)
|
|
|
|
ProcessNewBlock(state, chainparams, pfrom, &block, true, NULL); |
|
|
|
// BIP 152 permits peers to relay compact blocks after validating
|
|
|
|
|
|
|
|
// the header only; we should not punish peers if the block turns
|
|
|
|
|
|
|
|
// out to be invalid.
|
|
|
|
|
|
|
|
ProcessNewBlock(state, chainparams, pfrom, &block, true, NULL, false); |
|
|
|
int nDoS; |
|
|
|
int nDoS; |
|
|
|
if (state.IsInvalid(nDoS)) { |
|
|
|
if (state.IsInvalid(nDoS)) { |
|
|
|
assert (state.GetRejectCode() < REJECT_INTERNAL); // Blocks are never rejected with internal reject codes
|
|
|
|
assert (state.GetRejectCode() < REJECT_INTERNAL); // Blocks are never rejected with internal reject codes
|
|
|
|
pfrom->PushMessage(NetMsgType::REJECT, strCommand, (unsigned char)state.GetRejectCode(), |
|
|
|
pfrom->PushMessage(NetMsgType::REJECT, strCommand, (unsigned char)state.GetRejectCode(), |
|
|
|
state.GetRejectReason().substr(0, MAX_REJECT_MESSAGE_LENGTH), block.GetHash()); |
|
|
|
state.GetRejectReason().substr(0, MAX_REJECT_MESSAGE_LENGTH), block.GetHash()); |
|
|
|
if (nDoS > 0) { |
|
|
|
|
|
|
|
LOCK(cs_main); |
|
|
|
|
|
|
|
Misbehaving(pfrom->GetId(), nDoS); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
@ -6056,7 +6074,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv, |
|
|
|
// need it even though it is not a candidate for a new best tip.
|
|
|
|
// need it even though it is not a candidate for a new best tip.
|
|
|
|
forceProcessing |= MarkBlockAsReceived(block.GetHash()); |
|
|
|
forceProcessing |= MarkBlockAsReceived(block.GetHash()); |
|
|
|
} |
|
|
|
} |
|
|
|
ProcessNewBlock(state, chainparams, pfrom, &block, forceProcessing, NULL); |
|
|
|
ProcessNewBlock(state, chainparams, pfrom, &block, forceProcessing, NULL, true); |
|
|
|
int nDoS; |
|
|
|
int nDoS; |
|
|
|
if (state.IsInvalid(nDoS)) { |
|
|
|
if (state.IsInvalid(nDoS)) { |
|
|
|
assert (state.GetRejectCode() < REJECT_INTERNAL); // Blocks are never rejected with internal reject codes
|
|
|
|
assert (state.GetRejectCode() < REJECT_INTERNAL); // Blocks are never rejected with internal reject codes
|
|
|
|