Changeset View
Changeset View
Standalone View
Standalone View
src/validation.cpp
Show First 20 Lines • Show All 357 Lines • ▼ Show 20 Lines | AcceptToMemoryPoolWorker(const Config &config, CTxMemPool &pool, | ||||
if (!CheckRegularTransaction(tx, state)) { | if (!CheckRegularTransaction(tx, state)) { | ||||
// state filled in by CheckRegularTransaction. | // state filled in by CheckRegularTransaction. | ||||
return false; | return false; | ||||
} | } | ||||
// Rather not work on nonstandard transactions (unless -testnet) | // Rather not work on nonstandard transactions (unless -testnet) | ||||
std::string reason; | std::string reason; | ||||
if (fRequireStandard && !IsStandardTx(tx, reason)) { | if (fRequireStandard && !IsStandardTx(tx, reason)) { | ||||
return state.DoS(0, ValidationInvalidReason::TX_NOT_STANDARD, false, | return state.DoS(0, ValidationInvalidReason::TX_NOT_STANDARD, false, REJECT_NONSTANDARD, reason); | ||||
REJECT_NONSTANDARD, 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. | ||||
CValidationState ctxState; | CValidationState ctxState; | ||||
if (!ContextualCheckTransactionForCurrentBlock( | if (!ContextualCheckTransactionForCurrentBlock( | ||||
consensusParams, tx, ctxState, STANDARD_LOCKTIME_VERIFY_FLAGS)) { | consensusParams, tx, ctxState, 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.DoS(0, ValidationInvalidReason::TX_NOT_STANDARD, false, | return state.DoS(0, ValidationInvalidReason::TX_NOT_STANDARD, false, REJECT_NONSTANDARD, ctxState.GetRejectReason(), ctxState.CorruptionPossible(), ctxState.GetDebugMessage()); | ||||
REJECT_NONSTANDARD, ctxState.GetRejectReason(), | |||||
ctxState.CorruptionPossible(), | |||||
ctxState.GetDebugMessage()); | |||||
} | } | ||||
// Is it already in the memory pool? | // Is it already in the memory pool? | ||||
if (pool.exists(txid)) { | if (pool.exists(txid)) { | ||||
return state.Invalid(ValidationInvalidReason::TX_CONFLICT, false, | return state.Invalid(ValidationInvalidReason::TX_CONFLICT, false, | ||||
REJECT_DUPLICATE, "txn-already-in-mempool"); | REJECT_DUPLICATE, "txn-already-in-mempool"); | ||||
} | } | ||||
▲ Show 20 Lines • Show All 62 Lines • ▼ Show 20 Lines | for (const CTxIn &txin : tx.vin) { | ||||
// 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. | ||||
if (!CheckSequenceLocks(pool, tx, STANDARD_LOCKTIME_VERIFY_FLAGS, | if (!CheckSequenceLocks(pool, tx, STANDARD_LOCKTIME_VERIFY_FLAGS, | ||||
&lp)) { | &lp)) { | ||||
return state.DoS(0, ValidationInvalidReason::TX_NOT_STANDARD, false, | return state.DoS(0, ValidationInvalidReason::TX_NOT_STANDARD, false, REJECT_NONSTANDARD, "non-BIP68-final"); | ||||
REJECT_NONSTANDARD, "non-BIP68-final"); | |||||
} | } | ||||
Amount nFees = Amount::zero(); | Amount nFees = Amount::zero(); | ||||
if (!Consensus::CheckTxInputs(tx, state, view, GetSpendHeight(view), | if (!Consensus::CheckTxInputs(tx, state, view, GetSpendHeight(view), | ||||
nFees)) { | nFees)) { | ||||
return error("%s: Consensus::CheckTxInputs: %s, %s", __func__, | return error("%s: Consensus::CheckTxInputs: %s, %s", __func__, | ||||
tx.GetId().ToString(), FormatStateMessage(state)); | tx.GetId().ToString(), FormatStateMessage(state)); | ||||
} | } | ||||
Show All 26 Lines | for (const CTxIn &txin : tx.vin) { | ||||
unsigned int nSize = tx.GetTotalSize(); | unsigned int nSize = tx.GetTotalSize(); | ||||
// No transactions are allowed below minRelayTxFee except from | // No transactions are allowed below minRelayTxFee except from | ||||
// disconnected blocks. | // disconnected blocks. | ||||
// Do not change this to use virtualsize without coordinating a network | // Do not change this to use virtualsize without coordinating a network | ||||
// policy upgrade. | // policy upgrade. | ||||
if (!bypass_limits && nModifiedFees < minRelayTxFee.GetFee(nSize)) { | if (!bypass_limits && nModifiedFees < minRelayTxFee.GetFee(nSize)) { | ||||
return state.DoS(0, ValidationInvalidReason::TX_MEMPOOL_POLICY, | return state.DoS(0, ValidationInvalidReason::TX_MEMPOOL_POLICY, false, REJECT_INSUFFICIENTFEE, "min relay fee not met"); | ||||
false, REJECT_INSUFFICIENTFEE, | |||||
"min relay fee not met"); | |||||
} | } | ||||
if (nAbsurdFee != Amount::zero() && nFees > nAbsurdFee) { | if (nAbsurdFee != Amount::zero() && nFees > nAbsurdFee) { | ||||
return state.Invalid(ValidationInvalidReason::TX_NOT_STANDARD, | return state.Invalid(ValidationInvalidReason::TX_NOT_STANDARD, | ||||
false, REJECT_HIGHFEE, "absurdly-high-fee", | false, REJECT_HIGHFEE, "absurdly-high-fee", | ||||
strprintf("%d > %d", nFees, nAbsurdFee)); | strprintf("%d > %d", nFees, nAbsurdFee)); | ||||
} | } | ||||
Show All 15 Lines | for (const CTxIn &txin : tx.vin) { | ||||
Amount mempoolRejectFee = | Amount mempoolRejectFee = | ||||
pool.GetMinFee( | pool.GetMinFee( | ||||
gArgs.GetArg("-maxmempool", DEFAULT_MAX_MEMPOOL_SIZE) * | gArgs.GetArg("-maxmempool", DEFAULT_MAX_MEMPOOL_SIZE) * | ||||
1000000) | 1000000) | ||||
.GetFee(nVirtualSize); | .GetFee(nVirtualSize); | ||||
if (!bypass_limits && mempoolRejectFee > Amount::zero() && | if (!bypass_limits && mempoolRejectFee > Amount::zero() && | ||||
nModifiedFees < mempoolRejectFee) { | nModifiedFees < mempoolRejectFee) { | ||||
return state.DoS( | return state.DoS(0, ValidationInvalidReason::TX_MEMPOOL_POLICY, false, REJECT_INSUFFICIENTFEE, "mempool min fee not met", false, strprintf("%d < %d", nModifiedFees, mempoolRejectFee)); | ||||
0, ValidationInvalidReason::TX_MEMPOOL_POLICY, false, | |||||
REJECT_INSUFFICIENTFEE, "mempool min fee not met", false, | |||||
strprintf("%d < %d", nModifiedFees, mempoolRejectFee)); | |||||
} | } | ||||
// Calculate in-mempool ancestors, up to a limit. | // Calculate in-mempool ancestors, up to a limit. | ||||
CTxMemPool::setEntries setAncestors; | CTxMemPool::setEntries setAncestors; | ||||
size_t nLimitAncestors = | size_t nLimitAncestors = | ||||
gArgs.GetArg("-limitancestorcount", DEFAULT_ANCESTOR_LIMIT); | gArgs.GetArg("-limitancestorcount", DEFAULT_ANCESTOR_LIMIT); | ||||
size_t nLimitAncestorSize = | size_t nLimitAncestorSize = | ||||
gArgs.GetArg("-limitancestorsize", DEFAULT_ANCESTOR_SIZE_LIMIT) * | gArgs.GetArg("-limitancestorsize", DEFAULT_ANCESTOR_SIZE_LIMIT) * | ||||
1000; | 1000; | ||||
size_t nLimitDescendants = | size_t nLimitDescendants = | ||||
gArgs.GetArg("-limitdescendantcount", DEFAULT_DESCENDANT_LIMIT); | gArgs.GetArg("-limitdescendantcount", DEFAULT_DESCENDANT_LIMIT); | ||||
size_t nLimitDescendantSize = | size_t nLimitDescendantSize = | ||||
gArgs.GetArg("-limitdescendantsize", | gArgs.GetArg("-limitdescendantsize", | ||||
DEFAULT_DESCENDANT_SIZE_LIMIT) * | DEFAULT_DESCENDANT_SIZE_LIMIT) * | ||||
1000; | 1000; | ||||
std::string errString; | std::string errString; | ||||
if (!pool.CalculateMemPoolAncestors( | if (!pool.CalculateMemPoolAncestors( | ||||
entry, setAncestors, nLimitAncestors, nLimitAncestorSize, | entry, setAncestors, nLimitAncestors, nLimitAncestorSize, | ||||
nLimitDescendants, nLimitDescendantSize, errString)) { | nLimitDescendants, nLimitDescendantSize, errString)) { | ||||
return state.DoS(0, ValidationInvalidReason::TX_MEMPOOL_POLICY, | return state.DoS(0, ValidationInvalidReason::TX_MEMPOOL_POLICY, false, REJECT_NONSTANDARD, "too-long-mempool-chain", false, errString); | ||||
false, REJECT_NONSTANDARD, | |||||
"too-long-mempool-chain", false, errString); | |||||
} | } | ||||
// Check again against the next block's script verification flags | // Check again against the next block's script verification flags | ||||
// to cache our script execution flags. | // to cache our script execution flags. | ||||
// | // | ||||
// 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 | ||||
Show All 34 Lines | for (const CTxIn &txin : tx.vin) { | ||||
// Trim mempool and check if tx was trimmed. | // Trim mempool and check if tx was trimmed. | ||||
if (!bypass_limits) { | if (!bypass_limits) { | ||||
pool.LimitSize( | pool.LimitSize( | ||||
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 (!pool.exists(txid)) { | if (!pool.exists(txid)) { | ||||
return state.DoS(0, ValidationInvalidReason::TX_MEMPOOL_POLICY, | return state.DoS(0, ValidationInvalidReason::TX_MEMPOOL_POLICY, false, REJECT_INSUFFICIENTFEE, "mempool full"); | ||||
false, REJECT_INSUFFICIENTFEE, "mempool full"); | |||||
} | } | ||||
} | } | ||||
} | } | ||||
GetMainSignals().TransactionAddedToMempool(ptx); | GetMainSignals().TransactionAddedToMempool(ptx); | ||||
return true; | return true; | ||||
} | } | ||||
▲ Show 20 Lines • Show All 421 Lines • ▼ Show 20 Lines | bool CheckInputs(const CTransaction &tx, CValidationState &state, | ||||
// Note that this assumes that the inputs provided are correct (ie that the | // Note that this assumes that the inputs provided are correct (ie that the | ||||
// transaction hash which is in tx's prevouts properly commits to the | // transaction hash which is in tx's prevouts properly commits to the | ||||
// scriptPubKey in the inputs view of that transaction). | // scriptPubKey in the inputs view of that transaction). | ||||
ScriptCacheKey hashCacheEntry(tx, flags); | ScriptCacheKey hashCacheEntry(tx, flags); | ||||
if (IsKeyInScriptCache(hashCacheEntry, !scriptCacheStore, nSigChecksOut)) { | if (IsKeyInScriptCache(hashCacheEntry, !scriptCacheStore, nSigChecksOut)) { | ||||
if (!txLimitSigChecks.consume_and_check(nSigChecksOut) || | if (!txLimitSigChecks.consume_and_check(nSigChecksOut) || | ||||
(pBlockLimitSigChecks && | (pBlockLimitSigChecks && | ||||
!pBlockLimitSigChecks->consume_and_check(nSigChecksOut))) { | !pBlockLimitSigChecks->consume_and_check(nSigChecksOut))) { | ||||
return state.DoS(100, ValidationInvalidReason::CONSENSUS, false, | return state.DoS(100, ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "too-many-sigchecks"); | ||||
REJECT_INVALID, "too-many-sigchecks"); | |||||
} | } | ||||
return true; | return true; | ||||
} | } | ||||
int nSigChecksTotal = 0; | int nSigChecksTotal = 0; | ||||
for (size_t i = 0; i < tx.vin.size(); i++) { | for (size_t i = 0; i < tx.vin.size(); i++) { | ||||
const COutPoint &prevout = tx.vin[i].prevout; | const COutPoint &prevout = tx.vin[i].prevout; | ||||
Show All 40 Lines | for (size_t i = 0; i < tx.vin.size(); i++) { | ||||
} | } | ||||
// Failures of other flags indicate a transaction that is invalid in | // Failures of other flags indicate a transaction that is invalid in | ||||
// new blocks, e.g. a invalid P2SH. We DoS ban such nodes as they | // new blocks, e.g. a invalid P2SH. We DoS ban such nodes as they | ||||
// are not following the protocol. That said during an upgrade | // are not following the protocol. That said during an upgrade | ||||
// careful thought should be taken as to the correct behavior - we | // careful thought should be taken as to the correct behavior - we | ||||
// may want to continue peering with non-upgraded nodes even after | // may want to continue peering with non-upgraded nodes even after | ||||
// soft-fork super-majority signaling has occurred. | // soft-fork super-majority signaling has occurred. | ||||
return state.DoS( | return state.DoS(100, ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, strprintf("mandatory-script-verify-flag-failed (%s)", ScriptErrorString(scriptError))); | ||||
100, ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, | |||||
strprintf("mandatory-script-verify-flag-failed (%s)", | |||||
ScriptErrorString(scriptError))); | |||||
} | } | ||||
nSigChecksTotal += check.GetScriptExecutionMetrics().nSigChecks; | nSigChecksTotal += check.GetScriptExecutionMetrics().nSigChecks; | ||||
} | } | ||||
nSigChecksOut = nSigChecksTotal; | nSigChecksOut = nSigChecksTotal; | ||||
if (scriptCacheStore && !pvChecks) { | if (scriptCacheStore && !pvChecks) { | ||||
▲ Show 20 Lines • Show All 495 Lines • ▼ Show 20 Lines | fEnforceBIP30 = | ||||
fEnforceBIP30 && | fEnforceBIP30 && | ||||
(!pindexBIP34height || | (!pindexBIP34height || | ||||
!(pindexBIP34height->GetBlockHash() == consensusParams.BIP34Hash)); | !(pindexBIP34height->GetBlockHash() == consensusParams.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->GetId(), o))) { | if (view.HaveCoin(COutPoint(tx->GetId(), o))) { | ||||
return state.DoS( | return state.DoS(100, ValidationInvalidReason::CONSENSUS, error("ConnectBlock(): tried to overwrite transaction"), REJECT_INVALID, "bad-txns-BIP30"); | ||||
100, ValidationInvalidReason::CONSENSUS, | |||||
error("ConnectBlock(): tried to overwrite transaction"), | |||||
REJECT_INVALID, "bad-txns-BIP30"); | |||||
} | } | ||||
} | } | ||||
} | } | ||||
} | } | ||||
// Start enforcing BIP68 (sequence locks). | // Start enforcing BIP68 (sequence locks). | ||||
int nLockTimeFlags = 0; | int nLockTimeFlags = 0; | ||||
if (pindex->nHeight >= consensusParams.CSVHeight) { | if (pindex->nHeight >= consensusParams.CSVHeight) { | ||||
Show All 39 Lines | try { | ||||
// This error will be thrown from AddCoin if we try to connect a block | // This error will be thrown from AddCoin if we try to connect a block | ||||
// containing duplicate transactions. Such a thing should normally be | // containing duplicate transactions. Such a thing should normally be | ||||
// caught early nowadays (due to ContextualCheckBlock's CTOR | // caught early nowadays (due to ContextualCheckBlock's CTOR | ||||
// enforcement) however some edge cases can escape that: | // enforcement) however some edge cases can escape that: | ||||
// - ContextualCheckBlock does not get re-run after saving the block to | // - ContextualCheckBlock does not get re-run after saving the block to | ||||
// disk, and older versions may have saved a weird block. | // disk, and older versions may have saved a weird block. | ||||
// - its checks are not applied to pre-CTOR chains, which we might visit | // - its checks are not applied to pre-CTOR chains, which we might visit | ||||
// with checkpointing off. | // with checkpointing off. | ||||
return state.DoS( | return state.DoS(100, ValidationInvalidReason::CONSENSUS, error("ConnectBlock(): tried to overwrite transaction"), REJECT_INVALID, "tx-duplicate"); | ||||
100, ValidationInvalidReason::CONSENSUS, | |||||
error("ConnectBlock(): tried to overwrite transaction"), | |||||
REJECT_INVALID, "tx-duplicate"); | |||||
} | } | ||||
size_t txIndex = 0; | size_t txIndex = 0; | ||||
for (const auto &ptx : block.vtx) { | for (const auto &ptx : block.vtx) { | ||||
const CTransaction &tx = *ptx; | const CTransaction &tx = *ptx; | ||||
const bool isCoinBase = tx.IsCoinBase(); | const bool isCoinBase = tx.IsCoinBase(); | ||||
nInputs += tx.vin.size(); | nInputs += tx.vin.size(); | ||||
Amount txfee = Amount::zero(); | Amount txfee = Amount::zero(); | ||||
if (!isCoinBase && !Consensus::CheckTxInputs(tx, state, view, | if (!isCoinBase && !Consensus::CheckTxInputs(tx, state, view, | ||||
pindex->nHeight, txfee)) { | pindex->nHeight, txfee)) { | ||||
if (state.GetReason() == | if (state.GetReason() == | ||||
ValidationInvalidReason::TX_MISSING_INPUTS) { | ValidationInvalidReason::TX_MISSING_INPUTS) { | ||||
// CheckTxInputs may return MISSING_INPUTS but we can't return | // CheckTxInputs may return MISSING_INPUTS but we can't return | ||||
// that, as it's not defined for a block, so we reset the reason | // that, as it's not defined for a block, so we reset the reason | ||||
// flag to CONSENSUS here. | // flag to CONSENSUS here. | ||||
state.DoS(100, ValidationInvalidReason::CONSENSUS, false, | state.DoS(100, ValidationInvalidReason::CONSENSUS, false, state.GetRejectCode(), state.GetRejectReason(), state.CorruptionPossible(), state.GetDebugMessage()); | ||||
state.GetRejectCode(), state.GetRejectReason(), | |||||
state.CorruptionPossible(), state.GetDebugMessage()); | |||||
} | } | ||||
return error("%s: Consensus::CheckTxInputs: %s, %s", __func__, | return error("%s: Consensus::CheckTxInputs: %s, %s", __func__, | ||||
tx.GetId().ToString(), FormatStateMessage(state)); | tx.GetId().ToString(), FormatStateMessage(state)); | ||||
} | } | ||||
nFees += txfee; | nFees += txfee; | ||||
if (!MoneyRange(nFees)) { | if (!MoneyRange(nFees)) { | ||||
return state.DoS( | return state.DoS(100, ValidationInvalidReason::CONSENSUS, error("%s: accumulated fee in the block out of range.", __func__), REJECT_INVALID, "bad-txns-accumulated-fee-outofrange"); | ||||
100, ValidationInvalidReason::CONSENSUS, | |||||
error("%s: accumulated fee in the block out of range.", | |||||
__func__), | |||||
REJECT_INVALID, "bad-txns-accumulated-fee-outofrange"); | |||||
} | } | ||||
// The following checks do not apply to the coinbase. | // The following checks do not apply to the coinbase. | ||||
if (isCoinBase) { | if (isCoinBase) { | ||||
continue; | continue; | ||||
} | } | ||||
// Check that transaction is BIP68 final BIP68 lock checks (as | // Check that transaction is BIP68 final BIP68 lock checks (as | ||||
// opposed to nLockTime checks) must be in ConnectBlock because they | // opposed to nLockTime checks) must be in ConnectBlock because they | ||||
// 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, ValidationInvalidReason::CONSENSUS, error("%s: contains a non-BIP68-final transaction", __func__), REJECT_INVALID, "bad-txns-nonfinal"); | ||||
100, ValidationInvalidReason::CONSENSUS, | |||||
error("%s: contains a non-BIP68-final transaction", __func__), | |||||
REJECT_INVALID, "bad-txns-nonfinal"); | |||||
} | } | ||||
// Don't cache results if we're actually connecting blocks (still | // Don't cache results if we're actually connecting blocks (still | ||||
// consult the cache, though). | // consult the cache, though). | ||||
bool fCacheResults = fJustCheck; | bool fCacheResults = fJustCheck; | ||||
const bool fEnforceSigCheck = flags & SCRIPT_ENFORCE_SIGCHECKS; | const bool fEnforceSigCheck = flags & SCRIPT_ENFORCE_SIGCHECKS; | ||||
if (!fEnforceSigCheck) { | if (!fEnforceSigCheck) { | ||||
Show All 13 Lines | for (const auto &ptx : block.vtx) { | ||||
&nSigChecksBlockLimiter, &vChecks)) { | &nSigChecksBlockLimiter, &vChecks)) { | ||||
if (state.GetReason() == ValidationInvalidReason::TX_NOT_STANDARD) { | if (state.GetReason() == ValidationInvalidReason::TX_NOT_STANDARD) { | ||||
// CheckInputs may return NOT_STANDARD for extra flags we | // CheckInputs may return NOT_STANDARD for extra flags we | ||||
// passed, but we can't return that, as it's not defined for a | // passed, but we can't return that, as it's not defined for a | ||||
// block, so we reset the reason flag to CONSENSUS here. In the | // block, so we reset the reason flag to CONSENSUS here. In the | ||||
// event of a future soft-fork, we may need to consider whether | // event of a future soft-fork, we may need to consider whether | ||||
// rewriting to CONSENSUS or RECENT_CONSENSUS_CHANGE would be | // rewriting to CONSENSUS or RECENT_CONSENSUS_CHANGE would be | ||||
// more appropriate. | // more appropriate. | ||||
state.DoS(100 - state.GetDoS(), | state.DoS(100 - state.GetDoS(), ValidationInvalidReason::CONSENSUS, false, state.GetRejectCode(), state.GetRejectReason(), state.CorruptionPossible(), state.GetDebugMessage()); | ||||
ValidationInvalidReason::CONSENSUS, false, | |||||
state.GetRejectCode(), state.GetRejectReason(), | |||||
state.CorruptionPossible(), state.GetDebugMessage()); | |||||
} | } | ||||
return error("ConnectBlock(): CheckInputs on %s failed with %s", | return error("ConnectBlock(): CheckInputs on %s failed with %s", | ||||
tx.GetId().ToString(), FormatStateMessage(state)); | tx.GetId().ToString(), FormatStateMessage(state)); | ||||
} | } | ||||
control.Add(vChecks); | control.Add(vChecks); | ||||
// Note: this must execute in the same iteration as CheckTxInputs (not | // Note: this must execute in the same iteration as CheckTxInputs (not | ||||
Show All 13 Lines | LogPrint(BCLog::BENCH, | ||||
(unsigned)block.vtx.size(), MILLI * (nTime3 - nTime2), | (unsigned)block.vtx.size(), MILLI * (nTime3 - nTime2), | ||||
MILLI * (nTime3 - nTime2) / block.vtx.size(), | MILLI * (nTime3 - nTime2) / block.vtx.size(), | ||||
nInputs <= 1 ? 0 : MILLI * (nTime3 - nTime2) / (nInputs - 1), | nInputs <= 1 ? 0 : MILLI * (nTime3 - nTime2) / (nInputs - 1), | ||||
nTimeConnect * MICRO, nTimeConnect * MILLI / nBlocksTotal); | nTimeConnect * MICRO, nTimeConnect * MILLI / nBlocksTotal); | ||||
Amount blockReward = | Amount blockReward = | ||||
nFees + GetBlockSubsidy(pindex->nHeight, consensusParams); | nFees + GetBlockSubsidy(pindex->nHeight, consensusParams); | ||||
if (block.vtx[0]->GetValueOut() > blockReward) { | if (block.vtx[0]->GetValueOut() > blockReward) { | ||||
return state.DoS(100, ValidationInvalidReason::CONSENSUS, | return state.DoS(100, ValidationInvalidReason::CONSENSUS, error("ConnectBlock(): coinbase pays too much ""(actual=%d vs limit=%d)", block.vtx[0]->GetValueOut(), blockReward), REJECT_INVALID, "bad-cb-amount"); | ||||
error("ConnectBlock(): coinbase pays too much " | |||||
"(actual=%d vs limit=%d)", | |||||
block.vtx[0]->GetValueOut(), blockReward), | |||||
REJECT_INVALID, "bad-cb-amount"); | |||||
} | } | ||||
const std::vector<CTxDestination> whitelist = | const std::vector<CTxDestination> whitelist = | ||||
GetMinerFundWhitelist(consensusParams, pindex->pprev); | GetMinerFundWhitelist(consensusParams, pindex->pprev); | ||||
if (!whitelist.empty()) { | if (!whitelist.empty()) { | ||||
const Amount required = blockReward / MINER_FUND_RATIO; | const Amount required = blockReward / MINER_FUND_RATIO; | ||||
for (auto &o : block.vtx[0]->vout) { | for (auto &o : block.vtx[0]->vout) { | ||||
Show All 10 Lines | if (!whitelist.empty()) { | ||||
if (std::find(whitelist.begin(), whitelist.end(), address) != | if (std::find(whitelist.begin(), whitelist.end(), address) != | ||||
whitelist.end()) { | whitelist.end()) { | ||||
goto MinerFundSuccess; | goto MinerFundSuccess; | ||||
} | } | ||||
} | } | ||||
// We did not find an output that match the miner fund requirements. | // We did not find an output that match the miner fund requirements. | ||||
return state.DoS(100, ValidationInvalidReason::CONSENSUS, false, | return state.DoS(100, ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-cb-minerfund"); | ||||
REJECT_INVALID, "bad-cb-minerfund"); | |||||
} | } | ||||
MinerFundSuccess: | MinerFundSuccess: | ||||
if (!control.Wait()) { | if (!control.Wait()) { | ||||
return state.DoS(100, ValidationInvalidReason::CONSENSUS, false, | return state.DoS(100, ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "blk-bad-inputs", false, "parallel script check failed"); | ||||
REJECT_INVALID, "blk-bad-inputs", false, | |||||
"parallel script check failed"); | |||||
} | } | ||||
int64_t nTime4 = GetTimeMicros(); | int64_t nTime4 = GetTimeMicros(); | ||||
nTimeVerify += nTime4 - nTime2; | nTimeVerify += nTime4 - nTime2; | ||||
LogPrint( | LogPrint( | ||||
BCLog::BENCH, | BCLog::BENCH, | ||||
" - Verify %u txins: %.2fms (%.3fms/txin) [%.2fs (%.2fms/blk)]\n", | " - Verify %u txins: %.2fms (%.3fms/txin) [%.2fs (%.2fms/blk)]\n", | ||||
nInputs - 1, MILLI * (nTime4 - nTime2), | nInputs - 1, MILLI * (nTime4 - nTime2), | ||||
▲ Show 20 Lines • Show All 387 Lines • ▼ Show 20 Lines | if (pindex->nStatus.isInvalid()) { | ||||
return state.Invalid(ValidationInvalidReason::CACHED_INVALID, | return state.Invalid(ValidationInvalidReason::CACHED_INVALID, | ||||
error("%s: Trying to finalize invalid block %s", | error("%s: Trying to finalize invalid block %s", | ||||
__func__, pindex->GetBlockHash().ToString()), | __func__, pindex->GetBlockHash().ToString()), | ||||
REJECT_INVALID, "finalize-invalid-block"); | REJECT_INVALID, "finalize-invalid-block"); | ||||
} | } | ||||
// Check that the request is consistent with current finalization. | // Check that the request is consistent with current finalization. | ||||
if (pindexFinalized && !AreOnTheSameFork(pindex, pindexFinalized)) { | if (pindexFinalized && !AreOnTheSameFork(pindex, pindexFinalized)) { | ||||
return state.DoS( | return state.DoS(20, ValidationInvalidReason::BLOCK_FINALIZATION, error("%s: Trying to finalize block %s which conflicts ""with already finalized block", __func__, pindex->GetBlockHash().ToString()), REJECT_AGAINST_FINALIZED, "bad-fork-prior-finalized"); | ||||
20, ValidationInvalidReason::BLOCK_FINALIZATION, | |||||
error("%s: Trying to finalize block %s which conflicts " | |||||
"with already finalized block", | |||||
__func__, pindex->GetBlockHash().ToString()), | |||||
REJECT_AGAINST_FINALIZED, "bad-fork-prior-finalized"); | |||||
} | } | ||||
if (IsBlockFinalized(pindex)) { | if (IsBlockFinalized(pindex)) { | ||||
// The block is already finalized. | // The block is already finalized. | ||||
return true; | return true; | ||||
} | } | ||||
// We have a new block to finalize. | // We have a new block to finalize. | ||||
▲ Show 20 Lines • Show All 1,150 Lines • ▼ Show 20 Lines | |||||
* For context-dependent calls, see ContextualCheckBlockHeader. | * For context-dependent calls, see ContextualCheckBlockHeader. | ||||
*/ | */ | ||||
static bool CheckBlockHeader(const CBlockHeader &block, CValidationState &state, | static bool CheckBlockHeader(const CBlockHeader &block, CValidationState &state, | ||||
const Consensus::Params ¶ms, | const Consensus::Params ¶ms, | ||||
BlockValidationOptions validationOptions) { | BlockValidationOptions validationOptions) { | ||||
// Check proof of work matches claimed amount | // Check proof of work matches claimed amount | ||||
if (validationOptions.shouldValidatePoW() && | if (validationOptions.shouldValidatePoW() && | ||||
!CheckProofOfWork(block.GetHash(), block.nBits, params)) { | !CheckProofOfWork(block.GetHash(), block.nBits, params)) { | ||||
return state.DoS(100, ValidationInvalidReason::BLOCK_INVALID_HEADER, | return state.DoS(100, ValidationInvalidReason::BLOCK_INVALID_HEADER, false, REJECT_INVALID, "high-hash", false, "proof of work failed"); | ||||
false, REJECT_INVALID, "high-hash", false, | |||||
"proof of work failed"); | |||||
} | } | ||||
return true; | return true; | ||||
} | } | ||||
bool CheckBlock(const CBlock &block, CValidationState &state, | bool CheckBlock(const CBlock &block, CValidationState &state, | ||||
const Consensus::Params ¶ms, | const Consensus::Params ¶ms, | ||||
BlockValidationOptions validationOptions) { | BlockValidationOptions validationOptions) { | ||||
// These are checks that are independent of context. | // These are checks that are independent of context. | ||||
if (block.fChecked) { | if (block.fChecked) { | ||||
return true; | return true; | ||||
} | } | ||||
// Check that the header is valid (particularly PoW). This is mostly | // Check that the header is valid (particularly PoW). This is mostly | ||||
// redundant with the call in AcceptBlockHeader. | // redundant with the call in AcceptBlockHeader. | ||||
if (!CheckBlockHeader(block, state, params, validationOptions)) { | if (!CheckBlockHeader(block, state, params, validationOptions)) { | ||||
return false; | return false; | ||||
} | } | ||||
// Check the merkle root. | // Check the merkle root. | ||||
if (validationOptions.shouldValidateMerkleRoot()) { | if (validationOptions.shouldValidateMerkleRoot()) { | ||||
bool mutated; | bool mutated; | ||||
uint256 hashMerkleRoot2 = BlockMerkleRoot(block, &mutated); | uint256 hashMerkleRoot2 = BlockMerkleRoot(block, &mutated); | ||||
if (block.hashMerkleRoot != hashMerkleRoot2) { | if (block.hashMerkleRoot != hashMerkleRoot2) { | ||||
return state.DoS(100, ValidationInvalidReason::BLOCK_MUTATED, false, | return state.DoS(100, ValidationInvalidReason::BLOCK_MUTATED, false, REJECT_INVALID, "bad-txnmrklroot", true, "hashMerkleRoot mismatch"); | ||||
REJECT_INVALID, "bad-txnmrklroot", true, | |||||
"hashMerkleRoot mismatch"); | |||||
} | } | ||||
// Check for merkle tree malleability (CVE-2012-2459): repeating | // Check for merkle tree malleability (CVE-2012-2459): repeating | ||||
// sequences of transactions in a block without affecting the merkle | // sequences of transactions in a block without affecting the merkle | ||||
// root of a block, while still invalidating it. | // root of a block, while still invalidating it. | ||||
if (mutated) { | if (mutated) { | ||||
return state.DoS(100, ValidationInvalidReason::BLOCK_MUTATED, false, | return state.DoS(100, ValidationInvalidReason::BLOCK_MUTATED, false, REJECT_INVALID, "bad-txns-duplicate", true, "duplicate transaction"); | ||||
REJECT_INVALID, "bad-txns-duplicate", true, | |||||
"duplicate transaction"); | |||||
} | } | ||||
} | } | ||||
// All potential-corruption validation must be done before we do any | // All potential-corruption validation must be done before we do any | ||||
// transaction validation, as otherwise we may mark the header as invalid | // transaction validation, as otherwise we may mark the header as invalid | ||||
// because we receive the wrong transactions for it. | // because we receive the wrong transactions for it. | ||||
// First transaction must be coinbase. | // First transaction must be coinbase. | ||||
if (block.vtx.empty()) { | if (block.vtx.empty()) { | ||||
return state.DoS(100, ValidationInvalidReason::CONSENSUS, false, | return state.DoS(100, ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-cb-missing", false, "first tx is not coinbase"); | ||||
REJECT_INVALID, "bad-cb-missing", false, | |||||
"first tx is not coinbase"); | |||||
} | } | ||||
// Size limits. | // Size limits. | ||||
auto nMaxBlockSize = validationOptions.getExcessiveBlockSize(); | auto nMaxBlockSize = validationOptions.getExcessiveBlockSize(); | ||||
// Bail early if there is no way this block is of reasonable size. | // Bail early if there is no way this block is of reasonable size. | ||||
if ((block.vtx.size() * MIN_TRANSACTION_SIZE) > nMaxBlockSize) { | if ((block.vtx.size() * MIN_TRANSACTION_SIZE) > nMaxBlockSize) { | ||||
return state.DoS(100, ValidationInvalidReason::CONSENSUS, false, | return state.DoS(100, ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-blk-length", false, "size limits failed"); | ||||
REJECT_INVALID, "bad-blk-length", false, | |||||
"size limits failed"); | |||||
} | } | ||||
auto currentBlockSize = ::GetSerializeSize(block, PROTOCOL_VERSION); | auto currentBlockSize = ::GetSerializeSize(block, PROTOCOL_VERSION); | ||||
if (currentBlockSize > nMaxBlockSize) { | if (currentBlockSize > nMaxBlockSize) { | ||||
return state.DoS(100, ValidationInvalidReason::CONSENSUS, false, | return state.DoS(100, ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-blk-length", false, "size limits failed"); | ||||
REJECT_INVALID, "bad-blk-length", false, | |||||
"size limits failed"); | |||||
} | } | ||||
// And a valid coinbase. | // And a valid coinbase. | ||||
if (!CheckCoinbase(*block.vtx[0], state)) { | if (!CheckCoinbase(*block.vtx[0], state)) { | ||||
return state.Invalid(ValidationInvalidReason::CONSENSUS, false, | return state.Invalid(ValidationInvalidReason::CONSENSUS, false, | ||||
state.GetRejectCode(), state.GetRejectReason(), | state.GetRejectCode(), state.GetRejectReason(), | ||||
strprintf("Coinbase check failed (txid %s) %s", | strprintf("Coinbase check failed (txid %s) %s", | ||||
block.vtx[0]->GetId().ToString(), | block.vtx[0]->GetId().ToString(), | ||||
Show All 39 Lines | ContextualCheckBlockHeader(const CChainParams ¶ms, | ||||
assert(pindexPrev != nullptr); | assert(pindexPrev != nullptr); | ||||
const int nHeight = pindexPrev->nHeight + 1; | const int nHeight = pindexPrev->nHeight + 1; | ||||
// Check proof of work | // Check proof of work | ||||
const Consensus::Params &consensusParams = params.GetConsensus(); | const Consensus::Params &consensusParams = params.GetConsensus(); | ||||
if (block.nBits != | if (block.nBits != | ||||
GetNextWorkRequired(pindexPrev, &block, consensusParams)) { | GetNextWorkRequired(pindexPrev, &block, consensusParams)) { | ||||
LogPrintf("bad bits after height: %d\n", pindexPrev->nHeight); | LogPrintf("bad bits after height: %d\n", pindexPrev->nHeight); | ||||
return state.DoS(100, ValidationInvalidReason::BLOCK_INVALID_HEADER, | return state.DoS(100, ValidationInvalidReason::BLOCK_INVALID_HEADER, false, REJECT_INVALID, "bad-diffbits", false, "incorrect proof of work"); | ||||
false, REJECT_INVALID, "bad-diffbits", false, | |||||
"incorrect proof of work"); | |||||
} | } | ||||
// Check against checkpoints | // Check against checkpoints | ||||
if (fCheckpointsEnabled) { | if (fCheckpointsEnabled) { | ||||
const CCheckpointData &checkpoints = params.Checkpoints(); | const CCheckpointData &checkpoints = params.Checkpoints(); | ||||
// Check that the block chain matches the known block chain up to a | // Check that the block chain matches the known block chain up to a | ||||
// checkpoint. | // checkpoint. | ||||
if (!Checkpoints::CheckBlock(checkpoints, nHeight, block.GetHash())) { | if (!Checkpoints::CheckBlock(checkpoints, nHeight, block.GetHash())) { | ||||
return state.DoS(100, ValidationInvalidReason::BLOCK_CHECKPOINT, | return state.DoS(100, ValidationInvalidReason::BLOCK_CHECKPOINT, error("%s: rejected by checkpoint lock-in at %d", __func__, nHeight), REJECT_CHECKPOINT, "checkpoint mismatch"); | ||||
error("%s: rejected by checkpoint lock-in at %d", | |||||
__func__, nHeight), | |||||
REJECT_CHECKPOINT, "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 MapBlockIndex. | // in our MapBlockIndex. | ||||
CBlockIndex *pcheckpoint = Checkpoints::GetLastCheckpoint(checkpoints); | CBlockIndex *pcheckpoint = Checkpoints::GetLastCheckpoint(checkpoints); | ||||
if (pcheckpoint && nHeight < pcheckpoint->nHeight) { | if (pcheckpoint && nHeight < pcheckpoint->nHeight) { | ||||
return state.DoS( | return state.DoS(100, ValidationInvalidReason::BLOCK_CHECKPOINT, error("%s: forked chain older than last checkpoint (height %d)", __func__, nHeight), REJECT_CHECKPOINT, "bad-fork-prior-to-checkpoint"); | ||||
100, ValidationInvalidReason::BLOCK_CHECKPOINT, | |||||
error("%s: forked chain older than last checkpoint (height %d)", | |||||
__func__, nHeight), | |||||
REJECT_CHECKPOINT, "bad-fork-prior-to-checkpoint"); | |||||
} | } | ||||
} | } | ||||
// Check timestamp against prev | // Check timestamp against prev | ||||
if (block.GetBlockTime() <= pindexPrev->GetMedianTimePast()) { | if (block.GetBlockTime() <= pindexPrev->GetMedianTimePast()) { | ||||
return state.DoS(100, ValidationInvalidReason::BLOCK_INVALID_HEADER, | return state.DoS(100, ValidationInvalidReason::BLOCK_INVALID_HEADER, false, REJECT_INVALID, "time-too-old", false, "block's timestamp is too early"); | ||||
false, REJECT_INVALID, "time-too-old", false, | |||||
"block's timestamp is too early"); | |||||
} | } | ||||
// Check timestamp | // Check timestamp | ||||
if (block.GetBlockTime() > nAdjustedTime + MAX_FUTURE_BLOCK_TIME) { | if (block.GetBlockTime() > nAdjustedTime + MAX_FUTURE_BLOCK_TIME) { | ||||
return state.Invalid(ValidationInvalidReason::BLOCK_TIME_FUTURE, false, | return state.Invalid(ValidationInvalidReason::BLOCK_TIME_FUTURE, false, | ||||
REJECT_INVALID, "time-too-new", | REJECT_INVALID, "time-too-new", | ||||
"block timestamp too far in the future"); | "block timestamp too far in the future"); | ||||
} | } | ||||
// Reject outdated version blocks when 95% (75% on testnet) of the network | // Reject outdated version blocks when 95% (75% on testnet) of the network | ||||
// has upgraded: | // has upgraded: | ||||
// check for version 2, 3 and 4 upgrades | // check for version 2, 3 and 4 upgrades | ||||
if ((block.nVersion < 2 && nHeight >= consensusParams.BIP34Height) || | if ((block.nVersion < 2 && nHeight >= consensusParams.BIP34Height) || | ||||
(block.nVersion < 3 && nHeight >= consensusParams.BIP66Height) || | (block.nVersion < 3 && nHeight >= consensusParams.BIP66Height) || | ||||
(block.nVersion < 4 && nHeight >= consensusParams.BIP65Height)) { | (block.nVersion < 4 && nHeight >= consensusParams.BIP65Height)) { | ||||
return state.DoS( | return state.DoS(100, ValidationInvalidReason::BLOCK_INVALID_HEADER, false, REJECT_OBSOLETE, strprintf("bad-version(0x%08x)", block.nVersion), false, strprintf("rejected nVersion=0x%08x block", block.nVersion)); | ||||
100, ValidationInvalidReason::BLOCK_INVALID_HEADER, false, | |||||
REJECT_OBSOLETE, strprintf("bad-version(0x%08x)", block.nVersion), | |||||
false, strprintf("rejected nVersion=0x%08x block", block.nVersion)); | |||||
} | } | ||||
return true; | return true; | ||||
} | } | ||||
bool ContextualCheckTransactionForCurrentBlock(const Consensus::Params ¶ms, | bool ContextualCheckTransactionForCurrentBlock(const Consensus::Params ¶ms, | ||||
const CTransaction &tx, | const CTransaction &tx, | ||||
CValidationState &state, | CValidationState &state, | ||||
▲ Show 20 Lines • Show All 69 Lines • ▼ Show 20 Lines | static bool ContextualCheckBlock(const CBlock &block, CValidationState &state, | ||||
// - perform a transaction-sigops check (again, a more strict check will | // - perform a transaction-sigops check (again, a more strict check will | ||||
// happen in ConnectBlock). | // happen in ConnectBlock). | ||||
const CTransaction *prevTx = nullptr; | const CTransaction *prevTx = nullptr; | ||||
for (const auto &ptx : block.vtx) { | for (const auto &ptx : block.vtx) { | ||||
const CTransaction &tx = *ptx; | const CTransaction &tx = *ptx; | ||||
if (fIsMagneticAnomalyEnabled) { | if (fIsMagneticAnomalyEnabled) { | ||||
if (prevTx && (tx.GetId() <= prevTx->GetId())) { | if (prevTx && (tx.GetId() <= prevTx->GetId())) { | ||||
if (tx.GetId() == prevTx->GetId()) { | if (tx.GetId() == prevTx->GetId()) { | ||||
return state.DoS(100, ValidationInvalidReason::CONSENSUS, | return state.DoS(100, ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "tx-duplicate", false, strprintf("Duplicated transaction %s", tx.GetId().ToString())); | ||||
false, REJECT_INVALID, "tx-duplicate", | |||||
false, | |||||
strprintf("Duplicated transaction %s", | |||||
tx.GetId().ToString())); | |||||
} | } | ||||
return state.DoS( | return state.DoS(100, ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "tx-ordering", false, strprintf("Transaction order is invalid (%s < %s)", tx.GetId().ToString(), prevTx->GetId().ToString())); | ||||
100, ValidationInvalidReason::CONSENSUS, false, | |||||
REJECT_INVALID, "tx-ordering", false, | |||||
strprintf("Transaction order is invalid (%s < %s)", | |||||
tx.GetId().ToString(), | |||||
prevTx->GetId().ToString())); | |||||
} | } | ||||
if (prevTx || !tx.IsCoinBase()) { | if (prevTx || !tx.IsCoinBase()) { | ||||
prevTx = &tx; | prevTx = &tx; | ||||
} | } | ||||
} | } | ||||
if (!ContextualCheckTransaction(params, tx, state, nHeight, | if (!ContextualCheckTransaction(params, tx, state, nHeight, | ||||
nLockTimeCutoff, nMedianTimePast)) { | nLockTimeCutoff, nMedianTimePast)) { | ||||
// state set by ContextualCheckTransaction. | // state set by ContextualCheckTransaction. | ||||
return false; | return false; | ||||
} | } | ||||
} | } | ||||
// Enforce rule that the coinbase starts with serialized block height | // Enforce rule that the coinbase starts with serialized block height | ||||
if (nHeight >= params.BIP34Height) { | if (nHeight >= params.BIP34Height) { | ||||
CScript expect = CScript() << nHeight; | CScript expect = CScript() << nHeight; | ||||
if (block.vtx[0]->vin[0].scriptSig.size() < expect.size() || | if (block.vtx[0]->vin[0].scriptSig.size() < expect.size() || | ||||
!std::equal(expect.begin(), expect.end(), | !std::equal(expect.begin(), expect.end(), | ||||
block.vtx[0]->vin[0].scriptSig.begin())) { | block.vtx[0]->vin[0].scriptSig.begin())) { | ||||
return state.DoS(100, ValidationInvalidReason::CONSENSUS, false, | return state.DoS(100, ValidationInvalidReason::CONSENSUS, false, REJECT_INVALID, "bad-cb-height", false, "block height mismatch in coinbase"); | ||||
REJECT_INVALID, "bad-cb-height", false, | |||||
"block height mismatch in coinbase"); | |||||
} | } | ||||
} | } | ||||
return true; | return true; | ||||
} | } | ||||
/** | /** | ||||
* If the provided block header is valid, add it to the block index. | * If the provided block header is valid, add it to the block index. | ||||
Show All 33 Lines | if (hash != chainparams.GetConsensus().hashGenesisBlock) { | ||||
BlockValidationOptions(config))) { | BlockValidationOptions(config))) { | ||||
return error("%s: Consensus::CheckBlockHeader: %s, %s", __func__, | return error("%s: Consensus::CheckBlockHeader: %s, %s", __func__, | ||||
hash.ToString(), FormatStateMessage(state)); | hash.ToString(), FormatStateMessage(state)); | ||||
} | } | ||||
// Get prev block index | // Get prev block index | ||||
BlockMap::iterator mi = mapBlockIndex.find(block.hashPrevBlock); | BlockMap::iterator mi = mapBlockIndex.find(block.hashPrevBlock); | ||||
if (mi == mapBlockIndex.end()) { | if (mi == mapBlockIndex.end()) { | ||||
return state.DoS(10, ValidationInvalidReason::BLOCK_MISSING_PREV, | return state.DoS(10, ValidationInvalidReason::BLOCK_MISSING_PREV, error("%s: prev block not found", __func__), 0, "prev-blk-not-found"); | ||||
error("%s: prev block not found", __func__), 0, | |||||
"prev-blk-not-found"); | |||||
} | } | ||||
CBlockIndex *pindexPrev = (*mi).second; | CBlockIndex *pindexPrev = (*mi).second; | ||||
assert(pindexPrev); | assert(pindexPrev); | ||||
if (pindexPrev->nStatus.isInvalid()) { | if (pindexPrev->nStatus.isInvalid()) { | ||||
return state.DoS(100, ValidationInvalidReason::BLOCK_INVALID_PREV, | return state.DoS(100, ValidationInvalidReason::BLOCK_INVALID_PREV, error("%s: prev block invalid", __func__), REJECT_INVALID, "bad-prevblk"); | ||||
error("%s: prev block invalid", __func__), | |||||
REJECT_INVALID, "bad-prevblk"); | |||||
} | } | ||||
if (!ContextualCheckBlockHeader(chainparams, block, state, pindexPrev, | if (!ContextualCheckBlockHeader(chainparams, block, state, pindexPrev, | ||||
GetAdjustedTime())) { | GetAdjustedTime())) { | ||||
return error("%s: Consensus::ContextualCheckBlockHeader: %s, %s", | return error("%s: Consensus::ContextualCheckBlockHeader: %s, %s", | ||||
__func__, hash.ToString(), FormatStateMessage(state)); | __func__, hash.ToString(), FormatStateMessage(state)); | ||||
} | } | ||||
Show All 27 Lines | if (hash != chainparams.GetConsensus().hashGenesisBlock) { | ||||
assert(failedit->nStatus.hasFailed()); | assert(failedit->nStatus.hasFailed()); | ||||
CBlockIndex *invalid_walk = pindexPrev; | CBlockIndex *invalid_walk = pindexPrev; | ||||
while (invalid_walk != failedit) { | while (invalid_walk != failedit) { | ||||
invalid_walk->nStatus = | invalid_walk->nStatus = | ||||
invalid_walk->nStatus.withFailedParent(); | invalid_walk->nStatus.withFailedParent(); | ||||
setDirtyBlockIndex.insert(invalid_walk); | setDirtyBlockIndex.insert(invalid_walk); | ||||
invalid_walk = invalid_walk->pprev; | invalid_walk = invalid_walk->pprev; | ||||
} | } | ||||
return state.DoS( | return state.DoS(100, ValidationInvalidReason::BLOCK_INVALID_PREV, error("%s: prev block invalid", __func__), REJECT_INVALID, "bad-prevblk"); | ||||
100, ValidationInvalidReason::BLOCK_INVALID_PREV, | |||||
error("%s: prev block invalid", __func__), | |||||
REJECT_INVALID, "bad-prevblk"); | |||||
} | } | ||||
} | } | ||||
} | } | ||||
} | } | ||||
if (pindex == nullptr) { | if (pindex == nullptr) { | ||||
pindex = AddToBlockIndex(block); | pindex = AddToBlockIndex(block); | ||||
} | } | ||||
▲ Show 20 Lines • Show All 1,822 Lines • Show Last 20 Lines |