Auto merge of #1501 - ebfull:100kb-max-tx, r=ebfull
Make 100KB transaction size limit a consensus rule, rather than a standard rule Closes #1475
This commit is contained in:
commit
4210e20c9c
|
@ -10,6 +10,8 @@
|
||||||
static const unsigned int MAX_BLOCK_SIZE = 2000000;
|
static const unsigned int MAX_BLOCK_SIZE = 2000000;
|
||||||
/** The maximum allowed number of signature check operations in a block (network rule) */
|
/** The maximum allowed number of signature check operations in a block (network rule) */
|
||||||
static const unsigned int MAX_BLOCK_SIGOPS = 20000;
|
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) */
|
/** Coinbase transaction outputs can only be spent after this number of new blocks (network rule) */
|
||||||
static const int COINBASE_MATURITY = 100;
|
static const int COINBASE_MATURITY = 100;
|
||||||
|
|
||||||
|
|
|
@ -121,18 +121,31 @@ TEST(checktransaction_tests, bad_txns_oversize) {
|
||||||
CMutableTransaction mtx = GetValidTransaction();
|
CMutableTransaction mtx = GetValidTransaction();
|
||||||
|
|
||||||
mtx.vin[0].scriptSig = CScript();
|
mtx.vin[0].scriptSig = CScript();
|
||||||
// 18 * (520char + DROP) + OP_1 = 9433 bytes
|
|
||||||
std::vector<unsigned char> vchData(520);
|
std::vector<unsigned char> 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 << vchData << OP_DROP;
|
||||||
mtx.vin[0].scriptSig << OP_1;
|
mtx.vin[0].scriptSig << OP_1;
|
||||||
|
|
||||||
|
{
|
||||||
|
// Transaction is just under the limit...
|
||||||
CTransaction tx(mtx);
|
CTransaction tx(mtx);
|
||||||
|
CValidationState state;
|
||||||
|
ASSERT_TRUE(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;
|
MockCValidationState state;
|
||||||
EXPECT_CALL(state, DoS(100, false, REJECT_INVALID, "bad-txns-oversize", false)).Times(1);
|
EXPECT_CALL(state, DoS(100, false, REJECT_INVALID, "bad-txns-oversize", false)).Times(1);
|
||||||
CheckTransactionWithoutProofVerification(tx, state);
|
CheckTransactionWithoutProofVerification(tx, state);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
TEST(checktransaction_tests, bad_txns_vout_negative) {
|
TEST(checktransaction_tests, bad_txns_vout_negative) {
|
||||||
CMutableTransaction mtx = GetValidTransaction();
|
CMutableTransaction mtx = GetValidTransaction();
|
||||||
|
|
13
src/main.cpp
13
src/main.cpp
|
@ -644,16 +644,6 @@ bool IsStandardTx(const CTransaction& tx, string& reason)
|
||||||
return false;
|
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)
|
BOOST_FOREACH(const CTxIn& txin, tx.vin)
|
||||||
{
|
{
|
||||||
// Biggest 'standard' txin is a 15-of-15 P2SH multisig with compressed
|
// 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");
|
REJECT_INVALID, "bad-txns-vout-empty");
|
||||||
|
|
||||||
// Size limits
|
// 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"),
|
return state.DoS(100, error("CheckTransaction(): size limits failed"),
|
||||||
REJECT_INVALID, "bad-txns-oversize");
|
REJECT_INVALID, "bad-txns-oversize");
|
||||||
|
|
||||||
|
|
|
@ -56,8 +56,6 @@ static const unsigned int DEFAULT_BLOCK_PRIORITY_SIZE = 50000;
|
||||||
static const bool DEFAULT_ALERTS = true;
|
static const bool DEFAULT_ALERTS = true;
|
||||||
/** Minimum alert priority for enabling safe mode. */
|
/** Minimum alert priority for enabling safe mode. */
|
||||||
static const int ALERT_PRIORITY_SAFE_MODE = 4000;
|
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 */
|
/** Maximum number of signature check operations in an IsStandard() P2SH script */
|
||||||
static const unsigned int MAX_P2SH_SIGOPS = 15;
|
static const unsigned int MAX_P2SH_SIGOPS = 15;
|
||||||
/** The maximum number of sigops we're willing to relay/mine in a single tx */
|
/** The maximum number of sigops we're willing to relay/mine in a single tx */
|
||||||
|
|
|
@ -2471,7 +2471,7 @@ bool CWallet::CreateTransaction(const vector<CRecipient>& vecSend,
|
||||||
|
|
||||||
// Limit size
|
// Limit size
|
||||||
unsigned int nBytes = ::GetSerializeSize(*(CTransaction*)&wtxNew, SER_NETWORK, PROTOCOL_VERSION);
|
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");
|
strFailReason = _("Transaction too large");
|
||||||
return false;
|
return false;
|
||||||
|
|
|
@ -164,7 +164,7 @@ double benchmark_verify_equihash()
|
||||||
double benchmark_large_tx()
|
double benchmark_large_tx()
|
||||||
{
|
{
|
||||||
// Number of inputs in the spending transaction that we will simulate
|
// 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
|
// Create priv/pub key
|
||||||
CKey priv;
|
CKey priv;
|
||||||
|
@ -201,9 +201,9 @@ double benchmark_large_tx()
|
||||||
ss << spending_tx;
|
ss << spending_tx;
|
||||||
//std::cout << "SIZE OF SPENDING TX: " << ss.size() << std::endl;
|
//std::cout << "SIZE OF SPENDING TX: " << ss.size() << std::endl;
|
||||||
|
|
||||||
auto error = MAX_BLOCK_SIZE / 20; // 5% error
|
auto error = MAX_TX_SIZE / 20; // 5% error
|
||||||
assert(ss.size() < MAX_BLOCK_SIZE + error);
|
assert(ss.size() < MAX_TX_SIZE + error);
|
||||||
assert(ss.size() > MAX_BLOCK_SIZE - error);
|
assert(ss.size() > MAX_TX_SIZE - error);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Spending tx has all its inputs signed and does not need to be mutated anymore
|
// Spending tx has all its inputs signed and does not need to be mutated anymore
|
||||||
|
|
Loading…
Reference in New Issue