Changeset View
Changeset View
Standalone View
Standalone View
src/validation.cpp
Show First 20 Lines • Show All 145 Lines • ▼ Show 20 Lines | |||||
} // namespace | } // namespace | ||||
BlockValidationOptions::BlockValidationOptions(const Config &config) | BlockValidationOptions::BlockValidationOptions(const Config &config) | ||||
: excessiveBlockSize(config.GetMaxBlockSize()), checkPoW(true), | : excessiveBlockSize(config.GetMaxBlockSize()), checkPoW(true), | ||||
checkMerkleRoot(true) {} | checkMerkleRoot(true) {} | ||||
CBlockIndex *BlockManager::LookupBlockIndex(const BlockHash &hash) const { | CBlockIndex *BlockManager::LookupBlockIndex(const BlockHash &hash) const { | ||||
AssertLockHeld(cs_main); | AssertLockHeld(cs_main); | ||||
assert(std::addressof(g_chainman.BlockIndex()) == | |||||
std::addressof(m_block_index)); | |||||
BlockMap::const_iterator it = m_block_index.find(hash); | BlockMap::const_iterator it = m_block_index.find(hash); | ||||
return it == m_block_index.end() ? nullptr : it->second; | return it == m_block_index.end() ? nullptr : it->second; | ||||
} | } | ||||
CBlockIndex *BlockManager::FindForkInGlobalIndex(const CChain &chain, | CBlockIndex *BlockManager::FindForkInGlobalIndex(const CChain &chain, | ||||
const CBlockLocator &locator) { | const CBlockLocator &locator) { | ||||
AssertLockHeld(cs_main); | AssertLockHeld(cs_main); | ||||
assert(std::addressof(g_chainman.m_blockman) == std::addressof(*this)); | |||||
// Find the latest block common to locator and chain - we expect that | // Find the latest block common to locator and chain - we expect that | ||||
// locator.vHave is sorted descending by height. | // locator.vHave is sorted descending by height. | ||||
for (const BlockHash &hash : locator.vHave) { | for (const BlockHash &hash : locator.vHave) { | ||||
CBlockIndex *pindex = LookupBlockIndex(hash); | CBlockIndex *pindex = LookupBlockIndex(hash); | ||||
if (pindex) { | if (pindex) { | ||||
if (chain.Contains(pindex)) { | if (chain.Contains(pindex)) { | ||||
return pindex; | return pindex; | ||||
} | } | ||||
Show All 15 Lines | bool TestLockPointValidity(const CChain &active_chain, const LockPoints *lp) { | ||||
assert(lp); | assert(lp); | ||||
// If there are relative lock times then the maxInputBlock will be set | // If there are relative lock times then the maxInputBlock will be set | ||||
// If there are no relative lock times, the LockPoints don't depend on the | // If there are no relative lock times, the LockPoints don't depend on the | ||||
// chain | // chain | ||||
if (lp->maxInputBlock) { | if (lp->maxInputBlock) { | ||||
// Check whether ::ChainActive() is an extension of the block at which | // Check whether ::ChainActive() is an extension of the block at which | ||||
// the LockPoints calculation was valid. If not LockPoints are no longer | // the LockPoints calculation was valid. If not LockPoints are no longer | ||||
// valid. | // valid. | ||||
assert(std::addressof(::ChainActive()) == std::addressof(active_chain)); | |||||
if (!active_chain.Contains(lp->maxInputBlock)) { | if (!active_chain.Contains(lp->maxInputBlock)) { | ||||
return false; | return false; | ||||
} | } | ||||
} | } | ||||
// LockPoints still valid | // LockPoints still valid | ||||
return true; | return true; | ||||
} | } | ||||
bool CheckSequenceLocks(CChainState &active_chainstate, const CTxMemPool &pool, | bool CheckSequenceLocks(CChainState &active_chainstate, const CTxMemPool &pool, | ||||
const CTransaction &tx, int flags, LockPoints *lp, | const CTransaction &tx, int flags, LockPoints *lp, | ||||
bool useExistingLockPoints) { | bool useExistingLockPoints) { | ||||
AssertLockHeld(cs_main); | AssertLockHeld(cs_main); | ||||
AssertLockHeld(pool.cs); | AssertLockHeld(pool.cs); | ||||
assert(std::addressof(::ChainstateActive()) == | |||||
std::addressof(active_chainstate)); | |||||
CBlockIndex *tip = active_chainstate.m_chain.Tip(); | CBlockIndex *tip = active_chainstate.m_chain.Tip(); | ||||
assert(tip != nullptr); | assert(tip != nullptr); | ||||
CBlockIndex index; | CBlockIndex index; | ||||
index.pprev = tip; | index.pprev = tip; | ||||
// CheckSequenceLocks() uses active_chainstate.m_chain.Height()+1 to | // CheckSequenceLocks() uses active_chainstate.m_chain.Height()+1 to | ||||
// evaluate height based locks because when SequenceLocks() is called within | // evaluate height based locks because when SequenceLocks() is called within | ||||
▲ Show 20 Lines • Show All 102 Lines • ▼ Show 20 Lines | for (const CTxIn &txin : tx.vin) { | ||||
// Check equivalence for available inputs. | // Check equivalence for available inputs. | ||||
const CTransactionRef &txFrom = pool.get(txin.prevout.GetTxId()); | const CTransactionRef &txFrom = pool.get(txin.prevout.GetTxId()); | ||||
if (txFrom) { | if (txFrom) { | ||||
assert(txFrom->GetId() == txin.prevout.GetTxId()); | assert(txFrom->GetId() == txin.prevout.GetTxId()); | ||||
assert(txFrom->vout.size() > txin.prevout.GetN()); | assert(txFrom->vout.size() > txin.prevout.GetN()); | ||||
assert(txFrom->vout[txin.prevout.GetN()] == coin.GetTxOut()); | assert(txFrom->vout[txin.prevout.GetN()] == coin.GetTxOut()); | ||||
} else { | } else { | ||||
assert(std::addressof(::ChainstateActive().CoinsTip()) == | |||||
std::addressof(coins_tip)); | |||||
const Coin &coinFromDisk = coins_tip.AccessCoin(txin.prevout); | const Coin &coinFromDisk = coins_tip.AccessCoin(txin.prevout); | ||||
assert(!coinFromDisk.IsSpent()); | assert(!coinFromDisk.IsSpent()); | ||||
assert(coinFromDisk.GetTxOut() == coin.GetTxOut()); | assert(coinFromDisk.GetTxOut() == coin.GetTxOut()); | ||||
} | } | ||||
} | } | ||||
// Call CheckInputScripts() to cache signature and script validity against | // Call CheckInputScripts() to cache signature and script validity against | ||||
// current tip consensus rules. | // current tip consensus rules. | ||||
Show All 15 Lines | MemPoolAccept(CTxMemPool &mempool, CChainState &active_chainstate) | ||||
m_limit_ancestor_size( | m_limit_ancestor_size( | ||||
gArgs.GetArg("-limitancestorsize", DEFAULT_ANCESTOR_SIZE_LIMIT) * | gArgs.GetArg("-limitancestorsize", DEFAULT_ANCESTOR_SIZE_LIMIT) * | ||||
1000), | 1000), | ||||
m_limit_descendants( | m_limit_descendants( | ||||
gArgs.GetArg("-limitdescendantcount", DEFAULT_DESCENDANT_LIMIT)), | gArgs.GetArg("-limitdescendantcount", DEFAULT_DESCENDANT_LIMIT)), | ||||
m_limit_descendant_size(gArgs.GetArg("-limitdescendantsize", | m_limit_descendant_size(gArgs.GetArg("-limitdescendantsize", | ||||
DEFAULT_DESCENDANT_SIZE_LIMIT) * | DEFAULT_DESCENDANT_SIZE_LIMIT) * | ||||
1000) { | 1000) { | ||||
assert(std::addressof(::ChainstateActive()) == | |||||
std::addressof(m_active_chainstate)); | |||||
} | } | ||||
// We put the arguments we're handed into a struct, so we can pass them | // We put the arguments we're handed into a struct, so we can pass them | ||||
// around easier. | // around easier. | ||||
struct ATMPArgs { | struct ATMPArgs { | ||||
const Config &m_config; | const Config &m_config; | ||||
TxValidationState &m_state; | TxValidationState &m_state; | ||||
const int64_t m_accept_time; | const int64_t m_accept_time; | ||||
▲ Show 20 Lines • Show All 101 Lines • ▼ Show 20 Lines | bool MemPoolAccept::PreChecks(ATMPArgs &args, Workspace &ws) { | ||||
std::string reason; | std::string reason; | ||||
if (fRequireStandard && !IsStandardTx(tx, reason)) { | if (fRequireStandard && !IsStandardTx(tx, reason)) { | ||||
return state.Invalid(TxValidationResult::TX_NOT_STANDARD, reason); | return state.Invalid(TxValidationResult::TX_NOT_STANDARD, reason); | ||||
} | } | ||||
// Only accept nLockTime-using transactions that can be mined in the next | // Only accept nLockTime-using transactions that can be mined in the next | ||||
// block; we don't want our mempool filled up with transactions that can't | // block; we don't want our mempool filled up with transactions that can't | ||||
// be mined yet. | // be mined yet. | ||||
assert(std::addressof(::ChainActive()) == | |||||
std::addressof(m_active_chainstate.m_chain)); | |||||
TxValidationState ctxState; | TxValidationState ctxState; | ||||
if (!ContextualCheckTransactionForCurrentBlock( | if (!ContextualCheckTransactionForCurrentBlock( | ||||
m_active_chainstate.m_chain.Tip(), | m_active_chainstate.m_chain.Tip(), | ||||
args.m_config.GetChainParams().GetConsensus(), tx, ctxState, | args.m_config.GetChainParams().GetConsensus(), tx, ctxState, | ||||
STANDARD_LOCKTIME_VERIFY_FLAGS)) { | STANDARD_LOCKTIME_VERIFY_FLAGS)) { | ||||
// We copy the state from a dummy to ensure we don't increase the | // We copy the state from a dummy to ensure we don't increase the | ||||
// ban score of peer for transaction that could be valid in the future. | // ban score of peer for transaction that could be valid in the future. | ||||
return state.Invalid(TxValidationResult::TX_PREMATURE_SPEND, | return state.Invalid(TxValidationResult::TX_PREMATURE_SPEND, | ||||
Show All 15 Lines | for (const CTxIn &txin : tx.vin) { | ||||
return state.Invalid(TxValidationResult::TX_MEMPOOL_POLICY, | return state.Invalid(TxValidationResult::TX_MEMPOOL_POLICY, | ||||
"txn-mempool-conflict"); | "txn-mempool-conflict"); | ||||
} | } | ||||
} | } | ||||
LockPoints lp; | LockPoints lp; | ||||
m_view.SetBackend(m_viewmempool); | m_view.SetBackend(m_viewmempool); | ||||
assert(std::addressof(::ChainstateActive().CoinsTip()) == | |||||
std::addressof(m_active_chainstate.CoinsTip())); | |||||
const CCoinsViewCache &coins_cache = m_active_chainstate.CoinsTip(); | const CCoinsViewCache &coins_cache = m_active_chainstate.CoinsTip(); | ||||
// Do all inputs exist? | // Do all inputs exist? | ||||
for (const CTxIn &txin : tx.vin) { | for (const CTxIn &txin : tx.vin) { | ||||
if (!coins_cache.HaveCoinInCache(txin.prevout)) { | if (!coins_cache.HaveCoinInCache(txin.prevout)) { | ||||
coins_to_uncache.push_back(txin.prevout); | coins_to_uncache.push_back(txin.prevout); | ||||
} | } | ||||
// Note: this call may add txin.prevout to the coins cache | // Note: this call may add txin.prevout to the coins cache | ||||
Show All 32 Lines | bool MemPoolAccept::PreChecks(ATMPArgs &args, Workspace &ws) { | ||||
// added to coins_to_uncache) | // added to coins_to_uncache) | ||||
m_view.SetBackend(m_dummy); | m_view.SetBackend(m_dummy); | ||||
// Only accept BIP68 sequence locked transactions that can be mined in | // Only accept BIP68 sequence locked transactions that can be mined in | ||||
// the next block; we don't want our mempool filled up with transactions | // the next block; we don't want our mempool filled up with transactions | ||||
// that can't be mined yet. Must keep pool.cs for this unless we change | // that can't be mined yet. Must keep pool.cs for this unless we change | ||||
// CheckSequenceLocks to take a CoinsViewCache instead of create its | // CheckSequenceLocks to take a CoinsViewCache instead of create its | ||||
// own. | // own. | ||||
assert(std::addressof(::ChainstateActive()) == | |||||
std::addressof(m_active_chainstate)); | |||||
if (!CheckSequenceLocks(m_active_chainstate, m_pool, tx, | if (!CheckSequenceLocks(m_active_chainstate, m_pool, tx, | ||||
STANDARD_LOCKTIME_VERIFY_FLAGS, &lp)) { | STANDARD_LOCKTIME_VERIFY_FLAGS, &lp)) { | ||||
return state.Invalid(TxValidationResult::TX_PREMATURE_SPEND, | return state.Invalid(TxValidationResult::TX_PREMATURE_SPEND, | ||||
"non-BIP68-final"); | "non-BIP68-final"); | ||||
} | } | ||||
assert(std::addressof(g_chainman.m_blockman) == | |||||
std::addressof(m_active_chainstate.m_blockman)); | |||||
Amount nFees = Amount::zero(); | Amount nFees = Amount::zero(); | ||||
if (!Consensus::CheckTxInputs( | if (!Consensus::CheckTxInputs( | ||||
tx, state, m_view, | tx, state, m_view, | ||||
m_active_chainstate.m_blockman.GetSpendHeight(m_view), nFees)) { | m_active_chainstate.m_blockman.GetSpendHeight(m_view), nFees)) { | ||||
// state filled in by CheckTxInputs | // state filled in by CheckTxInputs | ||||
return false; | return false; | ||||
} | } | ||||
▲ Show 20 Lines • Show All 41 Lines • ▼ Show 20 Lines | const uint32_t scriptVerifyFlags = | ||||
ws.m_next_block_script_verify_flags | STANDARD_SCRIPT_VERIFY_FLAGS; | ws.m_next_block_script_verify_flags | STANDARD_SCRIPT_VERIFY_FLAGS; | ||||
PrecomputedTransactionData txdata(tx); | PrecomputedTransactionData txdata(tx); | ||||
if (!CheckInputScripts(tx, state, m_view, scriptVerifyFlags, true, false, | if (!CheckInputScripts(tx, state, m_view, scriptVerifyFlags, true, false, | ||||
txdata, ws.m_sig_checks_standard)) { | txdata, ws.m_sig_checks_standard)) { | ||||
// State filled in by CheckInputScripts | // State filled in by CheckInputScripts | ||||
return false; | return false; | ||||
} | } | ||||
assert(std::addressof(::ChainActive()) == | |||||
std::addressof(m_active_chainstate.m_chain)); | |||||
entry.reset(new CTxMemPoolEntry( | entry.reset(new CTxMemPoolEntry( | ||||
ptx, nFees, nAcceptTime, m_active_chainstate.m_chain.Height(), | ptx, nFees, nAcceptTime, m_active_chainstate.m_chain.Height(), | ||||
fSpendsCoinbase, ws.m_sig_checks_standard, lp)); | fSpendsCoinbase, ws.m_sig_checks_standard, lp)); | ||||
unsigned int nVirtualSize = entry->GetTxVirtualSize(); | unsigned int nVirtualSize = entry->GetTxVirtualSize(); | ||||
Amount mempoolRejectFee = | Amount mempoolRejectFee = | ||||
m_pool | m_pool | ||||
Show All 31 Lines | bool MemPoolAccept::ConsensusScriptChecks(ATMPArgs &args, const Workspace &ws, | ||||
// This is also useful in case of bugs in the standard flags that cause | // This is also useful in case of bugs in the standard flags that cause | ||||
// transactions to pass as valid when they're actually invalid. For | // transactions to pass as valid when they're actually invalid. For | ||||
// instance the STRICTENC flag was incorrectly allowing certain CHECKSIG | // instance the STRICTENC flag was incorrectly allowing certain CHECKSIG | ||||
// NOT scripts to pass, even though they were invalid. | // NOT scripts to pass, even though they were invalid. | ||||
// | // | ||||
// There is a similar check in CreateNewBlock() to prevent creating | // There is a similar check in CreateNewBlock() to prevent creating | ||||
// invalid blocks (using TestBlockValidity), however allowing such | // invalid blocks (using TestBlockValidity), however allowing such | ||||
// transactions into the mempool can be exploited as a DoS attack. | // transactions into the mempool can be exploited as a DoS attack. | ||||
assert(std::addressof(::ChainstateActive().CoinsTip()) == | |||||
std::addressof(m_active_chainstate.CoinsTip())); | |||||
int nSigChecksConsensus; | int nSigChecksConsensus; | ||||
if (!CheckInputsFromMempoolAndCache( | if (!CheckInputsFromMempoolAndCache( | ||||
tx, state, m_view, m_pool, ws.m_next_block_script_verify_flags, | tx, state, m_view, m_pool, ws.m_next_block_script_verify_flags, | ||||
txdata, nSigChecksConsensus, m_active_chainstate.CoinsTip())) { | txdata, nSigChecksConsensus, m_active_chainstate.CoinsTip())) { | ||||
// This can occur under some circumstances, if the node receives an | // This can occur under some circumstances, if the node receives an | ||||
// unrequested tx which is invalid due to new consensus rules not | // unrequested tx which is invalid due to new consensus rules not | ||||
// being activated yet (during IBD). | // being activated yet (during IBD). | ||||
return error("%s: BUG! PLEASE REPORT THIS! CheckInputScripts failed " | return error("%s: BUG! PLEASE REPORT THIS! CheckInputScripts failed " | ||||
Show All 21 Lines | bool MemPoolAccept::Finalize(ATMPArgs &args, Workspace &ws) { | ||||
CTxMemPool::setEntries &setAncestors = ws.m_ancestors; | CTxMemPool::setEntries &setAncestors = ws.m_ancestors; | ||||
std::unique_ptr<CTxMemPoolEntry> &entry = ws.m_entry; | std::unique_ptr<CTxMemPoolEntry> &entry = ws.m_entry; | ||||
// Store transaction in memory. | // Store transaction in memory. | ||||
m_pool.addUnchecked(*entry, setAncestors); | m_pool.addUnchecked(*entry, setAncestors); | ||||
// Trim mempool and check if tx was trimmed. | // Trim mempool and check if tx was trimmed. | ||||
if (!bypass_limits) { | if (!bypass_limits) { | ||||
assert(std::addressof(::ChainstateActive().CoinsTip()) == | |||||
std::addressof(m_active_chainstate.CoinsTip())); | |||||
m_pool.LimitSize( | m_pool.LimitSize( | ||||
m_active_chainstate.CoinsTip(), | m_active_chainstate.CoinsTip(), | ||||
gArgs.GetArg("-maxmempool", DEFAULT_MAX_MEMPOOL_SIZE) * 1000000, | gArgs.GetArg("-maxmempool", DEFAULT_MAX_MEMPOOL_SIZE) * 1000000, | ||||
std::chrono::hours{ | std::chrono::hours{ | ||||
gArgs.GetArg("-mempoolexpiry", DEFAULT_MEMPOOL_EXPIRY)}); | gArgs.GetArg("-mempoolexpiry", DEFAULT_MEMPOOL_EXPIRY)}); | ||||
if (!m_pool.exists(txid)) { | if (!m_pool.exists(txid)) { | ||||
return state.Invalid(TxValidationResult::TX_MEMPOOL_POLICY, | return state.Invalid(TxValidationResult::TX_MEMPOOL_POLICY, | ||||
"mempool full"); | "mempool full"); | ||||
▲ Show 20 Lines • Show All 52 Lines • ▼ Show 20 Lines | static bool AcceptToMemoryPoolWithTime( | ||||
TxValidationState &state, const CTransactionRef &tx, int64_t nAcceptTime, | TxValidationState &state, const CTransactionRef &tx, int64_t nAcceptTime, | ||||
bool bypass_limits, bool test_accept, Amount *fee_out = nullptr) | bool bypass_limits, bool test_accept, Amount *fee_out = nullptr) | ||||
EXCLUSIVE_LOCKS_REQUIRED(cs_main) { | EXCLUSIVE_LOCKS_REQUIRED(cs_main) { | ||||
AssertLockHeld(cs_main); | AssertLockHeld(cs_main); | ||||
std::vector<COutPoint> coins_to_uncache; | std::vector<COutPoint> coins_to_uncache; | ||||
MemPoolAccept::ATMPArgs args{ | MemPoolAccept::ATMPArgs args{ | ||||
config, state, nAcceptTime, bypass_limits, | config, state, nAcceptTime, bypass_limits, | ||||
coins_to_uncache, test_accept, fee_out}; | coins_to_uncache, test_accept, fee_out}; | ||||
assert(std::addressof(::ChainstateActive()) == | |||||
std::addressof(active_chainstate)); | |||||
bool res = MemPoolAccept(pool, active_chainstate) | bool res = MemPoolAccept(pool, active_chainstate) | ||||
.AcceptSingleTransaction(tx, args); | .AcceptSingleTransaction(tx, args); | ||||
if (!res) { | if (!res) { | ||||
// 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`). | ||||
▲ Show 20 Lines • Show All 151 Lines • ▼ Show 20 Lines | #if defined(HAVE_SYSTEM) | ||||
std::thread t(runCommand, strCmd); | std::thread t(runCommand, strCmd); | ||||
// thread runs free | // thread runs free | ||||
t.detach(); | t.detach(); | ||||
#endif | #endif | ||||
} | } | ||||
void CChainState::CheckForkWarningConditions() { | void CChainState::CheckForkWarningConditions() { | ||||
AssertLockHeld(cs_main); | AssertLockHeld(cs_main); | ||||
assert(std::addressof(::ChainstateActive()) == std::addressof(*this)); | |||||
// Before we get past initial download, we cannot reliably alert about forks | // Before we get past initial download, we cannot reliably alert about forks | ||||
// (we assume we don't get stuck on a fork before finishing our initial | // (we assume we don't get stuck on a fork before finishing our initial | ||||
// sync) | // sync) | ||||
if (IsInitialBlockDownload()) { | if (IsInitialBlockDownload()) { | ||||
return; | return; | ||||
} | } | ||||
Show All 36 Lines | if (pindexBestForkTip || | ||||
SetfLargeWorkForkFound(false); | SetfLargeWorkForkFound(false); | ||||
SetfLargeWorkInvalidChainFound(false); | SetfLargeWorkInvalidChainFound(false); | ||||
} | } | ||||
} | } | ||||
void CChainState::CheckForkWarningConditionsOnNewFork( | void CChainState::CheckForkWarningConditionsOnNewFork( | ||||
CBlockIndex *pindexNewForkTip) { | CBlockIndex *pindexNewForkTip) { | ||||
AssertLockHeld(cs_main); | AssertLockHeld(cs_main); | ||||
assert(std::addressof(::ChainstateActive()) == std::addressof(*this)); | |||||
// If we are on a fork that is sufficiently large, set a warning flag. | // If we are on a fork that is sufficiently large, set a warning flag. | ||||
const CBlockIndex *pfork = m_chain.FindFork(pindexNewForkTip); | const CBlockIndex *pfork = m_chain.FindFork(pindexNewForkTip); | ||||
// We define a condition where we should warn the user about as a fork of at | // We define a condition where we should warn the user about as a fork of at | ||||
// least 7 blocks with a tip within 72 blocks (+/- 12 hours if no one mines | // least 7 blocks with a tip within 72 blocks (+/- 12 hours if no one mines | ||||
// it) of ours. We use 7 blocks rather arbitrarily as it represents just | // it) of ours. We use 7 blocks rather arbitrarily as it represents just | ||||
// under 10% of sustained network hash rate operating on the fork, or a | // under 10% of sustained network hash rate operating on the fork, or a | ||||
Show All 12 Lines | void CChainState::CheckForkWarningConditionsOnNewFork( | ||||
} | } | ||||
CheckForkWarningConditions(); | CheckForkWarningConditions(); | ||||
} | } | ||||
// Called both upon regular invalid block discovery *and* InvalidateBlock | // Called both upon regular invalid block discovery *and* InvalidateBlock | ||||
void CChainState::InvalidChainFound(CBlockIndex *pindexNew) { | void CChainState::InvalidChainFound(CBlockIndex *pindexNew) { | ||||
AssertLockHeld(cs_main); | AssertLockHeld(cs_main); | ||||
assert(std::addressof(::ChainstateActive()) == std::addressof(*this)); | |||||
if (!pindexBestInvalid || | if (!pindexBestInvalid || | ||||
pindexNew->nChainWork > pindexBestInvalid->nChainWork) { | pindexNew->nChainWork > pindexBestInvalid->nChainWork) { | ||||
pindexBestInvalid = pindexNew; | pindexBestInvalid = pindexNew; | ||||
} | } | ||||
if (pindexBestHeader != nullptr && | if (pindexBestHeader != nullptr && | ||||
pindexBestHeader->GetAncestor(pindexNew->nHeight) == pindexNew) { | pindexBestHeader->GetAncestor(pindexNew->nHeight) == pindexNew) { | ||||
pindexBestHeader = m_chain.Tip(); | pindexBestHeader = m_chain.Tip(); | ||||
} | } | ||||
▲ Show 20 Lines • Show All 81 Lines • ▼ Show 20 Lines | if ((pTxLimitSigChecks && | ||||
error = ScriptError::SIGCHECKS_LIMIT_EXCEEDED; | error = ScriptError::SIGCHECKS_LIMIT_EXCEEDED; | ||||
return false; | return false; | ||||
} | } | ||||
return true; | return true; | ||||
} | } | ||||
int BlockManager::GetSpendHeight(const CCoinsViewCache &inputs) { | int BlockManager::GetSpendHeight(const CCoinsViewCache &inputs) { | ||||
AssertLockHeld(cs_main); | AssertLockHeld(cs_main); | ||||
assert(std::addressof(g_chainman.m_blockman) == std::addressof(*this)); | |||||
CBlockIndex *pindexPrev = LookupBlockIndex(inputs.GetBestBlock()); | CBlockIndex *pindexPrev = LookupBlockIndex(inputs.GetBestBlock()); | ||||
return pindexPrev->nHeight + 1; | return pindexPrev->nHeight + 1; | ||||
} | } | ||||
bool CheckInputScripts(const CTransaction &tx, TxValidationState &state, | bool CheckInputScripts(const CTransaction &tx, TxValidationState &state, | ||||
const CCoinsViewCache &inputs, const uint32_t flags, | const CCoinsViewCache &inputs, const uint32_t flags, | ||||
bool sigCacheStore, bool scriptCacheStore, | bool sigCacheStore, bool scriptCacheStore, | ||||
const PrecomputedTransactionData &txdata, | const PrecomputedTransactionData &txdata, | ||||
▲ Show 20 Lines • Show All 1,153 Lines • ▼ Show 20 Lines | static void UpdateTip(CTxMemPool &mempool, CBlockIndex *pindexNew, | ||||
mempool.AddTransactionsUpdated(1); | mempool.AddTransactionsUpdated(1); | ||||
{ | { | ||||
LOCK(g_best_block_mutex); | LOCK(g_best_block_mutex); | ||||
g_best_block = pindexNew->GetBlockHash(); | g_best_block = pindexNew->GetBlockHash(); | ||||
g_best_block_cv.notify_all(); | g_best_block_cv.notify_all(); | ||||
} | } | ||||
assert(std::addressof(::ChainstateActive()) == | |||||
std::addressof(active_chainstate)); | |||||
LogPrintf( | LogPrintf( | ||||
"%s: new best=%s height=%d version=0x%08x log2_work=%f tx=%ld " | "%s: new best=%s height=%d version=0x%08x log2_work=%f tx=%ld " | ||||
"date='%s' progress=%f cache=%.1fMiB(%utxo)\n", | "date='%s' progress=%f cache=%.1fMiB(%utxo)\n", | ||||
__func__, pindexNew->GetBlockHash().ToString(), pindexNew->nHeight, | __func__, pindexNew->GetBlockHash().ToString(), pindexNew->nHeight, | ||||
pindexNew->nVersion, log(pindexNew->nChainWork.getdouble()) / log(2.0), | pindexNew->nVersion, log(pindexNew->nChainWork.getdouble()) / log(2.0), | ||||
pindexNew->GetChainTxCount(), | pindexNew->GetChainTxCount(), | ||||
FormatISO8601DateTime(pindexNew->GetBlockTime()), | FormatISO8601DateTime(pindexNew->GetBlockTime()), | ||||
GuessVerificationProgress(params.TxData(), pindexNew), | GuessVerificationProgress(params.TxData(), pindexNew), | ||||
▲ Show 20 Lines • Show All 531 Lines • ▼ Show 20 Lines | |||||
* @returns true unless a system error occurred | * @returns true unless a system error occurred | ||||
*/ | */ | ||||
bool CChainState::ActivateBestChainStep( | bool CChainState::ActivateBestChainStep( | ||||
const Config &config, BlockValidationState &state, | const Config &config, BlockValidationState &state, | ||||
CBlockIndex *pindexMostWork, const std::shared_ptr<const CBlock> &pblock, | CBlockIndex *pindexMostWork, const std::shared_ptr<const CBlock> &pblock, | ||||
bool &fInvalidFound, ConnectTrace &connectTrace) { | bool &fInvalidFound, ConnectTrace &connectTrace) { | ||||
AssertLockHeld(cs_main); | AssertLockHeld(cs_main); | ||||
AssertLockHeld(m_mempool.cs); | AssertLockHeld(m_mempool.cs); | ||||
assert(std::addressof(::ChainstateActive()) == std::addressof(*this)); | |||||
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) { | ||||
▲ Show 20 Lines • Show All 108 Lines • ▼ Show 20 Lines | static bool NotifyHeaderTip(CChainState &chainstate) LOCKS_EXCLUDED(cs_main) { | ||||
static CBlockIndex *pindexHeaderOld = nullptr; | static CBlockIndex *pindexHeaderOld = nullptr; | ||||
CBlockIndex *pindexHeader = nullptr; | CBlockIndex *pindexHeader = nullptr; | ||||
{ | { | ||||
LOCK(cs_main); | LOCK(cs_main); | ||||
pindexHeader = pindexBestHeader; | pindexHeader = pindexBestHeader; | ||||
if (pindexHeader != pindexHeaderOld) { | if (pindexHeader != pindexHeaderOld) { | ||||
fNotify = true; | fNotify = true; | ||||
assert(std::addressof(::ChainstateActive()) == | |||||
std::addressof(chainstate)); | |||||
fInitialBlockDownload = chainstate.IsInitialBlockDownload(); | fInitialBlockDownload = chainstate.IsInitialBlockDownload(); | ||||
pindexHeaderOld = pindexHeader; | pindexHeaderOld = pindexHeader; | ||||
} | } | ||||
} | } | ||||
// Send block tip changed notifications without cs_main | // Send block tip changed notifications without cs_main | ||||
if (fNotify) { | if (fNotify) { | ||||
uiInterface.NotifyHeaderTip( | uiInterface.NotifyHeaderTip( | ||||
▲ Show 20 Lines • Show All 257 Lines • ▼ Show 20 Lines | while (true) { | ||||
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). | ||||
assert(std::addressof(::ChainstateActive()) == std::addressof(*this)); | |||||
disconnectpool.updateMempoolForReorg( | disconnectpool.updateMempoolForReorg( | ||||
config, *this, | config, *this, | ||||
/* fAddToMempool = */ (++disconnected <= 10) && ret, m_mempool); | /* fAddToMempool = */ (++disconnected <= 10) && ret, m_mempool); | ||||
if (!ret) { | if (!ret) { | ||||
return false; | return false; | ||||
} | } | ||||
▲ Show 20 Lines • Show All 393 Lines • ▼ Show 20 Lines | bool FindBlockPos(FlatFilePos &pos, unsigned int nAddSize, unsigned int nHeight, | ||||
if (!fKnown) { | if (!fKnown) { | ||||
while (vinfoBlockFile[nFile].nSize + nAddSize >= | while (vinfoBlockFile[nFile].nSize + nAddSize >= | ||||
(gArgs.GetBoolArg("-fastprune", false) ? 0x10000 /* 64kb */ | (gArgs.GetBoolArg("-fastprune", false) ? 0x10000 /* 64kb */ | ||||
: MAX_BLOCKFILE_SIZE)) { | : MAX_BLOCKFILE_SIZE)) { | ||||
// when the undo file is keeping up with the block file, we want to | // when the undo file is keeping up with the block file, we want to | ||||
// flush it explicitly when it is lagging behind (more blocks arrive | // flush it explicitly when it is lagging behind (more blocks arrive | ||||
// than are being connected), we let the undo block write case | // than are being connected), we let the undo block write case | ||||
// handle it | // handle it | ||||
assert(std::addressof(::ChainActive()) == | |||||
std::addressof(active_chain)); | |||||
finalize_undo = (vinfoBlockFile[nFile].nHeightLast == | finalize_undo = (vinfoBlockFile[nFile].nHeightLast == | ||||
(unsigned int)active_chain.Tip()->nHeight); | (unsigned int)active_chain.Tip()->nHeight); | ||||
nFile++; | nFile++; | ||||
if (vinfoBlockFile.size() <= nFile) { | if (vinfoBlockFile.size() <= nFile) { | ||||
vinfoBlockFile.resize(nFile + 1); | vinfoBlockFile.resize(nFile + 1); | ||||
} | } | ||||
} | } | ||||
pos.nFile = nFile; | pos.nFile = nFile; | ||||
▲ Show 20 Lines • Show All 168 Lines • ▼ Show 20 Lines | bool CheckBlock(const CBlock &block, BlockValidationState &state, | ||||
return true; | return true; | ||||
} | } | ||||
CBlockIndex *BlockManager::GetLastCheckpoint(const CCheckpointData &data) { | CBlockIndex *BlockManager::GetLastCheckpoint(const CCheckpointData &data) { | ||||
const MapCheckpoints &checkpoints = data.mapCheckpoints; | const MapCheckpoints &checkpoints = data.mapCheckpoints; | ||||
for (const MapCheckpoints::value_type &i : reverse_iterate(checkpoints)) { | for (const MapCheckpoints::value_type &i : reverse_iterate(checkpoints)) { | ||||
const BlockHash &hash = i.second; | const BlockHash &hash = i.second; | ||||
assert(std::addressof(g_chainman.m_blockman) == std::addressof(*this)); | |||||
CBlockIndex *pindex = LookupBlockIndex(hash); | CBlockIndex *pindex = LookupBlockIndex(hash); | ||||
if (pindex) { | if (pindex) { | ||||
return pindex; | return pindex; | ||||
} | } | ||||
} | } | ||||
return nullptr; | return nullptr; | ||||
} | } | ||||
Show All 35 Lines | if (fCheckpointsEnabled) { | ||||
__func__, nHeight); | __func__, nHeight); | ||||
return state.Invalid(BlockValidationResult::BLOCK_CHECKPOINT, | return state.Invalid(BlockValidationResult::BLOCK_CHECKPOINT, | ||||
"checkpoint mismatch"); | "checkpoint mismatch"); | ||||
} | } | ||||
// Don't accept any forks from the main chain prior to last checkpoint. | // Don't accept any forks from the main chain prior to last checkpoint. | ||||
// GetLastCheckpoint finds the last checkpoint in MapCheckpoints that's | // GetLastCheckpoint finds the last checkpoint in MapCheckpoints that's | ||||
// in our BlockIndex(). | // in our BlockIndex(). | ||||
assert(std::addressof(g_chainman.m_blockman) == | |||||
std::addressof(blockman)); | |||||
CBlockIndex *pcheckpoint = blockman.GetLastCheckpoint(checkpoints); | CBlockIndex *pcheckpoint = blockman.GetLastCheckpoint(checkpoints); | ||||
if (pcheckpoint && nHeight < pcheckpoint->nHeight) { | if (pcheckpoint && nHeight < pcheckpoint->nHeight) { | ||||
LogPrintf("ERROR: %s: forked chain older than last checkpoint " | LogPrintf("ERROR: %s: forked chain older than last checkpoint " | ||||
"(height %d)\n", | "(height %d)\n", | ||||
__func__, nHeight); | __func__, nHeight); | ||||
return state.Invalid(BlockValidationResult::BLOCK_CHECKPOINT, | return state.Invalid(BlockValidationResult::BLOCK_CHECKPOINT, | ||||
"bad-fork-prior-to-checkpoint"); | "bad-fork-prior-to-checkpoint"); | ||||
Show All 30 Lines | |||||
} | } | ||||
bool ContextualCheckTransactionForCurrentBlock( | bool ContextualCheckTransactionForCurrentBlock( | ||||
const CBlockIndex *active_chain_tip, const Consensus::Params ¶ms, | const CBlockIndex *active_chain_tip, const Consensus::Params ¶ms, | ||||
const CTransaction &tx, TxValidationState &state, int flags) { | const CTransaction &tx, TxValidationState &state, int flags) { | ||||
AssertLockHeld(cs_main); | AssertLockHeld(cs_main); | ||||
// TODO: Make active_chain_tip a reference | // TODO: Make active_chain_tip a reference | ||||
assert(active_chain_tip); | assert(active_chain_tip); | ||||
assert(std::addressof(*::ChainActive().Tip()) == | |||||
std::addressof(*active_chain_tip)); | |||||
// By convention a negative value for flags indicates that the current | // By convention a negative value for flags indicates that the current | ||||
// network-enforced consensus rules should be used. In a future soft-fork | // network-enforced consensus rules should be used. In a future soft-fork | ||||
// scenario that would mean checking which rules would be enforced for the | // scenario that would mean checking which rules would be enforced for the | ||||
// next block and setting the appropriate flags. At the present time no | // next block and setting the appropriate flags. At the present time no | ||||
// soft-forks are scheduled, so no flags are set. | // soft-forks are scheduled, so no flags are set. | ||||
flags = std::max(flags, 0); | flags = std::max(flags, 0); | ||||
▲ Show 20 Lines • Show All 223 Lines • ▼ Show 20 Lines | bool BlockManager::AcceptBlockHeader(const Config &config, | ||||
return true; | return true; | ||||
} | } | ||||
// Exposed wrapper for AcceptBlockHeader | // Exposed wrapper for AcceptBlockHeader | ||||
bool ChainstateManager::ProcessNewBlockHeaders( | bool ChainstateManager::ProcessNewBlockHeaders( | ||||
const Config &config, const std::vector<CBlockHeader> &headers, | const Config &config, const std::vector<CBlockHeader> &headers, | ||||
BlockValidationState &state, const CBlockIndex **ppindex) { | BlockValidationState &state, const CBlockIndex **ppindex) { | ||||
assert(std::addressof(::ChainstateActive()) == | |||||
std::addressof(ActiveChainstate())); | |||||
AssertLockNotHeld(cs_main); | AssertLockNotHeld(cs_main); | ||||
{ | { | ||||
LOCK(cs_main); | LOCK(cs_main); | ||||
for (const CBlockHeader &header : headers) { | for (const CBlockHeader &header : headers) { | ||||
// Use a temp pindex instead of ppindex to avoid a const_cast | // Use a temp pindex instead of ppindex to avoid a const_cast | ||||
CBlockIndex *pindex = nullptr; | CBlockIndex *pindex = nullptr; | ||||
bool accepted = | bool accepted = | ||||
m_blockman.AcceptBlockHeader(config, header, state, &pindex); | m_blockman.AcceptBlockHeader(config, header, state, &pindex); | ||||
▲ Show 20 Lines • Show All 168 Lines • ▼ Show 20 Lines | bool CChainState::AcceptBlock(const Config &config, | ||||
if (!IsInitialBlockDownload() && m_chain.Tip() == pindex->pprev) { | if (!IsInitialBlockDownload() && m_chain.Tip() == pindex->pprev) { | ||||
GetMainSignals().NewPoWValidBlock(pindex, pblock); | GetMainSignals().NewPoWValidBlock(pindex, pblock); | ||||
} | } | ||||
// Write block to history file | // Write block to history file | ||||
if (fNewBlock) { | if (fNewBlock) { | ||||
*fNewBlock = true; | *fNewBlock = true; | ||||
} | } | ||||
assert(std::addressof(::ChainActive()) == std::addressof(m_chain)); | |||||
try { | try { | ||||
FlatFilePos blockPos = | FlatFilePos blockPos = | ||||
SaveBlockToDisk(block, pindex->nHeight, m_chain, chainparams, dbp); | SaveBlockToDisk(block, pindex->nHeight, m_chain, chainparams, dbp); | ||||
if (blockPos.IsNull()) { | if (blockPos.IsNull()) { | ||||
state.Error(strprintf( | state.Error(strprintf( | ||||
"%s: Failed to find position to write new block to disk", | "%s: Failed to find position to write new block to disk", | ||||
__func__)); | __func__)); | ||||
return false; | return false; | ||||
Show All 9 Lines | bool CChainState::AcceptBlock(const Config &config, | ||||
return true; | return true; | ||||
} | } | ||||
bool ChainstateManager::ProcessNewBlock( | bool ChainstateManager::ProcessNewBlock( | ||||
const Config &config, const std::shared_ptr<const CBlock> pblock, | const Config &config, const std::shared_ptr<const CBlock> pblock, | ||||
bool fForceProcessing, bool *fNewBlock) { | bool fForceProcessing, bool *fNewBlock) { | ||||
AssertLockNotHeld(cs_main); | AssertLockNotHeld(cs_main); | ||||
assert(std::addressof(::ChainstateActive()) == | |||||
std::addressof(ActiveChainstate())); | |||||
{ | { | ||||
if (fNewBlock) { | if (fNewBlock) { | ||||
*fNewBlock = false; | *fNewBlock = false; | ||||
} | } | ||||
BlockValidationState state; | BlockValidationState state; | ||||
Show All 33 Lines | bool ChainstateManager::ProcessNewBlock( | ||||
return true; | return true; | ||||
} | } | ||||
bool TestBlockValidity(BlockValidationState &state, const CChainParams ¶ms, | bool TestBlockValidity(BlockValidationState &state, const CChainParams ¶ms, | ||||
CChainState &chainstate, const CBlock &block, | CChainState &chainstate, const CBlock &block, | ||||
CBlockIndex *pindexPrev, | CBlockIndex *pindexPrev, | ||||
BlockValidationOptions validationOptions) { | BlockValidationOptions validationOptions) { | ||||
AssertLockHeld(cs_main); | AssertLockHeld(cs_main); | ||||
assert(std::addressof(::ChainstateActive()) == std::addressof(chainstate)); | |||||
assert(pindexPrev && pindexPrev == chainstate.m_chain.Tip()); | assert(pindexPrev && pindexPrev == chainstate.m_chain.Tip()); | ||||
CCoinsViewCache viewNew(&chainstate.CoinsTip()); | CCoinsViewCache viewNew(&chainstate.CoinsTip()); | ||||
BlockHash block_hash(block.GetHash()); | BlockHash block_hash(block.GetHash()); | ||||
CBlockIndex indexDummy(block); | CBlockIndex indexDummy(block); | ||||
indexDummy.pprev = pindexPrev; | indexDummy.pprev = pindexPrev; | ||||
indexDummy.nHeight = pindexPrev->nHeight + 1; | indexDummy.nHeight = pindexPrev->nHeight + 1; | ||||
indexDummy.phashBlock = &block_hash; | indexDummy.phashBlock = &block_hash; | ||||
// NOTE: CheckBlockHeader is called by CheckBlock | // NOTE: CheckBlockHeader is called by CheckBlock | ||||
assert(std::addressof(g_chainman.m_blockman) == | |||||
std::addressof(chainstate.m_blockman)); | |||||
if (!ContextualCheckBlockHeader(params, block, state, chainstate.m_blockman, | if (!ContextualCheckBlockHeader(params, block, state, chainstate.m_blockman, | ||||
pindexPrev, GetAdjustedTime())) { | pindexPrev, GetAdjustedTime())) { | ||||
return error("%s: Consensus::ContextualCheckBlockHeader: %s", __func__, | return error("%s: Consensus::ContextualCheckBlockHeader: %s", __func__, | ||||
state.ToString()); | state.ToString()); | ||||
} | } | ||||
if (!CheckBlock(block, state, params.GetConsensus(), validationOptions)) { | if (!CheckBlock(block, state, params.GetConsensus(), validationOptions)) { | ||||
return error("%s: Consensus::CheckBlock: %s", __func__, | return error("%s: Consensus::CheckBlock: %s", __func__, | ||||
▲ Show 20 Lines • Show All 103 Lines • ▼ Show 20 Lines | LogPrintf("Prune (Manual): prune_height=%d removed %d blk/rev pairs\n", | ||||
nLastBlockWeCanPrune, count); | nLastBlockWeCanPrune, count); | ||||
} | } | ||||
/* This function is called from the RPC code for pruneblockchain */ | /* This function is called from the RPC code for pruneblockchain */ | ||||
void PruneBlockFilesManual(CChainState &active_chainstate, | void PruneBlockFilesManual(CChainState &active_chainstate, | ||||
int nManualPruneHeight) { | int nManualPruneHeight) { | ||||
BlockValidationState state; | BlockValidationState state; | ||||
const CChainParams &chainparams = Params(); | const CChainParams &chainparams = Params(); | ||||
assert(std::addressof(::ChainstateActive()) == | |||||
std::addressof(active_chainstate)); | |||||
if (active_chainstate.FlushStateToDisk( | if (active_chainstate.FlushStateToDisk( | ||||
chainparams, state, FlushStateMode::NONE, nManualPruneHeight)) { | chainparams, state, FlushStateMode::NONE, nManualPruneHeight)) { | ||||
LogPrintf("%s: failed to flush state (%s)\n", __func__, | LogPrintf("%s: failed to flush state (%s)\n", __func__, | ||||
state.ToString()); | state.ToString()); | ||||
} | } | ||||
} | } | ||||
void BlockManager::FindFilesToPrune(std::set<int> &setFilesToPrune, | void BlockManager::FindFilesToPrune(std::set<int> &setFilesToPrune, | ||||
▲ Show 20 Lines • Show All 167 Lines • ▼ Show 20 Lines | void BlockManager::Unload() { | ||||
for (const BlockMap::value_type &entry : m_block_index) { | for (const BlockMap::value_type &entry : m_block_index) { | ||||
delete entry.second; | delete entry.second; | ||||
} | } | ||||
m_block_index.clear(); | m_block_index.clear(); | ||||
} | } | ||||
bool CChainState::LoadBlockIndexDB(const Consensus::Params ¶ms) { | bool CChainState::LoadBlockIndexDB(const Consensus::Params ¶ms) { | ||||
assert(std::addressof(::ChainstateActive()) == std::addressof(*this)); | |||||
if (!m_blockman.LoadBlockIndex(params, *pblocktree, | if (!m_blockman.LoadBlockIndex(params, *pblocktree, | ||||
setBlockIndexCandidates)) { | setBlockIndexCandidates)) { | ||||
return false; | return false; | ||||
} | } | ||||
// Load block file info | // Load block file info | ||||
pblocktree->ReadLastBlockFile(nLastBlockFile); | pblocktree->ReadLastBlockFile(nLastBlockFile); | ||||
vinfoBlockFile.resize(nLastBlockFile + 1); | vinfoBlockFile.resize(nLastBlockFile + 1); | ||||
▲ Show 20 Lines • Show All 43 Lines • ▼ Show 20 Lines | if (pblocktree->IsReindexing()) { | ||||
fReindex = true; | fReindex = true; | ||||
} | } | ||||
return true; | return true; | ||||
} | } | ||||
void CChainState::LoadMempool(const Config &config, const ArgsManager &args) { | void CChainState::LoadMempool(const Config &config, const ArgsManager &args) { | ||||
if (args.GetArg("-persistmempool", DEFAULT_PERSIST_MEMPOOL)) { | if (args.GetArg("-persistmempool", DEFAULT_PERSIST_MEMPOOL)) { | ||||
assert(std::addressof(::ChainstateActive()) == std::addressof(*this)); | |||||
::LoadMempool(config, m_mempool, *this); | ::LoadMempool(config, m_mempool, *this); | ||||
} | } | ||||
m_mempool.SetIsLoaded(!ShutdownRequested()); | m_mempool.SetIsLoaded(!ShutdownRequested()); | ||||
} | } | ||||
bool CChainState::LoadChainTip(const CChainParams &chainparams) { | bool CChainState::LoadChainTip(const CChainParams &chainparams) { | ||||
AssertLockHeld(cs_main); | AssertLockHeld(cs_main); | ||||
const CCoinsViewCache &coins_cache = CoinsTip(); | const CCoinsViewCache &coins_cache = CoinsTip(); | ||||
Show All 31 Lines | CVerifyDB::~CVerifyDB() { | ||||
uiInterface.ShowProgress("", 100, false); | uiInterface.ShowProgress("", 100, false); | ||||
} | } | ||||
bool CVerifyDB::VerifyDB(CChainState &chainstate, const Config &config, | bool CVerifyDB::VerifyDB(CChainState &chainstate, const Config &config, | ||||
CCoinsView &coinsview, int nCheckLevel, | CCoinsView &coinsview, int nCheckLevel, | ||||
int nCheckDepth) { | int nCheckDepth) { | ||||
AssertLockHeld(cs_main); | AssertLockHeld(cs_main); | ||||
assert(std::addressof(::ChainstateActive()) == std::addressof(chainstate)); | |||||
const CChainParams ¶ms = config.GetChainParams(); | const CChainParams ¶ms = config.GetChainParams(); | ||||
const Consensus::Params &consensusParams = params.GetConsensus(); | const Consensus::Params &consensusParams = params.GetConsensus(); | ||||
if (chainstate.m_chain.Tip() == nullptr || | if (chainstate.m_chain.Tip() == nullptr || | ||||
chainstate.m_chain.Tip()->pprev == nullptr) { | chainstate.m_chain.Tip()->pprev == nullptr) { | ||||
return true; | return true; | ||||
} | } | ||||
▲ Show 20 Lines • Show All 347 Lines • ▼ Show 20 Lines | bool CChainState::LoadGenesisBlock(const CChainParams &chainparams) { | ||||
// Check whether we're already initialized by checking for genesis in | // Check whether we're already initialized by checking for genesis in | ||||
// m_blockman.m_block_index. Note that we can't use m_chain here, since it | // m_blockman.m_block_index. Note that we can't use m_chain here, since it | ||||
// is set based on the coins db, not the block index db, which is the only | // is set based on the coins db, not the block index db, which is the only | ||||
// thing loaded at this point. | // thing loaded at this point. | ||||
if (m_blockman.m_block_index.count(chainparams.GenesisBlock().GetHash())) { | if (m_blockman.m_block_index.count(chainparams.GenesisBlock().GetHash())) { | ||||
return true; | return true; | ||||
} | } | ||||
assert(std::addressof(::ChainActive()) == std::addressof(m_chain)); | |||||
try { | try { | ||||
const CBlock &block = chainparams.GenesisBlock(); | const CBlock &block = chainparams.GenesisBlock(); | ||||
FlatFilePos blockPos = | FlatFilePos blockPos = | ||||
SaveBlockToDisk(block, 0, m_chain, chainparams, nullptr); | SaveBlockToDisk(block, 0, m_chain, chainparams, nullptr); | ||||
if (blockPos.IsNull()) { | if (blockPos.IsNull()) { | ||||
return error("%s: writing genesis block to disk failed", __func__); | return error("%s: writing genesis block to disk failed", __func__); | ||||
} | } | ||||
CBlockIndex *pindex = m_blockman.AddToBlockIndex(block); | CBlockIndex *pindex = m_blockman.AddToBlockIndex(block); | ||||
▲ Show 20 Lines • Show All 66 Lines • ▼ Show 20 Lines | try { | ||||
CBlock &block = *pblock; | CBlock &block = *pblock; | ||||
blkdat >> block; | blkdat >> block; | ||||
nRewind = blkdat.GetPos(); | nRewind = blkdat.GetPos(); | ||||
const BlockHash hash = block.GetHash(); | const BlockHash hash = block.GetHash(); | ||||
{ | { | ||||
LOCK(cs_main); | LOCK(cs_main); | ||||
// detect out of order blocks, and store them for later | // detect out of order blocks, and store them for later | ||||
assert(std::addressof(g_chainman.m_blockman) == | |||||
std::addressof(m_blockman)); | |||||
if (hash != chainparams.GetConsensus().hashGenesisBlock && | if (hash != chainparams.GetConsensus().hashGenesisBlock && | ||||
!m_blockman.LookupBlockIndex(block.hashPrevBlock)) { | !m_blockman.LookupBlockIndex(block.hashPrevBlock)) { | ||||
LogPrint( | LogPrint( | ||||
BCLog::REINDEX, | BCLog::REINDEX, | ||||
"%s: Out of order block %s, parent %s not known\n", | "%s: Out of order block %s, parent %s not known\n", | ||||
__func__, hash.ToString(), | __func__, hash.ToString(), | ||||
block.hashPrevBlock.ToString()); | block.hashPrevBlock.ToString()); | ||||
if (dbp) { | if (dbp) { | ||||
mapBlocksUnknownParent.insert( | mapBlocksUnknownParent.insert( | ||||
std::make_pair(block.hashPrevBlock, *dbp)); | std::make_pair(block.hashPrevBlock, *dbp)); | ||||
} | } | ||||
continue; | continue; | ||||
} | } | ||||
// process in case the block isn't known yet | // process in case the block isn't known yet | ||||
assert(std::addressof(g_chainman.m_blockman) == | |||||
std::addressof(m_blockman)); | |||||
CBlockIndex *pindex = m_blockman.LookupBlockIndex(hash); | CBlockIndex *pindex = m_blockman.LookupBlockIndex(hash); | ||||
if (!pindex || !pindex->nStatus.hasData()) { | if (!pindex || !pindex->nStatus.hasData()) { | ||||
BlockValidationState state; | BlockValidationState state; | ||||
assert(std::addressof(::ChainstateActive()) == | |||||
std::addressof(*this)); | |||||
if (AcceptBlock(config, pblock, state, true, dbp, | if (AcceptBlock(config, pblock, state, true, dbp, | ||||
nullptr)) { | nullptr)) { | ||||
nLoaded++; | nLoaded++; | ||||
} | } | ||||
if (state.IsError()) { | if (state.IsError()) { | ||||
break; | break; | ||||
} | } | ||||
} else if (hash != chainparams.GetConsensus() | } else if (hash != chainparams.GetConsensus() | ||||
.hashGenesisBlock && | .hashGenesisBlock && | ||||
pindex->nHeight % 1000 == 0) { | pindex->nHeight % 1000 == 0) { | ||||
LogPrint( | LogPrint( | ||||
BCLog::REINDEX, | BCLog::REINDEX, | ||||
"Block Import: already had block %s at height %d\n", | "Block Import: already had block %s at height %d\n", | ||||
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 == chainparams.GetConsensus().hashGenesisBlock) { | if (hash == chainparams.GetConsensus().hashGenesisBlock) { | ||||
BlockValidationState state; | BlockValidationState state; | ||||
assert(std::addressof(::ChainstateActive()) == | |||||
std::addressof(*this)); | |||||
if (!ActivateBestChain(config, state, nullptr)) { | if (!ActivateBestChain(config, state, nullptr)) { | ||||
break; | break; | ||||
} | } | ||||
} | } | ||||
assert(std::addressof(::ChainstateActive()) == | |||||
std::addressof(*this)); | |||||
NotifyHeaderTip(*this); | NotifyHeaderTip(*this); | ||||
// Recursively process earlier encountered successors of this | // Recursively process earlier encountered successors of this | ||||
// block | // block | ||||
std::deque<uint256> queue; | std::deque<uint256> queue; | ||||
queue.push_back(hash); | queue.push_back(hash); | ||||
while (!queue.empty()) { | while (!queue.empty()) { | ||||
uint256 head = queue.front(); | uint256 head = queue.front(); | ||||
Show All 10 Lines | try { | ||||
chainparams.GetConsensus())) { | chainparams.GetConsensus())) { | ||||
LogPrint( | LogPrint( | ||||
BCLog::REINDEX, | BCLog::REINDEX, | ||||
"%s: Processing out of order child %s of %s\n", | "%s: Processing out of order child %s of %s\n", | ||||
__func__, pblockrecursive->GetHash().ToString(), | __func__, pblockrecursive->GetHash().ToString(), | ||||
head.ToString()); | head.ToString()); | ||||
LOCK(cs_main); | LOCK(cs_main); | ||||
BlockValidationState dummy; | BlockValidationState dummy; | ||||
assert(std::addressof(::ChainstateActive()) == | |||||
std::addressof(*this)); | |||||
if (AcceptBlock(config, pblockrecursive, dummy, | if (AcceptBlock(config, pblockrecursive, dummy, | ||||
true, &it->second, nullptr)) { | true, &it->second, nullptr)) { | ||||
nLoaded++; | nLoaded++; | ||||
queue.push_back(pblockrecursive->GetHash()); | queue.push_back(pblockrecursive->GetHash()); | ||||
} | } | ||||
} | } | ||||
range.first++; | range.first++; | ||||
mapBlocksUnknownParent.erase(it); | mapBlocksUnknownParent.erase(it); | ||||
assert(std::addressof(::ChainstateActive()) == | |||||
std::addressof(*this)); | |||||
NotifyHeaderTip(*this); | NotifyHeaderTip(*this); | ||||
} | } | ||||
} | } | ||||
} catch (const std::exception &e) { | } catch (const std::exception &e) { | ||||
LogPrintf("%s: Deserialize or I/O error - %s\n", __func__, | LogPrintf("%s: Deserialize or I/O error - %s\n", __func__, | ||||
e.what()); | e.what()); | ||||
} | } | ||||
} | } | ||||
▲ Show 20 Lines • Show All 418 Lines • ▼ Show 20 Lines | try { | ||||
Amount amountdelta = nFeeDelta * SATOSHI; | Amount amountdelta = nFeeDelta * SATOSHI; | ||||
if (amountdelta != Amount::zero()) { | if (amountdelta != Amount::zero()) { | ||||
pool.PrioritiseTransaction(tx->GetId(), amountdelta); | pool.PrioritiseTransaction(tx->GetId(), amountdelta); | ||||
} | } | ||||
TxValidationState state; | TxValidationState state; | ||||
if (nTime > nNow - nExpiryTimeout) { | if (nTime > nNow - nExpiryTimeout) { | ||||
LOCK(cs_main); | LOCK(cs_main); | ||||
assert(std::addressof(::ChainstateActive()) == | |||||
std::addressof(active_chainstate)); | |||||
AcceptToMemoryPoolWithTime( | AcceptToMemoryPoolWithTime( | ||||
config, pool, active_chainstate, state, tx, nTime, | config, pool, active_chainstate, state, tx, nTime, | ||||
false /* bypass_limits */, false /* test_accept */); | false /* bypass_limits */, false /* test_accept */); | ||||
if (state.IsValid()) { | if (state.IsValid()) { | ||||
++count; | ++count; | ||||
} else { | } else { | ||||
// mempool may contain the transaction already, e.g. from | // mempool may contain the transaction already, e.g. from | ||||
// wallet(s) having loaded it while we were processing | // wallet(s) having loaded it while we were processing | ||||
▲ Show 20 Lines • Show All 554 Lines • Show Last 20 Lines |