Store block on disk. If dbp is non-nullptr, the file is known to already reside on disk */
| 4306 | |
| 4307 | /** Store block on disk. If dbp is non-nullptr, the file is known to already reside on disk */ |
| 4308 | bool ChainstateManager::AcceptBlock(const std::shared_ptr<const CBlock>& pblock, BlockValidationState& state, CBlockIndex** ppindex, bool fRequested, const FlatFilePos* dbp, bool* fNewBlock, bool min_pow_checked) |
| 4309 | { |
| 4310 | const CBlock& block = *pblock; |
| 4311 | |
| 4312 | if (fNewBlock) *fNewBlock = false; |
| 4313 | AssertLockHeld(cs_main); |
| 4314 | |
| 4315 | CBlockIndex *pindexDummy = nullptr; |
| 4316 | CBlockIndex *&pindex = ppindex ? *ppindex : pindexDummy; |
| 4317 | |
| 4318 | bool accepted_header{AcceptBlockHeader(block, state, &pindex, min_pow_checked)}; |
| 4319 | CheckBlockIndex(); |
| 4320 | |
| 4321 | if (!accepted_header) |
| 4322 | return false; |
| 4323 | |
| 4324 | // Check all requested blocks that we do not already have for validity and |
| 4325 | // save them to disk. Skip processing of unrequested blocks as an anti-DoS |
| 4326 | // measure, unless the blocks have more work than the active chain tip, and |
| 4327 | // aren't too far ahead of it, so are likely to be attached soon. |
| 4328 | bool fAlreadyHave = pindex->nStatus & BLOCK_HAVE_DATA; |
| 4329 | bool fHasMoreOrSameWork = (ActiveTip() ? pindex->nChainWork >= ActiveTip()->nChainWork : true); |
| 4330 | // Blocks that are too out-of-order needlessly limit the effectiveness of |
| 4331 | // pruning, because pruning will not delete block files that contain any |
| 4332 | // blocks which are too close in height to the tip. Apply this test |
| 4333 | // regardless of whether pruning is enabled; it should generally be safe to |
| 4334 | // not process unrequested blocks. |
| 4335 | bool fTooFarAhead{pindex->nHeight > ActiveHeight() + int(MIN_BLOCKS_TO_KEEP)}; |
| 4336 | |
| 4337 | // TODO: Decouple this function from the block download logic by removing fRequested |
| 4338 | // This requires some new chain data structure to efficiently look up if a |
| 4339 | // block is in a chain leading to a candidate for best tip, despite not |
| 4340 | // being such a candidate itself. |
| 4341 | // Note that this would break the getblockfrompeer RPC |
| 4342 | |
| 4343 | // TODO: deal better with return value and error conditions for duplicate |
| 4344 | // and unrequested blocks. |
| 4345 | if (fAlreadyHave) return true; |
| 4346 | if (!fRequested) { // If we didn't ask for it: |
| 4347 | if (pindex->nTx != 0) return true; // This is a previously-processed block that was pruned |
| 4348 | if (!fHasMoreOrSameWork) return true; // Don't process less-work chains |
| 4349 | if (fTooFarAhead) return true; // Block height is too high |
| 4350 | |
| 4351 | // Protect against DoS attacks from low-work chains. |
| 4352 | // If our tip is behind, a peer could try to send us |
| 4353 | // low-work blocks on a fake chain that we would never |
| 4354 | // request; don't process these. |
| 4355 | if (pindex->nChainWork < MinimumChainWork()) return true; |
| 4356 | } |
| 4357 | |
| 4358 | const CChainParams& params{GetParams()}; |
| 4359 | |
| 4360 | if (!CheckBlock(block, state, params.GetConsensus()) || |
| 4361 | !ContextualCheckBlock(block, state, *this, pindex->pprev)) { |
| 4362 | if (Assume(state.IsInvalid())) { |
| 4363 | ActiveChainstate().InvalidBlockFound(pindex, state); |
| 4364 | } |
| 4365 | LogError("%s: %s\n", __func__, state.ToString()); |