diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -473,6 +473,7 @@ config.cpp consensus/activation.cpp consensus/tx_verify.cpp + consensus/tx_check.cpp dbwrapper.cpp flatfile.cpp globals.cpp diff --git a/src/Makefile.am b/src/Makefile.am --- a/src/Makefile.am +++ b/src/Makefile.am @@ -145,6 +145,7 @@ config.h \ consensus/activation.h \ consensus/consensus.h \ + consensus/tx_check.h \ consensus/tx_verify.h \ core_io.h \ core_memusage.h \ @@ -430,6 +431,7 @@ consensus/merkle.cpp \ consensus/merkle.h \ consensus/params.h \ + consensus/tx_check.cpp \ consensus/validation.h \ feerate.h \ hash.cpp \ diff --git a/src/consensus/tx_check.h b/src/consensus/tx_check.h new file mode 100644 --- /dev/null +++ b/src/consensus/tx_check.h @@ -0,0 +1,26 @@ +// 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. + +#ifndef BITCOIN_CONSENSUS_TX_CHECK_H +#define BITCOIN_CONSENSUS_TX_CHECK_H + +/** + * Context-independent transaction checking code that can be called outside the + * bitcoin server and doesn't depend on chain or mempool state. Transaction + * verification code that does call server functions or depend on server state + * belongs in tx_verify.h/cpp instead. + */ + +class CTransaction; +class CValidationState; + +/** + * Context-independent validity checks for coinbase and non-coinbase + * transactions. + */ + +bool CheckRegularTransaction(const CTransaction &tx, CValidationState &state); +bool CheckCoinbase(const CTransaction &tx, CValidationState &state); + +#endif // BITCOIN_CONSENSUS_TX_CHECK_H diff --git a/src/consensus/tx_check.cpp b/src/consensus/tx_check.cpp new file mode 100644 --- /dev/null +++ b/src/consensus/tx_check.cpp @@ -0,0 +1,95 @@ +// 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 + +#include + +static bool CheckTransactionCommon(const CTransaction &tx, + CValidationState &state) { + // 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, 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"); + } + } + + return true; +} + +bool CheckCoinbase(const CTransaction &tx, CValidationState &state) { + if (!tx.IsCoinBase()) { + return state.DoS(100, false, REJECT_INVALID, "bad-cb-missing", false, + "first tx is not coinbase"); + } + + if (!CheckTransactionCommon(tx, state)) { + // 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) { + if (tx.IsCoinBase()) { + return state.DoS(100, false, REJECT_INVALID, "bad-tx-coinbase"); + } + + if (!CheckTransactionCommon(tx, state)) { + // CheckTransactionCommon fill in the state. + return false; + } + + std::unordered_set vInOutPoints; + for (const auto &txin : tx.vin) { + if (txin.prevout.IsNull()) { + return state.DoS(10, false, REJECT_INVALID, + "bad-txns-prevout-null"); + } + + if (!vInOutPoints.insert(txin.prevout).second) { + return state.DoS(100, false, REJECT_INVALID, + "bad-txns-inputs-duplicate"); + } + } + + return true; +} diff --git a/src/consensus/tx_verify.h b/src/consensus/tx_verify.h --- a/src/consensus/tx_verify.h +++ b/src/consensus/tx_verify.h @@ -14,13 +14,6 @@ class CTransaction; class CValidationState; -/** - * Context-independent validity checks for coinbase and non-coinbase - * transactions. - */ -bool CheckRegularTransaction(const CTransaction &tx, CValidationState &state); -bool CheckCoinbase(const CTransaction &tx, CValidationState &state); - namespace Consensus { struct Params; diff --git a/src/consensus/tx_verify.cpp b/src/consensus/tx_verify.cpp --- a/src/consensus/tx_verify.cpp +++ b/src/consensus/tx_verify.cpp @@ -186,90 +186,6 @@ GetP2SHSigOpCount(tx, view, flags); } -static bool CheckTransactionCommon(const CTransaction &tx, - CValidationState &state) { - // 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, 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"); - } - } - - return true; -} - -bool CheckCoinbase(const CTransaction &tx, CValidationState &state) { - if (!tx.IsCoinBase()) { - return state.DoS(100, false, REJECT_INVALID, "bad-cb-missing", false, - "first tx is not coinbase"); - } - - if (!CheckTransactionCommon(tx, state)) { - // 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) { - if (tx.IsCoinBase()) { - return state.DoS(100, false, REJECT_INVALID, "bad-tx-coinbase"); - } - - if (!CheckTransactionCommon(tx, state)) { - // CheckTransactionCommon fill in the state. - return false; - } - - std::unordered_set vInOutPoints; - for (const auto &txin : tx.vin) { - if (txin.prevout.IsNull()) { - return state.DoS(10, false, REJECT_INVALID, - "bad-txns-prevout-null"); - } - - if (!vInOutPoints.insert(txin.prevout).second) { - return state.DoS(100, false, REJECT_INVALID, - "bad-txns-inputs-duplicate"); - } - } - - return true; -} - namespace Consensus { bool CheckTxInputs(const CTransaction &tx, CValidationState &state, const CCoinsViewCache &inputs, int nSpendHeight, 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,7 +2,7 @@ // 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