diff options
Diffstat (limited to 'src/script')
-rw-r--r-- | src/script/interpreter.cpp | 14 | ||||
-rw-r--r-- | src/script/interpreter.h | 4 | ||||
-rw-r--r-- | src/script/script_error.cpp | 2 | ||||
-rw-r--r-- | src/script/script_error.h | 1 |
4 files changed, 20 insertions, 1 deletions
diff --git a/src/script/interpreter.cpp b/src/script/interpreter.cpp index fd356fed0a..41756ea711 100644 --- a/src/script/interpreter.cpp +++ b/src/script/interpreter.cpp @@ -885,6 +885,9 @@ bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, un } bool fSuccess = checker.CheckSig(vchSig, vchPubKey, scriptCode, sigversion); + if (!fSuccess && (flags & SCRIPT_VERIFY_NULLFAIL) && vchSig.size()) + return set_error(serror, SCRIPT_ERR_SIG_NULLFAIL); + popstack(stack); popstack(stack); stack.push_back(fSuccess ? vchTrue : vchFalse); @@ -914,6 +917,9 @@ bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, un if (nOpCount > MAX_OPS_PER_SCRIPT) return set_error(serror, SCRIPT_ERR_OP_COUNT); int ikey = ++i; + // ikey2 is the position of last non-signature item in the stack. Top stack item = 1. + // With SCRIPT_VERIFY_NULLFAIL, this is used for cleanup if operation fails. + int ikey2 = nKeysCount + 2; i += nKeysCount; if ((int)stack.size() < i) return set_error(serror, SCRIPT_ERR_INVALID_STACK_OPERATION); @@ -970,8 +976,14 @@ bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, un } // Clean up stack of actual arguments - while (i-- > 1) + while (i-- > 1) { + // If the operation failed, we require that all signatures must be empty vector + if (!fSuccess && (flags & SCRIPT_VERIFY_NULLFAIL) && !ikey2 && stacktop(-1).size()) + return set_error(serror, SCRIPT_ERR_SIG_NULLFAIL); + if (ikey2 > 0) + ikey2--; popstack(stack); + } // A bug causes CHECKMULTISIG to consume one extra argument // whose contents were not checked in any way. diff --git a/src/script/interpreter.h b/src/script/interpreter.h index 2ce4b23e54..0adc9482ff 100644 --- a/src/script/interpreter.h +++ b/src/script/interpreter.h @@ -98,6 +98,10 @@ enum // Segwit script only: Require the argument of OP_IF/NOTIF to be exactly 0x01 or empty vector // SCRIPT_VERIFY_MINIMALIF = (1U << 13), + + // Signature(s) must be empty vector if an CHECK(MULTI)SIG operation failed + // + SCRIPT_VERIFY_NULLFAIL = (1U << 14), }; bool CheckSignatureEncoding(const std::vector<unsigned char> &vchSig, unsigned int flags, ScriptError* serror); diff --git a/src/script/script_error.cpp b/src/script/script_error.cpp index 9969c232fc..e27b715c2c 100644 --- a/src/script/script_error.cpp +++ b/src/script/script_error.cpp @@ -65,6 +65,8 @@ const char* ScriptErrorString(const ScriptError serror) return "Dummy CHECKMULTISIG argument must be zero"; case SCRIPT_ERR_MINIMALIF: return "OP_IF/NOTIF argument must be minimal"; + case SCRIPT_ERR_SIG_NULLFAIL: + return "Signature must be zero for failed CHECK(MULTI)SIG operation"; case SCRIPT_ERR_DISCOURAGE_UPGRADABLE_NOPS: return "NOPx reserved for soft-fork upgrades"; case SCRIPT_ERR_DISCOURAGE_UPGRADABLE_WITNESS_PROGRAM: diff --git a/src/script/script_error.h b/src/script/script_error.h index 6d34d37925..bccfdb99e2 100644 --- a/src/script/script_error.h +++ b/src/script/script_error.h @@ -49,6 +49,7 @@ typedef enum ScriptError_t SCRIPT_ERR_PUBKEYTYPE, SCRIPT_ERR_CLEANSTACK, SCRIPT_ERR_MINIMALIF, + SCRIPT_ERR_SIG_NULLFAIL, /* softfork safeness */ SCRIPT_ERR_DISCOURAGE_UPGRADABLE_NOPS, |