Skip to content

Commit 015865e

Browse files
committed
Fix compact block handling to not ban if block is invalid
1 parent 8290506 commit 015865e

File tree

7 files changed

+40
-21
lines changed

7 files changed

+40
-21
lines changed

src/blockencodings.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -167,7 +167,7 @@ ReadStatus PartiallyDownloadedBlock::FillBlock(CBlock& block, const std::vector<
167167
// check its own merkle root and cache that check.
168168
if (state.CorruptionPossible())
169169
return READ_STATUS_FAILED; // Possible Short ID collision
170-
return READ_STATUS_INVALID;
170+
return READ_STATUS_CHECKBLOCK_FAILED;
171171
}
172172

173173
LogPrint("cmpctblock", "Successfully reconstructed block %s with %lu txn prefilled, %lu txn from mempool and %lu txn requested\n", header.GetHash().ToString(), prefilled_count, mempool_count, vtx_missing.size());

src/blockencodings.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,8 @@ typedef enum ReadStatus_t
124124
READ_STATUS_OK,
125125
READ_STATUS_INVALID, // Invalid object, peer is sending bogus crap
126126
READ_STATUS_FAILED, // Failed to process object
127+
READ_STATUS_CHECKBLOCK_FAILED, // Used only by FillBlock to indicate a
128+
// failure in CheckBlock.
127129
} ReadStatus;
128130

