diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -182,6 +182,7 @@ checkpoints.cpp config.cpp consensus/activation.cpp + consensus/tx_verify.cpp globals.cpp httprpc.cpp httpserver.cpp diff --git a/src/Makefile.am b/src/Makefile.am --- a/src/Makefile.am +++ b/src/Makefile.am @@ -113,6 +113,7 @@ config.h \ consensus/activation.h \ consensus/consensus.h \ + consensus/tx_verify.h \ core_io.h \ core_memusage.h \ cuckoocache.h \ @@ -213,6 +214,7 @@ checkpoints.cpp \ config.cpp \ consensus/activation.cpp \ + consensus/tx_verify.cpp \ globals.cpp \ httprpc.cpp \ httpserver.cpp \ diff --git a/src/consensus/tx_verify.h b/src/consensus/tx_verify.h new file mode 100644 --- /dev/null +++ b/src/consensus/tx_verify.h @@ -0,0 +1,102 @@ +// Copyright (c) 2018 The Bitcoin developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#ifndef BITCOIN_CONSENSUS_TX_VERIFY_H +#define BITCOIN_CONSENSUS_TX_VERIFY_H + +#include +#include + +class CBlockIndex; +class CCoinsViewCache; +class Config; +class CTransaction; +class CValidationState; + +/** + * Context-independent validity checks for coinbase and non-coinbase + * transactions. + */ +bool CheckRegularTransaction(const CTransaction &tx, CValidationState &state, + bool fCheckDuplicateInputs = true); +bool CheckCoinbase(const CTransaction &tx, CValidationState &state, + bool fCheckDuplicateInputs = true); + +namespace Consensus { + +/** + * Check whether all inputs of this transaction are valid (no double spends and + * amounts). This does not modify the UTXO set. This does not check scripts and + * sigs. Preconditions: tx.IsCoinBase() is false. + */ +bool CheckTxInputs(const CTransaction &tx, CValidationState &state, + const CCoinsViewCache &inputs, int nSpendHeight); + +} // namespace Consensus + +/** + * Context dependent validity checks for non coinbase transactions. This + * doesn't check the validity of the transaction against the UTXO set, but + * simply characteristic that are suceptible to change over time such as feature + * activation/deactivation and CLTV. + */ +bool ContextualCheckTransaction(const Config &config, const CTransaction &tx, + CValidationState &state, int nHeight, + int64_t nLockTimeCutoff, + int64_t nMedianTimePast); + +/** + * 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. + */ +std::pair CalculateSequenceLocks(const CTransaction &tx, + int flags, + std::vector *prevHeights, + const CBlockIndex &block); + +bool EvaluateSequenceLocks(const CBlockIndex &block, + std::pair lockPair); + +/** + * Check if transaction is final per BIP 68 sequence numbers and can be included + * in a block. Consensus critical. Takes as input a list of heights at which + * tx's inputs (in order) confirmed. + */ +bool SequenceLocks(const CTransaction &tx, int flags, + std::vector *prevHeights, const CBlockIndex &block); + +/** + * Count ECDSA signature operations the old-fashioned (pre-0.6) way + * @return number of sigops this transaction's outputs will produce when spent + * @see CTransaction::FetchInputs + */ +uint64_t GetSigOpCountWithoutP2SH(const CTransaction &tx, uint32_t flags); + +/** + * Count ECDSA signature operations in pay-to-script-hash inputs. + * + * @param[in] mapInputs Map of previous transactions that have outputs we're + * spending + * @return maximum number of sigops required to validate this transaction's + * inputs + * @see CTransaction::FetchInputs + */ +uint64_t GetP2SHSigOpCount(const CTransaction &tx, + const CCoinsViewCache &mapInputs, uint32_t flags); + +/** + * Compute total signature operation of a transaction. + * @param[in] tx Transaction for which we are computing the cost + * @param[in] inputs Map of previous transactions that have outputs we're + * spending + * @param[in] flags Script verification flags + * @return Total signature operation cost of tx + */ +uint64_t GetTransactionSigOpCount(const CTransaction &tx, + const CCoinsViewCache &inputs, + uint32_t flags); + +#endif // BITCOIN_CONSENSUS_TX_VERIFY_H diff --git a/src/consensus/tx_verify.cpp b/src/consensus/tx_verify.cpp new file mode 100644 --- /dev/null +++ b/src/consensus/tx_verify.cpp @@ -0,0 +1,341 @@ +// Copyright (c) 2018 The Bitcoin developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include "tx_verify.h" + +#include "chain.h" +#include "coins.h" +#include "consensus/activation.h" +#include "consensus/consensus.h" +#include "consensus/validation.h" +#include "primitives/transaction.h" +#include "script/script_flags.h" +#include "utilmoneystr.h" // For FormatMoney +#include "version.h" // For PROTOCOL_VERSION + +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; +} + +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; +} + +/** + * 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. + */ +std::pair CalculateSequenceLocks(const CTransaction &tx, + int flags, + std::vector *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(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); +} + +bool EvaluateSequenceLocks(const CBlockIndex &block, + std::pair 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 *prevHeights, const CBlockIndex &block) { + return EvaluateSequenceLocks( + block, CalculateSequenceLocks(tx, flags, prevHeights, block)); +} + +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, SCRIPT_ENABLE_CHECKDATASIG) > + 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 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; +} + +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 diff --git a/src/miner.cpp b/src/miner.cpp --- a/src/miner.cpp +++ b/src/miner.cpp @@ -13,6 +13,7 @@ #include "consensus/activation.h" #include "consensus/consensus.h" #include "consensus/merkle.h" +#include "consensus/tx_verify.h" #include "consensus/validation.h" #include "hash.h" #include "net.h" diff --git a/src/test/miner_tests.cpp b/src/test/miner_tests.cpp --- a/src/test/miner_tests.cpp +++ b/src/test/miner_tests.cpp @@ -10,6 +10,7 @@ #include "config.h" #include "consensus/consensus.h" #include "consensus/merkle.h" +#include "consensus/tx_verify.h" #include "consensus/validation.h" #include "policy/policy.h" #include "pubkey.h" diff --git a/src/test/script_P2SH_tests.cpp b/src/test/script_P2SH_tests.cpp --- a/src/test/script_P2SH_tests.cpp +++ b/src/test/script_P2SH_tests.cpp @@ -2,6 +2,7 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. +#include "consensus/tx_verify.h" #include "core_io.h" #include "key.h" #include "keystore.h" diff --git a/src/test/sighash_tests.cpp b/src/test/sighash_tests.cpp --- a/src/test/sighash_tests.cpp +++ b/src/test/sighash_tests.cpp @@ -2,6 +2,7 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. +#include "consensus/tx_verify.h" #include "consensus/validation.h" #include "data/sighash.json.h" #include "hash.h" @@ -13,7 +14,6 @@ #include "test/test_bitcoin.h" #include "util.h" #include "utilstrencodings.h" -#include "validation.h" // For CheckRegularTransaction #include "version.h" #include diff --git a/src/test/sigopcount_tests.cpp b/src/test/sigopcount_tests.cpp --- a/src/test/sigopcount_tests.cpp +++ b/src/test/sigopcount_tests.cpp @@ -3,6 +3,7 @@ // file COPYING or http://www.opensource.org/licenses/mit-license.php. #include "consensus/consensus.h" +#include "consensus/tx_verify.h" #include "consensus/validation.h" #include "key.h" #include "policy/policy.h" // For STANDARD_CHECKDATASIG_VERIFY_FLAGS. @@ -12,7 +13,6 @@ #include "script/standard.h" #include "test/test_bitcoin.h" #include "uint256.h" -#include "validation.h" #include #include diff --git a/src/test/transaction_tests.cpp b/src/test/transaction_tests.cpp --- a/src/test/transaction_tests.cpp +++ b/src/test/transaction_tests.cpp @@ -11,6 +11,7 @@ #include "checkqueue.h" #include "clientversion.h" #include "config.h" +#include "consensus/tx_verify.h" #include "consensus/validation.h" #include "core_io.h" #include "key.h" @@ -23,7 +24,7 @@ #include "test/jsonutil.h" #include "test/scriptflags.h" #include "utilstrencodings.h" -#include "validation.h" // For CheckRegularTransaction and ContextualCheckTransaction +#include "validation.h" #include #include diff --git a/src/txmempool.cpp b/src/txmempool.cpp --- a/src/txmempool.cpp +++ b/src/txmempool.cpp @@ -8,6 +8,7 @@ #include "chainparams.h" // for GetConsensus. #include "clientversion.h" #include "consensus/consensus.h" +#include "consensus/tx_verify.h" #include "consensus/validation.h" #include "policy/fees.h" #include "policy/policy.h" diff --git a/src/validation.h b/src/validation.h --- a/src/validation.h +++ b/src/validation.h @@ -449,37 +449,6 @@ /** Convert CValidationState to a human-readable message for logging */ std::string FormatStateMessage(const CValidationState &state); -/** - * Count ECDSA signature operations the old-fashioned (pre-0.6) way - * @return number of sigops this transaction's outputs will produce when spent - * @see CTransaction::FetchInputs - */ -uint64_t GetSigOpCountWithoutP2SH(const CTransaction &tx, uint32_t flags); - -/** - * Count ECDSA signature operations in pay-to-script-hash inputs. - * - * @param[in] mapInputs Map of previous transactions that have outputs we're - * spending - * @return maximum number of sigops required to validate this transaction's - * inputs - * @see CTransaction::FetchInputs - */ -uint64_t GetP2SHSigOpCount(const CTransaction &tx, - const CCoinsViewCache &mapInputs, uint32_t flags); - -/** - * Compute total signature operation of a transaction. - * @param[in] tx Transaction for which we are computing the cost - * @param[in] inputs Map of previous transactions that have outputs we're - * spending - * @param[in] flags Script verification flags - * @return Total signature operation cost of tx - */ -uint64_t GetTransactionSigOpCount(const CTransaction &tx, - const CCoinsViewCache &inputs, - uint32_t flags); - /** * Check whether all inputs of this transaction are valid (no double spends, * scripts & sigs, amounts). This does not modify the UTXO set. @@ -512,43 +481,12 @@ void UpdateCoins(CCoinsViewCache &view, const CTransaction &tx, CTxUndo &txundo, int nHeight); -/** Transaction validation functions */ - -/** - * Context-independent validity checks for coinbase and non-coinbase - * transactions. - */ -bool CheckRegularTransaction(const CTransaction &tx, CValidationState &state, - bool fCheckDuplicateInputs = true); -bool CheckCoinbase(const CTransaction &tx, CValidationState &state, - bool fCheckDuplicateInputs = true); - -namespace Consensus { - -/** - * Check whether all inputs of this transaction are valid (no double spends and - * amounts). This does not modify the UTXO set. This does not check scripts and - * sigs. Preconditions: tx.IsCoinBase() is false. - */ -bool CheckTxInputs(const CTransaction &tx, CValidationState &state, - const CCoinsViewCache &inputs, int nSpendHeight); - -} // namespace Consensus - /** * Test whether the LockPoints height and time are still valid on the current * chain. */ bool TestLockPointValidity(const LockPoints *lp); -/** - * Check if transaction is final per BIP 68 sequence numbers and can be included - * in a block. Consensus critical. Takes as input a list of heights at which - * tx's inputs (in order) confirmed. - */ -bool SequenceLocks(const CTransaction &tx, int flags, - std::vector *prevHeights, const CBlockIndex &block); - /** * Check if transaction will be BIP 68 final in the next block to be created. * @@ -626,17 +564,6 @@ const Config &Config, const CBlock &block, CValidationState &state, BlockValidationOptions validationOptions = BlockValidationOptions()); -/** - * Context dependent validity checks for non coinbase transactions. This - * doesn't check the validity of the transaction against the UTXO set, but - * simply characteristic that are suceptible to change over time such as feature - * activation/deactivation and CLTV. - */ -bool ContextualCheckTransaction(const Config &config, const CTransaction &tx, - CValidationState &state, int nHeight, - int64_t nLockTimeCutoff, - int64_t nMedianTimePast); - /** * This is a variant of ContextualCheckTransaction which computes the contextual * check for a transaction based on the chain tip. diff --git a/src/validation.cpp b/src/validation.cpp --- a/src/validation.cpp +++ b/src/validation.cpp @@ -16,6 +16,7 @@ #include "consensus/activation.h" #include "consensus/consensus.h" #include "consensus/merkle.h" +#include "consensus/tx_verify.h" #include "consensus/validation.h" #include "fs.h" #include "hash.h" @@ -180,121 +181,6 @@ static uint32_t GetBlockScriptFlags(const Config &config, 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 -CalculateSequenceLocks(const CTransaction &tx, int flags, - std::vector *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(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 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 *prevHeights, const CBlockIndex &block) { - return EvaluateSequenceLocks( - block, CalculateSequenceLocks(tx, flags, prevHeights, block)); -} - bool TestLockPointValidity(const LockPoints *lp) { AssertLockHeld(cs_main); assert(lp); @@ -383,138 +269,6 @@ 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 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 */ std::string FormatStateMessage(const CValidationState &state) { return strprintf( @@ -1362,63 +1116,6 @@ 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, const CCoinsViewCache &inputs, bool fScriptChecks, const uint32_t flags, bool sigCacheStore, @@ -3514,28 +3211,6 @@ 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, const CTransaction &tx, CValidationState &state, diff --git a/src/wallet/walletdb.cpp b/src/wallet/walletdb.cpp --- a/src/wallet/walletdb.cpp +++ b/src/wallet/walletdb.cpp @@ -7,6 +7,7 @@ #include "wallet/walletdb.h" #include "base58.h" +#include "consensus/tx_verify.h" #include "consensus/validation.h" #include "dstencode.h" #include "fs.h" @@ -15,7 +16,6 @@ #include "sync.h" #include "util.h" #include "utiltime.h" -#include "validation.h" // For CheckRegularTransaction #include "wallet/wallet.h" #include