diff --git a/src/consensus/consensus.h b/src/consensus/consensus.h index e7f4e02f3..0d1a3fdde 100644 --- a/src/consensus/consensus.h +++ b/src/consensus/consensus.h @@ -10,6 +10,8 @@ static const unsigned int MAX_BLOCK_SIZE = 2000000; /** The maximum allowed number of signature check operations in a block (network rule) */ static const unsigned int MAX_BLOCK_SIGOPS = 20000; +/** The maximum size of a transaction (network rule) */ +static const unsigned int MAX_TX_SIZE = 100000; /** Coinbase transaction outputs can only be spent after this number of new blocks (network rule) */ static const int COINBASE_MATURITY = 100; diff --git a/src/gtest/test_checktransaction.cpp b/src/gtest/test_checktransaction.cpp index 0030af756..7dd1b86d2 100644 --- a/src/gtest/test_checktransaction.cpp +++ b/src/gtest/test_checktransaction.cpp @@ -121,17 +121,30 @@ TEST(checktransaction_tests, bad_txns_oversize) { CMutableTransaction mtx = GetValidTransaction(); mtx.vin[0].scriptSig = CScript(); - // 18 * (520char + DROP) + OP_1 = 9433 bytes std::vector vchData(520); - for (unsigned int i = 0; i < 4000; ++i) + for (unsigned int i = 0; i < 190; ++i) mtx.vin[0].scriptSig << vchData << OP_DROP; mtx.vin[0].scriptSig << OP_1; - CTransaction tx(mtx); + { + // Transaction is just under the limit... + CTransaction tx(mtx); + CValidationState state; + ASSERT_TRUE(CheckTransactionWithoutProofVerification(tx, state)); + } - MockCValidationState state; - EXPECT_CALL(state, DoS(100, false, REJECT_INVALID, "bad-txns-oversize", false)).Times(1); - CheckTransactionWithoutProofVerification(tx, state); + // Not anymore! + mtx.vin[1].scriptSig << vchData << OP_DROP; + mtx.vin[1].scriptSig << OP_1; + + { + CTransaction tx(mtx); + ASSERT_EQ(::GetSerializeSize(tx, SER_NETWORK, PROTOCOL_VERSION), 100202); + + MockCValidationState state; + EXPECT_CALL(state, DoS(100, false, REJECT_INVALID, "bad-txns-oversize", false)).Times(1); + CheckTransactionWithoutProofVerification(tx, state); + } } TEST(checktransaction_tests, bad_txns_vout_negative) { diff --git a/src/main.cpp b/src/main.cpp index 93e7e16c6..35bda48be 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -644,16 +644,6 @@ bool IsStandardTx(const CTransaction& tx, string& reason) return false; } - // Extremely large transactions with lots of inputs can cost the network - // almost as much to process as they cost the sender in fees, because - // computing signature hashes is O(ninputs*txsize). Limiting transactions - // to MAX_STANDARD_TX_SIZE mitigates CPU exhaustion attacks. - unsigned int sz = tx.GetSerializeSize(SER_NETWORK, CTransaction::CURRENT_VERSION); - if (sz >= MAX_STANDARD_TX_SIZE) { - reason = "tx-size"; - return false; - } - BOOST_FOREACH(const CTxIn& txin, tx.vin) { // Biggest 'standard' txin is a 15-of-15 P2SH multisig with compressed @@ -871,7 +861,8 @@ bool CheckTransactionWithoutProofVerification(const CTransaction& tx, CValidatio REJECT_INVALID, "bad-txns-vout-empty"); // Size limits - if (::GetSerializeSize(tx, SER_NETWORK, PROTOCOL_VERSION) > MAX_BLOCK_SIZE) + BOOST_STATIC_ASSERT(MAX_BLOCK_SIZE > MAX_TX_SIZE); // sanity + if (::GetSerializeSize(tx, SER_NETWORK, PROTOCOL_VERSION) > MAX_TX_SIZE) return state.DoS(100, error("CheckTransaction(): size limits failed"), REJECT_INVALID, "bad-txns-oversize"); diff --git a/src/main.h b/src/main.h index 2953162fe..aec92435c 100644 --- a/src/main.h +++ b/src/main.h @@ -56,8 +56,6 @@ static const unsigned int DEFAULT_BLOCK_PRIORITY_SIZE = 50000; static const bool DEFAULT_ALERTS = true; /** Minimum alert priority for enabling safe mode. */ static const int ALERT_PRIORITY_SAFE_MODE = 4000; -/** The maximum size for transactions we're willing to relay/mine */ -static const unsigned int MAX_STANDARD_TX_SIZE = 100000; /** Maximum number of signature check operations in an IsStandard() P2SH script */ static const unsigned int MAX_P2SH_SIGOPS = 15; /** The maximum number of sigops we're willing to relay/mine in a single tx */ diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index 87deb0241..495572bb0 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -2471,7 +2471,7 @@ bool CWallet::CreateTransaction(const vector& vecSend, // Limit size unsigned int nBytes = ::GetSerializeSize(*(CTransaction*)&wtxNew, SER_NETWORK, PROTOCOL_VERSION); - if (nBytes >= MAX_STANDARD_TX_SIZE) + if (nBytes >= MAX_TX_SIZE) { strFailReason = _("Transaction too large"); return false; diff --git a/src/zcbenchmarks.cpp b/src/zcbenchmarks.cpp index 015b93209..6ea99993c 100644 --- a/src/zcbenchmarks.cpp +++ b/src/zcbenchmarks.cpp @@ -164,7 +164,7 @@ double benchmark_verify_equihash() double benchmark_large_tx() { // Number of inputs in the spending transaction that we will simulate - const size_t NUM_INPUTS = 11100; + const size_t NUM_INPUTS = 555; // Create priv/pub key CKey priv; @@ -201,9 +201,9 @@ double benchmark_large_tx() ss << spending_tx; //std::cout << "SIZE OF SPENDING TX: " << ss.size() << std::endl; - auto error = MAX_BLOCK_SIZE / 20; // 5% error - assert(ss.size() < MAX_BLOCK_SIZE + error); - assert(ss.size() > MAX_BLOCK_SIZE - error); + auto error = MAX_TX_SIZE / 20; // 5% error + assert(ss.size() < MAX_TX_SIZE + error); + assert(ss.size() > MAX_TX_SIZE - error); } // Spending tx has all its inputs signed and does not need to be mutated anymore