mirror of
https://github.com/bitcoin/bitcoin.git
synced 2026-01-19 06:43:45 +01:00
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()
This commit is contained in:
40
src/main.cpp
40
src/main.cpp
@@ -296,7 +296,8 @@ void FinalizeNode(NodeId nodeid) {
|
||||
}
|
||||
|
||||
// Requires cs_main.
|
||||
void MarkBlockAsReceived(const uint256& hash) {
|
||||
// Returns a bool indicating whether we requested this block.
|
||||
bool MarkBlockAsReceived(const uint256& hash) {
|
||||
map<uint256, pair<NodeId, list<QueuedBlock>::iterator> >::iterator itInFlight = mapBlocksInFlight.find(hash);
|
||||
if (itInFlight != mapBlocksInFlight.end()) {
|
||||
CNodeState *state = State(itInFlight->second.first);
|
||||
@@ -306,7 +307,9 @@ void MarkBlockAsReceived(const uint256& hash) {
|
||||
state->nBlocksInFlight--;
|
||||
state->nStallingSince = 0;
|
||||
mapBlocksInFlight.erase(itInFlight);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// Requires cs_main.
|
||||
@@ -2826,7 +2829,7 @@ bool AcceptBlockHeader(const CBlockHeader& block, CValidationState& state, CBloc
|
||||
return true;
|
||||
}
|
||||
|
||||
bool AcceptBlock(CBlock& block, CValidationState& state, CBlockIndex** ppindex, CDiskBlockPos* dbp)
|
||||
bool AcceptBlock(CBlock& block, CValidationState& state, CBlockIndex** ppindex, bool fRequested, CDiskBlockPos* dbp)
|
||||
{
|
||||
const CChainParams& chainparams = Params();
|
||||
AssertLockHeld(cs_main);
|
||||
@@ -2836,13 +2839,18 @@ bool AcceptBlock(CBlock& block, CValidationState& state, CBlockIndex** ppindex,
|
||||
if (!AcceptBlockHeader(block, state, &pindex))
|
||||
return false;
|
||||
|
||||
// If we're pruning, ensure that we don't allow a peer to dump a copy
|
||||
// of old blocks. But we might need blocks that are not on the main chain
|
||||
// to handle a reorg, even if we've processed once.
|
||||
if (pindex->nStatus & BLOCK_HAVE_DATA || chainActive.Contains(pindex)) {
|
||||
// TODO: deal better with duplicate blocks.
|
||||
// return state.DoS(20, error("AcceptBlock(): already have block %d %s", pindex->nHeight, pindex->GetBlockHash().ToString()), REJECT_DUPLICATE, "duplicate");
|
||||
return true;
|
||||
// Try to process all requested blocks that we don't have, but only
|
||||
// process an unrequested block if it's new and has enough work to
|
||||
// advance our tip.
|
||||
bool fAlreadyHave = pindex->nStatus & BLOCK_HAVE_DATA;
|
||||
bool fHasMoreWork = (chainActive.Tip() ? pindex->nChainWork > chainActive.Tip()->nChainWork : true);
|
||||
|
||||
// TODO: deal better with return value and error conditions for duplicate
|
||||
// and unrequested blocks.
|
||||
if (fAlreadyHave) return true;
|
||||
if (!fRequested) { // If we didn't ask for it:
|
||||
if (pindex->nTx != 0) return true; // This is a previously-processed block that was pruned
|
||||
if (!fHasMoreWork) return true; // Don't process less-work chains
|
||||
}
|
||||
|
||||
if ((!CheckBlock(block, state)) || !ContextualCheckBlock(block, state, pindex->pprev)) {
|
||||
@@ -2891,21 +2899,22 @@ static bool IsSuperMajority(int minVersion, const CBlockIndex* pstart, unsigned
|
||||
}
|
||||
|
||||
|
||||
bool ProcessNewBlock(CValidationState &state, CNode* pfrom, CBlock* pblock, CDiskBlockPos *dbp)
|
||||
bool ProcessNewBlock(CValidationState &state, CNode* pfrom, CBlock* pblock, bool fForceProcessing, CDiskBlockPos *dbp)
|
||||
{
|
||||
// Preliminary checks
|
||||
bool checked = CheckBlock(*pblock, state);
|
||||
|
||||
{
|
||||
LOCK(cs_main);
|
||||
MarkBlockAsReceived(pblock->GetHash());
|
||||
bool fRequested = MarkBlockAsReceived(pblock->GetHash());
|
||||
fRequested |= fForceProcessing;
|
||||
if (!checked) {
|
||||
return error("%s: CheckBlock FAILED", __func__);
|
||||
}
|
||||
|
||||
// Store to disk
|
||||
CBlockIndex *pindex = NULL;
|
||||
bool ret = AcceptBlock(*pblock, state, &pindex, dbp);
|
||||
bool ret = AcceptBlock(*pblock, state, &pindex, fRequested, dbp);
|
||||
if (pindex && pfrom) {
|
||||
mapBlockSource[pindex->GetBlockHash()] = pfrom->GetId();
|
||||
}
|
||||
@@ -3453,7 +3462,7 @@ bool LoadExternalBlockFile(FILE* fileIn, CDiskBlockPos *dbp)
|
||||
// process in case the block isn't known yet
|
||||
if (mapBlockIndex.count(hash) == 0 || (mapBlockIndex[hash]->nStatus & BLOCK_HAVE_DATA) == 0) {
|
||||
CValidationState state;
|
||||
if (ProcessNewBlock(state, NULL, &block, dbp))
|
||||
if (ProcessNewBlock(state, NULL, &block, true, dbp))
|
||||
nLoaded++;
|
||||
if (state.IsError())
|
||||
break;
|
||||
@@ -3475,7 +3484,7 @@ bool LoadExternalBlockFile(FILE* fileIn, CDiskBlockPos *dbp)
|
||||
LogPrintf("%s: Processing out of order child %s of %s\n", __func__, block.GetHash().ToString(),
|
||||
head.ToString());
|
||||
CValidationState dummy;
|
||||
if (ProcessNewBlock(dummy, NULL, &block, &it->second))
|
||||
if (ProcessNewBlock(dummy, NULL, &block, true, &it->second))
|
||||
{
|
||||
nLoaded++;
|
||||
queue.push_back(block.GetHash());
|
||||
@@ -4462,7 +4471,8 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv,
|
||||
pfrom->AddInventoryKnown(inv);
|
||||
|
||||
CValidationState state;
|
||||
ProcessNewBlock(state, pfrom, &block);
|
||||
// Process all blocks from whitelisted peers, even if not requested.
|
||||
ProcessNewBlock(state, pfrom, &block, pfrom->fWhitelisted, NULL);
|
||||
int nDoS;
|
||||
if (state.IsInvalid(nDoS)) {
|
||||
pfrom->PushMessage("reject", strCommand, state.GetRejectCode(),
|
||||
|
||||
Reference in New Issue
Block a user