// Copyright (c) 2017-2018 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. #include #include #include #include #include bool CheckTransaction(const CTransaction& tx, CValidationState& state) { bool allowEmptyTxInOut = false; if (tx.nType == TRANSACTION_QUORUM_COMMITMENT) { allowEmptyTxInOut = true; } // Basic checks that don't depend on any context if (!allowEmptyTxInOut && tx.vin.empty()) return state.DoS(10, false, REJECT_INVALID, "bad-txns-vin-empty"); if (!allowEmptyTxInOut && tx.vout.empty()) return state.DoS(10, false, REJECT_INVALID, "bad-txns-vout-empty"); // Size limits if (::GetSerializeSize(tx, SER_NETWORK, PROTOCOL_VERSION) > MAX_LEGACY_BLOCK_SIZE) return state.DoS(100, false, REJECT_INVALID, "bad-txns-oversize"); if (tx.vExtraPayload.size() > MAX_TX_EXTRA_PAYLOAD) return state.DoS(100, false, REJECT_INVALID, "bad-txns-payload-oversize"); // Check for negative or overflow output values (see CVE-2010-5139) CAmount nValueOut = 0; for (const auto& txout : tx.vout) { if (txout.nValue < 0) 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"); } // Check for duplicate inputs 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"); } if (tx.IsCoinBase()) { size_t minCbSize = 2; if (tx.nType == TRANSACTION_COINBASE) { // With the introduction of CbTx, coinbase scripts are not required anymore to hold a valid block height minCbSize = 1; } if (tx.vin[0].scriptSig.size() < minCbSize || tx.vin[0].scriptSig.size() > 100) return state.DoS(100, false, REJECT_INVALID, "bad-cb-length"); } else { for (const auto& txin : tx.vin) if (txin.prevout.IsNull()) return state.DoS(10, false, REJECT_INVALID, "bad-txns-prevout-null"); } return true; }