Browse Source

Log reason for non-standard transaction rejection

miguelfreitas
Jeff Garzik 12 years ago
parent
commit
980bfe6ef8
  1. 37
      src/main.cpp
  2. 2
      src/main.h
  3. 8
      src/test/script_P2SH_tests.cpp
  4. 9
      src/test/transaction_tests.cpp

37
src/main.cpp

@ -457,38 +457,53 @@ unsigned int LimitOrphanTxSize(unsigned int nMaxOrphans)
bool IsStandardTx(const CTransaction& tx) bool IsStandardTx(const CTransaction& tx, string& reason)
{ {
if (tx.nVersion > CTransaction::CURRENT_VERSION) if (tx.nVersion > CTransaction::CURRENT_VERSION) {
reason = "version";
return false; return false;
}
if (!IsFinalTx(tx)) if (!IsFinalTx(tx)) {
reason = "non-final";
return false; return false;
}
// Extremely large transactions with lots of inputs can cost the network // Extremely large transactions with lots of inputs can cost the network
// almost as much to process as they cost the sender in fees, because // almost as much to process as they cost the sender in fees, because
// computing signature hashes is O(ninputs*txsize). Limiting transactions // computing signature hashes is O(ninputs*txsize). Limiting transactions
// to MAX_STANDARD_TX_SIZE mitigates CPU exhaustion attacks. // to MAX_STANDARD_TX_SIZE mitigates CPU exhaustion attacks.
unsigned int sz = tx.GetSerializeSize(SER_NETWORK, CTransaction::CURRENT_VERSION); unsigned int sz = tx.GetSerializeSize(SER_NETWORK, CTransaction::CURRENT_VERSION);
if (sz >= MAX_STANDARD_TX_SIZE) if (sz >= MAX_STANDARD_TX_SIZE) {
reason = "tx-size";
return false; return false;
}
BOOST_FOREACH(const CTxIn& txin, tx.vin) BOOST_FOREACH(const CTxIn& txin, tx.vin)
{ {
// Biggest 'standard' txin is a 3-signature 3-of-3 CHECKMULTISIG // Biggest 'standard' txin is a 3-signature 3-of-3 CHECKMULTISIG
// pay-to-script-hash, which is 3 ~80-byte signatures, 3 // pay-to-script-hash, which is 3 ~80-byte signatures, 3
// ~65-byte public keys, plus a few script ops. // ~65-byte public keys, plus a few script ops.
if (txin.scriptSig.size() > 500) if (txin.scriptSig.size() > 500) {
reason = "scriptsig-size";
return false; return false;
if (!txin.scriptSig.IsPushOnly()) }
if (!txin.scriptSig.IsPushOnly()) {
reason = "scriptsig-not-pushonly";
return false; return false;
}
} }
BOOST_FOREACH(const CTxOut& txout, tx.vout) { BOOST_FOREACH(const CTxOut& txout, tx.vout) {
if (!::IsStandard(txout.scriptPubKey)) if (!::IsStandard(txout.scriptPubKey)) {
reason = "scriptpubkey";
return false; return false;
if (txout.IsDust(CTransaction::nMinRelayTxFee)) }
if (txout.IsDust(CTransaction::nMinRelayTxFee)) {
reason = "dust";
return false; return false;
}
} }
return true; return true;
} }
@ -782,8 +797,10 @@ bool CTxMemPool::accept(CValidationState &state, CTransaction &tx, bool fLimitFr
return error("CTxMemPool::accept() : not accepting nLockTime beyond 2038 yet"); return error("CTxMemPool::accept() : not accepting nLockTime beyond 2038 yet");
// Rather not work on nonstandard transactions (unless -testnet) // Rather not work on nonstandard transactions (unless -testnet)
if (!TestNet() && !IsStandardTx(tx)) string reason;
return error("CTxMemPool::accept() : nonstandard transaction type"); if (!TestNet() && !IsStandardTx(tx, reason))
return error("CTxMemPool::accept() : nonstandard transaction: %s",
reason.c_str());
// is it already in the memory pool? // is it already in the memory pool?
uint256 hash = tx.GetHash(); uint256 hash = tx.GetHash();

2
src/main.h

@ -324,7 +324,7 @@ bool CheckTransaction(const CTransaction& tx, CValidationState& state);
/** Check for standard transaction types /** Check for standard transaction types
@return True if all outputs (scriptPubKeys) use only standard transaction forms @return True if all outputs (scriptPubKeys) use only standard transaction forms
*/ */
bool IsStandardTx(const CTransaction& tx); bool IsStandardTx(const CTransaction& tx, std::string& reason);
bool IsFinalTx(const CTransaction &tx, int nBlockHeight = 0, int64 nBlockTime = 0); bool IsFinalTx(const CTransaction &tx, int nBlockHeight = 0, int64 nBlockTime = 0);

8
src/test/script_P2SH_tests.cpp

@ -74,6 +74,7 @@ BOOST_AUTO_TEST_CASE(sign)
} }
CTransaction txFrom; // Funding transaction: CTransaction txFrom; // Funding transaction:
string reason;
txFrom.vout.resize(8); txFrom.vout.resize(8);
for (int i = 0; i < 4; i++) for (int i = 0; i < 4; i++)
{ {
@ -82,7 +83,7 @@ BOOST_AUTO_TEST_CASE(sign)
txFrom.vout[i+4].scriptPubKey = standardScripts[i]; txFrom.vout[i+4].scriptPubKey = standardScripts[i];
txFrom.vout[i+4].nValue = COIN; txFrom.vout[i+4].nValue = COIN;
} }
BOOST_CHECK(IsStandardTx(txFrom)); BOOST_CHECK(IsStandardTx(txFrom, reason));
CTransaction txTo[8]; // Spending transactions CTransaction txTo[8]; // Spending transactions
for (int i = 0; i < 8; i++) for (int i = 0; i < 8; i++)
@ -167,13 +168,14 @@ BOOST_AUTO_TEST_CASE(set)
} }
CTransaction txFrom; // Funding transaction: CTransaction txFrom; // Funding transaction:
string reason;
txFrom.vout.resize(4); txFrom.vout.resize(4);
for (int i = 0; i < 4; i++) for (int i = 0; i < 4; i++)
{ {
txFrom.vout[i].scriptPubKey = outer[i]; txFrom.vout[i].scriptPubKey = outer[i];
txFrom.vout[i].nValue = CENT; txFrom.vout[i].nValue = CENT;
} }
BOOST_CHECK(IsStandardTx(txFrom)); BOOST_CHECK(IsStandardTx(txFrom, reason));
CTransaction txTo[4]; // Spending transactions CTransaction txTo[4]; // Spending transactions
for (int i = 0; i < 4; i++) for (int i = 0; i < 4; i++)
@ -189,7 +191,7 @@ BOOST_AUTO_TEST_CASE(set)
for (int i = 0; i < 4; i++) for (int i = 0; i < 4; i++)
{ {
BOOST_CHECK_MESSAGE(SignSignature(keystore, txFrom, txTo[i], 0), strprintf("SignSignature %d", i)); BOOST_CHECK_MESSAGE(SignSignature(keystore, txFrom, txTo[i], 0), strprintf("SignSignature %d", i));
BOOST_CHECK_MESSAGE(IsStandardTx(txTo[i]), strprintf("txTo[%d].IsStandard", i)); BOOST_CHECK_MESSAGE(IsStandardTx(txTo[i], reason), strprintf("txTo[%d].IsStandard", i));
} }
} }

