Changeset View
Changeset View
Standalone View
Standalone View
src/validation.cpp
Show All 10 Lines | |||||
#include "blockvalidity.h" | #include "blockvalidity.h" | ||||
#include "chainparams.h" | #include "chainparams.h" | ||||
#include "checkpoints.h" | #include "checkpoints.h" | ||||
#include "checkqueue.h" | #include "checkqueue.h" | ||||
#include "config.h" | #include "config.h" | ||||
#include "consensus/activation.h" | #include "consensus/activation.h" | ||||
#include "consensus/consensus.h" | #include "consensus/consensus.h" | ||||
#include "consensus/merkle.h" | #include "consensus/merkle.h" | ||||
#include "consensus/tx_verify.h" | |||||
#include "consensus/validation.h" | #include "consensus/validation.h" | ||||
#include "fs.h" | #include "fs.h" | ||||
#include "hash.h" | #include "hash.h" | ||||
#include "init.h" | #include "init.h" | ||||
#include "policy/fees.h" | #include "policy/fees.h" | ||||
#include "policy/policy.h" | #include "policy/policy.h" | ||||
#include "pow.h" | #include "pow.h" | ||||
#include "primitives/block.h" | #include "primitives/block.h" | ||||
▲ Show 20 Lines • Show All 148 Lines • ▼ Show 20 Lines | |||||
static void FindFilesToPruneManual(std::set<int> &setFilesToPrune, | static void FindFilesToPruneManual(std::set<int> &setFilesToPrune, | ||||
int nManualPruneHeight); | int nManualPruneHeight); | ||||
static void FindFilesToPrune(std::set<int> &setFilesToPrune, | static void FindFilesToPrune(std::set<int> &setFilesToPrune, | ||||
uint64_t nPruneAfterHeight); | uint64_t nPruneAfterHeight); | ||||
static FILE *OpenUndoFile(const CDiskBlockPos &pos, bool fReadOnly = false); | static FILE *OpenUndoFile(const CDiskBlockPos &pos, bool fReadOnly = false); | ||||
static uint32_t GetBlockScriptFlags(const Config &config, | static uint32_t GetBlockScriptFlags(const Config &config, | ||||
const CBlockIndex *pChainTip); | const CBlockIndex *pChainTip); | ||||
static bool IsFinalTx(const CTransaction &tx, int nBlockHeight, | |||||
int64_t nBlockTime) { | |||||
if (tx.nLockTime == 0) { | |||||
return true; | |||||
} | |||||
int64_t lockTime = tx.nLockTime; | |||||
int64_t lockTimeLimit = | |||||
(lockTime < LOCKTIME_THRESHOLD) ? nBlockHeight : nBlockTime; | |||||
if (lockTime < lockTimeLimit) { | |||||
return true; | |||||
} | |||||
for (const auto &txin : tx.vin) { | |||||
if (txin.nSequence != CTxIn::SEQUENCE_FINAL) { | |||||
return false; | |||||
} | |||||
} | |||||
return true; | |||||
} | |||||
/** | |||||
* Calculates the block height and previous block's median time past at | |||||
* which the transaction will be considered final in the context of BIP 68. | |||||
* Also removes from the vector of input heights any entries which did not | |||||
* correspond to sequence locked inputs as they do not affect the calculation. | |||||
*/ | |||||
static std::pair<int, int64_t> | |||||
CalculateSequenceLocks(const CTransaction &tx, int flags, | |||||
std::vector<int> *prevHeights, | |||||
const CBlockIndex &block) { | |||||
assert(prevHeights->size() == tx.vin.size()); | |||||
// Will be set to the equivalent height- and time-based nLockTime | |||||
// values that would be necessary to satisfy all relative lock- | |||||
// time constraints given our view of block chain history. | |||||
// The semantics of nLockTime are the last invalid height/time, so | |||||
// use -1 to have the effect of any height or time being valid. | |||||
int nMinHeight = -1; | |||||
int64_t nMinTime = -1; | |||||
// tx.nVersion is signed integer so requires cast to unsigned otherwise | |||||
// we would be doing a signed comparison and half the range of nVersion | |||||
// wouldn't support BIP 68. | |||||
bool fEnforceBIP68 = static_cast<uint32_t>(tx.nVersion) >= 2 && | |||||
flags & LOCKTIME_VERIFY_SEQUENCE; | |||||
// Do not enforce sequence numbers as a relative lock time | |||||
// unless we have been instructed to | |||||
if (!fEnforceBIP68) { | |||||
return std::make_pair(nMinHeight, nMinTime); | |||||
} | |||||
for (size_t txinIndex = 0; txinIndex < tx.vin.size(); txinIndex++) { | |||||
const CTxIn &txin = tx.vin[txinIndex]; | |||||
// Sequence numbers with the most significant bit set are not | |||||
// treated as relative lock-times, nor are they given any | |||||
// consensus-enforced meaning at this point. | |||||
if (txin.nSequence & CTxIn::SEQUENCE_LOCKTIME_DISABLE_FLAG) { | |||||
// The height of this input is not relevant for sequence locks | |||||
(*prevHeights)[txinIndex] = 0; | |||||
continue; | |||||
} | |||||
int nCoinHeight = (*prevHeights)[txinIndex]; | |||||
if (txin.nSequence & CTxIn::SEQUENCE_LOCKTIME_TYPE_FLAG) { | |||||
int64_t nCoinTime = block.GetAncestor(std::max(nCoinHeight - 1, 0)) | |||||
->GetMedianTimePast(); | |||||
// NOTE: Subtract 1 to maintain nLockTime semantics. | |||||
// BIP 68 relative lock times have the semantics of calculating the | |||||
// first block or time at which the transaction would be valid. When | |||||
// calculating the effective block time or height for the entire | |||||
// transaction, we switch to using the semantics of nLockTime which | |||||
// is the last invalid block time or height. Thus we subtract 1 from | |||||
// the calculated time or height. | |||||
// Time-based relative lock-times are measured from the smallest | |||||
// allowed timestamp of the block containing the txout being spent, | |||||
// which is the median time past of the block prior. | |||||
nMinTime = std::max( | |||||
nMinTime, | |||||
nCoinTime + | |||||
(int64_t)((txin.nSequence & CTxIn::SEQUENCE_LOCKTIME_MASK) | |||||
<< CTxIn::SEQUENCE_LOCKTIME_GRANULARITY) - | |||||
1); | |||||
} else { | |||||
nMinHeight = std::max( | |||||
nMinHeight, | |||||
nCoinHeight + | |||||
(int)(txin.nSequence & CTxIn::SEQUENCE_LOCKTIME_MASK) - 1); | |||||
} | |||||
} | |||||
return std::make_pair(nMinHeight, nMinTime); | |||||
} | |||||
static bool EvaluateSequenceLocks(const CBlockIndex &block, | |||||
std::pair<int, int64_t> lockPair) { | |||||
assert(block.pprev); | |||||
int64_t nBlockTime = block.pprev->GetMedianTimePast(); | |||||
if (lockPair.first >= block.nHeight || lockPair.second >= nBlockTime) { | |||||
return false; | |||||
} | |||||
return true; | |||||
} | |||||
bool SequenceLocks(const CTransaction &tx, int flags, | |||||
std::vector<int> *prevHeights, const CBlockIndex &block) { | |||||
return EvaluateSequenceLocks( | |||||
block, CalculateSequenceLocks(tx, flags, prevHeights, block)); | |||||
} | |||||
bool TestLockPointValidity(const LockPoints *lp) { | bool TestLockPointValidity(const LockPoints *lp) { | ||||
AssertLockHeld(cs_main); | AssertLockHeld(cs_main); | ||||
assert(lp); | assert(lp); | ||||
// If there are relative lock times then the maxInputBlock will be set | // If there are relative lock times then the maxInputBlock will be set | ||||
// If there are no relative lock times, the LockPoints don't depend on the | // If there are no relative lock times, the LockPoints don't depend on the | ||||
// chain | // chain | ||||
if (lp->maxInputBlock) { | if (lp->maxInputBlock) { | ||||
// Check whether chainActive is an extension of the block at which the | // Check whether chainActive is an extension of the block at which the | ||||
▲ Show 20 Lines • Show All 72 Lines • ▼ Show 20 Lines | if (useExistingLockPoints) { | ||||
} | } | ||||
} | } | ||||
lp->maxInputBlock = tip->GetAncestor(maxInputHeight); | lp->maxInputBlock = tip->GetAncestor(maxInputHeight); | ||||
} | } | ||||
} | } | ||||
return EvaluateSequenceLocks(index, lockPair); | return EvaluateSequenceLocks(index, lockPair); | ||||
} | } | ||||
uint64_t GetSigOpCountWithoutP2SH(const CTransaction &tx, uint32_t flags) { | |||||
uint64_t nSigOps = 0; | |||||
for (const auto &txin : tx.vin) { | |||||
nSigOps += txin.scriptSig.GetSigOpCount(flags, false); | |||||
} | |||||
for (const auto &txout : tx.vout) { | |||||
nSigOps += txout.scriptPubKey.GetSigOpCount(flags, false); | |||||
} | |||||
return nSigOps; | |||||
} | |||||
uint64_t GetP2SHSigOpCount(const CTransaction &tx, const CCoinsViewCache &view, | |||||
uint32_t flags) { | |||||
if ((flags & SCRIPT_VERIFY_P2SH) == 0 || tx.IsCoinBase()) { | |||||
return 0; | |||||
} | |||||
uint64_t nSigOps = 0; | |||||
for (auto &i : tx.vin) { | |||||
const CTxOut &prevout = view.GetOutputFor(i); | |||||
if (prevout.scriptPubKey.IsPayToScriptHash()) { | |||||
nSigOps += prevout.scriptPubKey.GetSigOpCount(flags, i.scriptSig); | |||||
} | |||||
} | |||||
return nSigOps; | |||||
} | |||||
uint64_t GetTransactionSigOpCount(const CTransaction &tx, | |||||
const CCoinsViewCache &view, uint32_t flags) { | |||||
return GetSigOpCountWithoutP2SH(tx, flags) + | |||||
GetP2SHSigOpCount(tx, view, flags); | |||||
} | |||||
static bool CheckTransactionCommon(const CTransaction &tx, | |||||
CValidationState &state, | |||||
bool fCheckDuplicateInputs) { | |||||
// Basic checks that don't depend on any context | |||||
if (tx.vin.empty()) { | |||||
return state.DoS(10, false, REJECT_INVALID, "bad-txns-vin-empty"); | |||||
} | |||||
if (tx.vout.empty()) { | |||||
return state.DoS(10, false, REJECT_INVALID, "bad-txns-vout-empty"); | |||||
} | |||||
// Size limit | |||||
if (::GetSerializeSize(tx, SER_NETWORK, PROTOCOL_VERSION) > MAX_TX_SIZE) { | |||||
return state.DoS(100, false, REJECT_INVALID, "bad-txns-oversize"); | |||||
} | |||||
// Check for negative or overflow output values | |||||
Amount nValueOut = Amount::zero(); | |||||
for (const auto &txout : tx.vout) { | |||||
if (txout.nValue < Amount::zero()) { | |||||
return state.DoS(100, false, REJECT_INVALID, | |||||
"bad-txns-vout-negative"); | |||||
} | |||||
if (txout.nValue > MAX_MONEY) { | |||||
return state.DoS(100, false, REJECT_INVALID, | |||||
"bad-txns-vout-toolarge"); | |||||
} | |||||
nValueOut += txout.nValue; | |||||
if (!MoneyRange(nValueOut)) { | |||||
return state.DoS(100, false, REJECT_INVALID, | |||||
"bad-txns-txouttotal-toolarge"); | |||||
} | |||||
} | |||||
if (GetSigOpCountWithoutP2SH(tx, STANDARD_CHECKDATASIG_VERIFY_FLAGS) > | |||||
MAX_TX_SIGOPS_COUNT) { | |||||
return state.DoS(100, false, REJECT_INVALID, "bad-txn-sigops"); | |||||
} | |||||
// Check for duplicate inputs - note that this check is slow so we skip it | |||||
// in CheckBlock | |||||
if (fCheckDuplicateInputs) { | |||||
std::set<COutPoint> vInOutPoints; | |||||
for (const auto &txin : tx.vin) { | |||||
if (!vInOutPoints.insert(txin.prevout).second) { | |||||
return state.DoS(100, false, REJECT_INVALID, | |||||
"bad-txns-inputs-duplicate"); | |||||
} | |||||
} | |||||
} | |||||
return true; | |||||
} | |||||
bool CheckCoinbase(const CTransaction &tx, CValidationState &state, | |||||
bool fCheckDuplicateInputs) { | |||||
if (!tx.IsCoinBase()) { | |||||
return state.DoS(100, false, REJECT_INVALID, "bad-cb-missing", false, | |||||
"first tx is not coinbase"); | |||||
} | |||||
if (!CheckTransactionCommon(tx, state, fCheckDuplicateInputs)) { | |||||
// CheckTransactionCommon fill in the state. | |||||
return false; | |||||
} | |||||
if (tx.vin[0].scriptSig.size() < 2 || | |||||
tx.vin[0].scriptSig.size() > MAX_COINBASE_SCRIPTSIG_SIZE) { | |||||
return state.DoS(100, false, REJECT_INVALID, "bad-cb-length"); | |||||
} | |||||
return true; | |||||
} | |||||
bool CheckRegularTransaction(const CTransaction &tx, CValidationState &state, | |||||
bool fCheckDuplicateInputs) { | |||||
if (tx.IsCoinBase()) { | |||||
return state.DoS(100, false, REJECT_INVALID, "bad-tx-coinbase"); | |||||
} | |||||
if (!CheckTransactionCommon(tx, state, fCheckDuplicateInputs)) { | |||||
// CheckTransactionCommon fill in the state. | |||||
return false; | |||||
} | |||||
for (const auto &txin : tx.vin) { | |||||
if (txin.prevout.IsNull()) { | |||||
return state.DoS(10, false, REJECT_INVALID, | |||||
"bad-txns-prevout-null"); | |||||
} | |||||
} | |||||
return true; | |||||
} | |||||
/** Convert CValidationState to a human-readable message for logging */ | /** Convert CValidationState to a human-readable message for logging */ | ||||
std::string FormatStateMessage(const CValidationState &state) { | std::string FormatStateMessage(const CValidationState &state) { | ||||
return strprintf( | return strprintf( | ||||
"%s%s (code %i)", state.GetRejectReason(), | "%s%s (code %i)", state.GetRejectReason(), | ||||
state.GetDebugMessage().empty() ? "" : ", " + state.GetDebugMessage(), | state.GetDebugMessage().empty() ? "" : ", " + state.GetDebugMessage(), | ||||
state.GetRejectCode()); | state.GetRejectCode()); | ||||
} | } | ||||
▲ Show 20 Lines • Show All 831 Lines • ▼ Show 20 Lines | |||||
} | } | ||||
int GetSpendHeight(const CCoinsViewCache &inputs) { | int GetSpendHeight(const CCoinsViewCache &inputs) { | ||||
LOCK(cs_main); | LOCK(cs_main); | ||||
CBlockIndex *pindexPrev = mapBlockIndex.find(inputs.GetBestBlock())->second; | CBlockIndex *pindexPrev = mapBlockIndex.find(inputs.GetBestBlock())->second; | ||||
return pindexPrev->nHeight + 1; | return pindexPrev->nHeight + 1; | ||||
} | } | ||||
namespace Consensus { | |||||
bool CheckTxInputs(const CTransaction &tx, CValidationState &state, | |||||
const CCoinsViewCache &inputs, int nSpendHeight) { | |||||
// This doesn't trigger the DoS code on purpose; if it did, it would make it | |||||
// easier for an attacker to attempt to split the network. | |||||
if (!inputs.HaveInputs(tx)) { | |||||
return state.Invalid(false, 0, "", "Inputs unavailable"); | |||||
} | |||||
Amount nValueIn = Amount::zero(); | |||||
Amount nFees = Amount::zero(); | |||||
for (const auto &in : tx.vin) { | |||||
const COutPoint &prevout = in.prevout; | |||||
const Coin &coin = inputs.AccessCoin(prevout); | |||||
assert(!coin.IsSpent()); | |||||
// If prev is coinbase, check that it's matured | |||||
if (coin.IsCoinBase()) { | |||||
if (nSpendHeight - coin.GetHeight() < COINBASE_MATURITY) { | |||||
return state.Invalid( | |||||
false, REJECT_INVALID, | |||||
"bad-txns-premature-spend-of-coinbase", | |||||
strprintf("tried to spend coinbase at depth %d", | |||||
nSpendHeight - coin.GetHeight())); | |||||
} | |||||
} | |||||
// Check for negative or overflow input values | |||||
nValueIn += coin.GetTxOut().nValue; | |||||
if (!MoneyRange(coin.GetTxOut().nValue) || !MoneyRange(nValueIn)) { | |||||
return state.DoS(100, false, REJECT_INVALID, | |||||
"bad-txns-inputvalues-outofrange"); | |||||
} | |||||
} | |||||
if (nValueIn < tx.GetValueOut()) { | |||||
return state.DoS(100, false, REJECT_INVALID, "bad-txns-in-belowout", | |||||
false, strprintf("value in (%s) < value out (%s)", | |||||
FormatMoney(nValueIn), | |||||
FormatMoney(tx.GetValueOut()))); | |||||
} | |||||
// Tally transaction fees | |||||
Amount nTxFee = nValueIn - tx.GetValueOut(); | |||||
if (nTxFee < Amount::zero()) { | |||||
return state.DoS(100, false, REJECT_INVALID, "bad-txns-fee-negative"); | |||||
} | |||||
nFees += nTxFee; | |||||
if (!MoneyRange(nFees)) { | |||||
return state.DoS(100, false, REJECT_INVALID, "bad-txns-fee-outofrange"); | |||||
} | |||||
return true; | |||||
} | |||||
} // namespace Consensus | |||||
bool CheckInputs(const CTransaction &tx, CValidationState &state, | bool CheckInputs(const CTransaction &tx, CValidationState &state, | ||||
const CCoinsViewCache &inputs, bool fScriptChecks, | const CCoinsViewCache &inputs, bool fScriptChecks, | ||||
const uint32_t flags, bool sigCacheStore, | const uint32_t flags, bool sigCacheStore, | ||||
bool scriptCacheStore, | bool scriptCacheStore, | ||||
const PrecomputedTransactionData &txdata, | const PrecomputedTransactionData &txdata, | ||||
std::vector<CScriptCheck> *pvChecks) { | std::vector<CScriptCheck> *pvChecks) { | ||||
assert(!tx.IsCoinBase()); | assert(!tx.IsCoinBase()); | ||||
▲ Show 20 Lines • Show All 2,079 Lines • ▼ Show 20 Lines | if ((block.nVersion < 2 && nHeight >= consensusParams.BIP34Height) || | ||||
false, REJECT_OBSOLETE, | false, REJECT_OBSOLETE, | ||||
strprintf("bad-version(0x%08x)", block.nVersion), | strprintf("bad-version(0x%08x)", block.nVersion), | ||||
strprintf("rejected nVersion=0x%08x block", block.nVersion)); | strprintf("rejected nVersion=0x%08x block", block.nVersion)); | ||||
} | } | ||||
return true; | return true; | ||||
} | } | ||||
bool ContextualCheckTransaction(const Config &config, const CTransaction &tx, | |||||
CValidationState &state, int nHeight, | |||||
int64_t nLockTimeCutoff, | |||||
int64_t nMedianTimePast) { | |||||
if (!IsFinalTx(tx, nHeight, nLockTimeCutoff)) { | |||||
// While this is only one transaction, we use txns in the error to | |||||
// ensure continuity with other clients. | |||||
return state.DoS(10, false, REJECT_INVALID, "bad-txns-nonfinal", false, | |||||
"non-final transaction"); | |||||
} | |||||
if (IsMagneticAnomalyEnabled(config, nMedianTimePast)) { | |||||
// Size limit | |||||
if (::GetSerializeSize(tx, SER_NETWORK, PROTOCOL_VERSION) < | |||||
MIN_TX_SIZE) { | |||||
return state.DoS(100, false, REJECT_INVALID, "bad-txns-undersize"); | |||||
} | |||||
} | |||||
return true; | |||||
} | |||||
bool ContextualCheckTransactionForCurrentBlock(const Config &config, | bool ContextualCheckTransactionForCurrentBlock(const Config &config, | ||||
const CTransaction &tx, | const CTransaction &tx, | ||||
CValidationState &state, | CValidationState &state, | ||||
int flags) { | int flags) { | ||||
AssertLockHeld(cs_main); | AssertLockHeld(cs_main); | ||||
// By convention a negative value for flags indicates that the current | // By convention a negative value for flags indicates that the current | ||||
// network-enforced consensus rules should be used. In a future soft-fork | // network-enforced consensus rules should be used. In a future soft-fork | ||||
▲ Show 20 Lines • Show All 1,907 Lines • Show Last 20 Lines |