aboutsummaryrefslogtreecommitdiff
path: root/src/script
diff options
context:
space:
mode:
Diffstat (limited to 'src/script')
-rw-r--r--src/script/interpreter.cpp14
-rw-r--r--src/script/interpreter.h4
-rw-r--r--src/script/script_error.cpp2
-rw-r--r--src/script/script_error.h1
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,