9
src/test/transaction_tests.cpp

@ -260,16 +260,17 @@ BOOST_AUTO_TEST_CASE(test_IsStandard)
key.MakeNewKey(true); key.MakeNewKey(true);
t.vout[0].scriptPubKey.SetDestination(key.GetPubKey().GetID()); t.vout[0].scriptPubKey.SetDestination(key.GetPubKey().GetID());
BOOST_CHECK(IsStandardTx(t)); string reason;
BOOST_CHECK(IsStandardTx(t, reason));
t.vout[0].nValue = 5011; // dust t.vout[0].nValue = 5011; // dust
BOOST_CHECK(!IsStandardTx(t)); BOOST_CHECK(!IsStandardTx(t, reason));
t.vout[0].nValue = 6011; // not dust t.vout[0].nValue = 6011; // not dust
BOOST_CHECK(IsStandardTx(t)); BOOST_CHECK(IsStandardTx(t, reason));
t.vout[0].scriptPubKey = CScript() << OP_1; t.vout[0].scriptPubKey = CScript() << OP_1;
BOOST_CHECK(!IsStandardTx(t)); BOOST_CHECK(!IsStandardTx(t, reason));
} }
BOOST_AUTO_TEST_SUITE_END() BOOST_AUTO_TEST_SUITE_END()

Loading…
Cancel
Save