Store block on disk. If dbp is non-nullptr, the file is known to already reside on disk */
| 4074 | |
| 4075 | /** Store block on disk. If dbp is non-nullptr, the file is known to already reside on disk */ |
| 4076 | bool CChainState::AcceptBlock(const std::shared_ptr<const CBlock>& pblock, BlockValidationState& state, CBlockIndex** ppindex, bool fRequested, const FlatFilePos* dbp, bool* fNewBlock) |
| 4077 | { |
| 4078 | const CBlock& block = *pblock; |
| 4079 | |
| 4080 | if (fNewBlock) *fNewBlock = false; |
| 4081 | AssertLockHeld(cs_main); |
| 4082 | |
| 4083 | CBlockIndex *pindexDummy = nullptr; |
| 4084 | CBlockIndex *&pindex = ppindex ? *ppindex : pindexDummy; |
| 4085 | |
| 4086 | bool accepted_header{m_chainman.AcceptBlockHeader(block, state, m_params, &pindex)}; |
| 4087 | CheckBlockIndex(); |
| 4088 | |
| 4089 | if (!accepted_header) |
| 4090 | return false; |
| 4091 | |
| 4092 | // Try to process all requested blocks that we don't have, but only |
| 4093 | // process an unrequested block if it's new and has enough work to |
| 4094 | // advance our tip, and isn't too many blocks ahead. |
| 4095 | bool fAlreadyHave = pindex->nStatus & BLOCK_HAVE_DATA; |
| 4096 | bool fHasMoreOrSameWork = (m_chain.Tip() ? pindex->nChainWork >= m_chain.Tip()->nChainWork : true); |
| 4097 | // Blocks that are too out-of-order needlessly limit the effectiveness of |
| 4098 | // pruning, because pruning will not delete block files that contain any |
| 4099 | // blocks which are too close in height to the tip. Apply this test |
| 4100 | // regardless of whether pruning is enabled; it should generally be safe to |
| 4101 | // not process unrequested blocks. |
| 4102 | bool fTooFarAhead{pindex->nHeight > m_chain.Height() + int(MIN_BLOCKS_TO_KEEP)}; |
| 4103 | |
| 4104 | // TODO: Decouple this function from the block download logic by removing fRequested |
| 4105 | // This requires some new chain data structure to efficiently look up if a |
| 4106 | // block is in a chain leading to a candidate for best tip, despite not |
| 4107 | // being such a candidate itself. |
| 4108 | // Note that this would break the getblockfrompeer RPC |
| 4109 | |
| 4110 | // TODO: deal better with return value and error conditions for duplicate |
| 4111 | // and unrequested blocks. |
| 4112 | if (fAlreadyHave) return true; |
| 4113 | if (!fRequested) { // If we didn't ask for it: |
| 4114 | if (pindex->nTx != 0) return true; // This is a previously-processed block that was pruned |
| 4115 | if (!fHasMoreOrSameWork) return true; // Don't process less-work chains |
| 4116 | if (fTooFarAhead) return true; // Block height is too high |
| 4117 | |
| 4118 | // Protect against DoS attacks from low-work chains. |
| 4119 | // If our tip is behind, a peer could try to send us |
| 4120 | // low-work blocks on a fake chain that we would never |
| 4121 | // request; don't process these. |
| 4122 | if (pindex->nChainWork < nMinimumChainWork) return true; |
| 4123 | } |
| 4124 | |
| 4125 | if (m_params.GetConsensus().hashGenesisBlock != block.GetHash() && |
| 4126 | (!CheckBlock(block, state, m_params.GetConsensus()) || |
| 4127 | !ContextualCheckBlock(block, state, m_params.GetConsensus(), pindex->pprev))) { |
| 4128 | if (state.IsInvalid() && state.GetResult() != BlockValidationResult::BLOCK_MUTATED) { |
| 4129 | pindex->nStatus |= BLOCK_FAILED_VALID; |
| 4130 | m_blockman.m_dirty_blockindex.insert(pindex); |
| 4131 | } |
| 4132 | return error("%s: %s", __func__, state.ToString()); |
| 4133 | } |