Changeset View
Changeset View
Standalone View
Standalone View
src/validation.cpp
Show First 20 Lines • Show All 2,338 Lines • ▼ Show 20 Lines | |||||
* the last entry in blocksConnected in case of failure. | * the last entry in blocksConnected in case of failure. | ||||
*/ | */ | ||||
bool CChainState::ConnectTip(const Config &config, BlockValidationState &state, | bool CChainState::ConnectTip(const Config &config, BlockValidationState &state, | ||||
CBlockIndex *pindexNew, | CBlockIndex *pindexNew, | ||||
const std::shared_ptr<const CBlock> &pblock, | const std::shared_ptr<const CBlock> &pblock, | ||||
ConnectTrace &connectTrace, | ConnectTrace &connectTrace, | ||||
DisconnectedBlockTransactions &disconnectpool) { | DisconnectedBlockTransactions &disconnectpool) { | ||||
AssertLockHeld(cs_main); | AssertLockHeld(cs_main); | ||||
AssertLockHeld(g_mempool.cs); | |||||
const CChainParams ¶ms = config.GetChainParams(); | const CChainParams ¶ms = config.GetChainParams(); | ||||
const Consensus::Params &consensusParams = params.GetConsensus(); | const Consensus::Params &consensusParams = params.GetConsensus(); | ||||
assert(pindexNew->pprev == m_chain.Tip()); | assert(pindexNew->pprev == m_chain.Tip()); | ||||
// Read block from disk. | // Read block from disk. | ||||
int64_t nTime1 = GetTimeMicros(); | int64_t nTime1 = GetTimeMicros(); | ||||
std::shared_ptr<const CBlock> pthisBlock; | std::shared_ptr<const CBlock> pthisBlock; | ||||
▲ Show 20 Lines • Show All 463 Lines • ▼ Show 20 Lines | do { | ||||
// never happen in normal operation, however may happen during | // never happen in normal operation, however may happen during | ||||
// reindex, causing memory blowup if we run too far ahead. | // reindex, causing memory blowup if we run too far ahead. | ||||
// Note that if a validationinterface callback ends up calling | // Note that if a validationinterface callback ends up calling | ||||
// ActivateBestChain this may lead to a deadlock! We should | // ActivateBestChain this may lead to a deadlock! We should | ||||
// probably have a DEBUG_LOCKORDER test for this in the future. | // probably have a DEBUG_LOCKORDER test for this in the future. | ||||
LimitValidationInterfaceQueue(); | LimitValidationInterfaceQueue(); | ||||
{ | { | ||||
LOCK(cs_main); | // Lock transaction pool for at least as long as it takes for | ||||
// connectTrace to be consumed | |||||
LOCK2(cs_main, ::g_mempool.cs); | |||||
CBlockIndex *starting_tip = m_chain.Tip(); | CBlockIndex *starting_tip = m_chain.Tip(); | ||||
bool blocks_connected = false; | bool blocks_connected = false; | ||||
do { | do { | ||||
// We absolutely may not unlock cs_main until we've made forward | // We absolutely may not unlock cs_main until we've made forward | ||||
// progress (with the exception of shutdown due to hardware | // progress (with the exception of shutdown due to hardware | ||||
// issues, low disk space, etc). | // issues, low disk space, etc). | ||||
// Destructed before cs_main is unlocked | // Destructed before cs_main is unlocked | ||||
▲ Show 20 Lines • Show All 186 Lines • ▼ Show 20 Lines | while (true) { | ||||
if (ShutdownRequested()) { | if (ShutdownRequested()) { | ||||
break; | break; | ||||
} | } | ||||
// Make sure the queue of validation callbacks doesn't grow unboundedly. | // Make sure the queue of validation callbacks doesn't grow unboundedly. | ||||
LimitValidationInterfaceQueue(); | LimitValidationInterfaceQueue(); | ||||
LOCK(cs_main); | LOCK(cs_main); | ||||
// Lock for as long as disconnectpool is in scope to make sure | |||||
// UpdateMempoolForReorg is called after DisconnectTip without unlocking | |||||
// in between | |||||
LOCK(::g_mempool.cs); | |||||
if (!m_chain.Contains(pindex)) { | if (!m_chain.Contains(pindex)) { | ||||
break; | break; | ||||
} | } | ||||
pindex_was_in_chain = true; | pindex_was_in_chain = true; | ||||
CBlockIndex *invalid_walk_tip = m_chain.Tip(); | CBlockIndex *invalid_walk_tip = m_chain.Tip(); | ||||
// ActivateBestChain considers blocks already in m_chain | // ActivateBestChain considers blocks already in m_chain | ||||
// unconditionally valid already, so force disconnect away from it. | // unconditionally valid already, so force disconnect away from it. | ||||
DisconnectedBlockTransactions disconnectpool; | DisconnectedBlockTransactions disconnectpool; | ||||
bool ret = DisconnectTip(chainparams, state, &disconnectpool); | bool ret = DisconnectTip(chainparams, state, &disconnectpool); | ||||
// DisconnectTip will add transactions to disconnectpool. | // DisconnectTip will add transactions to disconnectpool. | ||||
// Adjust the mempool to be consistent with the new tip, adding | // Adjust the mempool to be consistent with the new tip, adding | ||||
// transactions back to the mempool if disconnecting was successful, | // transactions back to the mempool if disconnecting was successful, | ||||
// and we're not doing a very deep invalidation (in which case | // and we're not doing a very deep invalidation (in which case | ||||
// keeping the mempool up to date is probably futile anyway). | // keeping the mempool up to date is probably futile anyway). | ||||
disconnectpool.updateMempoolForReorg( | disconnectpool.updateMempoolForReorg( | ||||
config, /* fAddToMempool = */ (++disconnected <= 10) && ret, | config, /* fAddToMempool = */ (++disconnected <= 10) && ret, | ||||
g_mempool); | ::g_mempool); | ||||
if (!ret) { | if (!ret) { | ||||
return false; | return false; | ||||
} | } | ||||
assert(invalid_walk_tip->pprev == m_chain.Tip()); | assert(invalid_walk_tip->pprev == m_chain.Tip()); | ||||
// We immediately mark the disconnected blocks as invalid. | // We immediately mark the disconnected blocks as invalid. | ||||
▲ Show 20 Lines • Show All 2,731 Lines • Show Last 20 Lines |