AreInputsStandard: Return specific reject reasons

This commit is contained in:
Luke Dashjr 2016-01-16 23:49:42 +00:00
parent ee375a4c2f
commit 3badcde965
4 changed files with 26 additions and 6 deletions

View File

@ -133,6 +133,9 @@ bool IsStandardTx(const CTransaction& tx, const std::optional<unsigned>& 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<unsigned>& 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<std::vector<unsigned char> > 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<std::vector<unsigned char> > 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;
}
}

View File

@ -143,7 +143,13 @@ bool IsStandardTx(const CTransaction& tx, const std::optional<unsigned>& 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

View File

@ -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.

View File

@ -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)