Changeset View
Changeset View
Standalone View
Standalone View
src/validation.cpp
// Copyright (c) 2009-2010 Satoshi Nakamoto | // Copyright (c) 2009-2010 Satoshi Nakamoto | ||||
Lint: Code style violation: '/Users/jacox/personalprojects/bitcoin-abc/src/validation.cpp' has code style errors. | |||||
// Copyright (c) 2009-2016 The Bitcoin Core developers | // Copyright (c) 2009-2016 The Bitcoin Core developers | ||||
// Copyright (c) 2017 The Bitcoin developers | // Copyright (c) 2017 The Bitcoin developers | ||||
// Distributed under the MIT software license, see the accompanying | // Distributed under the MIT software license, see the accompanying | ||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php. | // file COPYING or http://www.opensource.org/licenses/mit-license.php. | ||||
#include "validation.h" | #include "validation.h" | ||||
#include "arith_uint256.h" | #include "arith_uint256.h" | ||||
▲ Show 20 Lines • Show All 1,868 Lines • ▼ Show 20 Lines | |||||
/** | /** | ||||
* Apply the effects of this block (with given index) on the UTXO set | * Apply the effects of this block (with given index) on the UTXO set | ||||
* represented by coins. Validity checks that depend on the UTXO set are also | * represented by coins. Validity checks that depend on the UTXO set are also | ||||
* done; ConnectBlock() can fail if those validity checks fail (among other | * done; ConnectBlock() can fail if those validity checks fail (among other | ||||
* reasons). | * reasons). | ||||
*/ | */ | ||||
static bool ConnectBlock(const Config &config, const CBlock &block, | static bool ConnectBlock(const Config &config, const CBlock &block, | ||||
CValidationState &state, CBlockIndex *pindex, | CValidationState &state, CBlockIndex *pindex, | ||||
CCoinsViewCache &view, const CChainParams &chainparams, | CCoinsViewCache &view, bool fJustCheck = false) { | ||||
bool fJustCheck = false) { | |||||
AssertLockHeld(cs_main); | AssertLockHeld(cs_main); | ||||
int64_t nTimeStart = GetTimeMicros(); | int64_t nTimeStart = GetTimeMicros(); | ||||
// Check it again in case a previous version let a bad block in | // Check it again in case a previous version let a bad block in | ||||
if (!CheckBlock(config, block, state, !fJustCheck, !fJustCheck)) { | if (!CheckBlock(config, block, state, !fJustCheck, !fJustCheck)) { | ||||
return error("%s: Consensus::CheckBlock: %s", __func__, | return error("%s: Consensus::CheckBlock: %s", __func__, | ||||
FormatStateMessage(state)); | FormatStateMessage(state)); | ||||
} | } | ||||
// Verify that the view's current state corresponds to the previous block | // Verify that the view's current state corresponds to the previous block | ||||
uint256 hashPrevBlock = | uint256 hashPrevBlock = | ||||
pindex->pprev == nullptr ? uint256() : pindex->pprev->GetBlockHash(); | pindex->pprev == nullptr ? uint256() : pindex->pprev->GetBlockHash(); | ||||
assert(hashPrevBlock == view.GetBestBlock()); | assert(hashPrevBlock == view.GetBestBlock()); | ||||
// Special case for the genesis block, skipping connection of its | // Special case for the genesis block, skipping connection of its | ||||
// transactions (its coinbase is unspendable) | // transactions (its coinbase is unspendable) | ||||
if (block.GetHash() == chainparams.GetConsensus().hashGenesisBlock) { | if (block.GetHash() == config.GetChainParams().GetConsensus().hashGenesisBlock) { | ||||
deadalnixUnsubmitted Done Inline ActionsSounds like you have a lot of GetChainParams in there. You should probably assign this to a local variable. deadalnix: Sounds like you have a lot of GetChainParams in there. You should probably assign this to a… | |||||
if (!fJustCheck) { | if (!fJustCheck) { | ||||
view.SetBestBlock(pindex->GetBlockHash()); | view.SetBestBlock(pindex->GetBlockHash()); | ||||
} | } | ||||
return true; | return true; | ||||
} | } | ||||
bool fScriptChecks = true; | bool fScriptChecks = true; | ||||
if (!hashAssumeValid.IsNull()) { | if (!hashAssumeValid.IsNull()) { | ||||
// We've been configured with the hash of a block which has been | // We've been configured with the hash of a block which has been | ||||
// externally verified to have a valid history. A suitable default value | // externally verified to have a valid history. A suitable default value | ||||
// is included with the software and updated from time to time. Because | // is included with the software and updated from time to time. Because | ||||
// validity relative to a piece of software is an objective fact these | // validity relative to a piece of software is an objective fact these | ||||
// defaults can be easily reviewed. This setting doesn't force the | // defaults can be easily reviewed. This setting doesn't force the | ||||
// selection of any particular chain but makes validating some faster by | // selection of any particular chain but makes validating some faster by | ||||
// effectively caching the result of part of the verification. | // effectively caching the result of part of the verification. | ||||
BlockMap::const_iterator it = mapBlockIndex.find(hashAssumeValid); | BlockMap::const_iterator it = mapBlockIndex.find(hashAssumeValid); | ||||
if (it != mapBlockIndex.end()) { | if (it != mapBlockIndex.end()) { | ||||
if (it->second->GetAncestor(pindex->nHeight) == pindex && | if (it->second->GetAncestor(pindex->nHeight) == pindex && | ||||
pindexBestHeader->GetAncestor(pindex->nHeight) == pindex && | pindexBestHeader->GetAncestor(pindex->nHeight) == pindex && | ||||
pindexBestHeader->nChainWork >= | pindexBestHeader->nChainWork >= | ||||
UintToArith256( | UintToArith256( | ||||
chainparams.GetConsensus().nMinimumChainWork)) { | config.GetChainParams().GetConsensus().nMinimumChainWork)) { | ||||
// This block is a member of the assumed verified chain and an | // This block is a member of the assumed verified chain and an | ||||
// ancestor of the best header. The equivalent time check | // ancestor of the best header. The equivalent time check | ||||
// discourages hashpower from extorting the network via DOS | // discourages hashpower from extorting the network via DOS | ||||
// attack into accepting an invalid block through telling users | // attack into accepting an invalid block through telling users | ||||
// they must manually set assumevalid. Requiring a software | // they must manually set assumevalid. Requiring a software | ||||
// change or burying the invalid block, regardless of the | // change or burying the invalid block, regardless of the | ||||
// setting, makes it hard to hide the implication of the demand. | // setting, makes it hard to hide the implication of the demand. | ||||
// This also avoids having release candidates that are hardly | // This also avoids having release candidates that are hardly | ||||
// doing any signature verification at all in testing without | // doing any signature verification at all in testing without | ||||
// having to artificially set the default assumed verified block | // having to artificially set the default assumed verified block | ||||
// further back. The test against nMinimumChainWork prevents the | // further back. The test against nMinimumChainWork prevents the | ||||
// skipping when denied access to any chain at least as good as | // skipping when denied access to any chain at least as good as | ||||
// the expected chain. | // the expected chain. | ||||
fScriptChecks = | fScriptChecks = | ||||
(GetBlockProofEquivalentTime( | (GetBlockProofEquivalentTime( | ||||
*pindexBestHeader, *pindex, *pindexBestHeader, | *pindexBestHeader, *pindex, *pindexBestHeader, | ||||
chainparams.GetConsensus()) <= 60 * 60 * 24 * 7 * 2); | config.GetChainParams().GetConsensus()) <= 60 * 60 * 24 * 7 * 2); | ||||
} | } | ||||
} | } | ||||
} | } | ||||
int64_t nTime1 = GetTimeMicros(); | int64_t nTime1 = GetTimeMicros(); | ||||
nTimeCheck += nTime1 - nTimeStart; | nTimeCheck += nTime1 - nTimeStart; | ||||
LogPrint(BCLog::BENCH, " - Sanity checks: %.2fms [%.2fs]\n", | LogPrint(BCLog::BENCH, " - Sanity checks: %.2fms [%.2fs]\n", | ||||
0.001 * (nTime1 - nTimeStart), nTimeCheck * 0.000001); | 0.001 * (nTime1 - nTimeStart), nTimeCheck * 0.000001); | ||||
Show All 28 Lines | static bool ConnectBlock(const Config &config, const CBlock &block, | ||||
// coinbase pairs, not possible to create overwriting txs. But by the time | // coinbase pairs, not possible to create overwriting txs. But by the time | ||||
// BIP34 activated, in each of the existing pairs the duplicate coinbase had | // BIP34 activated, in each of the existing pairs the duplicate coinbase had | ||||
// overwritten the first before the first had been spent. Since those | // overwritten the first before the first had been spent. Since those | ||||
// coinbases are sufficiently buried its no longer possible to create | // coinbases are sufficiently buried its no longer possible to create | ||||
// further duplicate transactions descending from the known pairs either. If | // further duplicate transactions descending from the known pairs either. If | ||||
// we're on the known chain at height greater than where BIP34 activated, we | // we're on the known chain at height greater than where BIP34 activated, we | ||||
// can save the db accesses needed for the BIP30 check. | // can save the db accesses needed for the BIP30 check. | ||||
CBlockIndex *pindexBIP34height = | CBlockIndex *pindexBIP34height = | ||||
pindex->pprev->GetAncestor(chainparams.GetConsensus().BIP34Height); | pindex->pprev->GetAncestor(config.GetChainParams().GetConsensus().BIP34Height); | ||||
// Only continue to enforce if we're below BIP34 activation height or the | // Only continue to enforce if we're below BIP34 activation height or the | ||||
// block hash at that height doesn't correspond. | // block hash at that height doesn't correspond. | ||||
fEnforceBIP30 = fEnforceBIP30 && (!pindexBIP34height || | fEnforceBIP30 = fEnforceBIP30 && (!pindexBIP34height || | ||||
!(pindexBIP34height->GetBlockHash() == | !(pindexBIP34height->GetBlockHash() == | ||||
chainparams.GetConsensus().BIP34Hash)); | config.GetChainParams().GetConsensus().BIP34Hash)); | ||||
if (fEnforceBIP30) { | if (fEnforceBIP30) { | ||||
for (const auto &tx : block.vtx) { | for (const auto &tx : block.vtx) { | ||||
for (size_t o = 0; o < tx->vout.size(); o++) { | for (size_t o = 0; o < tx->vout.size(); o++) { | ||||
if (view.HaveCoin(COutPoint(tx->GetHash(), o))) { | if (view.HaveCoin(COutPoint(tx->GetHash(), o))) { | ||||
return state.DoS( | return state.DoS( | ||||
100, | 100, | ||||
error("ConnectBlock(): tried to overwrite transaction"), | error("ConnectBlock(): tried to overwrite transaction"), | ||||
REJECT_INVALID, "bad-txns-BIP30"); | REJECT_INVALID, "bad-txns-BIP30"); | ||||
} | } | ||||
} | } | ||||
} | } | ||||
} | } | ||||
// Start enforcing BIP68 (sequence locks) using versionbits logic. | // Start enforcing BIP68 (sequence locks) using versionbits logic. | ||||
int nLockTimeFlags = 0; | int nLockTimeFlags = 0; | ||||
if (VersionBitsState(pindex->pprev, chainparams.GetConsensus(), | if (VersionBitsState(pindex->pprev, config.GetChainParams().GetConsensus(), | ||||
Consensus::DEPLOYMENT_CSV, | Consensus::DEPLOYMENT_CSV, | ||||
versionbitscache) == THRESHOLD_ACTIVE) { | versionbitscache) == THRESHOLD_ACTIVE) { | ||||
nLockTimeFlags |= LOCKTIME_VERIFY_SEQUENCE; | nLockTimeFlags |= LOCKTIME_VERIFY_SEQUENCE; | ||||
} | } | ||||
uint32_t flags = GetBlockScriptFlags(pindex, config); | uint32_t flags = GetBlockScriptFlags(pindex, config); | ||||
int64_t nTime2 = GetTimeMicros(); | int64_t nTime2 = GetTimeMicros(); | ||||
▲ Show 20 Lines • Show All 100 Lines • ▼ Show 20 Lines | LogPrint(BCLog::BENCH, | ||||
" - Connect %u transactions: %.2fms (%.3fms/tx, " | " - Connect %u transactions: %.2fms (%.3fms/tx, " | ||||
"%.3fms/txin) [%.2fs]\n", | "%.3fms/txin) [%.2fs]\n", | ||||
(unsigned)block.vtx.size(), 0.001 * (nTime3 - nTime2), | (unsigned)block.vtx.size(), 0.001 * (nTime3 - nTime2), | ||||
0.001 * (nTime3 - nTime2) / block.vtx.size(), | 0.001 * (nTime3 - nTime2) / block.vtx.size(), | ||||
nInputs <= 1 ? 0 : 0.001 * (nTime3 - nTime2) / (nInputs - 1), | nInputs <= 1 ? 0 : 0.001 * (nTime3 - nTime2) / (nInputs - 1), | ||||
nTimeConnect * 0.000001); | nTimeConnect * 0.000001); | ||||
Amount blockReward = | Amount blockReward = | ||||
nFees + GetBlockSubsidy(pindex->nHeight, chainparams.GetConsensus()); | nFees + GetBlockSubsidy(pindex->nHeight, config.GetChainParams().GetConsensus()); | ||||
if (block.vtx[0]->GetValueOut() > blockReward) { | if (block.vtx[0]->GetValueOut() > blockReward) { | ||||
return state.DoS(100, error("ConnectBlock(): coinbase pays too much " | return state.DoS(100, error("ConnectBlock(): coinbase pays too much " | ||||
"(actual=%d vs limit=%d)", | "(actual=%d vs limit=%d)", | ||||
block.vtx[0]->GetValueOut(), blockReward), | block.vtx[0]->GetValueOut(), blockReward), | ||||
REJECT_INVALID, "bad-cb-amount"); | REJECT_INVALID, "bad-cb-amount"); | ||||
} | } | ||||
if (!control.Wait()) { | if (!control.Wait()) { | ||||
Show All 20 Lines | if (pindex->GetUndoPos().IsNull() || | ||||
CDiskBlockPos _pos; | CDiskBlockPos _pos; | ||||
if (!FindUndoPos( | if (!FindUndoPos( | ||||
state, pindex->nFile, _pos, | state, pindex->nFile, _pos, | ||||
::GetSerializeSize(blockundo, SER_DISK, CLIENT_VERSION) + | ::GetSerializeSize(blockundo, SER_DISK, CLIENT_VERSION) + | ||||
40)) { | 40)) { | ||||
return error("ConnectBlock(): FindUndoPos failed"); | return error("ConnectBlock(): FindUndoPos failed"); | ||||
} | } | ||||
if (!UndoWriteToDisk(blockundo, _pos, pindex->pprev->GetBlockHash(), | if (!UndoWriteToDisk(blockundo, _pos, pindex->pprev->GetBlockHash(), | ||||
chainparams.DiskMagic())) { | config.GetChainParams().DiskMagic())) { | ||||
return AbortNode(state, "Failed to write undo data"); | return AbortNode(state, "Failed to write undo data"); | ||||
} | } | ||||
// update nUndoPos in block index | // update nUndoPos in block index | ||||
pindex->nUndoPos = _pos.nPos; | pindex->nUndoPos = _pos.nPos; | ||||
pindex->nStatus |= BLOCK_HAVE_UNDO; | pindex->nStatus |= BLOCK_HAVE_UNDO; | ||||
} | } | ||||
▲ Show 20 Lines • Show All 438 Lines • ▼ Show 20 Lines | static bool ConnectTip(const Config &config, CValidationState &state, | ||||
// Apply the block atomically to the chain state. | // Apply the block atomically to the chain state. | ||||
int64_t nTime2 = GetTimeMicros(); | int64_t nTime2 = GetTimeMicros(); | ||||
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) * 0.001, nTimeReadFromDisk * 0.000001); | (nTime2 - nTime1) * 0.001, nTimeReadFromDisk * 0.000001); | ||||
{ | { | ||||
CCoinsViewCache view(pcoinsTip); | CCoinsViewCache view(pcoinsTip); | ||||
bool rv = ConnectBlock(config, blockConnecting, state, pindexNew, view, | bool rv = ConnectBlock(config, blockConnecting, state, pindexNew, view); | ||||
config.GetChainParams()); | |||||
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("ConnectTip(): ConnectBlock %s failed", | return error("ConnectTip(): ConnectBlock %s failed", | ||||
pindexNew->GetBlockHash().ToString()); | pindexNew->GetBlockHash().ToString()); | ||||
} | } | ||||
▲ Show 20 Lines • Show All 1,217 Lines • ▼ Show 20 Lines | if (!CheckBlock(config, block, state, fCheckPOW, fCheckMerkleRoot)) { | ||||
return error("%s: Consensus::CheckBlock: %s", __func__, | return error("%s: Consensus::CheckBlock: %s", __func__, | ||||
FormatStateMessage(state)); | FormatStateMessage(state)); | ||||
} | } | ||||
if (!ContextualCheckBlock(config, block, state, chainparams.GetConsensus(), | if (!ContextualCheckBlock(config, block, state, chainparams.GetConsensus(), | ||||
pindexPrev)) { | pindexPrev)) { | ||||
return error("%s: Consensus::ContextualCheckBlock: %s", __func__, | return error("%s: Consensus::ContextualCheckBlock: %s", __func__, | ||||
FormatStateMessage(state)); | FormatStateMessage(state)); | ||||
} | } | ||||
if (!ConnectBlock(config, block, state, &indexDummy, viewNew, chainparams, | if (!ConnectBlock(config, block, state, &indexDummy, viewNew, true)) { | ||||
true)) { | |||||
return false; | return false; | ||||
} | } | ||||
assert(state.IsValid()); | assert(state.IsValid()); | ||||
return true; | return true; | ||||
} | } | ||||
/** | /** | ||||
▲ Show 20 Lines • Show All 362 Lines • ▼ Show 20 Lines | bool CVerifyDB::VerifyDB(const Config &config, CCoinsView *coinsview, | ||||
if (nCheckDepth > chainActive.Height()) { | if (nCheckDepth > chainActive.Height()) { | ||||
nCheckDepth = chainActive.Height(); | nCheckDepth = chainActive.Height(); | ||||
} | } | ||||
nCheckLevel = std::max(0, std::min(4, nCheckLevel)); | nCheckLevel = std::max(0, std::min(4, nCheckLevel)); | ||||
LogPrintf("Verifying last %i blocks at level %i\n", nCheckDepth, | LogPrintf("Verifying last %i blocks at level %i\n", nCheckDepth, | ||||
nCheckLevel); | nCheckLevel); | ||||
const CChainParams &chainparams = config.GetChainParams(); | |||||
CCoinsViewCache coins(coinsview); | CCoinsViewCache coins(coinsview); | ||||
CBlockIndex *pindexState = chainActive.Tip(); | CBlockIndex *pindexState = chainActive.Tip(); | ||||
CBlockIndex *pindexFailure = nullptr; | CBlockIndex *pindexFailure = nullptr; | ||||
int nGoodTransactions = 0; | int nGoodTransactions = 0; | ||||
CValidationState state; | CValidationState state; | ||||
int reportDone = 0; | int reportDone = 0; | ||||
LogPrintf("[0%%]..."); | LogPrintf("[0%%]..."); | ||||
for (CBlockIndex *pindex = chainActive.Tip(); pindex && pindex->pprev; | for (CBlockIndex *pindex = chainActive.Tip(); pindex && pindex->pprev; | ||||
▲ Show 20 Lines • Show All 102 Lines • ▼ Show 20 Lines | if (nCheckLevel >= 4) { | ||||
(double)nCheckDepth * 50)))); | (double)nCheckDepth * 50)))); | ||||
pindex = chainActive.Next(pindex); | pindex = chainActive.Next(pindex); | ||||
CBlock block; | CBlock block; | ||||
if (!ReadBlockFromDisk(block, pindex, config)) { | if (!ReadBlockFromDisk(block, pindex, config)) { | ||||
return error( | return error( | ||||
"VerifyDB(): *** ReadBlockFromDisk failed at %d, hash=%s", | "VerifyDB(): *** ReadBlockFromDisk failed at %d, hash=%s", | ||||
pindex->nHeight, pindex->GetBlockHash().ToString()); | pindex->nHeight, pindex->GetBlockHash().ToString()); | ||||
} | } | ||||
if (!ConnectBlock(config, block, state, pindex, coins, | if (!ConnectBlock(config, block, state, pindex, coins)) { | ||||
chainparams)) { | |||||
return error( | return error( | ||||
"VerifyDB(): *** found unconnectable block at %d, hash=%s", | "VerifyDB(): *** found unconnectable block at %d, hash=%s", | ||||
pindex->nHeight, pindex->GetBlockHash().ToString()); | pindex->nHeight, pindex->GetBlockHash().ToString()); | ||||
} | } | ||||
} | } | ||||
} | } | ||||
LogPrintf("[DONE].\n"); | LogPrintf("[DONE].\n"); | ||||
▲ Show 20 Lines • Show All 782 Lines • Show Last 20 Lines |
'/Users/jacox/personalprojects/bitcoin-abc/src/validation.cpp' has code style errors.