129131
class CBlockHeaderAndShortTxIDs {

src/main.cpp

Lines changed: 32 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -178,8 +178,10 @@ namespace {
178178
* Sources of received blocks, saved to be able to send them reject
179179
* messages or ban them when processing happens afterwards. Protected by
180180
* cs_main.
181+
* Set mapBlockSource[hash].second to false if the node should not be
182+
* punished if the block is invalid.
181183
*/
182-
map<uint256, NodeId> mapBlockSource;
184+
map<uint256, std::pair<NodeId, bool>> mapBlockSource;
183185

184186
/**
185187
* Filter for transactions that were recently rejected by
@@ -1885,13 +1887,13 @@ void static InvalidChainFound(CBlockIndex* pindexNew)
18851887
void static InvalidBlockFound(CBlockIndex *pindex, const CValidationState &state) {
18861888
int nDoS = 0;
18871889
if (state.IsInvalid(nDoS)) {
1888-
std::map<uint256, NodeId>::iterator it = mapBlockSource.find(pindex->GetBlockHash());
1889-
if (it != mapBlockSource.end() && State(it->second)) {
1890+
std::map<uint256, std::pair<NodeId, bool>>::iterator it = mapBlockSource.find(pindex->GetBlockHash());
1891+
if (it != mapBlockSource.end() && State(it->second.first)) {
18901892
assert (state.GetRejectCode() < REJECT_INTERNAL); // Blocks are never rejected with internal reject codes
18911893
CBlockReject reject = {(unsigned char)state.GetRejectCode(), state.GetRejectReason().substr(0, MAX_REJECT_MESSAGE_LENGTH), pindex->GetBlockHash()};
1892-
State(it->second)->rejects.push_back(reject);
1893-
if (nDoS > 0)
1894-
Misbehaving(it->second, nDoS);
1894+
State(it->second.first)->rejects.push_back(reject);
1895+
if (nDoS > 0 && it->second.second)
1896+
Misbehaving(it->second.first, nDoS);
18951897
}
18961898
}
18971899
if (!state.CorruptionPossible()) {
@@ -3761,7 +3763,7 @@ static bool IsSuperMajority(int minVersion, const CBlockIndex* pstart, unsigned
37613763
}
37623764

37633765

3764-
bool ProcessNewBlock(CValidationState& state, const CChainParams& chainparams, CNode* pfrom, const CBlock* pblock, bool fForceProcessing, const CDiskBlockPos* dbp)
3766+
bool ProcessNewBlock(CValidationState& state, const CChainParams& chainparams, CNode* pfrom, const CBlock* pblock, bool fForceProcessing, const CDiskBlockPos* dbp, bool fMayBanPeerIfInvalid)
37653767
{
37663768
{
37673769
LOCK(cs_main);
@@ -3773,7 +3775,7 @@ bool ProcessNewBlock(CValidationState& state, const CChainParams& chainparams, C
37733775
bool fNewBlock = false;
37743776
bool ret = AcceptBlock(*pblock, state, chainparams, &pindex, fRequested, dbp, &fNewBlock);
37753777
if (pindex && pfrom) {
3776-
mapBlockSource[pindex->GetBlockHash()] = pfrom->GetId();
3778+
mapBlockSource[pindex->GetBlockHash()] = std::make_pair(pfrom->GetId(), fMayBanPeerIfInvalid);
37773779
if (fNewBlock) pfrom->nLastBlockTime = GetTime();
37783780
}
37793781
CheckBlockIndex(chainparams.GetConsensus());
@@ -4717,7 +4719,6 @@ std::string GetWarnings(const std::string& strFor)
47174719

47184720

47194721
//////////////////////////////////////////////////////////////////////////////
4720-
//
47214722
// Messages
47224723
//
47234724

@@ -5791,17 +5792,33 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
57915792
invs.push_back(CInv(MSG_BLOCK | GetFetchFlags(pfrom, chainActive.Tip(), chainparams.GetConsensus()), resp.blockhash));
57925793
pfrom->PushMessage(NetMsgType::GETDATA, invs);
57935794
} else {
5795+
// Block is either okay, or possibly we received
5796+
// READ_STATUS_CHECKBLOCK_FAILED.
5797+
// Note that CheckBlock can only fail for one of a few reasons:
5798+
// 1. bad-proof-of-work (impossible here, because we've already
5799+
// accepted the header)
5800+
// 2. merkleroot doesn't match the transactions given (already
5801+
// caught in FillBlock with READ_STATUS_FAILED, so
5802+
// impossible here)
5803+
// 3. the block is otherwise invalid (eg invalid coinbase,
5804+
// block is too big, too many legacy sigops, etc).
5805+
// So if CheckBlock failed, #3 is the only possibility.
5806+
// Under BIP 152, we don't DoS-ban unless proof of work is
5807+
// invalid (we don't require all the stateless checks to have
5808+
// been run). This is handled below, so just treat this as
5809+
// though the block was successfully read, and rely on the
5810+
// handling in ProcessNewBlock to ensure the block index is
5811+
// updated, reject messages go out, etc.
57945812
CValidationState state;
5795-
ProcessNewBlock(state, chainparams, pfrom, &block, false, NULL);
5813+
// BIP 152 permits peers to relay compact blocks after validating
5814+
// the header only; we should not punish peers if the block turns
5815+
// out to be invalid.
5816+
ProcessNewBlock(state, chainparams, pfrom, &block, false, NULL, false);
57965817
int nDoS;
57975818
if (state.IsInvalid(nDoS)) {
57985819
assert (state.GetRejectCode() < REJECT_INTERNAL); // Blocks are never rejected with internal reject codes
57995820
pfrom->PushMessage(NetMsgType::REJECT, strCommand, (unsigned char)state.GetRejectCode(),
58005821
state.GetRejectReason().substr(0, MAX_REJECT_MESSAGE_LENGTH), block.GetHash());
5801-
if (nDoS > 0) {
5802-
LOCK(cs_main);
5803-
Misbehaving(pfrom->GetId(), nDoS);
5804-
}
58055822
}
58065823
}
58075824
}
@@ -5968,7 +5985,7 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
59685985
// Such an unrequested block may still be processed, subject to the
59695986
// conditions in AcceptBlock().
59705987
bool forceProcessing = pfrom->fWhitelisted && !IsInitialBlockDownload();
5971-
ProcessNewBlock(state, chainparams, pfrom, &block, forceProcessing, NULL);
5988+
ProcessNewBlock(state, chainparams, pfrom, &block, forceProcessing, NULL, true);
59725989
int nDoS;
59735990
if (state.IsInvalid(nDoS)) {
59745991
assert (state.GetRejectCode() < REJECT_INTERNAL); // Blocks are never rejected with internal reject codes

src/main.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -222,7 +222,7 @@ void UnregisterNodeSignals(CNodeSignals& nodeSignals);
222222
* @param[out] dbp The already known disk position of pblock, or NULL if not yet stored.
223223
* @return True if state.IsValid()
224224
*/
225-
bool ProcessNewBlock(CValidationState& state, const CChainParams& chainparams, CNode* pfrom, const CBlock* pblock, bool fForceProcessing, const CDiskBlockPos* dbp);
225+
bool ProcessNewBlock(CValidationState& state, const CChainParams& chainparams, CNode* pfrom, const CBlock* pblock, bool fForceProcessing, const CDiskBlockPos* dbp, bool fMayBanPeerIfInvalid);
226226
/** Check whether enough disk space is available for an incoming block */
227227
bool CheckDiskSpace(uint64_t nAdditionalBytes = 0);
228228
/** Open a block file (blk?????.dat) */

src/rpc/mining.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -131,7 +131,7 @@ UniValue generateBlocks(boost::shared_ptr<CReserveScript> coinbaseScript, int nG
131131
continue;
132132
}
133133
CValidationState state;
134-
if (!ProcessNewBlock(state, Params(), NULL, pblock, true, NULL))
134+
if (!ProcessNewBlock(state, Params(), NULL, pblock, true, NULL, false))
135135
throw JSONRPCError(RPC_INTERNAL_ERROR, "ProcessNewBlock, block not accepted");
136136
++nHeight;
137137
blockHashes.push_back(pblock->GetHash().GetHex());
@@ -760,7 +760,7 @@ UniValue submitblock(const UniValue& params, bool fHelp)
760760
CValidationState state;
761761
submitblock_StateCatcher sc(block.GetHash());
762762
RegisterValidationInterface(&sc);
763-
bool fAccepted = ProcessNewBlock(state, Params(), NULL, &block, true, NULL);
763+
bool fAccepted = ProcessNewBlock(state, Params(), NULL, &block, true, NULL, false);
764764
UnregisterValidationInterface(&sc);
765765
if (fBlockPresent)
766766
{

src/test/miner_tests.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -222,7 +222,7 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity)
222222
pblock->hashMerkleRoot = BlockMerkleRoot(*pblock);
223223
pblock->nNonce = blockinfo[i].nonce;
224224
CValidationState state;
225-
BOOST_CHECK(ProcessNewBlock(state, chainparams, NULL, pblock, true, NULL));
225+
BOOST_CHECK(ProcessNewBlock(state, chainparams, NULL, pblock, true, NULL, false));
226226
BOOST_CHECK(state.IsValid());
227227
pblock->hashPrevBlock = pblock->GetHash();
228228
}

src/test/test_bitcoin.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -118,7 +118,7 @@ TestChain100Setup::CreateAndProcessBlock(const std::vector<CMutableTransaction>&
118118
while (!CheckProofOfWork(block.GetHash(), block.nBits, chainparams.GetConsensus())) ++block.nNonce;
119119

120120
CValidationState state;
121-
ProcessNewBlock(state, chainparams, NULL, &block, true, NULL);
121+
ProcessNewBlock(state, chainparams, NULL, &block, true, NULL, false);
122122

123123
CBlock result = block;
124124
delete pblocktemplate;

0 commit comments

Comments
 (0)