Changeset View
Changeset View
Standalone View
Standalone View
src/validation.cpp
- This file is larger than 256 KB, so syntax highlighting is disabled by default.
Show First 20 Lines • Show All 1,029 Lines • ▼ Show 20 Lines | PackageMempoolAcceptResult MemPoolAccept::AcceptPackage(const Package &package, | ||||
// Include already-in-mempool transaction results in the final result. | // Include already-in-mempool transaction results in the final result. | ||||
for (const auto &[txid, mempoolaccept_res] : results) { | for (const auto &[txid, mempoolaccept_res] : results) { | ||||
submission_result.m_tx_results.emplace(txid, mempoolaccept_res); | submission_result.m_tx_results.emplace(txid, mempoolaccept_res); | ||||
} | } | ||||
return submission_result; | return submission_result; | ||||
} | } | ||||
} // namespace | } // namespace | ||||
MempoolAcceptResult AcceptToMemoryPool(const Config &config, | MempoolAcceptResult AcceptToMemoryPool(Chainstate &active_chainstate, | ||||
Chainstate &active_chainstate, | |||||
const CTransactionRef &tx, | const CTransactionRef &tx, | ||||
int64_t accept_time, bool bypass_limits, | int64_t accept_time, bool bypass_limits, | ||||
bool test_accept, | bool test_accept, | ||||
unsigned int heightOverride) { | unsigned int heightOverride) { | ||||
AssertLockHeld(::cs_main); | AssertLockHeld(::cs_main); | ||||
assert(active_chainstate.GetMempool() != nullptr); | assert(active_chainstate.GetMempool() != nullptr); | ||||
CTxMemPool &pool{*active_chainstate.GetMempool()}; | CTxMemPool &pool{*active_chainstate.GetMempool()}; | ||||
std::vector<COutPoint> coins_to_uncache; | std::vector<COutPoint> coins_to_uncache; | ||||
auto args = MemPoolAccept::ATMPArgs::SingleAccept( | auto args = MemPoolAccept::ATMPArgs::SingleAccept( | ||||
config, accept_time, bypass_limits, coins_to_uncache, test_accept, | active_chainstate.m_chainman.GetConfig(), accept_time, bypass_limits, | ||||
heightOverride); | coins_to_uncache, test_accept, heightOverride); | ||||
const MempoolAcceptResult result = MemPoolAccept(pool, active_chainstate) | const MempoolAcceptResult result = MemPoolAccept(pool, active_chainstate) | ||||
.AcceptSingleTransaction(tx, args); | .AcceptSingleTransaction(tx, args); | ||||
if (result.m_result_type != MempoolAcceptResult::ResultType::VALID) { | if (result.m_result_type != MempoolAcceptResult::ResultType::VALID) { | ||||
// Remove coins that were not present in the coins cache before calling | // Remove coins that were not present in the coins cache before calling | ||||
// ATMPW; this is to prevent memory DoS in case we receive a large | // ATMPW; this is to prevent memory DoS in case we receive a large | ||||
// number of invalid transactions that attempt to overrun the in-memory | // number of invalid transactions that attempt to overrun the in-memory | ||||
// coins cache | // coins cache | ||||
// (`CCoinsViewCache::cacheCoins`). | // (`CCoinsViewCache::cacheCoins`). | ||||
for (const COutPoint &outpoint : coins_to_uncache) { | for (const COutPoint &outpoint : coins_to_uncache) { | ||||
active_chainstate.CoinsTip().Uncache(outpoint); | active_chainstate.CoinsTip().Uncache(outpoint); | ||||
} | } | ||||
} | } | ||||
// After we've (potentially) uncached entries, ensure our coins cache is | // After we've (potentially) uncached entries, ensure our coins cache is | ||||
// still within its size limits | // still within its size limits | ||||
BlockValidationState stateDummy; | BlockValidationState stateDummy; | ||||
active_chainstate.FlushStateToDisk(stateDummy, FlushStateMode::PERIODIC); | active_chainstate.FlushStateToDisk(stateDummy, FlushStateMode::PERIODIC); | ||||
return result; | return result; | ||||
} | } | ||||
PackageMempoolAcceptResult | PackageMempoolAcceptResult ProcessNewPackage(Chainstate &active_chainstate, | ||||
ProcessNewPackage(const Config &config, Chainstate &active_chainstate, | CTxMemPool &pool, | ||||
CTxMemPool &pool, const Package &package, bool test_accept) { | const Package &package, | ||||
bool test_accept) { | |||||
AssertLockHeld(cs_main); | AssertLockHeld(cs_main); | ||||
assert(!package.empty()); | assert(!package.empty()); | ||||
assert(std::all_of(package.cbegin(), package.cend(), | assert(std::all_of(package.cbegin(), package.cend(), | ||||
[](const auto &tx) { return tx != nullptr; })); | [](const auto &tx) { return tx != nullptr; })); | ||||
const Config &config = active_chainstate.m_chainman.GetConfig(); | |||||
std::vector<COutPoint> coins_to_uncache; | std::vector<COutPoint> coins_to_uncache; | ||||
const auto result = [&]() EXCLUSIVE_LOCKS_REQUIRED(cs_main) { | const auto result = [&]() EXCLUSIVE_LOCKS_REQUIRED(cs_main) { | ||||
AssertLockHeld(cs_main); | AssertLockHeld(cs_main); | ||||
if (test_accept) { | if (test_accept) { | ||||
auto args = MemPoolAccept::ATMPArgs::PackageTestAccept( | auto args = MemPoolAccept::ATMPArgs::PackageTestAccept( | ||||
config, GetTime(), coins_to_uncache); | config, GetTime(), coins_to_uncache); | ||||
return MemPoolAccept(pool, active_chainstate) | return MemPoolAccept(pool, active_chainstate) | ||||
.AcceptMultipleTransactions(package, args); | .AcceptMultipleTransactions(package, args); | ||||
▲ Show 20 Lines • Show All 1,430 Lines • ▼ Show 20 Lines | |||||
}; | }; | ||||
/** | /** | ||||
* Connect a new block to m_chain. pblock is either nullptr or a pointer to | * Connect a new block to m_chain. pblock is either nullptr or a pointer to | ||||
* a CBlock corresponding to pindexNew, to bypass loading it again from disk. | * a CBlock corresponding to pindexNew, to bypass loading it again from disk. | ||||
* | * | ||||
* The block is added to connectTrace if connection succeeds. | * The block is added to connectTrace if connection succeeds. | ||||
*/ | */ | ||||
bool Chainstate::ConnectTip(const Config &config, BlockValidationState &state, | bool Chainstate::ConnectTip(BlockValidationState &state, | ||||
BlockPolicyValidationState &blockPolicyState, | BlockPolicyValidationState &blockPolicyState, | ||||
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); | ||||
if (m_mempool) { | if (m_mempool) { | ||||
AssertLockHeld(m_mempool->cs); | AssertLockHeld(m_mempool->cs); | ||||
Show All 22 Lines | bool Chainstate::ConnectTip(BlockValidationState &state, | ||||
nTimeReadFromDisk += nTime2 - nTime1; | nTimeReadFromDisk += nTime2 - nTime1; | ||||
int64_t nTime3; | int64_t nTime3; | ||||
LogPrint(BCLog::BENCH, " - Load block from disk: %.2fms [%.2fs]\n", | LogPrint(BCLog::BENCH, " - Load block from disk: %.2fms [%.2fs]\n", | ||||
(nTime2 - nTime1) * MILLI, nTimeReadFromDisk * MICRO); | (nTime2 - nTime1) * MILLI, nTimeReadFromDisk * MICRO); | ||||
{ | { | ||||
Amount blockFees{Amount::zero()}; | Amount blockFees{Amount::zero()}; | ||||
CCoinsViewCache view(&CoinsTip()); | CCoinsViewCache view(&CoinsTip()); | ||||
bool rv = ConnectBlock(blockConnecting, state, pindexNew, view, | bool rv = ConnectBlock(blockConnecting, state, pindexNew, view, | ||||
BlockValidationOptions(config), &blockFees); | BlockValidationOptions(m_chainman.GetConfig()), | ||||
&blockFees); | |||||
GetMainSignals().BlockChecked(blockConnecting, state); | GetMainSignals().BlockChecked(blockConnecting, state); | ||||
if (!rv) { | if (!rv) { | ||||
if (state.IsInvalid()) { | if (state.IsInvalid()) { | ||||
InvalidBlockFound(pindexNew, state); | InvalidBlockFound(pindexNew, state); | ||||
} | } | ||||
return error("%s: ConnectBlock %s failed, %s", __func__, | return error("%s: ConnectBlock %s failed, %s", __func__, | ||||
pindexNew->GetBlockHash().ToString(), | pindexNew->GetBlockHash().ToString(), | ||||
▲ Show 20 Lines • Show All 320 Lines • ▼ Show 20 Lines | |||||
/** | /** | ||||
* Try to make some progress towards making pindexMostWork the active block. | * Try to make some progress towards making pindexMostWork the active block. | ||||
* pblock is either nullptr or a pointer to a CBlock corresponding to | * pblock is either nullptr or a pointer to a CBlock corresponding to | ||||
* pindexMostWork. | * pindexMostWork. | ||||
* | * | ||||
* @returns true unless a system error occurred | * @returns true unless a system error occurred | ||||
*/ | */ | ||||
bool Chainstate::ActivateBestChainStep( | bool Chainstate::ActivateBestChainStep( | ||||
const Config &config, BlockValidationState &state, | BlockValidationState &state, CBlockIndex *pindexMostWork, | ||||
CBlockIndex *pindexMostWork, const std::shared_ptr<const CBlock> &pblock, | const std::shared_ptr<const CBlock> &pblock, bool &fInvalidFound, | ||||
bool &fInvalidFound, ConnectTrace &connectTrace) { | ConnectTrace &connectTrace) { | ||||
AssertLockHeld(cs_main); | AssertLockHeld(cs_main); | ||||
if (m_mempool) { | if (m_mempool) { | ||||
AssertLockHeld(m_mempool->cs); | AssertLockHeld(m_mempool->cs); | ||||
} | } | ||||
const CBlockIndex *pindexOldTip = m_chain.Tip(); | const CBlockIndex *pindexOldTip = m_chain.Tip(); | ||||
const CBlockIndex *pindexFork = m_chain.FindFork(pindexMostWork); | const CBlockIndex *pindexFork = m_chain.FindFork(pindexMostWork); | ||||
// Disconnect active blocks which are no longer in the best chain. | // Disconnect active blocks which are no longer in the best chain. | ||||
bool fBlocksDisconnected = false; | bool fBlocksDisconnected = false; | ||||
DisconnectedBlockTransactions disconnectpool; | DisconnectedBlockTransactions disconnectpool; | ||||
while (m_chain.Tip() && m_chain.Tip() != pindexFork) { | while (m_chain.Tip() && m_chain.Tip() != pindexFork) { | ||||
if (!fBlocksDisconnected) { | if (!fBlocksDisconnected) { | ||||
// Import and clear mempool; we must do this to preserve | // Import and clear mempool; we must do this to preserve | ||||
// topological ordering in the mempool index. This is ok since | // topological ordering in the mempool index. This is ok since | ||||
// inserts into the mempool are very fast now in our new | // inserts into the mempool are very fast now in our new | ||||
// implementation. | // implementation. | ||||
disconnectpool.importMempool(*m_mempool); | disconnectpool.importMempool(*m_mempool); | ||||
} | } | ||||
if (!DisconnectTip(state, &disconnectpool)) { | if (!DisconnectTip(state, &disconnectpool)) { | ||||
// This is likely a fatal error, but keep the mempool consistent, | // This is likely a fatal error, but keep the mempool consistent, | ||||
// just in case. Only remove from the mempool in this case. | // just in case. Only remove from the mempool in this case. | ||||
if (m_mempool) { | if (m_mempool) { | ||||
disconnectpool.updateMempoolForReorg(config, *this, false, | disconnectpool.updateMempoolForReorg(*this, false, *m_mempool); | ||||
*m_mempool); | |||||
} | } | ||||
// If we're unable to disconnect a block during normal operation, | // If we're unable to disconnect a block during normal operation, | ||||
// then that is a failure of our local system -- we should abort | // then that is a failure of our local system -- we should abort | ||||
// rather than stay on a less work chain. | // rather than stay on a less work chain. | ||||
AbortNode(state, | AbortNode(state, | ||||
"Failed to disconnect block; see debug.log for details"); | "Failed to disconnect block; see debug.log for details"); | ||||
return false; | return false; | ||||
Show All 18 Lines | while (fContinue && nHeight != pindexMostWork->nHeight) { | ||||
pindexIter = pindexIter->pprev; | pindexIter = pindexIter->pprev; | ||||
} | } | ||||
nHeight = nTargetHeight; | nHeight = nTargetHeight; | ||||
// Connect new blocks. | // Connect new blocks. | ||||
for (CBlockIndex *pindexConnect : reverse_iterate(vpindexToConnect)) { | for (CBlockIndex *pindexConnect : reverse_iterate(vpindexToConnect)) { | ||||
BlockPolicyValidationState blockPolicyState; | BlockPolicyValidationState blockPolicyState; | ||||
if (!ConnectTip(config, state, blockPolicyState, pindexConnect, | if (!ConnectTip(state, blockPolicyState, pindexConnect, | ||||
pindexConnect == pindexMostWork | pindexConnect == pindexMostWork | ||||
? pblock | ? pblock | ||||
: std::shared_ptr<const CBlock>(), | : std::shared_ptr<const CBlock>(), | ||||
connectTrace, disconnectpool)) { | connectTrace, disconnectpool)) { | ||||
if (state.IsInvalid()) { | if (state.IsInvalid()) { | ||||
// The block violates a consensus rule. | // The block violates a consensus rule. | ||||
if (state.GetResult() != | if (state.GetResult() != | ||||
BlockValidationResult::BLOCK_MUTATED) { | BlockValidationResult::BLOCK_MUTATED) { | ||||
Show All 10 Lines | while (fContinue && nHeight != pindexMostWork->nHeight) { | ||||
fContinue = false; | fContinue = false; | ||||
break; | break; | ||||
} | } | ||||
// A system error occurred (disk space, database error, ...). | // A system error occurred (disk space, database error, ...). | ||||
// Make the mempool consistent with the current tip, just in | // Make the mempool consistent with the current tip, just in | ||||
// case any observers try to use it before shutdown. | // case any observers try to use it before shutdown. | ||||
if (m_mempool) { | if (m_mempool) { | ||||
disconnectpool.updateMempoolForReorg(config, *this, false, | disconnectpool.updateMempoolForReorg(*this, false, | ||||
*m_mempool); | *m_mempool); | ||||
} | } | ||||
return false; | return false; | ||||
} else { | } else { | ||||
PruneBlockIndexCandidates(); | PruneBlockIndexCandidates(); | ||||
if (!pindexOldTip || | if (!pindexOldTip || | ||||
m_chain.Tip()->nChainWork > pindexOldTip->nChainWork) { | m_chain.Tip()->nChainWork > pindexOldTip->nChainWork) { | ||||
// We're in a better position than we were. Return | // We're in a better position than we were. Return | ||||
Show All 9 Lines | if (m_mempool) { | ||||
if (fBlocksDisconnected || !disconnectpool.isEmpty()) { | if (fBlocksDisconnected || !disconnectpool.isEmpty()) { | ||||
// If any blocks were disconnected, we need to update the mempool | // If any blocks were disconnected, we need to update the mempool | ||||
// even if disconnectpool is empty. The disconnectpool may also be | // even if disconnectpool is empty. The disconnectpool may also be | ||||
// non-empty if the mempool was imported due to new validation rules | // non-empty if the mempool was imported due to new validation rules | ||||
// being in effect. | // being in effect. | ||||
LogPrint(BCLog::MEMPOOL, | LogPrint(BCLog::MEMPOOL, | ||||
"Updating mempool due to reorganization or " | "Updating mempool due to reorganization or " | ||||
"rules upgrade/downgrade\n"); | "rules upgrade/downgrade\n"); | ||||
disconnectpool.updateMempoolForReorg(config, *this, true, | disconnectpool.updateMempoolForReorg(*this, true, *m_mempool); | ||||
*m_mempool); | |||||
} | } | ||||
m_mempool->check(this->CoinsTip(), this->m_chain.Height() + 1); | m_mempool->check(this->CoinsTip(), this->m_chain.Height() + 1); | ||||
} | } | ||||
// Callbacks/notifications for a new best chain. | // Callbacks/notifications for a new best chain. | ||||
if (fInvalidFound) { | if (fInvalidFound) { | ||||
CheckForkWarningConditionsOnNewFork(pindexMostWork); | CheckForkWarningConditionsOnNewFork(pindexMostWork); | ||||
▲ Show 20 Lines • Show All 42 Lines • ▼ Show 20 Lines | |||||
static void LimitValidationInterfaceQueue() LOCKS_EXCLUDED(cs_main) { | static void LimitValidationInterfaceQueue() LOCKS_EXCLUDED(cs_main) { | ||||
AssertLockNotHeld(cs_main); | AssertLockNotHeld(cs_main); | ||||
if (GetMainSignals().CallbacksPending() > 10) { | if (GetMainSignals().CallbacksPending() > 10) { | ||||
SyncWithValidationInterfaceQueue(); | SyncWithValidationInterfaceQueue(); | ||||
} | } | ||||
} | } | ||||
bool Chainstate::ActivateBestChain(const Config &config, | bool Chainstate::ActivateBestChain(BlockValidationState &state, | ||||
BlockValidationState &state, | |||||
std::shared_ptr<const CBlock> pblock) { | std::shared_ptr<const CBlock> pblock) { | ||||
AssertLockNotHeld(m_chainstate_mutex); | AssertLockNotHeld(m_chainstate_mutex); | ||||
// Note that while we're often called here from ProcessNewBlock, this is | // Note that while we're often called here from ProcessNewBlock, this is | ||||
// far from a guarantee. Things in the P2P/RPC will often end up calling | // far from a guarantee. Things in the P2P/RPC will often end up calling | ||||
// us in the middle of ProcessNewBlock - do not assume pblock is set | // us in the middle of ProcessNewBlock - do not assume pblock is set | ||||
// sanely for performance or correctness! | // sanely for performance or correctness! | ||||
AssertLockNotHeld(::cs_main); | AssertLockNotHeld(::cs_main); | ||||
▲ Show 20 Lines • Show All 52 Lines • ▼ Show 20 Lines | do { | ||||
if (pindexMostWork == nullptr || | if (pindexMostWork == nullptr || | ||||
pindexMostWork == m_chain.Tip()) { | pindexMostWork == m_chain.Tip()) { | ||||
break; | break; | ||||
} | } | ||||
bool fInvalidFound = false; | bool fInvalidFound = false; | ||||
std::shared_ptr<const CBlock> nullBlockPtr; | std::shared_ptr<const CBlock> nullBlockPtr; | ||||
if (!ActivateBestChainStep( | if (!ActivateBestChainStep( | ||||
config, state, pindexMostWork, | state, pindexMostWork, | ||||
pblock && pblock->GetHash() == | pblock && pblock->GetHash() == | ||||
pindexMostWork->GetBlockHash() | pindexMostWork->GetBlockHash() | ||||
? pblock | ? pblock | ||||
: nullBlockPtr, | : nullBlockPtr, | ||||
fInvalidFound, connectTrace)) { | fInvalidFound, connectTrace)) { | ||||
// A system error occurred | // A system error occurred | ||||
return false; | return false; | ||||
} | } | ||||
▲ Show 20 Lines • Show All 88 Lines • ▼ Show 20 Lines | bool Chainstate::ActivateBestChain(BlockValidationState &state, | ||||
// Write changes periodically to disk, after relay. | // Write changes periodically to disk, after relay. | ||||
if (!FlushStateToDisk(state, FlushStateMode::PERIODIC)) { | if (!FlushStateToDisk(state, FlushStateMode::PERIODIC)) { | ||||
return false; | return false; | ||||
} | } | ||||
return true; | return true; | ||||
} | } | ||||
bool Chainstate::PreciousBlock(const Config &config, | bool Chainstate::PreciousBlock(BlockValidationState &state, | ||||
BlockValidationState &state, | |||||
CBlockIndex *pindex) { | CBlockIndex *pindex) { | ||||
AssertLockNotHeld(m_chainstate_mutex); | AssertLockNotHeld(m_chainstate_mutex); | ||||
AssertLockNotHeld(::cs_main); | AssertLockNotHeld(::cs_main); | ||||
{ | { | ||||
LOCK(cs_main); | LOCK(cs_main); | ||||
if (pindex->nChainWork < m_chain.Tip()->nChainWork) { | if (pindex->nChainWork < m_chain.Tip()->nChainWork) { | ||||
// Nothing to do, this block is not at the tip. | // Nothing to do, this block is not at the tip. | ||||
return true; | return true; | ||||
Show All 20 Lines | AssertLockNotHeld(::cs_main); | ||||
// Make sure it is added to the candidate list if appropriate. | // Make sure it is added to the candidate list if appropriate. | ||||
if (pindex->IsValid(BlockValidity::TRANSACTIONS) && | if (pindex->IsValid(BlockValidity::TRANSACTIONS) && | ||||
pindex->HaveTxsDownloaded()) { | pindex->HaveTxsDownloaded()) { | ||||
setBlockIndexCandidates.insert(pindex); | setBlockIndexCandidates.insert(pindex); | ||||
PruneBlockIndexCandidates(); | PruneBlockIndexCandidates(); | ||||
} | } | ||||
} | } | ||||
return ActivateBestChain(config, state); | return ActivateBestChain(state); | ||||
} | } | ||||
namespace { | namespace { | ||||
// Leverage RAII to run a functor at scope end | // Leverage RAII to run a functor at scope end | ||||
template <typename Func> struct Defer { | template <typename Func> struct Defer { | ||||
Func func; | Func func; | ||||
Defer(Func &&f) : func(std::move(f)) {} | Defer(Func &&f) : func(std::move(f)) {} | ||||
~Defer() { func(); } | ~Defer() { func(); } | ||||
▲ Show 20 Lines • Show All 65 Lines • ▼ Show 20 Lines | std::multimap<const arith_uint256, CBlockIndex *> candidate_blocks_by_work; | ||||
// as m_mempool can be null. We keep the runtime analysis though. | // as m_mempool can be null. We keep the runtime analysis though. | ||||
Defer deferred([&]() NO_THREAD_SAFETY_ANALYSIS { | Defer deferred([&]() NO_THREAD_SAFETY_ANALYSIS { | ||||
AssertLockHeld(cs_main); | AssertLockHeld(cs_main); | ||||
if (m_mempool && !disconnectpool.isEmpty()) { | if (m_mempool && !disconnectpool.isEmpty()) { | ||||
AssertLockHeld(m_mempool->cs); | AssertLockHeld(m_mempool->cs); | ||||
// DisconnectTip will add transactions to disconnectpool. | // DisconnectTip will add transactions to disconnectpool. | ||||
// When all unwinding is done and we are on a new tip, we must | // When all unwinding is done and we are on a new tip, we must | ||||
// add all transactions back to the mempool against the new tip. | // add all transactions back to the mempool against the new tip. | ||||
disconnectpool.updateMempoolForReorg(config, *this, | disconnectpool.updateMempoolForReorg(*this, | ||||
/* fAddToMempool = */ ret, | /* fAddToMempool = */ ret, | ||||
*m_mempool); | *m_mempool); | ||||
} | } | ||||
}); | }); | ||||
// Disconnect (descendants of) pindex, and mark them invalid. | // Disconnect (descendants of) pindex, and mark them invalid. | ||||
while (true) { | while (true) { | ||||
if (ShutdownRequested()) { | if (ShutdownRequested()) { | ||||
▲ Show 20 Lines • Show All 1,121 Lines • ▼ Show 20 Lines | AssertLockNotHeld(cs_main); | ||||
state.ToString()); | state.ToString()); | ||||
} | } | ||||
} | } | ||||
NotifyHeaderTip(ActiveChainstate()); | NotifyHeaderTip(ActiveChainstate()); | ||||
// Only used to report errors, not invalidity - ignore it | // Only used to report errors, not invalidity - ignore it | ||||
BlockValidationState state; | BlockValidationState state; | ||||
if (!ActiveChainstate().ActivateBestChain(config, state, block)) { | if (!ActiveChainstate().ActivateBestChain(state, block)) { | ||||
return error("%s: ActivateBestChain failed (%s)", __func__, | return error("%s: ActivateBestChain failed (%s)", __func__, | ||||
state.ToString()); | state.ToString()); | ||||
} | } | ||||
return true; | return true; | ||||
} | } | ||||
MempoolAcceptResult | MempoolAcceptResult | ||||
ChainstateManager::ProcessTransaction(const CTransactionRef &tx, | ChainstateManager::ProcessTransaction(const CTransactionRef &tx, | ||||
bool test_accept) { | bool test_accept) { | ||||
AssertLockHeld(cs_main); | AssertLockHeld(cs_main); | ||||
Chainstate &active_chainstate = ActiveChainstate(); | Chainstate &active_chainstate = ActiveChainstate(); | ||||
if (!active_chainstate.GetMempool()) { | if (!active_chainstate.GetMempool()) { | ||||
TxValidationState state; | TxValidationState state; | ||||
state.Invalid(TxValidationResult::TX_NO_MEMPOOL, "no-mempool"); | state.Invalid(TxValidationResult::TX_NO_MEMPOOL, "no-mempool"); | ||||
return MempoolAcceptResult::Failure(state); | return MempoolAcceptResult::Failure(state); | ||||
} | } | ||||
// Use GetConfig() temporarily. It will be removed in a follow-up by | auto result = AcceptToMemoryPool(active_chainstate, tx, GetTime(), | ||||
// making AcceptToMemoryPool take a CChainParams instead of a Config. | |||||
// This avoids passing an extra Config argument to this function that will | |||||
// be removed soon. | |||||
auto result = | |||||
AcceptToMemoryPool(::GetConfig(), active_chainstate, tx, GetTime(), | |||||
/*bypass_limits=*/false, test_accept); | /*bypass_limits=*/false, test_accept); | ||||
active_chainstate.GetMempool()->check( | active_chainstate.GetMempool()->check( | ||||
active_chainstate.CoinsTip(), active_chainstate.m_chain.Height() + 1); | active_chainstate.CoinsTip(), active_chainstate.m_chain.Height() + 1); | ||||
return result; | return result; | ||||
} | } | ||||
bool TestBlockValidity( | bool TestBlockValidity( | ||||
BlockValidationState &state, const CChainParams ¶ms, | BlockValidationState &state, const CChainParams ¶ms, | ||||
Chainstate &chainstate, const CBlock &block, CBlockIndex *pindexPrev, | Chainstate &chainstate, const CBlock &block, CBlockIndex *pindexPrev, | ||||
▲ Show 20 Lines • Show All 41 Lines • ▼ Show 20 Lines | void PruneBlockFilesManual(Chainstate &active_chainstate, | ||||
BlockValidationState state; | BlockValidationState state; | ||||
if (active_chainstate.FlushStateToDisk(state, FlushStateMode::NONE, | if (active_chainstate.FlushStateToDisk(state, FlushStateMode::NONE, | ||||
nManualPruneHeight)) { | nManualPruneHeight)) { | ||||
LogPrintf("%s: failed to flush state (%s)\n", __func__, | LogPrintf("%s: failed to flush state (%s)\n", __func__, | ||||
state.ToString()); | state.ToString()); | ||||
} | } | ||||
} | } | ||||
void Chainstate::LoadMempool(const Config &config, const fs::path &load_path, | void Chainstate::LoadMempool(const fs::path &load_path, | ||||
FopenFn mockable_fopen_function) { | FopenFn mockable_fopen_function) { | ||||
if (!m_mempool) { | if (!m_mempool) { | ||||
return; | return; | ||||
} | } | ||||
::LoadMempool(config, *m_mempool, load_path, *this, | ::LoadMempool(*m_mempool, load_path, *this, mockable_fopen_function); | ||||
mockable_fopen_function); | |||||
m_mempool->SetLoadTried(!ShutdownRequested()); | m_mempool->SetLoadTried(!ShutdownRequested()); | ||||
} | } | ||||
bool Chainstate::LoadChainTip() { | bool Chainstate::LoadChainTip() { | ||||
AssertLockHeld(cs_main); | AssertLockHeld(cs_main); | ||||
const CCoinsViewCache &coins_cache = CoinsTip(); | const CCoinsViewCache &coins_cache = CoinsTip(); | ||||
// Never called when the coins view is empty | // Never called when the coins view is empty | ||||
assert(!coins_cache.GetBestBlock().IsNull()); | assert(!coins_cache.GetBestBlock().IsNull()); | ||||
▲ Show 20 Lines • Show All 616 Lines • ▼ Show 20 Lines | try { | ||||
hash.ToString(), pindex->nHeight); | hash.ToString(), pindex->nHeight); | ||||
} | } | ||||
} | } | ||||
// Activate the genesis block so normal node progress can | // Activate the genesis block so normal node progress can | ||||
// continue | // continue | ||||
if (hash == params.GetConsensus().hashGenesisBlock) { | if (hash == params.GetConsensus().hashGenesisBlock) { | ||||
BlockValidationState state; | BlockValidationState state; | ||||
if (!ActivateBestChain(config, state, nullptr)) { | if (!ActivateBestChain(state, nullptr)) { | ||||
break; | break; | ||||
} | } | ||||
} | } | ||||
if (m_blockman.IsPruneMode() && !fReindex && pblock) { | if (m_blockman.IsPruneMode() && !fReindex && pblock) { | ||||
// Must update the tip for pruning to work while importing | // Must update the tip for pruning to work while importing | ||||
// with -loadblock. This is a tradeoff to conserve disk | // with -loadblock. This is a tradeoff to conserve disk | ||||
// space at the expense of time spent updating the tip to be | // space at the expense of time spent updating the tip to be | ||||
// able to prune. Otherwise, ActivateBestChain won't be | // able to prune. Otherwise, ActivateBestChain won't be | ||||
// called by the import process until after all of the block | // called by the import process until after all of the block | ||||
// files are loaded. ActivateBestChain can be called by | // files are loaded. ActivateBestChain can be called by | ||||
// concurrent network message processing, but that is not | // concurrent network message processing, but that is not | ||||
// reliable for the purpose of pruning while importing. | // reliable for the purpose of pruning while importing. | ||||
BlockValidationState state; | BlockValidationState state; | ||||
if (!ActivateBestChain(config, state, pblock)) { | if (!ActivateBestChain(state, pblock)) { | ||||
LogPrint(BCLog::REINDEX, | LogPrint(BCLog::REINDEX, | ||||
"failed to activate chain (%s)\n", | "failed to activate chain (%s)\n", | ||||
state.ToString()); | state.ToString()); | ||||
break; | break; | ||||
} | } | ||||
} | } | ||||
NotifyHeaderTip(*this); | NotifyHeaderTip(*this); | ||||
▲ Show 20 Lines • Show All 1,289 Lines • Show Last 20 Lines |