Changeset View
Changeset View
Standalone View
Standalone View
src/validation.cpp
Show First 20 Lines • Show All 443 Lines • ▼ Show 20 Lines | |||||
uint64_t GetP2SHSigOpCount(const CTransaction &tx, | uint64_t GetP2SHSigOpCount(const CTransaction &tx, | ||||
const CCoinsViewCache &inputs) { | const CCoinsViewCache &inputs) { | ||||
if (tx.IsCoinBase()) { | if (tx.IsCoinBase()) { | ||||
return 0; | return 0; | ||||
} | } | ||||
uint64_t nSigOps = 0; | uint64_t nSigOps = 0; | ||||
for (unsigned int i = 0; i < tx.vin.size(); i++) { | for (auto &i : tx.vin) { | ||||
const CTxOut &prevout = inputs.GetOutputFor(tx.vin[i]); | const CTxOut &prevout = inputs.GetOutputFor(i); | ||||
if (prevout.scriptPubKey.IsPayToScriptHash()) | if (prevout.scriptPubKey.IsPayToScriptHash()) { | ||||
nSigOps += prevout.scriptPubKey.GetSigOpCount(tx.vin[i].scriptSig); | nSigOps += prevout.scriptPubKey.GetSigOpCount(i.scriptSig); | ||||
} | |||||
} | } | ||||
return nSigOps; | return nSigOps; | ||||
} | } | ||||
uint64_t GetTransactionSigOpCount(const CTransaction &tx, | uint64_t GetTransactionSigOpCount(const CTransaction &tx, | ||||
const CCoinsViewCache &inputs, int flags) { | const CCoinsViewCache &inputs, int flags) { | ||||
uint64_t nSigOps = GetSigOpCountWithoutP2SH(tx); | uint64_t nSigOps = GetSigOpCountWithoutP2SH(tx); | ||||
if (tx.IsCoinBase()) { | if (tx.IsCoinBase()) { | ||||
▲ Show 20 Lines • Show All 379 Lines • ▼ Show 20 Lines | // Check for conflicts with in-memory transactions | ||||
CAmount mempoolRejectFee = | CAmount mempoolRejectFee = | ||||
pool.GetMinFee(GetArg("-maxmempool", DEFAULT_MAX_MEMPOOL_SIZE) * | pool.GetMinFee(GetArg("-maxmempool", DEFAULT_MAX_MEMPOOL_SIZE) * | ||||
1000000) | 1000000) | ||||
.GetFee(nSize); | .GetFee(nSize); | ||||
if (mempoolRejectFee > 0 && nModifiedFees < mempoolRejectFee) { | if (mempoolRejectFee > 0 && nModifiedFees < mempoolRejectFee) { | ||||
return state.DoS(0, false, REJECT_INSUFFICIENTFEE, | return state.DoS(0, false, REJECT_INSUFFICIENTFEE, | ||||
"mempool min fee not met", false, | "mempool min fee not met", false, | ||||
strprintf("%d < %d", nFees, mempoolRejectFee)); | strprintf("%d < %d", nFees, mempoolRejectFee)); | ||||
} else if (GetBoolArg("-relaypriority", DEFAULT_RELAYPRIORITY) && | } | ||||
if (GetBoolArg("-relaypriority", DEFAULT_RELAYPRIORITY) && | |||||
nModifiedFees < ::minRelayTxFee.GetFee(nSize) && | nModifiedFees < ::minRelayTxFee.GetFee(nSize) && | ||||
!AllowFree(entry.GetPriority(chainActive.Height() + 1))) { | !AllowFree(entry.GetPriority(chainActive.Height() + 1))) { | ||||
// Require that free transactions have sufficient priority to be | // Require that free transactions have sufficient priority to be | ||||
// mined in the next block. | // mined in the next block. | ||||
return state.DoS(0, false, REJECT_INSUFFICIENTFEE, | return state.DoS(0, false, REJECT_INSUFFICIENTFEE, | ||||
"insufficient priority"); | "insufficient priority"); | ||||
} | } | ||||
// Continuously rate-limit free (really, very-low-fee) transactions. | // Continuously rate-limit free (really, very-low-fee) transactions. | ||||
// This mitigates 'penny-flooding' -- sending thousands of free | // This mitigates 'penny-flooding' -- sending thousands of free | ||||
// transactions just to be annoying or make others' transactions take | // transactions just to be annoying or make others' transactions take | ||||
// longer to confirm. | // longer to confirm. | ||||
if (fLimitFree && nModifiedFees < ::minRelayTxFee.GetFee(nSize)) { | if (fLimitFree && nModifiedFees < ::minRelayTxFee.GetFee(nSize)) { | ||||
static CCriticalSection csFreeLimiter; | static CCriticalSection csFreeLimiter; | ||||
static double dFreeCount; | static double dFreeCount; | ||||
static int64_t nLastTime; | static int64_t nLastTime; | ||||
int64_t nNow = GetTime(); | int64_t nNow = GetTime(); | ||||
LOCK(csFreeLimiter); | LOCK(csFreeLimiter); | ||||
// Use an exponentially decaying ~10-minute window: | // Use an exponentially decaying ~10-minute window: | ||||
dFreeCount *= pow(1.0 - 1.0 / 600.0, (double)(nNow - nLastTime)); | dFreeCount *= pow(1.0 - 1.0 / 600.0, double(nNow - nLastTime)); | ||||
nLastTime = nNow; | nLastTime = nNow; | ||||
// -limitfreerelay unit is thousand-bytes-per-minute | // -limitfreerelay unit is thousand-bytes-per-minute | ||||
// At default rate it would take over a month to fill 1GB | // At default rate it would take over a month to fill 1GB | ||||
if (dFreeCount + nSize >= | if (dFreeCount + nSize >= | ||||
GetArg("-limitfreerelay", DEFAULT_LIMITFREERELAY) * 10 * 1000) { | GetArg("-limitfreerelay", DEFAULT_LIMITFREERELAY) * 10 * 1000) { | ||||
return state.DoS(0, false, REJECT_INSUFFICIENTFEE, | return state.DoS(0, false, REJECT_INSUFFICIENTFEE, | ||||
"rate limited free transaction"); | "rate limited free transaction"); | ||||
} | } | ||||
▲ Show 20 Lines • Show All 384 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 && | if (pfork && (!pindexBestForkTip || | ||||
(!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( | return state.DoS(100, false, REJECT_INVALID, "bad-txns-in-belowout", | ||||
100, false, REJECT_INVALID, "bad-txns-in-belowout", false, | false, strprintf("value in (%s) < value out (%s)", | ||||
strprintf("value in (%s) < value out (%s)", FormatMoney(nValueIn), | 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 616 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, | 100, error("%s: contains a non-BIP68-final transaction", | ||||
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", | LogPrint("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); | ||||
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, | return state.DoS(100, error("ConnectBlock(): coinbase pays too much " | ||||
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 697 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->GetHash() == | pblock && | ||||
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 && !CheckIndexAgainstCheckpoint( | if (fCheckpointsEnabled && | ||||
pindexPrev, state, chainparams, hash)) { | !CheckIndexAgainstCheckpoint(pindexPrev, state, chainparams, | ||||
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", | LogPrint("prune", "Prune: target=%dMiB actual=%dMiB diff=%dMiB " | ||||
"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 |