diff --git a/src/script/interpreter.cpp b/src/script/interpreter.cpp --- a/src/script/interpreter.cpp +++ b/src/script/interpreter.cpp @@ -1725,6 +1725,7 @@ return set_error(serror, ScriptError::EVAL_FALSE); } + bool segwit_exempt = false; // Additional validation for spend-to-script-hash transactions: if ((flags & SCRIPT_VERIFY_P2SH) && scriptPubKey.IsPayToScriptHash()) { // scriptSig must be literals-only or validation fails @@ -1744,32 +1745,25 @@ CScript pubKey2(pubKeySerialized.begin(), pubKeySerialized.end()); popstack(stack); - // Bail out early if SCRIPT_DISALLOW_SEGWIT_RECOVERY is not set, the - // redeem script is a p2sh segwit program, and it was the only item - // pushed onto the stack. + // If SCRIPT_DISALLOW_SEGWIT_RECOVERY is not set and redeem script is a + // p2sh segwit program, and it was the only item pushed onto the stack, + // then mark for special exemptions from regular script rules. if ((flags & SCRIPT_DISALLOW_SEGWIT_RECOVERY) == 0 && stack.empty() && pubKey2.IsWitnessProgram()) { - // must set metricsOut for all successful returns - - // Prior to activation of this flag, all transactions will count as - // having a sigchecks count of 0 for accounting purposes outside of - // VerifyScript. - if (!(flags & SCRIPT_REPORT_SIGCHECKS)) { - metrics.nSigChecks = 0; - } - metricsOut = metrics; - return set_success(serror); + segwit_exempt = true; } - if (!EvalScript(stack, pubKey2, flags, checker, metrics, serror)) { - // serror is set - return false; - } - if (stack.empty()) { - return set_error(serror, ScriptError::EVAL_FALSE); - } - if (!CastToBool(stack.back())) { - return set_error(serror, ScriptError::EVAL_FALSE); + if (!segwit_exempt) { + if (!EvalScript(stack, pubKey2, flags, checker, metrics, serror)) { + // serror is set + return false; + } + if (stack.empty()) { + return set_error(serror, ScriptError::EVAL_FALSE); + } + if (!CastToBool(stack.back())) { + return set_error(serror, ScriptError::EVAL_FALSE); + } } } @@ -1777,7 +1771,7 @@ // as the non-P2SH evaluation of a P2SH script will obviously not result in // a clean stack (the P2SH inputs remain). The same holds for witness // evaluation. - if ((flags & SCRIPT_VERIFY_CLEANSTACK) != 0) { + if (!segwit_exempt && (flags & SCRIPT_VERIFY_CLEANSTACK)) { // Disallow CLEANSTACK without P2SH, as otherwise a switch // CLEANSTACK->P2SH+CLEANSTACK would be possible, which is not a // softfork (and P2SH should be one). @@ -1787,7 +1781,7 @@ } } - if (flags & SCRIPT_VERIFY_INPUT_SIGCHECKS) { + if (!segwit_exempt && (flags & SCRIPT_VERIFY_INPUT_SIGCHECKS)) { // This limit is intended for standard use, and is based on an // examination of typical and historical standard uses. // - allowing P2SH ECDSA multisig with compressed keys, which at an diff --git a/src/test/sigcheckcount_tests.cpp b/src/test/sigcheckcount_tests.cpp --- a/src/test/sigcheckcount_tests.cpp +++ b/src/test/sigcheckcount_tests.cpp @@ -334,8 +334,8 @@ CHECK_VERIFYSCRIPT(CScript() << sigschnorr, CScript() << pub << OP_CHECKSIG, SCRIPT_VERIFY_NONE, 1); - // Correct behaviour occurs for segwit recovery special case (which returns - // success from an alternative location) + // Correct behaviour occurs for segwit recovery special case (which used to + // return success from an alternative location) CScript swscript; swscript << OP_0 << std::vector(20); CHECK_VERIFYSCRIPT(CScript() << ToByteVector(swscript),