aboutsummaryrefslogtreecommitdiff
path: root/src/validation.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/validation.cpp')
-rw-r--r--src/validation.cpp91
1 files changed, 46 insertions, 45 deletions
diff --git a/src/validation.cpp b/src/validation.cpp
index 9791d6e2d8..811530d40e 100644
--- a/src/validation.cpp
+++ b/src/validation.cpp
@@ -1,5 +1,5 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
-// Copyright (c) 2009-2017 The Bitcoin Core developers
+// Copyright (c) 2009-2018 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
@@ -17,7 +17,6 @@
#include <cuckoocache.h>
#include <hash.h>
#include <index/txindex.h>
-#include <init.h>
#include <policy/fees.h>
#include <policy/policy.h>
#include <policy/rbf.h>
@@ -29,6 +28,7 @@
#include <script/script.h>
#include <script/sigcache.h>
#include <script/standard.h>
+#include <shutdown.h>
#include <timedata.h>
#include <tinyformat.h>
#include <txdb.h>
@@ -157,7 +157,7 @@ public:
std::multimap<CBlockIndex*, CBlockIndex*> mapBlocksUnlinked;
CBlockIndex *pindexBestInvalid = nullptr;
- bool LoadBlockIndex(const Consensus::Params& consensus_params, CBlockTreeDB& blocktree);
+ bool LoadBlockIndex(const Consensus::Params& consensus_params, CBlockTreeDB& blocktree) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
bool ActivateBestChain(CValidationState &state, const CChainParams& chainparams, std::shared_ptr<const CBlock> pblock);
@@ -165,8 +165,8 @@ public:
* If a block header hasn't already been seen, call CheckBlockHeader on it, ensure
* that it doesn't descend from an invalid block, and then add it to mapBlockIndex.
*/
- bool AcceptBlockHeader(const CBlockHeader& block, CValidationState& state, const CChainParams& chainparams, CBlockIndex** ppindex);
- bool AcceptBlock(const std::shared_ptr<const CBlock>& pblock, CValidationState& state, const CChainParams& chainparams, CBlockIndex** ppindex, bool fRequested, const CDiskBlockPos* dbp, bool* fNewBlock);
+ bool AcceptBlockHeader(const CBlockHeader& block, CValidationState& state, const CChainParams& chainparams, CBlockIndex** ppindex) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
+ bool AcceptBlock(const std::shared_ptr<const CBlock>& pblock, CValidationState& state, const CChainParams& chainparams, CBlockIndex** ppindex, bool fRequested, const CDiskBlockPos* dbp, bool* fNewBlock) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
// Block (dis)connection on a given view:
DisconnectResult DisconnectBlock(const CBlock& block, const CBlockIndex* pindex, CCoinsViewCache& view);
@@ -177,9 +177,9 @@ public:
bool DisconnectTip(CValidationState& state, const CChainParams& chainparams, DisconnectedBlockTransactions *disconnectpool);
// Manual block validity manipulation:
- bool PreciousBlock(CValidationState& state, const CChainParams& params, CBlockIndex *pindex);
- bool InvalidateBlock(CValidationState& state, const CChainParams& chainparams, CBlockIndex *pindex);
- bool ResetBlockFailureFlags(CBlockIndex *pindex);
+ bool PreciousBlock(CValidationState& state, const CChainParams& params, CBlockIndex* pindex) LOCKS_EXCLUDED(cs_main);
+ bool InvalidateBlock(CValidationState& state, const CChainParams& chainparams, CBlockIndex* pindex) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
+ bool ResetBlockFailureFlags(CBlockIndex* pindex) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
bool ReplayBlocks(const CChainParams& params, CCoinsView* view);
bool RewindBlockIndex(const CChainParams& params);
@@ -193,9 +193,9 @@ private:
bool ActivateBestChainStep(CValidationState& state, const CChainParams& chainparams, CBlockIndex* pindexMostWork, const std::shared_ptr<const CBlock>& pblock, bool& fInvalidFound, ConnectTrace& connectTrace);
bool ConnectTip(CValidationState& state, const CChainParams& chainparams, CBlockIndex* pindexNew, const std::shared_ptr<const CBlock>& pblock, ConnectTrace& connectTrace, DisconnectedBlockTransactions &disconnectpool);
- CBlockIndex* AddToBlockIndex(const CBlockHeader& block);
+ CBlockIndex* AddToBlockIndex(const CBlockHeader& block) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
/** Create a new block index entry for a given block hash */
- CBlockIndex * InsertBlockIndex(const uint256& hash);
+ CBlockIndex* InsertBlockIndex(const uint256& hash) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
/**
* Make various assertions about the state of the block index.
*
@@ -204,11 +204,11 @@ private:
void CheckBlockIndex(const Consensus::Params& consensusParams);
void InvalidBlockFound(CBlockIndex *pindex, const CValidationState &state);
- CBlockIndex* FindMostWorkChain();
- bool ReceivedBlockTransactions(const CBlock &block, CValidationState& state, CBlockIndex *pindexNew, const CDiskBlockPos& pos, const Consensus::Params& consensusParams);
+ CBlockIndex* FindMostWorkChain() EXCLUSIVE_LOCKS_REQUIRED(cs_main);
+ void ReceivedBlockTransactions(const CBlock& block, CBlockIndex* pindexNew, const CDiskBlockPos& pos, const Consensus::Params& consensusParams) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
- bool RollforwardBlock(const CBlockIndex* pindex, CCoinsViewCache& inputs, const CChainParams& params);
+ bool RollforwardBlock(const CBlockIndex* pindex, CCoinsViewCache& inputs, const CChainParams& params) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
} g_chainstate;
@@ -577,15 +577,9 @@ static bool AcceptToMemoryPoolWorker(const CChainParams& chainparams, CTxMemPool
if (tx.IsCoinBase())
return state.DoS(100, false, REJECT_INVALID, "coinbase");
- // Reject transactions with witness before segregated witness activates (override with -prematurewitness)
- bool witnessEnabled = IsWitnessEnabled(chainActive.Tip(), chainparams.GetConsensus());
- if (!gArgs.GetBoolArg("-prematurewitness", false) && tx.HasWitness() && !witnessEnabled) {
- return state.DoS(0, false, REJECT_NONSTANDARD, "no-witness-yet", true);
- }
-
// Rather not work on nonstandard transactions (unless -testnet/-regtest)
std::string reason;
- if (fRequireStandard && !IsStandardTx(tx, reason, witnessEnabled))
+ if (fRequireStandard && !IsStandardTx(tx, reason))
return state.DoS(0, false, REJECT_NONSTANDARD, reason);
// Do not work on transactions that are too small.
@@ -657,7 +651,7 @@ static bool AcceptToMemoryPoolWorker(const CChainParams& chainparams, CTxMemPool
view.SetBackend(viewMemPool);
// do all inputs exist?
- for (const CTxIn txin : tx.vin) {
+ for (const CTxIn& txin : tx.vin) {
if (!pcoinsTip->HaveCoinInCache(txin.prevout)) {
coins_to_uncache.push_back(txin.prevout);
}
@@ -963,7 +957,7 @@ static bool AcceptToMemoryPoolWorker(const CChainParams& chainparams, CTxMemPool
}
// Remove conflicting transactions from the mempool
- for (const CTxMemPool::txiter it : allConflicting)
+ for (CTxMemPool::txiter it : allConflicting)
{
LogPrint(BCLog::MEMPOOL, "replacing tx %s with %s for %s BTC additional fees, %d delta bytes\n",
it->GetTx().GetHash().ToString(),
@@ -2651,7 +2645,7 @@ bool CChainState::ActivateBestChainStep(CValidationState& state, const CChainPar
return true;
}
-static void NotifyHeaderTip() {
+static void NotifyHeaderTip() LOCKS_EXCLUDED(cs_main) {
bool fNotify = false;
bool fInitialBlockDownload = false;
static CBlockIndex* pindexHeaderOld = nullptr;
@@ -2704,6 +2698,9 @@ bool CChainState::ActivateBestChain(CValidationState &state, const CChainParams&
// Block until the validation queue drains. This should largely
// never happen in normal operation, however may happen during
// reindex, causing memory blowup if we run too far ahead.
+ // Note that if a validationinterface callback ends up calling
+ // ActivateBestChain this may lead to a deadlock! We should
+ // probably have a DEBUG_LOCKORDER test for this in the future.
SyncWithValidationInterfaceQueue();
}
@@ -2956,7 +2953,7 @@ CBlockIndex* CChainState::AddToBlockIndex(const CBlockHeader& block)
}
/** Mark a block as having its data received and checked (up to BLOCK_VALID_TRANSACTIONS). */
-bool CChainState::ReceivedBlockTransactions(const CBlock &block, CValidationState& state, CBlockIndex *pindexNew, const CDiskBlockPos& pos, const Consensus::Params& consensusParams)
+void CChainState::ReceivedBlockTransactions(const CBlock& block, CBlockIndex* pindexNew, const CDiskBlockPos& pos, const Consensus::Params& consensusParams)
{
pindexNew->nTx = block.vtx.size();
pindexNew->nChainTx = 0;
@@ -3000,8 +2997,6 @@ bool CChainState::ReceivedBlockTransactions(const CBlock &block, CValidationStat
mapBlocksUnlinked.insert(std::make_pair(pindexNew->pprev, pindexNew));
}
}
-
- return true;
}
static bool FindBlockPos(CDiskBlockPos &pos, unsigned int nAddSize, unsigned int nHeight, uint64_t nTime, bool fKnown = false)
@@ -3400,7 +3395,7 @@ bool CChainState::AcceptBlockHeader(const CBlockHeader& block, CValidationState&
return error("%s: Consensus::ContextualCheckBlockHeader: %s, %s", __func__, hash.ToString(), FormatStateMessage(state));
// If the previous block index isn't valid, determine if it descends from any block which
- // has been found invalid (g_failed_blocks), then mark pindexPrev and any blocks
+ // has been found invalid (m_failed_blocks), then mark pindexPrev and any blocks
// between them as failed.
if (!pindexPrev->IsValid(BLOCK_VALID_SCRIPTS)) {
for (const CBlockIndex* failedit : m_failed_blocks) {
@@ -3513,7 +3508,6 @@ bool CChainState::AcceptBlock(const std::shared_ptr<const CBlock>& pblock, CVali
// request; don't process these.
if (pindex->nChainWork < nMinimumChainWork) return true;
}
- if (fNewBlock) *fNewBlock = true;
if (!CheckBlock(block, state, chainparams.GetConsensus()) ||
!ContextualCheckBlock(block, state, chainparams.GetConsensus(), pindex->pprev)) {
@@ -3530,14 +3524,14 @@ bool CChainState::AcceptBlock(const std::shared_ptr<const CBlock>& pblock, CVali
GetMainSignals().NewPoWValidBlock(pindex, pblock);
// Write block to history file
+ if (fNewBlock) *fNewBlock = true;
try {
CDiskBlockPos blockPos = SaveBlockToDisk(block, pindex->nHeight, chainparams, dbp);
if (blockPos.IsNull()) {
state.Error(strprintf("%s: Failed to find position to write new block to disk", __func__));
return false;
}
- if (!ReceivedBlockTransactions(block, state, pindex, blockPos, chainparams.GetConsensus()))
- return error("AcceptBlock(): ReceivedBlockTransactions failed");
+ ReceivedBlockTransactions(block, pindex, blockPos, chainparams.GetConsensus());
} catch (const std::runtime_error& e) {
return AbortNode(state, std::string("System error: ") + e.what());
}
@@ -3735,6 +3729,15 @@ static void FindFilesToPrune(std::set<int>& setFilesToPrune, uint64_t nPruneAfte
int count=0;
if (nCurrentUsage + nBuffer >= nPruneTarget) {
+ // On a prune event, the chainstate DB is flushed.
+ // To avoid excessive prune events negating the benefit of high dbcache
+ // values, we should not prune too rapidly.
+ // So when pruning in IBD, increase the buffer a bit to avoid a re-prune too soon.
+ if (IsInitialBlockDownload()) {
+ // Since this is only relevant during IBD, we use a fixed 10%
+ nBuffer += nPruneTarget / 10;
+ }
+
for (int fileNumber = 0; fileNumber < nLastBlockFile; fileNumber++) {
nBytesToPrune = vinfoBlockFile[fileNumber].nSize + vinfoBlockFile[fileNumber].nUndoSize;
@@ -3832,7 +3835,7 @@ CBlockIndex * CChainState::InsertBlockIndex(const uint256& hash)
bool CChainState::LoadBlockIndex(const Consensus::Params& consensus_params, CBlockTreeDB& blocktree)
{
- if (!blocktree.LoadBlockIndexGuts(consensus_params, [this](const uint256& hash){ return this->InsertBlockIndex(hash); }))
+ if (!blocktree.LoadBlockIndexGuts(consensus_params, [this](const uint256& hash) EXCLUSIVE_LOCKS_REQUIRED(cs_main) { return this->InsertBlockIndex(hash); }))
return false;
boost::this_thread::interruption_point();
@@ -3840,7 +3843,7 @@ bool CChainState::LoadBlockIndex(const Consensus::Params& consensus_params, CBlo
// Calculate nChainWork
std::vector<std::pair<int, CBlockIndex*> > vSortedByHeight;
vSortedByHeight.reserve(mapBlockIndex.size());
- for (const std::pair<uint256, CBlockIndex*>& item : mapBlockIndex)
+ for (const std::pair<const uint256, CBlockIndex*>& item : mapBlockIndex)
{
CBlockIndex* pindex = item.second;
vSortedByHeight.push_back(std::make_pair(pindex->nHeight, pindex));
@@ -3882,7 +3885,7 @@ bool CChainState::LoadBlockIndex(const Consensus::Params& consensus_params, CBlo
return true;
}
-bool static LoadBlockIndexDB(const CChainParams& chainparams)
+bool static LoadBlockIndexDB(const CChainParams& chainparams) EXCLUSIVE_LOCKS_REQUIRED(cs_main)
{
if (!g_chainstate.LoadBlockIndex(chainparams.GetConsensus(), *pblocktree))
return false;
@@ -3907,7 +3910,7 @@ bool static LoadBlockIndexDB(const CChainParams& chainparams)
// Check presence of blk files
LogPrintf("Checking all blk files are present...\n");
std::set<int> setBlkDataFiles;
- for (const std::pair<uint256, CBlockIndex*>& item : mapBlockIndex)
+ for (const std::pair<const uint256, CBlockIndex*>& item : mapBlockIndex)
{
CBlockIndex* pindex = item.second;
if (pindex->nStatus & BLOCK_HAVE_DATA) {
@@ -3990,14 +3993,13 @@ bool CVerifyDB::VerifyDB(const CChainParams& chainparams, CCoinsView *coinsview,
nCheckLevel = std::max(0, std::min(4, nCheckLevel));
LogPrintf("Verifying last %i blocks at level %i\n", nCheckDepth, nCheckLevel);
CCoinsViewCache coins(coinsview);
- CBlockIndex* pindexState = chainActive.Tip();
+ CBlockIndex* pindex;
CBlockIndex* pindexFailure = nullptr;
int nGoodTransactions = 0;
CValidationState state;
int reportDone = 0;
LogPrintf("[0%%]..."); /* Continued */
- for (CBlockIndex* pindex = chainActive.Tip(); pindex && pindex->pprev; pindex = pindex->pprev)
- {
+ for (pindex = chainActive.Tip(); pindex && pindex->pprev; pindex = pindex->pprev) {
boost::this_thread::interruption_point();
int percentageDone = std::max(1, std::min(99, (int)(((double)(chainActive.Height() - pindex->nHeight)) / (double)nCheckDepth * (nCheckLevel >= 4 ? 50 : 100))));
if (reportDone < percentageDone/10) {
@@ -4006,7 +4008,7 @@ bool CVerifyDB::VerifyDB(const CChainParams& chainparams, CCoinsView *coinsview,
reportDone = percentageDone/10;
}
uiInterface.ShowProgress(_("Verifying blocks..."), percentageDone, false);
- if (pindex->nHeight < chainActive.Height()-nCheckDepth)
+ if (pindex->nHeight <= chainActive.Height()-nCheckDepth)
break;
if (fPruneMode && !(pindex->nStatus & BLOCK_HAVE_DATA)) {
// If pruning, only go back as far as we have data.
@@ -4031,13 +4033,12 @@ bool CVerifyDB::VerifyDB(const CChainParams& chainparams, CCoinsView *coinsview,
}
}
// check level 3: check for inconsistencies during memory-only disconnect of tip blocks
- if (nCheckLevel >= 3 && pindex == pindexState && (coins.DynamicMemoryUsage() + pcoinsTip->DynamicMemoryUsage()) <= nCoinCacheUsage) {
+ if (nCheckLevel >= 3 && (coins.DynamicMemoryUsage() + pcoinsTip->DynamicMemoryUsage()) <= nCoinCacheUsage) {
assert(coins.GetBestBlock() == pindex->GetBlockHash());
DisconnectResult res = g_chainstate.DisconnectBlock(block, pindex, coins);
if (res == DISCONNECT_FAILED) {
return error("VerifyDB(): *** irrecoverable inconsistency in block data at %d, hash=%s", pindex->nHeight, pindex->GetBlockHash().ToString());
}
- pindexState = pindex->pprev;
if (res == DISCONNECT_UNCLEAN) {
nGoodTransactions = 0;
pindexFailure = pindex;
@@ -4051,9 +4052,11 @@ bool CVerifyDB::VerifyDB(const CChainParams& chainparams, CCoinsView *coinsview,
if (pindexFailure)
return error("VerifyDB(): *** coin database inconsistencies found (last %i blocks, %i good transactions before that)\n", chainActive.Height() - pindexFailure->nHeight + 1, nGoodTransactions);
+ // store block count as we move pindex at check level >= 4
+ int block_count = chainActive.Height() - pindex->nHeight;
+
// check level 4: try reconnecting blocks
if (nCheckLevel >= 4) {
- CBlockIndex *pindex = pindexState;
while (pindex != chainActive.Tip()) {
boost::this_thread::interruption_point();
uiInterface.ShowProgress(_("Verifying blocks..."), std::max(1, std::min(99, 100 - (int)(((double)(chainActive.Height() - pindex->nHeight)) / (double)nCheckDepth * 50))), false);
@@ -4067,7 +4070,7 @@ bool CVerifyDB::VerifyDB(const CChainParams& chainparams, CCoinsView *coinsview,
}
LogPrintf("[DONE].\n");
- LogPrintf("No coin database inconsistencies in last %i blocks (%i transactions)\n", chainActive.Height() - pindexState->nHeight, nGoodTransactions);
+ LogPrintf("No coin database inconsistencies in last %i blocks (%i transactions)\n", block_count, nGoodTransactions);
return true;
}
@@ -4346,9 +4349,7 @@ bool CChainState::LoadGenesisBlock(const CChainParams& chainparams)
if (blockPos.IsNull())
return error("%s: writing genesis block to disk failed", __func__);
CBlockIndex *pindex = AddToBlockIndex(block);
- CValidationState state;
- if (!ReceivedBlockTransactions(block, state, pindex, blockPos, chainparams.GetConsensus()))
- return error("%s: genesis block not accepted (%s)", __func__, FormatStateMessage(state));
+ ReceivedBlockTransactions(block, pindex, blockPos, chainparams.GetConsensus());
} catch (const std::runtime_error& e) {
return error("%s: failed to write genesis block: %s", __func__, e.what());
}