Skip to content

Commit 9be0e68

Browse files
committed
Be stricter in processing unrequested blocks
AcceptBlock will no longer process an unrequested block, unless it has not been previously processed and has more work than chainActive.Tip()
1 parent f00b623 commit 9be0e68

File tree

5 files changed

+33
-22
lines changed

5 files changed

+33
-22
lines changed

src/main.cpp

Lines changed: 25 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -296,7 +296,8 @@ void FinalizeNode(NodeId nodeid) {
296296
}
297297

298298
// Requires cs_main.
299-
void MarkBlockAsReceived(const uint256& hash) {
299+
// Returns a bool indicating whether we requested this block.
300+
bool MarkBlockAsReceived(const uint256& hash) {
300301
map<uint256, pair<NodeId, list<QueuedBlock>::iterator> >::iterator itInFlight = mapBlocksInFlight.find(hash);
301302
if (itInFlight != mapBlocksInFlight.end()) {
302303
CNodeState *state = State(itInFlight->second.first);
@@ -306,7 +307,9 @@ void MarkBlockAsReceived(const uint256& hash) {
306307
state->nBlocksInFlight--;
307308
state->nStallingSince = 0;
308309
mapBlocksInFlight.erase(itInFlight);
310+
return true;
309311
}
312+
return false;
310313
}
311314

312315
// Requires cs_main.
@@ -2826,7 +2829,7 @@ bool AcceptBlockHeader(const CBlockHeader& block, CValidationState& state, CBloc
28262829
return true;
28272830
}
28282831

2829-
bool AcceptBlock(CBlock& block, CValidationState& state, CBlockIndex** ppindex, CDiskBlockPos* dbp)
2832+
bool AcceptBlock(CBlock& block, CValidationState& state, CBlockIndex** ppindex, bool fRequested, CDiskBlockPos* dbp)
28302833
{
28312834
const CChainParams& chainparams = Params();
28322835
AssertLockHeld(cs_main);
@@ -2836,13 +2839,18 @@ bool AcceptBlock(CBlock& block, CValidationState& state, CBlockIndex** ppindex,
28362839
if (!AcceptBlockHeader(block, state, &pindex))
28372840
return false;
28382841

2839-
// If we're pruning, ensure that we don't allow a peer to dump a copy
2840-
// of old blocks. But we might need blocks that are not on the main chain
2841-
// to handle a reorg, even if we've processed once.
2842-
if (pindex->nStatus & BLOCK_HAVE_DATA || chainActive.Contains(pindex)) {
2843-
// TODO: deal better with duplicate blocks.
2844-
// return state.DoS(20, error("AcceptBlock(): already have block %d %s", pindex->nHeight, pindex->GetBlockHash().ToString()), REJECT_DUPLICATE, "duplicate");
2845-
return true;
2842+
// Try to process all requested blocks that we don't have, but only
2843+
// process an unrequested block if it's new and has enough work to
2844+
// advance our tip.
2845+
bool fAlreadyHave = pindex->nStatus & BLOCK_HAVE_DATA;
2846+
bool fHasMoreWork = (chainActive.Tip() ? pindex->nChainWork > chainActive.Tip()->nChainWork : true);
2847+
2848+
// TODO: deal better with return value and error conditions for duplicate
2849+
// and unrequested blocks.
2850+
if (fAlreadyHave) return true;
2851+
if (!fRequested) { // If we didn't ask for it:
2852+
if (pindex->nTx != 0) return true; // This is a previously-processed block that was pruned
2853+
if (!fHasMoreWork) return true; // Don't process less-work chains
28462854
}
28472855

28482856
if ((!CheckBlock(block, state)) || !ContextualCheckBlock(block, state, pindex->pprev)) {
@@ -2891,21 +2899,22 @@ static bool IsSuperMajority(int minVersion, const CBlockIndex* pstart, unsigned
28912899
}
28922900

28932901

2894-
bool ProcessNewBlock(CValidationState &state, CNode* pfrom, CBlock* pblock, CDiskBlockPos *dbp)
2902+
bool ProcessNewBlock(CValidationState &state, CNode* pfrom, CBlock* pblock, bool fForceProcessing, CDiskBlockPos *dbp)
28952903
{
28962904
// Preliminary checks
28972905
bool checked = CheckBlock(*pblock, state);
28982906

28992907
{
29002908
LOCK(cs_main);
2901-
MarkBlockAsReceived(pblock->GetHash());
2909+
bool fRequested = MarkBlockAsReceived(pblock->GetHash());
2910+
fRequested |= fForceProcessing;
29022911
if (!checked) {
29032912
return error("%s: CheckBlock FAILED", __func__);
29042913
}
29052914

29062915
// Store to disk
29072916
CBlockIndex *pindex = NULL;
2908-
bool ret = AcceptBlock(*pblock, state, &pindex, dbp);
2917+
bool ret = AcceptBlock(*pblock, state, &pindex, fRequested, dbp);
29092918
if (pindex && pfrom) {
29102919
mapBlockSource[pindex->GetBlockHash()] = pfrom->GetId();
29112920
}
@@ -3453,7 +3462,7 @@ bool LoadExternalBlockFile(FILE* fileIn, CDiskBlockPos *dbp)
34533462
// process in case the block isn't known yet
34543463
if (mapBlockIndex.count(hash) == 0 || (mapBlockIndex[hash]->nStatus & BLOCK_HAVE_DATA) == 0) {
34553464
CValidationState state;
3456-
if (ProcessNewBlock(state, NULL, &block, dbp))
3465+
if (ProcessNewBlock(state, NULL, &block, true, dbp))
34573466
nLoaded++;
34583467
if (state.IsError())
34593468
break;
@@ -3475,7 +3484,7 @@ bool LoadExternalBlockFile(FILE* fileIn, CDiskBlockPos *dbp)
34753484
LogPrintf("%s: Processing out of order child %s of %s\n", __func__, block.GetHash().ToString(),
34763485
head.ToString());
34773486
CValidationState dummy;
3478-
if (ProcessNewBlock(dummy, NULL, &block, &it->second))
3487+
if (ProcessNewBlock(dummy, NULL, &block, true, &it->second))
34793488
{
34803489
nLoaded++;
34813490
queue.push_back(block.GetHash());
@@ -4462,7 +4471,8 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
44624471
pfrom->AddInventoryKnown(inv);
44634472

44644473
CValidationState state;
4465-
ProcessNewBlock(state, pfrom, &block);
4474+
// Process all blocks from whitelisted peers, even if not requested.
4475+
ProcessNewBlock(state, pfrom, &block, pfrom->fWhitelisted, NULL);
44664476
int nDoS;
44674477
if (state.IsInvalid(nDoS)) {
44684478
pfrom->PushMessage("reject", strCommand, state.GetRejectCode(),

src/main.h

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -153,10 +153,11 @@ void UnregisterNodeSignals(CNodeSignals& nodeSignals);
153153
* @param[out] state This may be set to an Error state if any error occurred processing it, including during validation/connection/etc of otherwise unrelated blocks during reorganisation; or it may be set to an Invalid state if pblock is itself invalid (but this is not guaranteed even when the block is checked). If you want to *possibly* get feedback on whether pblock is valid, you must also install a CValidationInterface (see validationinterface.h) - this will have its BlockChecked method called whenever *any* block completes validation.
154154
* @param[in] pfrom The node which we are receiving the block from; it is added to mapBlockSource and may be penalised if the block is invalid.
155155
* @param[in] pblock The block we want to process.
156+
* @param[in] fForceProcessing Process this block even if unrequested; used for non-network block sources and whitelisted peers.
156157
* @param[out] dbp If pblock is stored to disk (or already there), this will be set to its location.
157158
* @return True if state.IsValid()
158159
*/
159-
bool ProcessNewBlock(CValidationState &state, CNode* pfrom, CBlock* pblock, CDiskBlockPos *dbp = NULL);
160+
bool ProcessNewBlock(CValidationState &state, CNode* pfrom, CBlock* pblock, bool fForceProcessing, CDiskBlockPos *dbp);
160161
/** Check whether enough disk space is available for an incoming block */
161162
bool CheckDiskSpace(uint64_t nAdditionalBytes = 0);
162163
/** Open a block file (blk?????.dat) */
@@ -400,8 +401,8 @@ bool ContextualCheckBlock(const CBlock& block, CValidationState& state, CBlockIn
400401
/** Check a block is completely valid from start to finish (only works on top of our current best block, with cs_main held) */
401402
bool TestBlockValidity(CValidationState &state, const CBlock& block, CBlockIndex *pindexPrev, bool fCheckPOW = true, bool fCheckMerkleRoot = true);
402403

403-
/** Store block on disk. If dbp is provided, the file is known to already reside on disk */
404-
bool AcceptBlock(CBlock& block, CValidationState& state, CBlockIndex **pindex, CDiskBlockPos* dbp = NULL);
404+
/** Store block on disk. If dbp is non-NULL, the file is known to already reside on disk */
405+
bool AcceptBlock(CBlock& block, CValidationState& state, CBlockIndex **pindex, bool fRequested, CDiskBlockPos* dbp);
405406
bool AcceptBlockHeader(const CBlockHeader& block, CValidationState& state, CBlockIndex **ppindex= NULL);
406407

407408

src/miner.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -434,7 +434,7 @@ static bool ProcessBlockFound(CBlock* pblock, CWallet& wallet, CReserveKey& rese
434434

435435
// Process this block the same as if we had received it from another node
436436
CValidationState state;
437-
if (!ProcessNewBlock(state, NULL, pblock))
437+
if (!ProcessNewBlock(state, NULL, pblock, true, NULL))
438438
return error("BitcoinMiner: ProcessNewBlock, block not accepted");
439439

440440
return true;

src/rpcmining.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -164,7 +164,7 @@ Value generate(const Array& params, bool fHelp)
164164
++pblock->nNonce;
165165
}
166166
CValidationState state;
167-
if (!ProcessNewBlock(state, NULL, pblock))
167+
if (!ProcessNewBlock(state, NULL, pblock, true, NULL))
168168
throw JSONRPCError(RPC_INTERNAL_ERROR, "ProcessNewBlock, block not accepted");
169169
++nHeight;
170170
blockHashes.push_back(pblock->GetHash().GetHex());
@@ -650,7 +650,7 @@ Value submitblock(const Array& params, bool fHelp)
650650
CValidationState state;
651651
submitblock_StateCatcher sc(block.GetHash());
652652
RegisterValidationInterface(&sc);
653-
bool fAccepted = ProcessNewBlock(state, NULL, &block);
653+
bool fAccepted = ProcessNewBlock(state, NULL, &block, true, NULL);
654654
UnregisterValidationInterface(&sc);
655655
if (fBlockPresent)
656656
{

src/test/miner_tests.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ BOOST_AUTO_TEST_CASE(CreateNewBlock_validity)
8484
pblock->hashMerkleRoot = pblock->BuildMerkleTree();
8585
pblock->nNonce = blockinfo[i].nonce;
8686
CValidationState state;
87-
BOOST_CHECK(ProcessNewBlock(state, NULL, pblock));
87+
BOOST_CHECK(ProcessNewBlock(state, NULL, pblock, true, NULL));
8888
BOOST_CHECK(state.IsValid());
8989
pblock->hashPrevBlock = pblock->GetHash();
9090
}

0 commit comments

Comments
 (0)