Changeset View
Changeset View
Standalone View
Standalone View
src/validation.cpp
Show First 20 Lines • Show All 150 Lines • ▼ Show 20 Lines | |||||
/** chainwork for the last block that preciousblock has been applied to. */ | /** chainwork for the last block that preciousblock has been applied to. */ | ||||
arith_uint256 nLastPreciousChainwork = 0; | arith_uint256 nLastPreciousChainwork = 0; | ||||
/** Dirty block index entries. */ | /** Dirty block index entries. */ | ||||
std::set<CBlockIndex *> setDirtyBlockIndex; | std::set<CBlockIndex *> setDirtyBlockIndex; | ||||
/** Dirty block file entries. */ | /** Dirty block file entries. */ | ||||
std::set<int> setDirtyFileInfo; | std::set<int> setDirtyFileInfo; | ||||
} // anon namespace | } // namespace | ||||
/* Use this class to start tracking transactions that are removed from the | /* Use this class to start tracking transactions that are removed from the | ||||
* mempool and pass all those transactions through SyncTransaction when the | * mempool and pass all those transactions through SyncTransaction when the | ||||
* object goes out of scope. This is currently only used to call SyncTransaction | * object goes out of scope. This is currently only used to call SyncTransaction | ||||
* on conflicts removed from the mempool during block connection. Applied in | * on conflicts removed from the mempool during block connection. Applied in | ||||
* ActivateBestChain around ActivateBestStep which in turn calls: | * ActivateBestChain around ActivateBestStep which in turn calls: | ||||
* ConnectTip->removeForBlock->removeConflicts | * ConnectTip->removeForBlock->removeConflicts | ||||
*/ | */ | ||||
▲ Show 20 Lines • Show All 913 Lines • ▼ Show 20 Lines | bool ReadBlockFromDisk(CBlock &block, const CBlockIndex *pindex, | ||||
return true; | return true; | ||||
} | } | ||||
CAmount GetBlockSubsidy(int nHeight, const Consensus::Params &consensusParams) { | CAmount GetBlockSubsidy(int nHeight, const Consensus::Params &consensusParams) { | ||||
int halvings = nHeight / consensusParams.nSubsidyHalvingInterval; | int halvings = nHeight / consensusParams.nSubsidyHalvingInterval; | ||||
// Force block reward to zero when right shift is undefined. | // Force block reward to zero when right shift is undefined. | ||||
if (halvings >= 64) return 0; | if (halvings >= 64) return 0; | ||||
CAmount nSubsidy = 50 * COIN; | CAmount nSubsidy = 50 * COIN.GetSatoshis(); | ||||
// Subsidy is cut in half every 210,000 blocks which will occur | // Subsidy is cut in half every 210,000 blocks which will occur | ||||
// approximately every 4 years. | // approximately every 4 years. | ||||
nSubsidy >>= halvings; | nSubsidy >>= halvings; | ||||
return nSubsidy; | return nSubsidy; | ||||
} | } | ||||
bool IsInitialBlockDownload() { | bool IsInitialBlockDownload() { | ||||
const CChainParams &chainParams = Params(); | const CChainParams &chainParams = Params(); | ||||
▲ Show 20 Lines • Show All 96 Lines • ▼ Show 20 Lines | void CheckForkWarningConditionsOnNewFork(CBlockIndex *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 | ||||
// chain that is entirely longer than ours and invalid (note that this | // chain that is entirely longer than ours and invalid (note that this | ||||
// should be detected by both). We define it this way because it allows us | // should be detected by both). We define it this way because it allows us | ||||
// to only store the highest fork tip (+ base) which meets the 7-block | // to only store the highest fork tip (+ base) which meets the 7-block | ||||
// condition and from this always have the most-likely-to-cause-warning fork | // condition and from this always have the most-likely-to-cause-warning fork | ||||
if (pfork && (!pindexBestForkTip || | if (pfork && | ||||
(!pindexBestForkTip || | |||||
(pindexBestForkTip && | (pindexBestForkTip && | ||||
pindexNewForkTip->nHeight > pindexBestForkTip->nHeight)) && | pindexNewForkTip->nHeight > pindexBestForkTip->nHeight)) && | ||||
pindexNewForkTip->nChainWork - pfork->nChainWork > | pindexNewForkTip->nChainWork - pfork->nChainWork > | ||||
(GetBlockProof(*pfork) * 7) && | (GetBlockProof(*pfork) * 7) && | ||||
chainActive.Height() - pindexNewForkTip->nHeight < 72) { | chainActive.Height() - pindexNewForkTip->nHeight < 72) { | ||||
pindexBestForkTip = pindexNewForkTip; | pindexBestForkTip = pindexNewForkTip; | ||||
pindexBestForkBase = pfork; | pindexBestForkBase = pfork; | ||||
} | } | ||||
CheckForkWarningConditions(); | CheckForkWarningConditions(); | ||||
▲ Show 20 Lines • Show All 98 Lines • ▼ Show 20 Lines | for (size_t i = 0; i < tx.vin.size(); i++) { | ||||
nValueIn += coin.GetTxOut().nValue; | nValueIn += coin.GetTxOut().nValue; | ||||
if (!MoneyRange(coin.GetTxOut().nValue) || !MoneyRange(nValueIn)) { | if (!MoneyRange(coin.GetTxOut().nValue) || !MoneyRange(nValueIn)) { | ||||
return state.DoS(100, false, REJECT_INVALID, | return state.DoS(100, false, REJECT_INVALID, | ||||
"bad-txns-inputvalues-outofrange"); | "bad-txns-inputvalues-outofrange"); | ||||
} | } | ||||
} | } | ||||
if (nValueIn < tx.GetValueOut()) { | if (nValueIn < tx.GetValueOut()) { | ||||
return state.DoS(100, false, REJECT_INVALID, "bad-txns-in-belowout", | return state.DoS( | ||||
false, strprintf("value in (%s) < value out (%s)", | 100, false, REJECT_INVALID, "bad-txns-in-belowout", false, | ||||
FormatMoney(nValueIn), | strprintf("value in (%s) < value out (%s)", FormatMoney(nValueIn), | ||||
FormatMoney(tx.GetValueOut()))); | FormatMoney(tx.GetValueOut()))); | ||||
} | } | ||||
// Tally transaction fees | // Tally transaction fees | ||||
CAmount nTxFee = nValueIn - tx.GetValueOut(); | CAmount nTxFee = nValueIn - tx.GetValueOut(); | ||||
if (nTxFee < 0) { | if (nTxFee < 0) { | ||||
return state.DoS(100, false, REJECT_INVALID, "bad-txns-fee-negative"); | return state.DoS(100, false, REJECT_INVALID, "bad-txns-fee-negative"); | ||||
} | } | ||||
nFees += nTxFee; | nFees += nTxFee; | ||||
▲ Show 20 Lines • Show All 157 Lines • ▼ Show 20 Lines | |||||
} | } | ||||
bool AbortNode(CValidationState &state, const std::string &strMessage, | bool AbortNode(CValidationState &state, const std::string &strMessage, | ||||
const std::string &userMessage = "") { | const std::string &userMessage = "") { | ||||
AbortNode(strMessage, userMessage); | AbortNode(strMessage, userMessage); | ||||
return state.Error(strMessage); | return state.Error(strMessage); | ||||
} | } | ||||
} // anon namespace | } // namespace | ||||
/** Restore the UTXO in a Coin at a given COutPoint. */ | /** Restore the UTXO in a Coin at a given COutPoint. */ | ||||
DisconnectResult UndoCoinSpend(const Coin &undo, CCoinsViewCache &view, | DisconnectResult UndoCoinSpend(const Coin &undo, CCoinsViewCache &view, | ||||
const COutPoint &out) { | const COutPoint &out) { | ||||
bool fClean = true; | bool fClean = true; | ||||
if (view.HaveCoin(out)) { | if (view.HaveCoin(out)) { | ||||
// Overwriting transaction output. | // Overwriting transaction output. | ||||
▲ Show 20 Lines • Show All 411 Lines • ▼ Show 20 Lines | for (size_t i = 0; i < block.vtx.size(); i++) { | ||||
// require the UTXO set. | // require the UTXO set. | ||||
prevheights.resize(tx.vin.size()); | prevheights.resize(tx.vin.size()); | ||||
for (size_t j = 0; j < tx.vin.size(); j++) { | for (size_t j = 0; j < tx.vin.size(); j++) { | ||||
prevheights[j] = view.AccessCoin(tx.vin[j].prevout).GetHeight(); | prevheights[j] = view.AccessCoin(tx.vin[j].prevout).GetHeight(); | ||||
} | } | ||||
if (!SequenceLocks(tx, nLockTimeFlags, &prevheights, *pindex)) { | if (!SequenceLocks(tx, nLockTimeFlags, &prevheights, *pindex)) { | ||||
return state.DoS( | return state.DoS( | ||||
100, error("%s: contains a non-BIP68-final transaction", | 100, | ||||
error("%s: contains a non-BIP68-final transaction", | |||||
__func__), | __func__), | ||||
REJECT_INVALID, "bad-txns-nonfinal"); | REJECT_INVALID, "bad-txns-nonfinal"); | ||||
} | } | ||||
} | } | ||||
// GetTransactionSigOpCount counts 2 types of sigops: | // GetTransactionSigOpCount counts 2 types of sigops: | ||||
// * legacy (always) | // * legacy (always) | ||||
// * p2sh (when P2SH enabled in flags and excludes coinbase) | // * p2sh (when P2SH enabled in flags and excludes coinbase) | ||||
auto txSigOpsCount = GetTransactionSigOpCount(tx, view, flags); | auto txSigOpsCount = GetTransactionSigOpCount(tx, view, flags); | ||||
Show All 33 Lines | for (size_t i = 0; i < block.vtx.size(); i++) { | ||||
pindex->nHeight); | pindex->nHeight); | ||||
vPos.push_back(std::make_pair(tx.GetId(), pos)); | vPos.push_back(std::make_pair(tx.GetId(), pos)); | ||||
pos.nTxOffset += ::GetSerializeSize(tx, SER_DISK, CLIENT_VERSION); | pos.nTxOffset += ::GetSerializeSize(tx, SER_DISK, CLIENT_VERSION); | ||||
} | } | ||||
int64_t nTime3 = GetTimeMicros(); | int64_t nTime3 = GetTimeMicros(); | ||||
nTimeConnect += nTime3 - nTime2; | nTimeConnect += nTime3 - nTime2; | ||||
LogPrint("bench", " - Connect %u transactions: %.2fms (%.3fms/tx, " | LogPrint("bench", | ||||
" - 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); | ||||
CAmount blockReward = | CAmount blockReward = | ||||
nFees + GetBlockSubsidy(pindex->nHeight, chainparams.GetConsensus()); | nFees + GetBlockSubsidy(pindex->nHeight, chainparams.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()) { | ||||
return state.DoS(100, false, REJECT_INVALID, "blk-bad-inputs", false, | return state.DoS(100, false, REJECT_INVALID, "blk-bad-inputs", false, | ||||
"parallel script check failed"); | "parallel script check failed"); | ||||
} | } | ||||
▲ Show 20 Lines • Show All 695 Lines • ▼ Show 20 Lines | do { | ||||
if (pindexMostWork == nullptr || | if (pindexMostWork == nullptr || | ||||
pindexMostWork == chainActive.Tip()) | pindexMostWork == chainActive.Tip()) | ||||
return true; | return true; | ||||
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, | config, state, pindexMostWork, | ||||
pblock && | pblock && pblock->GetHash() == | ||||
pblock->GetHash() == | |||||
pindexMostWork->GetBlockHash() | pindexMostWork->GetBlockHash() | ||||
? pblock | ? pblock | ||||
: nullBlockPtr, | : nullBlockPtr, | ||||
fInvalidFound, connectTrace)) | fInvalidFound, connectTrace)) | ||||
return false; | return false; | ||||
if (fInvalidFound) { | if (fInvalidFound) { | ||||
// Wipe cache, we may need another branch now. | // Wipe cache, we may need another branch now. | ||||
pindexMostWork = nullptr; | pindexMostWork = nullptr; | ||||
▲ Show 20 Lines • Show All 684 Lines • ▼ Show 20 Lines | if (hash != chainparams.GetConsensus().hashGenesisBlock) { | ||||
} | } | ||||
pindexPrev = (*mi).second; | pindexPrev = (*mi).second; | ||||
if (pindexPrev->nStatus & BLOCK_FAILED_MASK) { | if (pindexPrev->nStatus & BLOCK_FAILED_MASK) { | ||||
return state.DoS(100, error("%s: prev block invalid", __func__), | return state.DoS(100, error("%s: prev block invalid", __func__), | ||||
REJECT_INVALID, "bad-prevblk"); | REJECT_INVALID, "bad-prevblk"); | ||||
} | } | ||||
assert(pindexPrev); | assert(pindexPrev); | ||||
if (fCheckpointsEnabled && | if (fCheckpointsEnabled && !CheckIndexAgainstCheckpoint( | ||||
!CheckIndexAgainstCheckpoint(pindexPrev, state, chainparams, | pindexPrev, state, chainparams, hash)) { | ||||
hash)) { | |||||
return error("%s: CheckIndexAgainstCheckpoint(): %s", __func__, | return error("%s: CheckIndexAgainstCheckpoint(): %s", __func__, | ||||
state.GetRejectReason().c_str()); | state.GetRejectReason().c_str()); | ||||
} | } | ||||
if (!ContextualCheckBlockHeader(block, state, | if (!ContextualCheckBlockHeader(block, state, | ||||
chainparams.GetConsensus(), pindexPrev, | chainparams.GetConsensus(), pindexPrev, | ||||
GetAdjustedTime())) { | GetAdjustedTime())) { | ||||
return error("%s: Consensus::ContextualCheckBlockHeader: %s, %s", | return error("%s: Consensus::ContextualCheckBlockHeader: %s, %s", | ||||
▲ Show 20 Lines • Show All 384 Lines • ▼ Show 20 Lines | if (nCurrentUsage + nBuffer >= nPruneTarget) { | ||||
PruneOneBlockFile(fileNumber); | PruneOneBlockFile(fileNumber); | ||||
// Queue up the files for removal | // Queue up the files for removal | ||||
setFilesToPrune.insert(fileNumber); | setFilesToPrune.insert(fileNumber); | ||||
nCurrentUsage -= nBytesToPrune; | nCurrentUsage -= nBytesToPrune; | ||||
count++; | count++; | ||||
} | } | ||||
} | } | ||||
LogPrint("prune", "Prune: target=%dMiB actual=%dMiB diff=%dMiB " | LogPrint("prune", | ||||
"Prune: target=%dMiB actual=%dMiB diff=%dMiB " | |||||
"max_prune_height=%d removed %d blk/rev pairs\n", | "max_prune_height=%d removed %d blk/rev pairs\n", | ||||
nPruneTarget / 1024 / 1024, nCurrentUsage / 1024 / 1024, | nPruneTarget / 1024 / 1024, nCurrentUsage / 1024 / 1024, | ||||
((int64_t)nPruneTarget - (int64_t)nCurrentUsage) / 1024 / 1024, | ((int64_t)nPruneTarget - (int64_t)nCurrentUsage) / 1024 / 1024, | ||||
nLastBlockWeCanPrune, count); | nLastBlockWeCanPrune, count); | ||||
} | } | ||||
bool CheckDiskSpace(uint64_t nAdditionalBytes) { | bool CheckDiskSpace(uint64_t nAdditionalBytes) { | ||||
uint64_t nFreeBytesAvailable = | uint64_t nFreeBytesAvailable = | ||||
boost::filesystem::space(GetDataDir()).available; | boost::filesystem::space(GetDataDir()).available; | ||||
▲ Show 20 Lines • Show All 1,126 Lines • Show Last 20 Lines |