Merge pull request #2743 from jgarzik/reject-reason
Log reason for non-standard transaction rejection
This commit is contained in:
commit
d598872726
4 changed files with 38 additions and 18 deletions
39
src/main.cpp
39
src/main.cpp
|
@ -471,38 +471,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;
|
||||
}
|
||||
|
||||
if (!IsFinalTx(tx))
|
||||
if (!IsFinalTx(tx)) {
|
||||
reason = "non-final";
|
||||
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)
|
||||
if (sz >= MAX_STANDARD_TX_SIZE) {
|
||||
reason = "tx-size";
|
||||
return false;
|
||||
}
|
||||
|
||||
BOOST_FOREACH(const CTxIn& txin, tx.vin)
|
||||
{
|
||||
// Biggest 'standard' txin is a 3-signature 3-of-3 CHECKMULTISIG
|
||||
// pay-to-script-hash, which is 3 ~80-byte signatures, 3
|
||||
// ~65-byte public keys, plus a few script ops.
|
||||
if (txin.scriptSig.size() > 500)
|
||||
if (txin.scriptSig.size() > 500) {
|
||||
reason = "scriptsig-size";
|
||||
return false;
|
||||
if (!txin.scriptSig.IsPushOnly())
|
||||
}
|
||||
if (!txin.scriptSig.IsPushOnly()) {
|
||||
reason = "scriptsig-not-pushonly";
|
||||
return false;
|
||||
}
|
||||
}
|
||||
BOOST_FOREACH(const CTxOut& txout, tx.vout) {
|
||||
if (!::IsStandard(txout.scriptPubKey))
|
||||
return false;
|
||||
if (txout.IsDust(CTransaction::nMinRelayTxFee))
|
||||
if (!::IsStandard(txout.scriptPubKey)) {
|
||||
reason = "scriptpubkey";
|
||||
return false;
|
||||
}
|
||||
if (txout.IsDust(CTransaction::nMinRelayTxFee)) {
|
||||
reason = "dust";
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -796,8 +811,10 @@ bool CTxMemPool::accept(CValidationState &state, CTransaction &tx, bool fLimitFr
|
|||
return error("CTxMemPool::accept() : not accepting nLockTime beyond 2038 yet");
|
||||
|
||||
// Rather not work on nonstandard transactions (unless -testnet)
|
||||
if (!TestNet() && !IsStandardTx(tx))
|
||||
return error("CTxMemPool::accept() : nonstandard transaction type");
|
||||
string reason;
|
||||
if (!TestNet() && !IsStandardTx(tx, reason))
|
||||
return error("CTxMemPool::accept() : nonstandard transaction: %s",
|
||||
reason.c_str());
|
||||
|
||||
// is it already in the memory pool?
|
||||
uint256 hash = tx.GetHash();
|
||||
|
|
|
@ -326,7 +326,7 @@ bool CheckTransaction(const CTransaction& tx, CValidationState& state);
|
|||
/** Check for standard transaction types
|
||||
@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);
|
||||
|
||||
|
|
|
@ -74,6 +74,7 @@ BOOST_AUTO_TEST_CASE(sign)
|
|||
}
|
||||
|
||||
CTransaction txFrom; // Funding transaction:
|
||||
string reason;
|
||||
txFrom.vout.resize(8);
|
||||
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].nValue = COIN;
|
||||
}
|
||||
BOOST_CHECK(IsStandardTx(txFrom));
|
||||
BOOST_CHECK(IsStandardTx(txFrom, reason));
|
||||
|
||||
CTransaction txTo[8]; // Spending transactions
|
||||
for (int i = 0; i < 8; i++)
|
||||
|
@ -167,13 +168,14 @@ BOOST_AUTO_TEST_CASE(set)
|
|||
}
|
||||
|
||||
CTransaction txFrom; // Funding transaction:
|
||||
string reason;
|
||||
txFrom.vout.resize(4);
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
txFrom.vout[i].scriptPubKey = outer[i];
|
||||
txFrom.vout[i].nValue = CENT;
|
||||
}
|
||||
BOOST_CHECK(IsStandardTx(txFrom));
|
||||
BOOST_CHECK(IsStandardTx(txFrom, reason));
|
||||
|
||||
CTransaction txTo[4]; // Spending transactions
|
||||
for (int i = 0; i < 4; i++)
|
||||
|
@ -189,7 +191,7 @@ BOOST_AUTO_TEST_CASE(set)
|
|||
for (int i = 0; i < 4; 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));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -260,16 +260,17 @@ BOOST_AUTO_TEST_CASE(test_IsStandard)
|
|||
key.MakeNewKey(true);
|
||||
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
|
||||
BOOST_CHECK(!IsStandardTx(t));
|
||||
BOOST_CHECK(!IsStandardTx(t, reason));
|
||||
|
||||
t.vout[0].nValue = 6011; // not dust
|
||||
BOOST_CHECK(IsStandardTx(t));
|
||||
BOOST_CHECK(IsStandardTx(t, reason));
|
||||
|
||||
t.vout[0].scriptPubKey = CScript() << OP_1;
|
||||
BOOST_CHECK(!IsStandardTx(t));
|
||||
BOOST_CHECK(!IsStandardTx(t, reason));
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_SUITE_END()
|
||||
|
|
Loading…
Reference in a new issue