From 3badcde96576959679c941a4807c9890c4dbabcf Mon Sep 17 00:00:00 2001 From: Luke Dashjr Date: Sat, 16 Jan 2016 23:49:42 +0000 Subject: [PATCH] AreInputsStandard: Return specific reject reasons --- src/policy/policy.cpp | 18 ++++++++++++++++-- src/policy/policy.h | 8 +++++++- src/validation.cpp | 4 ++-- test/functional/p2p_segwit.py | 2 +- 4 files changed, 26 insertions(+), 6 deletions(-) diff --git a/src/policy/policy.cpp b/src/policy/policy.cpp index d08ec4fb7f..bb5a87f376 100644 --- a/src/policy/policy.cpp +++ b/src/policy/policy.cpp @@ -133,6 +133,9 @@ bool IsStandardTx(const CTransaction& tx, const std::optional& max_dat for (const CTxOut& txout : tx.vout) { if (!::IsStandard(txout.scriptPubKey, max_datacarrier_bytes, whichType)) { reason = "scriptpubkey"; + if (whichType == TxoutType::WITNESS_UNKNOWN) { + reason += "-unknown-witnessversion"; + } return false; } @@ -174,7 +177,7 @@ bool IsStandardTx(const CTransaction& tx, const std::optional& max_dat * * Note that only the non-witness portion of the transaction is checked here. */ -bool AreInputsStandard(const CTransaction& tx, const CCoinsViewCache& mapInputs) +bool AreInputsStandard(const CTransaction& tx, const CCoinsViewCache& mapInputs, const std::string& reason_prefix, std::string& out_reason) { if (tx.IsCoinBase()) { return true; // Coinbases don't use vin normally @@ -185,21 +188,32 @@ bool AreInputsStandard(const CTransaction& tx, const CCoinsViewCache& mapInputs) std::vector > vSolutions; TxoutType whichType = Solver(prev.scriptPubKey, vSolutions); - if (whichType == TxoutType::NONSTANDARD || whichType == TxoutType::WITNESS_UNKNOWN) { + if (whichType == TxoutType::NONSTANDARD) { + out_reason = reason_prefix + "script-unknown"; + return false; + } else if (whichType == TxoutType::WITNESS_UNKNOWN) { // WITNESS_UNKNOWN failures are typically also caught with a policy // flag in the script interpreter, but it can be helpful to catch // this type of NONSTANDARD transaction earlier in transaction // validation. + out_reason = reason_prefix + "witness-unknown"; return false; } else if (whichType == TxoutType::SCRIPTHASH) { std::vector > stack; // convert the scriptSig into a stack, so we can inspect the redeemScript if (!EvalScript(stack, tx.vin[i].scriptSig, SCRIPT_VERIFY_NONE, BaseSignatureChecker(), SigVersion::BASE)) + { + out_reason = reason_prefix + "scriptsig-failure"; return false; + } if (stack.empty()) + { + out_reason = reason_prefix + "scriptcheck-missing"; return false; + } CScript subscript(stack.back().begin(), stack.back().end()); if (subscript.GetSigOpCount(true) > MAX_P2SH_SIGOPS) { + out_reason = reason_prefix + "scriptcheck-sigops"; return false; } } diff --git a/src/policy/policy.h b/src/policy/policy.h index d1c8148800..8973cfc690 100644 --- a/src/policy/policy.h +++ b/src/policy/policy.h @@ -143,7 +143,13 @@ bool IsStandardTx(const CTransaction& tx, const std::optional& max_dat * @param[in] mapInputs Map of previous transactions that have outputs we're spending * @return True if all inputs (scriptSigs) use only standard transaction forms */ -bool AreInputsStandard(const CTransaction& tx, const CCoinsViewCache& mapInputs); +bool AreInputsStandard(const CTransaction& tx, const CCoinsViewCache& mapInputs, const std::string& reason_prefix, std::string& out_reason); + +inline bool AreInputsStandard(const CTransaction& tx, const CCoinsViewCache& mapInputs) { + std::string reason; + return AreInputsStandard(tx, mapInputs, reason, reason); +} + /** * Check if the transaction is over standard P2WSH resources limit: * 3600bytes witnessScript size, 80bytes per witness stack element, 100 witness stack elements diff --git a/src/validation.cpp b/src/validation.cpp index a6cab6b095..4b57f200a4 100644 --- a/src/validation.cpp +++ b/src/validation.cpp @@ -823,8 +823,8 @@ bool MemPoolAccept::PreChecks(ATMPArgs& args, Workspace& ws) return false; // state filled in by CheckTxInputs } - if (m_pool.m_require_standard && !AreInputsStandard(tx, m_view)) { - return state.Invalid(TxValidationResult::TX_INPUTS_NOT_STANDARD, "bad-txns-nonstandard-inputs"); + if (m_pool.m_require_standard && !AreInputsStandard(tx, m_view, "bad-txns-input-", reason)) { + return state.Invalid(TxValidationResult::TX_INPUTS_NOT_STANDARD, reason); } // Check for non-standard witnesses. diff --git a/test/functional/p2p_segwit.py b/test/functional/p2p_segwit.py index d316c4b602..1009bd9ddb 100755 --- a/test/functional/p2p_segwit.py +++ b/test/functional/p2p_segwit.py @@ -1387,7 +1387,7 @@ class SegWitTest(BitcoinTestFramework): # First we test this transaction against std_node # making sure the txid is added to the reject filter self.std_node.announce_tx_and_wait_for_getdata(tx3) - test_transaction_acceptance(self.nodes[1], self.std_node, tx3, with_witness=True, accepted=False, reason="bad-txns-nonstandard-inputs") + test_transaction_acceptance(self.nodes[1], self.std_node, tx3, with_witness=True, accepted=False, reason="bad-txns-input-witness-unknown") # Now the node will no longer ask for getdata of this transaction when advertised by same txid self.std_node.announce_tx_and_wait_for_getdata(tx3, success=False)