Merge pull request #5212

219a147 script: check ScriptError values in script tests (Cory Fields)
ab9edbd script: create sane error return codes for script validation and remove logging (Cory Fields)
This commit is contained in:
Wladimir J. van der Laan 2014-11-17 21:05:25 +01:00
commit 8adf457047
No known key found for this signature in database
GPG key ID: 74810B012346C9A6
9 changed files with 400 additions and 157 deletions

View file

@ -112,6 +112,7 @@ BITCOIN_CORE_H = \
script/sigcache.h \ script/sigcache.h \
script/sign.h \ script/sign.h \
script/standard.h \ script/standard.h \
script/script_error.h \
serialize.h \ serialize.h \
streams.h \ streams.h \
sync.h \ sync.h \
@ -235,6 +236,7 @@ libbitcoin_common_a_SOURCES = \
script/script.cpp \ script/script.cpp \
script/sign.cpp \ script/sign.cpp \
script/standard.cpp \ script/standard.cpp \
script/script_error.cpp \
$(BITCOIN_CORE_H) $(BITCOIN_CORE_H)
# util: shared between all executables. # util: shared between all executables.

View file

@ -13,7 +13,6 @@
#include "pubkey.h" #include "pubkey.h"
#include "script/script.h" #include "script/script.h"
#include "uint256.h" #include "uint256.h"
#include "util.h"
using namespace std; using namespace std;
@ -26,6 +25,24 @@ static const CScriptNum bnOne(1);
static const CScriptNum bnFalse(0); static const CScriptNum bnFalse(0);
static const CScriptNum bnTrue(1); static const CScriptNum bnTrue(1);
namespace {
inline bool set_success(ScriptError* ret)
{
if (ret)
*ret = SCRIPT_ERR_OK;
return true;
}
inline bool set_error(ScriptError* ret, const ScriptError serror)
{
if (ret)
*ret = serror;
return false;
}
} // anon namespace
bool CastToBool(const valtype& vch) bool CastToBool(const valtype& vch)
{ {
for (unsigned int i = 0; i < vch.size(); i++) for (unsigned int i = 0; i < vch.size(); i++)
@ -55,16 +72,23 @@ static inline void popstack(vector<valtype>& stack)
} }
bool static IsCompressedOrUncompressedPubKey(const valtype &vchPubKey) { bool static IsCompressedOrUncompressedPubKey(const valtype &vchPubKey) {
if (vchPubKey.size() < 33) if (vchPubKey.size() < 33) {
return error("Non-canonical public key: too short"); // Non-canonical public key: too short
return false;
}
if (vchPubKey[0] == 0x04) { if (vchPubKey[0] == 0x04) {
if (vchPubKey.size() != 65) if (vchPubKey.size() != 65) {
return error("Non-canonical public key: invalid length for uncompressed key"); // Non-canonical public key: invalid length for uncompressed key
return false;
}
} else if (vchPubKey[0] == 0x02 || vchPubKey[0] == 0x03) { } else if (vchPubKey[0] == 0x02 || vchPubKey[0] == 0x03) {
if (vchPubKey.size() != 33) if (vchPubKey.size() != 33) {
return error("Non-canonical public key: invalid length for compressed key"); // Non-canonical public key: invalid length for compressed key
return false;
}
} else { } else {
return error("Non-canonical public key: neither compressed nor uncompressed"); // Non-canonical public key: neither compressed nor uncompressed
return false;
} }
return true; return true;
} }
@ -79,47 +103,74 @@ bool static IsCompressedOrUncompressedPubKey(const valtype &vchPubKey) {
*/ */
bool static IsDERSignature(const valtype &vchSig) { bool static IsDERSignature(const valtype &vchSig) {
if (vchSig.size() < 9) if (vchSig.size() < 9) {
return error("Non-canonical signature: too short"); // Non-canonical signature: too short
if (vchSig.size() > 73) return false;
return error("Non-canonical signature: too long"); }
if (vchSig[0] != 0x30) if (vchSig.size() > 73) {
return error("Non-canonical signature: wrong type"); // Non-canonical signature: too long
if (vchSig[1] != vchSig.size()-3) return false;
return error("Non-canonical signature: wrong length marker"); }
if (vchSig[0] != 0x30) {
// Non-canonical signature: wrong type
return false;
}
if (vchSig[1] != vchSig.size()-3) {
// Non-canonical signature: wrong length marker
return false;
}
unsigned int nLenR = vchSig[3]; unsigned int nLenR = vchSig[3];
if (5 + nLenR >= vchSig.size()) if (5 + nLenR >= vchSig.size()) {
return error("Non-canonical signature: S length misplaced"); // Non-canonical signature: S length misplaced
return false;
}
unsigned int nLenS = vchSig[5+nLenR]; unsigned int nLenS = vchSig[5+nLenR];
if ((unsigned long)(nLenR+nLenS+7) != vchSig.size()) if ((unsigned long)(nLenR+nLenS+7) != vchSig.size()) {
return error("Non-canonical signature: R+S length mismatch"); // Non-canonical signature: R+S length mismatch
return false;
}
const unsigned char *R = &vchSig[4]; const unsigned char *R = &vchSig[4];
if (R[-2] != 0x02) if (R[-2] != 0x02) {
return error("Non-canonical signature: R value type mismatch"); // Non-canonical signature: R value type mismatch
if (nLenR == 0) return false;
return error("Non-canonical signature: R length is zero"); }
if (R[0] & 0x80) if (nLenR == 0) {
return error("Non-canonical signature: R value negative"); // Non-canonical signature: R length is zero
if (nLenR > 1 && (R[0] == 0x00) && !(R[1] & 0x80)) return false;
return error("Non-canonical signature: R value excessively padded"); }
if (R[0] & 0x80) {
// Non-canonical signature: R value negative
return false;
}
if (nLenR > 1 && (R[0] == 0x00) && !(R[1] & 0x80)) {
// Non-canonical signature: R value excessively padded
return false;
}
const unsigned char *S = &vchSig[6+nLenR]; const unsigned char *S = &vchSig[6+nLenR];
if (S[-2] != 0x02) if (S[-2] != 0x02) {
return error("Non-canonical signature: S value type mismatch"); // Non-canonical signature: S value type mismatch
if (nLenS == 0) return false;
return error("Non-canonical signature: S length is zero"); }
if (S[0] & 0x80) if (nLenS == 0) {
return error("Non-canonical signature: S value negative"); // Non-canonical signature: S length is zero
if (nLenS > 1 && (S[0] == 0x00) && !(S[1] & 0x80)) return false;
return error("Non-canonical signature: S value excessively padded"); }
if (S[0] & 0x80) {
// Non-canonical signature: S value negative
return false;
}
if (nLenS > 1 && (S[0] == 0x00) && !(S[1] & 0x80)) {
// Non-canonical signature: S value excessively padded
return false;
}
return true; return true;
} }
bool static IsLowDERSignature(const valtype &vchSig) { bool static IsLowDERSignature(const valtype &vchSig, ScriptError* serror) {
if (!IsDERSignature(vchSig)) { if (!IsDERSignature(vchSig)) {
return false; return set_error(serror, SCRIPT_ERR_SIG_DER);
} }
unsigned int nLenR = vchSig[3]; unsigned int nLenR = vchSig[3];
unsigned int nLenS = vchSig[5+nLenR]; unsigned int nLenS = vchSig[5+nLenR];
@ -128,7 +179,7 @@ bool static IsLowDERSignature(const valtype &vchSig) {
// complement modulo the order could have been used instead, which is // complement modulo the order could have been used instead, which is
// one byte shorter when encoded correctly. // one byte shorter when encoded correctly.
if (!eccrypto::CheckSignatureElement(S, nLenS, true)) if (!eccrypto::CheckSignatureElement(S, nLenS, true))
return error("Non-canonical signature: S value is unnecessarily high"); return set_error(serror, SCRIPT_ERR_SIG_HIGH_S);
return true; return true;
} }
@ -139,18 +190,19 @@ bool static IsDefinedHashtypeSignature(const valtype &vchSig) {
} }
unsigned char nHashType = vchSig[vchSig.size() - 1] & (~(SIGHASH_ANYONECANPAY)); unsigned char nHashType = vchSig[vchSig.size() - 1] & (~(SIGHASH_ANYONECANPAY));
if (nHashType < SIGHASH_ALL || nHashType > SIGHASH_SINGLE) if (nHashType < SIGHASH_ALL || nHashType > SIGHASH_SINGLE)
return error("Non-canonical signature: unknown hashtype byte"); return false;
return true; return true;
} }
bool static CheckSignatureEncoding(const valtype &vchSig, unsigned int flags) { bool static CheckSignatureEncoding(const valtype &vchSig, unsigned int flags, ScriptError* serror) {
if ((flags & (SCRIPT_VERIFY_DERSIG | SCRIPT_VERIFY_LOW_S | SCRIPT_VERIFY_STRICTENC)) != 0 && !IsDERSignature(vchSig)) { if ((flags & (SCRIPT_VERIFY_DERSIG | SCRIPT_VERIFY_LOW_S | SCRIPT_VERIFY_STRICTENC)) != 0 && !IsDERSignature(vchSig)) {
return false; return set_error(serror, SCRIPT_ERR_SIG_DER);
} else if ((flags & SCRIPT_VERIFY_LOW_S) != 0 && !IsLowDERSignature(vchSig)) { } else if ((flags & SCRIPT_VERIFY_LOW_S) != 0 && !IsLowDERSignature(vchSig, serror)) {
// serror is set
return false; return false;
} else if ((flags & SCRIPT_VERIFY_STRICTENC) != 0 && !IsDefinedHashtypeSignature(vchSig)) { } else if ((flags & SCRIPT_VERIFY_STRICTENC) != 0 && !IsDefinedHashtypeSignature(vchSig)) {
return false; return set_error(serror, SCRIPT_ERR_SIG_HASHTYPE);
} }
return true; return true;
} }
@ -185,7 +237,7 @@ bool static CheckMinimalPush(const valtype& data, opcodetype opcode) {
return true; return true;
} }
bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, unsigned int flags, const BaseSignatureChecker& checker) bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, unsigned int flags, const BaseSignatureChecker& checker, ScriptError* serror)
{ {
CScript::const_iterator pc = script.begin(); CScript::const_iterator pc = script.begin();
CScript::const_iterator pend = script.end(); CScript::const_iterator pend = script.end();
@ -194,8 +246,9 @@ bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, un
valtype vchPushValue; valtype vchPushValue;
vector<bool> vfExec; vector<bool> vfExec;
vector<valtype> altstack; vector<valtype> altstack;
set_error(serror, SCRIPT_ERR_UNKNOWN_ERROR);
if (script.size() > 10000) if (script.size() > 10000)
return false; return set_error(serror, SCRIPT_ERR_SCRIPT_SIZE);
int nOpCount = 0; int nOpCount = 0;
bool fRequireMinimal = (flags & SCRIPT_VERIFY_MINIMALDATA) != 0; bool fRequireMinimal = (flags & SCRIPT_VERIFY_MINIMALDATA) != 0;
@ -209,13 +262,13 @@ bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, un
// Read instruction // Read instruction
// //
if (!script.GetOp(pc, opcode, vchPushValue)) if (!script.GetOp(pc, opcode, vchPushValue))
return false; return set_error(serror, SCRIPT_ERR_BAD_OPCODE);
if (vchPushValue.size() > MAX_SCRIPT_ELEMENT_SIZE) if (vchPushValue.size() > MAX_SCRIPT_ELEMENT_SIZE)
return false; return set_error(serror, SCRIPT_ERR_PUSH_SIZE);
// Note how OP_RESERVED does not count towards the opcode limit. // Note how OP_RESERVED does not count towards the opcode limit.
if (opcode > OP_16 && ++nOpCount > 201) if (opcode > OP_16 && ++nOpCount > 201)
return false; return set_error(serror, SCRIPT_ERR_OP_COUNT);
if (opcode == OP_CAT || if (opcode == OP_CAT ||
opcode == OP_SUBSTR || opcode == OP_SUBSTR ||
@ -232,11 +285,11 @@ bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, un
opcode == OP_MOD || opcode == OP_MOD ||
opcode == OP_LSHIFT || opcode == OP_LSHIFT ||
opcode == OP_RSHIFT) opcode == OP_RSHIFT)
return false; // Disabled opcodes. return set_error(serror, SCRIPT_ERR_DISABLED_OPCODE); // Disabled opcodes.
if (fExec && 0 <= opcode && opcode <= OP_PUSHDATA4) { if (fExec && 0 <= opcode && opcode <= OP_PUSHDATA4) {
if (fRequireMinimal && !CheckMinimalPush(vchPushValue, opcode)) { if (fRequireMinimal && !CheckMinimalPush(vchPushValue, opcode)) {
return false; return set_error(serror, SCRIPT_ERR_MINIMALDATA);
} }
stack.push_back(vchPushValue); stack.push_back(vchPushValue);
} else if (fExec || (OP_IF <= opcode && opcode <= OP_ENDIF)) } else if (fExec || (OP_IF <= opcode && opcode <= OP_ENDIF))
@ -288,7 +341,7 @@ bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, un
if (fExec) if (fExec)
{ {
if (stack.size() < 1) if (stack.size() < 1)
return false; return set_error(serror, SCRIPT_ERR_UNBALANCED_CONDITIONAL);
valtype& vch = stacktop(-1); valtype& vch = stacktop(-1);
fValue = CastToBool(vch); fValue = CastToBool(vch);
if (opcode == OP_NOTIF) if (opcode == OP_NOTIF)
@ -302,7 +355,7 @@ bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, un
case OP_ELSE: case OP_ELSE:
{ {
if (vfExec.empty()) if (vfExec.empty())
return false; return set_error(serror, SCRIPT_ERR_UNBALANCED_CONDITIONAL);
vfExec.back() = !vfExec.back(); vfExec.back() = !vfExec.back();
} }
break; break;
@ -310,7 +363,7 @@ bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, un
case OP_ENDIF: case OP_ENDIF:
{ {
if (vfExec.empty()) if (vfExec.empty())
return false; return set_error(serror, SCRIPT_ERR_UNBALANCED_CONDITIONAL);
vfExec.pop_back(); vfExec.pop_back();
} }
break; break;
@ -320,18 +373,18 @@ bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, un
// (true -- ) or // (true -- ) or
// (false -- false) and return // (false -- false) and return
if (stack.size() < 1) if (stack.size() < 1)
return false; return set_error(serror, SCRIPT_ERR_INVALID_STACK_OPERATION);
bool fValue = CastToBool(stacktop(-1)); bool fValue = CastToBool(stacktop(-1));
if (fValue) if (fValue)
popstack(stack); popstack(stack);
else else
return false; return set_error(serror, SCRIPT_ERR_VERIFY);
} }
break; break;
case OP_RETURN: case OP_RETURN:
{ {
return false; return set_error(serror, SCRIPT_ERR_OP_RETURN);
} }
break; break;
@ -342,7 +395,7 @@ bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, un
case OP_TOALTSTACK: case OP_TOALTSTACK:
{ {
if (stack.size() < 1) if (stack.size() < 1)
return false; return set_error(serror, SCRIPT_ERR_INVALID_STACK_OPERATION);
altstack.push_back(stacktop(-1)); altstack.push_back(stacktop(-1));
popstack(stack); popstack(stack);
} }
@ -351,7 +404,7 @@ bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, un
case OP_FROMALTSTACK: case OP_FROMALTSTACK:
{ {
if (altstack.size() < 1) if (altstack.size() < 1)
return false; return set_error(serror, SCRIPT_ERR_INVALID_ALTSTACK_OPERATION);
stack.push_back(altstacktop(-1)); stack.push_back(altstacktop(-1));
popstack(altstack); popstack(altstack);
} }
@ -361,7 +414,7 @@ bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, un
{ {
// (x1 x2 -- ) // (x1 x2 -- )
if (stack.size() < 2) if (stack.size() < 2)
return false; return set_error(serror, SCRIPT_ERR_INVALID_STACK_OPERATION);
popstack(stack); popstack(stack);
popstack(stack); popstack(stack);
} }
@ -371,7 +424,7 @@ bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, un
{ {
// (x1 x2 -- x1 x2 x1 x2) // (x1 x2 -- x1 x2 x1 x2)
if (stack.size() < 2) if (stack.size() < 2)
return false; return set_error(serror, SCRIPT_ERR_INVALID_STACK_OPERATION);
valtype vch1 = stacktop(-2); valtype vch1 = stacktop(-2);
valtype vch2 = stacktop(-1); valtype vch2 = stacktop(-1);
stack.push_back(vch1); stack.push_back(vch1);
@ -383,7 +436,7 @@ bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, un
{ {
// (x1 x2 x3 -- x1 x2 x3 x1 x2 x3) // (x1 x2 x3 -- x1 x2 x3 x1 x2 x3)
if (stack.size() < 3) if (stack.size() < 3)
return false; return set_error(serror, SCRIPT_ERR_INVALID_STACK_OPERATION);
valtype vch1 = stacktop(-3); valtype vch1 = stacktop(-3);
valtype vch2 = stacktop(-2); valtype vch2 = stacktop(-2);
valtype vch3 = stacktop(-1); valtype vch3 = stacktop(-1);
@ -397,7 +450,7 @@ bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, un
{ {
// (x1 x2 x3 x4 -- x1 x2 x3 x4 x1 x2) // (x1 x2 x3 x4 -- x1 x2 x3 x4 x1 x2)
if (stack.size() < 4) if (stack.size() < 4)
return false; return set_error(serror, SCRIPT_ERR_INVALID_STACK_OPERATION);
valtype vch1 = stacktop(-4); valtype vch1 = stacktop(-4);
valtype vch2 = stacktop(-3); valtype vch2 = stacktop(-3);
stack.push_back(vch1); stack.push_back(vch1);
@ -409,7 +462,7 @@ bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, un
{ {
// (x1 x2 x3 x4 x5 x6 -- x3 x4 x5 x6 x1 x2) // (x1 x2 x3 x4 x5 x6 -- x3 x4 x5 x6 x1 x2)
if (stack.size() < 6) if (stack.size() < 6)
return false; return set_error(serror, SCRIPT_ERR_INVALID_STACK_OPERATION);
valtype vch1 = stacktop(-6); valtype vch1 = stacktop(-6);
valtype vch2 = stacktop(-5); valtype vch2 = stacktop(-5);
stack.erase(stack.end()-6, stack.end()-4); stack.erase(stack.end()-6, stack.end()-4);
@ -422,7 +475,7 @@ bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, un
{ {
// (x1 x2 x3 x4 -- x3 x4 x1 x2) // (x1 x2 x3 x4 -- x3 x4 x1 x2)
if (stack.size() < 4) if (stack.size() < 4)
return false; return set_error(serror, SCRIPT_ERR_INVALID_STACK_OPERATION);
swap(stacktop(-4), stacktop(-2)); swap(stacktop(-4), stacktop(-2));
swap(stacktop(-3), stacktop(-1)); swap(stacktop(-3), stacktop(-1));
} }
@ -432,7 +485,7 @@ bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, un
{ {
// (x - 0 | x x) // (x - 0 | x x)
if (stack.size() < 1) if (stack.size() < 1)
return false; return set_error(serror, SCRIPT_ERR_INVALID_STACK_OPERATION);
valtype vch = stacktop(-1); valtype vch = stacktop(-1);
if (CastToBool(vch)) if (CastToBool(vch))
stack.push_back(vch); stack.push_back(vch);
@ -451,7 +504,7 @@ bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, un
{ {
// (x -- ) // (x -- )
if (stack.size() < 1) if (stack.size() < 1)
return false; return set_error(serror, SCRIPT_ERR_INVALID_STACK_OPERATION);
popstack(stack); popstack(stack);
} }
break; break;
@ -460,7 +513,7 @@ bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, un
{ {
// (x -- x x) // (x -- x x)
if (stack.size() < 1) if (stack.size() < 1)
return false; return set_error(serror, SCRIPT_ERR_INVALID_STACK_OPERATION);
valtype vch = stacktop(-1); valtype vch = stacktop(-1);
stack.push_back(vch); stack.push_back(vch);
} }
@ -470,7 +523,7 @@ bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, un
{ {
// (x1 x2 -- x2) // (x1 x2 -- x2)
if (stack.size() < 2) if (stack.size() < 2)
return false; return set_error(serror, SCRIPT_ERR_INVALID_STACK_OPERATION);
stack.erase(stack.end() - 2); stack.erase(stack.end() - 2);
} }
break; break;
@ -479,7 +532,7 @@ bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, un
{ {
// (x1 x2 -- x1 x2 x1) // (x1 x2 -- x1 x2 x1)
if (stack.size() < 2) if (stack.size() < 2)
return false; return set_error(serror, SCRIPT_ERR_INVALID_STACK_OPERATION);
valtype vch = stacktop(-2); valtype vch = stacktop(-2);
stack.push_back(vch); stack.push_back(vch);
} }
@ -491,11 +544,11 @@ bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, un
// (xn ... x2 x1 x0 n - xn ... x2 x1 x0 xn) // (xn ... x2 x1 x0 n - xn ... x2 x1 x0 xn)
// (xn ... x2 x1 x0 n - ... x2 x1 x0 xn) // (xn ... x2 x1 x0 n - ... x2 x1 x0 xn)
if (stack.size() < 2) if (stack.size() < 2)
return false; return set_error(serror, SCRIPT_ERR_INVALID_STACK_OPERATION);
int n = CScriptNum(stacktop(-1), fRequireMinimal).getint(); int n = CScriptNum(stacktop(-1), fRequireMinimal).getint();
popstack(stack); popstack(stack);
if (n < 0 || n >= (int)stack.size()) if (n < 0 || n >= (int)stack.size())
return false; return set_error(serror, SCRIPT_ERR_INVALID_STACK_OPERATION);
valtype vch = stacktop(-n-1); valtype vch = stacktop(-n-1);
if (opcode == OP_ROLL) if (opcode == OP_ROLL)
stack.erase(stack.end()-n-1); stack.erase(stack.end()-n-1);
@ -509,7 +562,7 @@ bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, un
// x2 x1 x3 after first swap // x2 x1 x3 after first swap
// x2 x3 x1 after second swap // x2 x3 x1 after second swap
if (stack.size() < 3) if (stack.size() < 3)
return false; return set_error(serror, SCRIPT_ERR_INVALID_STACK_OPERATION);
swap(stacktop(-3), stacktop(-2)); swap(stacktop(-3), stacktop(-2));
swap(stacktop(-2), stacktop(-1)); swap(stacktop(-2), stacktop(-1));
} }
@ -519,7 +572,7 @@ bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, un
{ {
// (x1 x2 -- x2 x1) // (x1 x2 -- x2 x1)
if (stack.size() < 2) if (stack.size() < 2)
return false; return set_error(serror, SCRIPT_ERR_INVALID_STACK_OPERATION);
swap(stacktop(-2), stacktop(-1)); swap(stacktop(-2), stacktop(-1));
} }
break; break;
@ -528,7 +581,7 @@ bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, un
{ {
// (x1 x2 -- x2 x1 x2) // (x1 x2 -- x2 x1 x2)
if (stack.size() < 2) if (stack.size() < 2)
return false; return set_error(serror, SCRIPT_ERR_INVALID_STACK_OPERATION);
valtype vch = stacktop(-1); valtype vch = stacktop(-1);
stack.insert(stack.end()-2, vch); stack.insert(stack.end()-2, vch);
} }
@ -539,7 +592,7 @@ bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, un
{ {
// (in -- in size) // (in -- in size)
if (stack.size() < 1) if (stack.size() < 1)
return false; return set_error(serror, SCRIPT_ERR_INVALID_STACK_OPERATION);
CScriptNum bn(stacktop(-1).size()); CScriptNum bn(stacktop(-1).size());
stack.push_back(bn.getvch()); stack.push_back(bn.getvch());
} }
@ -555,7 +608,7 @@ bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, un
{ {
// (x1 x2 - bool) // (x1 x2 - bool)
if (stack.size() < 2) if (stack.size() < 2)
return false; return set_error(serror, SCRIPT_ERR_INVALID_STACK_OPERATION);
valtype& vch1 = stacktop(-2); valtype& vch1 = stacktop(-2);
valtype& vch2 = stacktop(-1); valtype& vch2 = stacktop(-1);
bool fEqual = (vch1 == vch2); bool fEqual = (vch1 == vch2);
@ -572,7 +625,7 @@ bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, un
if (fEqual) if (fEqual)
popstack(stack); popstack(stack);
else else
return false; return set_error(serror, SCRIPT_ERR_EQUALVERIFY);
} }
} }
break; break;
@ -590,7 +643,7 @@ bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, un
{ {
// (in -- out) // (in -- out)
if (stack.size() < 1) if (stack.size() < 1)
return false; return set_error(serror, SCRIPT_ERR_INVALID_STACK_OPERATION);
CScriptNum bn(stacktop(-1), fRequireMinimal); CScriptNum bn(stacktop(-1), fRequireMinimal);
switch (opcode) switch (opcode)
{ {
@ -623,7 +676,7 @@ bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, un
{ {
// (x1 x2 -- out) // (x1 x2 -- out)
if (stack.size() < 2) if (stack.size() < 2)
return false; return set_error(serror, SCRIPT_ERR_INVALID_STACK_OPERATION);
CScriptNum bn1(stacktop(-2), fRequireMinimal); CScriptNum bn1(stacktop(-2), fRequireMinimal);
CScriptNum bn2(stacktop(-1), fRequireMinimal); CScriptNum bn2(stacktop(-1), fRequireMinimal);
CScriptNum bn(0); CScriptNum bn(0);
@ -659,7 +712,7 @@ bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, un
if (CastToBool(stacktop(-1))) if (CastToBool(stacktop(-1)))
popstack(stack); popstack(stack);
else else
return false; return set_error(serror, SCRIPT_ERR_NUMEQUALVERIFY);
} }
} }
break; break;
@ -668,7 +721,7 @@ bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, un
{ {
// (x min max -- out) // (x min max -- out)
if (stack.size() < 3) if (stack.size() < 3)
return false; return set_error(serror, SCRIPT_ERR_INVALID_STACK_OPERATION);
CScriptNum bn1(stacktop(-3), fRequireMinimal); CScriptNum bn1(stacktop(-3), fRequireMinimal);
CScriptNum bn2(stacktop(-2), fRequireMinimal); CScriptNum bn2(stacktop(-2), fRequireMinimal);
CScriptNum bn3(stacktop(-1), fRequireMinimal); CScriptNum bn3(stacktop(-1), fRequireMinimal);
@ -692,7 +745,7 @@ bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, un
{ {
// (in -- hash) // (in -- hash)
if (stack.size() < 1) if (stack.size() < 1)
return false; return set_error(serror, SCRIPT_ERR_INVALID_STACK_OPERATION);
valtype& vch = stacktop(-1); valtype& vch = stacktop(-1);
valtype vchHash((opcode == OP_RIPEMD160 || opcode == OP_SHA1 || opcode == OP_HASH160) ? 20 : 32); valtype vchHash((opcode == OP_RIPEMD160 || opcode == OP_SHA1 || opcode == OP_HASH160) ? 20 : 32);
if (opcode == OP_RIPEMD160) if (opcode == OP_RIPEMD160)
@ -722,7 +775,7 @@ bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, un
{ {
// (sig pubkey -- bool) // (sig pubkey -- bool)
if (stack.size() < 2) if (stack.size() < 2)
return false; return set_error(serror, SCRIPT_ERR_INVALID_STACK_OPERATION);
valtype& vchSig = stacktop(-2); valtype& vchSig = stacktop(-2);
valtype& vchPubKey = stacktop(-1); valtype& vchPubKey = stacktop(-1);
@ -733,10 +786,10 @@ bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, un
// Drop the signature, since there's no way for a signature to sign itself // Drop the signature, since there's no way for a signature to sign itself
scriptCode.FindAndDelete(CScript(vchSig)); scriptCode.FindAndDelete(CScript(vchSig));
if (!CheckSignatureEncoding(vchSig, flags)) { if (!CheckSignatureEncoding(vchSig, flags, serror)) {
//serror is set
return false; return false;
} }
bool fSuccess = CheckPubKeyEncoding(vchPubKey, flags) && checker.CheckSig(vchSig, vchPubKey, scriptCode); bool fSuccess = CheckPubKeyEncoding(vchPubKey, flags) && checker.CheckSig(vchSig, vchPubKey, scriptCode);
popstack(stack); popstack(stack);
@ -747,7 +800,7 @@ bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, un
if (fSuccess) if (fSuccess)
popstack(stack); popstack(stack);
else else
return false; return set_error(serror, SCRIPT_ERR_CHECKSIGVERIFY);
} }
} }
break; break;
@ -759,26 +812,26 @@ bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, un
int i = 1; int i = 1;
if ((int)stack.size() < i) if ((int)stack.size() < i)
return false; return set_error(serror, SCRIPT_ERR_INVALID_STACK_OPERATION);
int nKeysCount = CScriptNum(stacktop(-i), fRequireMinimal).getint(); int nKeysCount = CScriptNum(stacktop(-i), fRequireMinimal).getint();
if (nKeysCount < 0 || nKeysCount > 20) if (nKeysCount < 0 || nKeysCount > 20)
return false; return set_error(serror, SCRIPT_ERR_PUBKEY_COUNT);
nOpCount += nKeysCount; nOpCount += nKeysCount;
if (nOpCount > 201) if (nOpCount > 201)
return false; return set_error(serror, SCRIPT_ERR_OP_COUNT);
int ikey = ++i; int ikey = ++i;
i += nKeysCount; i += nKeysCount;
if ((int)stack.size() < i) if ((int)stack.size() < i)
return false; return set_error(serror, SCRIPT_ERR_INVALID_STACK_OPERATION);
int nSigsCount = CScriptNum(stacktop(-i), fRequireMinimal).getint(); int nSigsCount = CScriptNum(stacktop(-i), fRequireMinimal).getint();
if (nSigsCount < 0 || nSigsCount > nKeysCount) if (nSigsCount < 0 || nSigsCount > nKeysCount)
return false; return set_error(serror, SCRIPT_ERR_SIG_COUNT);
int isig = ++i; int isig = ++i;
i += nSigsCount; i += nSigsCount;
if ((int)stack.size() < i) if ((int)stack.size() < i)
return false; return set_error(serror, SCRIPT_ERR_INVALID_STACK_OPERATION);
// Subset of script starting at the most recent codeseparator // Subset of script starting at the most recent codeseparator
CScript scriptCode(pbegincodehash, pend); CScript scriptCode(pbegincodehash, pend);
@ -796,7 +849,8 @@ bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, un
valtype& vchSig = stacktop(-isig); valtype& vchSig = stacktop(-isig);
valtype& vchPubKey = stacktop(-ikey); valtype& vchPubKey = stacktop(-ikey);
if (!CheckSignatureEncoding(vchSig, flags)) { if (!CheckSignatureEncoding(vchSig, flags, serror)) {
// serror is set
return false; return false;
} }
@ -827,9 +881,9 @@ bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, un
// so optionally verify it is exactly equal to zero prior // so optionally verify it is exactly equal to zero prior
// to removing it from the stack. // to removing it from the stack.
if (stack.size() < 1) if (stack.size() < 1)
return false; return set_error(serror, SCRIPT_ERR_INVALID_STACK_OPERATION);
if ((flags & SCRIPT_VERIFY_NULLDUMMY) && stacktop(-1).size()) if ((flags & SCRIPT_VERIFY_NULLDUMMY) && stacktop(-1).size())
return error("CHECKMULTISIG dummy argument not null"); return set_error(serror, SCRIPT_ERR_SIG_NULLDUMMY);
popstack(stack); popstack(stack);
stack.push_back(fSuccess ? vchTrue : vchFalse); stack.push_back(fSuccess ? vchTrue : vchFalse);
@ -839,29 +893,29 @@ bool EvalScript(vector<vector<unsigned char> >& stack, const CScript& script, un
if (fSuccess) if (fSuccess)
popstack(stack); popstack(stack);
else else
return false; return set_error(serror, SCRIPT_ERR_CHECKMULTISIGVERIFY);
} }
} }
break; break;
default: default:
return false; return set_error(serror, SCRIPT_ERR_BAD_OPCODE);
} }
// Size limits // Size limits
if (stack.size() + altstack.size() > 1000) if (stack.size() + altstack.size() > 1000)
return false; return set_error(serror, SCRIPT_ERR_STACK_SIZE);
} }
} }
catch (...) catch (...)
{ {
return false; return set_error(serror, SCRIPT_ERR_UNKNOWN_ERROR);
} }
if (!vfExec.empty()) if (!vfExec.empty())
return false; return set_error(serror, SCRIPT_ERR_UNBALANCED_CONDITIONAL);
return true; return set_success(serror);
} }
namespace { namespace {
@ -966,14 +1020,14 @@ public:
uint256 SignatureHash(const CScript& scriptCode, const CTransaction& txTo, unsigned int nIn, int nHashType) uint256 SignatureHash(const CScript& scriptCode, const CTransaction& txTo, unsigned int nIn, int nHashType)
{ {
if (nIn >= txTo.vin.size()) { if (nIn >= txTo.vin.size()) {
LogPrintf("ERROR: SignatureHash() : nIn=%d out of range\n", nIn); // nIn out of range
return 1; return 1;
} }
// Check for invalid use of SIGHASH_SINGLE // Check for invalid use of SIGHASH_SINGLE
if ((nHashType & 0x1f) == SIGHASH_SINGLE) { if ((nHashType & 0x1f) == SIGHASH_SINGLE) {
if (nIn >= txTo.vout.size()) { if (nIn >= txTo.vout.size()) {
LogPrintf("ERROR: SignatureHash() : nOut=%d out of range\n", nIn); // nOut out of range
return 1; return 1;
} }
} }
@ -1013,30 +1067,35 @@ bool SignatureChecker::CheckSig(const vector<unsigned char>& vchSigIn, const vec
return true; return true;
} }
bool VerifyScript(const CScript& scriptSig, const CScript& scriptPubKey, unsigned int flags, const BaseSignatureChecker& checker) bool VerifyScript(const CScript& scriptSig, const CScript& scriptPubKey, unsigned int flags, const BaseSignatureChecker& checker, ScriptError* serror)
{ {
set_error(serror, SCRIPT_ERR_UNKNOWN_ERROR);
if ((flags & SCRIPT_VERIFY_SIGPUSHONLY) != 0 && !scriptSig.IsPushOnly()) { if ((flags & SCRIPT_VERIFY_SIGPUSHONLY) != 0 && !scriptSig.IsPushOnly()) {
return false; return set_error(serror, SCRIPT_ERR_SIG_PUSHONLY);
} }
vector<vector<unsigned char> > stack, stackCopy; vector<vector<unsigned char> > stack, stackCopy;
if (!EvalScript(stack, scriptSig, flags, checker)) if (!EvalScript(stack, scriptSig, flags, checker, serror))
// serror is set
return false; return false;
if (flags & SCRIPT_VERIFY_P2SH) if (flags & SCRIPT_VERIFY_P2SH)
stackCopy = stack; stackCopy = stack;
if (!EvalScript(stack, scriptPubKey, flags, checker)) if (!EvalScript(stack, scriptPubKey, flags, checker, serror))
// serror is set
return false; return false;
if (stack.empty()) if (stack.empty())
return false; return set_error(serror, SCRIPT_ERR_EVAL_FALSE);
if (CastToBool(stack.back()) == false) if (CastToBool(stack.back()) == false)
return false; return set_error(serror, SCRIPT_ERR_EVAL_FALSE);
// Additional validation for spend-to-script-hash transactions: // Additional validation for spend-to-script-hash transactions:
if ((flags & SCRIPT_VERIFY_P2SH) && scriptPubKey.IsPayToScriptHash()) if ((flags & SCRIPT_VERIFY_P2SH) && scriptPubKey.IsPayToScriptHash())
{ {
if (!scriptSig.IsPushOnly()) // scriptSig must be literals-only // scriptSig must be literals-only or validation fails
return false; // or validation fails if (!scriptSig.IsPushOnly())
return set_error(serror, SCRIPT_ERR_SIG_PUSHONLY);
// stackCopy cannot be empty here, because if it was the // stackCopy cannot be empty here, because if it was the
// P2SH HASH <> EQUAL scriptPubKey would be evaluated with // P2SH HASH <> EQUAL scriptPubKey would be evaluated with
@ -1047,12 +1106,16 @@ bool VerifyScript(const CScript& scriptSig, const CScript& scriptPubKey, unsigne
CScript pubKey2(pubKeySerialized.begin(), pubKeySerialized.end()); CScript pubKey2(pubKeySerialized.begin(), pubKeySerialized.end());
popstack(stackCopy); popstack(stackCopy);
if (!EvalScript(stackCopy, pubKey2, flags, checker)) if (!EvalScript(stackCopy, pubKey2, flags, checker, serror))
// serror is set
return false; return false;
if (stackCopy.empty()) if (stackCopy.empty())
return false; return set_error(serror, SCRIPT_ERR_EVAL_FALSE);
return CastToBool(stackCopy.back()); if (!CastToBool(stackCopy.back()))
return set_error(serror, SCRIPT_ERR_EVAL_FALSE);
else
return set_success(serror);
} }
return true; return set_success(serror);
} }

View file

@ -6,6 +6,8 @@
#ifndef BITCOIN_SCRIPT_INTERPRETER_H #ifndef BITCOIN_SCRIPT_INTERPRETER_H
#define BITCOIN_SCRIPT_INTERPRETER_H #define BITCOIN_SCRIPT_INTERPRETER_H
#include "script_error.h"
#include <vector> #include <vector>
#include <stdint.h> #include <stdint.h>
#include <string> #include <string>
@ -85,7 +87,7 @@ public:
bool CheckSig(const std::vector<unsigned char>& scriptSig, const std::vector<unsigned char>& vchPubKey, const CScript& scriptCode) const; bool CheckSig(const std::vector<unsigned char>& scriptSig, const std::vector<unsigned char>& vchPubKey, const CScript& scriptCode) const;
}; };
bool EvalScript(std::vector<std::vector<unsigned char> >& stack, const CScript& script, unsigned int flags, const BaseSignatureChecker& checker); bool EvalScript(std::vector<std::vector<unsigned char> >& stack, const CScript& script, unsigned int flags, const BaseSignatureChecker& checker, ScriptError* error = NULL);
bool VerifyScript(const CScript& scriptSig, const CScript& scriptPubKey, unsigned int flags, const BaseSignatureChecker& checker); bool VerifyScript(const CScript& scriptSig, const CScript& scriptPubKey, unsigned int flags, const BaseSignatureChecker& checker, ScriptError* error = NULL);
#endif // BITCOIN_SCRIPT_INTERPRETER_H #endif // BITCOIN_SCRIPT_INTERPRETER_H

View file

@ -0,0 +1,67 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
// Copyright (c) 2009-2014 The Bitcoin developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include "script_error.h"
const char* ScriptErrorString(const ScriptError serror)
{
switch (serror)
{
case SCRIPT_ERR_OK:
return "No error";
case SCRIPT_ERR_EVAL_FALSE:
return "Script evaluated without error but finished with a false/empty top stack element";
case SCRIPT_ERR_VERIFY:
return "Script failed an OP_VERIFY operation";
case SCRIPT_ERR_EQUALVERIFY:
return "Script failed an OP_EQUALVERIFY operation";
case SCRIPT_ERR_CHECKMULTISIGVERIFY:
return "Script failed an OP_CHECKMULTISIGVERIFY operation";
case SCRIPT_ERR_CHECKSIGVERIFY:
return "Script failed an OP_CHECKSIGVERIFY operation";
case SCRIPT_ERR_NUMEQUALVERIFY:
return "Script failed an OP_NUMEQUALVERIFY operation";
case SCRIPT_ERR_SCRIPT_SIZE:
return "Script is too big";
case SCRIPT_ERR_PUSH_SIZE:
return "Push value size limit exceeded";
case SCRIPT_ERR_OP_COUNT:
return "Operation limit exceeded";
case SCRIPT_ERR_STACK_SIZE:
return "Stack size limit exceeded";
case SCRIPT_ERR_SIG_COUNT:
return "Signature count negative or greater than pubkey count";
case SCRIPT_ERR_PUBKEY_COUNT:
return "Pubkey count negative or limit exceeded";
case SCRIPT_ERR_BAD_OPCODE:
return "Opcode missing or not understood";
case SCRIPT_ERR_DISABLED_OPCODE:
return "Attempted to use a disabled opcode";
case SCRIPT_ERR_INVALID_STACK_OPERATION:
return "Operation not valid with the current stack size";
case SCRIPT_ERR_INVALID_ALTSTACK_OPERATION:
return "Operation not valid with the current altstack size";
case SCRIPT_ERR_OP_RETURN:
return "OP_RETURN was encountered";
case SCRIPT_ERR_UNBALANCED_CONDITIONAL:
return "Invalid OP_IF construction";
case SCRIPT_ERR_SIG_HASHTYPE:
return "Signature hash type missing or not understood";
case SCRIPT_ERR_SIG_DER:
return "Non-canonical DER signature";
case SCRIPT_ERR_MINIMALDATA:
return "Data push larger than necessary";
case SCRIPT_ERR_SIG_PUSHONLY:
return "Only non-push operators allowed in signatures";
case SCRIPT_ERR_SIG_HIGH_S:
return "Non-canonical signature: S value is unnecessarily high";
case SCRIPT_ERR_SIG_NULLDUMMY:
return "Dummy CHECKMULTISIG argument must be zero";
case SCRIPT_ERR_UNKNOWN_ERROR:
case SCRIPT_ERR_ERROR_COUNT:
default: break;
}
return "unknown error";
}

53
src/script/script_error.h Normal file
View file

@ -0,0 +1,53 @@
// Copyright (c) 2009-2010 Satoshi Nakamoto
// Copyright (c) 2009-2014 The Bitcoin developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#ifndef BITCOIN_SCRIPT_ERROR_H
#define BITCOIN_SCRIPT_ERROR_H
typedef enum ScriptError_t
{
SCRIPT_ERR_OK = 0,
SCRIPT_ERR_UNKNOWN_ERROR,
SCRIPT_ERR_EVAL_FALSE,
SCRIPT_ERR_OP_RETURN,
/* Max sizes */
SCRIPT_ERR_SCRIPT_SIZE,
SCRIPT_ERR_PUSH_SIZE,
SCRIPT_ERR_OP_COUNT,
SCRIPT_ERR_STACK_SIZE,
SCRIPT_ERR_SIG_COUNT,
SCRIPT_ERR_PUBKEY_COUNT,
/* Failed verify operations */
SCRIPT_ERR_VERIFY,
SCRIPT_ERR_EQUALVERIFY,
SCRIPT_ERR_CHECKMULTISIGVERIFY,
SCRIPT_ERR_CHECKSIGVERIFY,
SCRIPT_ERR_NUMEQUALVERIFY,
/* Logical/Format/Canonical errors */
SCRIPT_ERR_BAD_OPCODE,
SCRIPT_ERR_DISABLED_OPCODE,
SCRIPT_ERR_INVALID_STACK_OPERATION,
SCRIPT_ERR_INVALID_ALTSTACK_OPERATION,
SCRIPT_ERR_UNBALANCED_CONDITIONAL,
/* BIP62 */
SCRIPT_ERR_SIG_HASHTYPE,
SCRIPT_ERR_SIG_DER,
SCRIPT_ERR_MINIMALDATA,
SCRIPT_ERR_SIG_PUSHONLY,
SCRIPT_ERR_SIG_HIGH_S,
SCRIPT_ERR_SIG_NULLDUMMY,
SCRIPT_ERR_ERROR_COUNT
} ScriptError;
#define SCRIPT_ERR_LAST SCRIPT_ERR_ERROR_COUNT
const char* ScriptErrorString(const ScriptError error);
#endif // BITCOIN_SCRIPT_ERROR_H

View file

@ -6,6 +6,7 @@
#include "keystore.h" #include "keystore.h"
#include "main.h" #include "main.h"
#include "script/script.h" #include "script/script.h"
#include "script/script_error.h"
#include "script/interpreter.h" #include "script/interpreter.h"
#include "script/sign.h" #include "script/sign.h"
#include "uint256.h" #include "uint256.h"
@ -46,6 +47,7 @@ BOOST_AUTO_TEST_CASE(multisig_verify)
{ {
unsigned int flags = SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_STRICTENC; unsigned int flags = SCRIPT_VERIFY_P2SH | SCRIPT_VERIFY_STRICTENC;
ScriptError err;
CKey key[4]; CKey key[4];
for (int i = 0; i < 4; i++) for (int i = 0; i < 4; i++)
key[i].MakeNewKey(true); key[i].MakeNewKey(true);
@ -82,19 +84,22 @@ BOOST_AUTO_TEST_CASE(multisig_verify)
keys.clear(); keys.clear();
keys += key[0],key[1]; // magic operator+= from boost.assign keys += key[0],key[1]; // magic operator+= from boost.assign
s = sign_multisig(a_and_b, keys, txTo[0], 0); s = sign_multisig(a_and_b, keys, txTo[0], 0);
BOOST_CHECK(VerifyScript(s, a_and_b, flags, SignatureChecker(txTo[0], 0))); BOOST_CHECK(VerifyScript(s, a_and_b, flags, SignatureChecker(txTo[0], 0), &err));
BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err));
for (int i = 0; i < 4; i++) for (int i = 0; i < 4; i++)
{ {
keys.clear(); keys.clear();
keys += key[i]; keys += key[i];
s = sign_multisig(a_and_b, keys, txTo[0], 0); s = sign_multisig(a_and_b, keys, txTo[0], 0);
BOOST_CHECK_MESSAGE(!VerifyScript(s, a_and_b, flags, SignatureChecker(txTo[0], 0)), strprintf("a&b 1: %d", i)); BOOST_CHECK_MESSAGE(!VerifyScript(s, a_and_b, flags, SignatureChecker(txTo[0], 0), &err), strprintf("a&b 1: %d", i));
BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_INVALID_STACK_OPERATION, ScriptErrorString(err));
keys.clear(); keys.clear();
keys += key[1],key[i]; keys += key[1],key[i];
s = sign_multisig(a_and_b, keys, txTo[0], 0); s = sign_multisig(a_and_b, keys, txTo[0], 0);
BOOST_CHECK_MESSAGE(!VerifyScript(s, a_and_b, flags, SignatureChecker(txTo[0], 0)), strprintf("a&b 2: %d", i)); BOOST_CHECK_MESSAGE(!VerifyScript(s, a_and_b, flags, SignatureChecker(txTo[0], 0), &err), strprintf("a&b 2: %d", i));
BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_EVAL_FALSE, ScriptErrorString(err));
} }
// Test a OR b: // Test a OR b:
@ -104,16 +109,24 @@ BOOST_AUTO_TEST_CASE(multisig_verify)
keys += key[i]; keys += key[i];
s = sign_multisig(a_or_b, keys, txTo[1], 0); s = sign_multisig(a_or_b, keys, txTo[1], 0);
if (i == 0 || i == 1) if (i == 0 || i == 1)
BOOST_CHECK_MESSAGE(VerifyScript(s, a_or_b, flags, SignatureChecker(txTo[1], 0)), strprintf("a|b: %d", i)); {
BOOST_CHECK_MESSAGE(VerifyScript(s, a_or_b, flags, SignatureChecker(txTo[1], 0), &err), strprintf("a|b: %d", i));
BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err));
}
else else
BOOST_CHECK_MESSAGE(!VerifyScript(s, a_or_b, flags, SignatureChecker(txTo[1], 0)), strprintf("a|b: %d", i)); {
BOOST_CHECK_MESSAGE(!VerifyScript(s, a_or_b, flags, SignatureChecker(txTo[1], 0), &err), strprintf("a|b: %d", i));
BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_EVAL_FALSE, ScriptErrorString(err));
}
} }
s.clear(); s.clear();
s << OP_0 << OP_0; s << OP_0 << OP_0;
BOOST_CHECK(!VerifyScript(s, a_or_b, flags, SignatureChecker(txTo[1], 0))); BOOST_CHECK(!VerifyScript(s, a_or_b, flags, SignatureChecker(txTo[1], 0), &err));
BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_SIG_DER, ScriptErrorString(err));
s.clear(); s.clear();
s << OP_0 << OP_1; s << OP_0 << OP_1;
BOOST_CHECK(!VerifyScript(s, a_or_b, flags, SignatureChecker(txTo[1], 0))); BOOST_CHECK(!VerifyScript(s, a_or_b, flags, SignatureChecker(txTo[1], 0), &err));
BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_SIG_DER, ScriptErrorString(err));
for (int i = 0; i < 4; i++) for (int i = 0; i < 4; i++)
@ -123,9 +136,15 @@ BOOST_AUTO_TEST_CASE(multisig_verify)
keys += key[i],key[j]; keys += key[i],key[j];
s = sign_multisig(escrow, keys, txTo[2], 0); s = sign_multisig(escrow, keys, txTo[2], 0);
if (i < j && i < 3 && j < 3) if (i < j && i < 3 && j < 3)
BOOST_CHECK_MESSAGE(VerifyScript(s, escrow, flags, SignatureChecker(txTo[2], 0)), strprintf("escrow 1: %d %d", i, j)); {
BOOST_CHECK_MESSAGE(VerifyScript(s, escrow, flags, SignatureChecker(txTo[2], 0), &err), strprintf("escrow 1: %d %d", i, j));
BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err));
}
else else
BOOST_CHECK_MESSAGE(!VerifyScript(s, escrow, flags, SignatureChecker(txTo[2], 0)), strprintf("escrow 2: %d %d", i, j)); {
BOOST_CHECK_MESSAGE(!VerifyScript(s, escrow, flags, SignatureChecker(txTo[2], 0), &err), strprintf("escrow 2: %d %d", i, j));
BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_EVAL_FALSE, ScriptErrorString(err));
}
} }
} }

View file

@ -6,6 +6,7 @@
#include "keystore.h" #include "keystore.h"
#include "main.h" #include "main.h"
#include "script/script.h" #include "script/script.h"
#include "script/script_error.h"
#include "script/sign.h" #include "script/sign.h"
#ifdef ENABLE_WALLET #ifdef ENABLE_WALLET
@ -27,7 +28,7 @@ Serialize(const CScript& s)
} }
static bool static bool
Verify(const CScript& scriptSig, const CScript& scriptPubKey, bool fStrict) Verify(const CScript& scriptSig, const CScript& scriptPubKey, bool fStrict, ScriptError& err)
{ {
// Create dummy to/from transactions: // Create dummy to/from transactions:
CMutableTransaction txFrom; CMutableTransaction txFrom;
@ -42,7 +43,7 @@ Verify(const CScript& scriptSig, const CScript& scriptPubKey, bool fStrict)
txTo.vin[0].scriptSig = scriptSig; txTo.vin[0].scriptSig = scriptSig;
txTo.vout[0].nValue = 1; txTo.vout[0].nValue = 1;
return VerifyScript(scriptSig, scriptPubKey, fStrict ? SCRIPT_VERIFY_P2SH : SCRIPT_VERIFY_NONE, SignatureChecker(txTo, 0)); return VerifyScript(scriptSig, scriptPubKey, fStrict ? SCRIPT_VERIFY_P2SH : SCRIPT_VERIFY_NONE, SignatureChecker(txTo, 0), &err);
} }
@ -124,6 +125,7 @@ BOOST_AUTO_TEST_CASE(sign)
BOOST_AUTO_TEST_CASE(norecurse) BOOST_AUTO_TEST_CASE(norecurse)
{ {
ScriptError err;
// Make sure only the outer pay-to-script-hash does the // Make sure only the outer pay-to-script-hash does the
// extra-validation thing: // extra-validation thing:
CScript invalidAsScript; CScript invalidAsScript;
@ -135,7 +137,8 @@ BOOST_AUTO_TEST_CASE(norecurse)
scriptSig << Serialize(invalidAsScript); scriptSig << Serialize(invalidAsScript);
// Should not verify, because it will try to execute OP_INVALIDOPCODE // Should not verify, because it will try to execute OP_INVALIDOPCODE
BOOST_CHECK(!Verify(scriptSig, p2sh, true)); BOOST_CHECK(!Verify(scriptSig, p2sh, true, err));
BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_BAD_OPCODE, ScriptErrorString(err));
// Try to recur, and verification should succeed because // Try to recur, and verification should succeed because
// the inner HASH160 <> EQUAL should only check the hash: // the inner HASH160 <> EQUAL should only check the hash:
@ -143,7 +146,8 @@ BOOST_AUTO_TEST_CASE(norecurse)
CScript scriptSig2; CScript scriptSig2;
scriptSig2 << Serialize(invalidAsScript) << Serialize(p2sh); scriptSig2 << Serialize(invalidAsScript) << Serialize(p2sh);
BOOST_CHECK(Verify(scriptSig2, p2sh2, true)); BOOST_CHECK(Verify(scriptSig2, p2sh2, true, err));
BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err));
} }
BOOST_AUTO_TEST_CASE(set) BOOST_AUTO_TEST_CASE(set)
@ -238,6 +242,7 @@ BOOST_AUTO_TEST_CASE(switchover)
{ {
// Test switch over code // Test switch over code
CScript notValid; CScript notValid;
ScriptError err;
notValid << OP_11 << OP_12 << OP_EQUALVERIFY; notValid << OP_11 << OP_12 << OP_EQUALVERIFY;
CScript scriptSig; CScript scriptSig;
scriptSig << Serialize(notValid); scriptSig << Serialize(notValid);
@ -246,9 +251,11 @@ BOOST_AUTO_TEST_CASE(switchover)
// Validation should succeed under old rules (hash is correct): // Validation should succeed under old rules (hash is correct):
BOOST_CHECK(Verify(scriptSig, fund, false)); BOOST_CHECK(Verify(scriptSig, fund, false, err));
BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err));
// Fail under new: // Fail under new:
BOOST_CHECK(!Verify(scriptSig, fund, true)); BOOST_CHECK(!Verify(scriptSig, fund, true, err));
BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_EQUALVERIFY, ScriptErrorString(err));
} }
BOOST_AUTO_TEST_CASE(AreInputsStandard) BOOST_AUTO_TEST_CASE(AreInputsStandard)

View file

@ -10,6 +10,7 @@
#include "keystore.h" #include "keystore.h"
#include "main.h" #include "main.h"
#include "script/script.h" #include "script/script.h"
#include "script/script_error.h"
#include "script/sign.h" #include "script/sign.h"
#include "util.h" #include "util.h"
@ -92,7 +93,9 @@ CMutableTransaction BuildSpendingTransaction(const CScript& scriptSig, const CMu
void DoTest(const CScript& scriptPubKey, const CScript& scriptSig, int flags, bool expect, const std::string& message) void DoTest(const CScript& scriptPubKey, const CScript& scriptSig, int flags, bool expect, const std::string& message)
{ {
BOOST_CHECK_MESSAGE(VerifyScript(scriptSig, scriptPubKey, flags, SignatureChecker(BuildSpendingTransaction(scriptSig, BuildCreditingTransaction(scriptPubKey)), 0)) == expect, message); ScriptError err;
BOOST_CHECK_MESSAGE(VerifyScript(scriptSig, scriptPubKey, flags, SignatureChecker(BuildSpendingTransaction(scriptSig, BuildCreditingTransaction(scriptPubKey)), 0), &err) == expect, message);
BOOST_CHECK_MESSAGE(expect == (err == SCRIPT_ERR_OK), std::string(ScriptErrorString(err)) + ": " + message);
} }
void static NegateSignatureS(std::vector<unsigned char>& vchSig) { void static NegateSignatureS(std::vector<unsigned char>& vchSig) {
@ -590,20 +593,25 @@ BOOST_AUTO_TEST_CASE(script_PushData)
static const unsigned char pushdata2[] = { OP_PUSHDATA2, 1, 0, 0x5a }; static const unsigned char pushdata2[] = { OP_PUSHDATA2, 1, 0, 0x5a };
static const unsigned char pushdata4[] = { OP_PUSHDATA4, 1, 0, 0, 0, 0x5a }; static const unsigned char pushdata4[] = { OP_PUSHDATA4, 1, 0, 0, 0, 0x5a };
ScriptError err;
vector<vector<unsigned char> > directStack; vector<vector<unsigned char> > directStack;
BOOST_CHECK(EvalScript(directStack, CScript(&direct[0], &direct[sizeof(direct)]), true, BaseSignatureChecker())); BOOST_CHECK(EvalScript(directStack, CScript(&direct[0], &direct[sizeof(direct)]), true, BaseSignatureChecker(), &err));
BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err));
vector<vector<unsigned char> > pushdata1Stack; vector<vector<unsigned char> > pushdata1Stack;
BOOST_CHECK(EvalScript(pushdata1Stack, CScript(&pushdata1[0], &pushdata1[sizeof(pushdata1)]), true, BaseSignatureChecker())); BOOST_CHECK(EvalScript(pushdata1Stack, CScript(&pushdata1[0], &pushdata1[sizeof(pushdata1)]), true, BaseSignatureChecker(), &err));
BOOST_CHECK(pushdata1Stack == directStack); BOOST_CHECK(pushdata1Stack == directStack);
BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err));
vector<vector<unsigned char> > pushdata2Stack; vector<vector<unsigned char> > pushdata2Stack;
BOOST_CHECK(EvalScript(pushdata2Stack, CScript(&pushdata2[0], &pushdata2[sizeof(pushdata2)]), true, BaseSignatureChecker())); BOOST_CHECK(EvalScript(pushdata2Stack, CScript(&pushdata2[0], &pushdata2[sizeof(pushdata2)]), true, BaseSignatureChecker(), &err));
BOOST_CHECK(pushdata2Stack == directStack); BOOST_CHECK(pushdata2Stack == directStack);
BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err));
vector<vector<unsigned char> > pushdata4Stack; vector<vector<unsigned char> > pushdata4Stack;
BOOST_CHECK(EvalScript(pushdata4Stack, CScript(&pushdata4[0], &pushdata4[sizeof(pushdata4)]), true, BaseSignatureChecker())); BOOST_CHECK(EvalScript(pushdata4Stack, CScript(&pushdata4[0], &pushdata4[sizeof(pushdata4)]), true, BaseSignatureChecker(), &err));
BOOST_CHECK(pushdata4Stack == directStack); BOOST_CHECK(pushdata4Stack == directStack);
BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err));
} }
CScript CScript
@ -640,6 +648,7 @@ sign_multisig(CScript scriptPubKey, const CKey &key, CTransaction transaction)
BOOST_AUTO_TEST_CASE(script_CHECKMULTISIG12) BOOST_AUTO_TEST_CASE(script_CHECKMULTISIG12)
{ {
ScriptError err;
CKey key1, key2, key3; CKey key1, key2, key3;
key1.MakeNewKey(true); key1.MakeNewKey(true);
key2.MakeNewKey(false); key2.MakeNewKey(false);
@ -652,19 +661,24 @@ BOOST_AUTO_TEST_CASE(script_CHECKMULTISIG12)
CMutableTransaction txTo12 = BuildSpendingTransaction(CScript(), txFrom12); CMutableTransaction txTo12 = BuildSpendingTransaction(CScript(), txFrom12);
CScript goodsig1 = sign_multisig(scriptPubKey12, key1, txTo12); CScript goodsig1 = sign_multisig(scriptPubKey12, key1, txTo12);
BOOST_CHECK(VerifyScript(goodsig1, scriptPubKey12, flags, SignatureChecker(txTo12, 0))); BOOST_CHECK(VerifyScript(goodsig1, scriptPubKey12, flags, SignatureChecker(txTo12, 0), &err));
BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err));
txTo12.vout[0].nValue = 2; txTo12.vout[0].nValue = 2;
BOOST_CHECK(!VerifyScript(goodsig1, scriptPubKey12, flags, SignatureChecker(txTo12, 0))); BOOST_CHECK(!VerifyScript(goodsig1, scriptPubKey12, flags, SignatureChecker(txTo12, 0), &err));
BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_EVAL_FALSE, ScriptErrorString(err));
CScript goodsig2 = sign_multisig(scriptPubKey12, key2, txTo12); CScript goodsig2 = sign_multisig(scriptPubKey12, key2, txTo12);
BOOST_CHECK(VerifyScript(goodsig2, scriptPubKey12, flags, SignatureChecker(txTo12, 0))); BOOST_CHECK(VerifyScript(goodsig2, scriptPubKey12, flags, SignatureChecker(txTo12, 0), &err));
BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err));
CScript badsig1 = sign_multisig(scriptPubKey12, key3, txTo12); CScript badsig1 = sign_multisig(scriptPubKey12, key3, txTo12);
BOOST_CHECK(!VerifyScript(badsig1, scriptPubKey12, flags, SignatureChecker(txTo12, 0))); BOOST_CHECK(!VerifyScript(badsig1, scriptPubKey12, flags, SignatureChecker(txTo12, 0), &err));
BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_EVAL_FALSE, ScriptErrorString(err));
} }
BOOST_AUTO_TEST_CASE(script_CHECKMULTISIG23) BOOST_AUTO_TEST_CASE(script_CHECKMULTISIG23)
{ {
ScriptError err;
CKey key1, key2, key3, key4; CKey key1, key2, key3, key4;
key1.MakeNewKey(true); key1.MakeNewKey(true);
key2.MakeNewKey(false); key2.MakeNewKey(false);
@ -680,46 +694,55 @@ BOOST_AUTO_TEST_CASE(script_CHECKMULTISIG23)
std::vector<CKey> keys; std::vector<CKey> keys;
keys.push_back(key1); keys.push_back(key2); keys.push_back(key1); keys.push_back(key2);
CScript goodsig1 = sign_multisig(scriptPubKey23, keys, txTo23); CScript goodsig1 = sign_multisig(scriptPubKey23, keys, txTo23);
BOOST_CHECK(VerifyScript(goodsig1, scriptPubKey23, flags, SignatureChecker(txTo23, 0))); BOOST_CHECK(VerifyScript(goodsig1, scriptPubKey23, flags, SignatureChecker(txTo23, 0), &err));
BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err));
keys.clear(); keys.clear();
keys.push_back(key1); keys.push_back(key3); keys.push_back(key1); keys.push_back(key3);
CScript goodsig2 = sign_multisig(scriptPubKey23, keys, txTo23); CScript goodsig2 = sign_multisig(scriptPubKey23, keys, txTo23);
BOOST_CHECK(VerifyScript(goodsig2, scriptPubKey23, flags, SignatureChecker(txTo23, 0))); BOOST_CHECK(VerifyScript(goodsig2, scriptPubKey23, flags, SignatureChecker(txTo23, 0), &err));
BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err));
keys.clear(); keys.clear();
keys.push_back(key2); keys.push_back(key3); keys.push_back(key2); keys.push_back(key3);
CScript goodsig3 = sign_multisig(scriptPubKey23, keys, txTo23); CScript goodsig3 = sign_multisig(scriptPubKey23, keys, txTo23);
BOOST_CHECK(VerifyScript(goodsig3, scriptPubKey23, flags, SignatureChecker(txTo23, 0))); BOOST_CHECK(VerifyScript(goodsig3, scriptPubKey23, flags, SignatureChecker(txTo23, 0), &err));
BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err));
keys.clear(); keys.clear();
keys.push_back(key2); keys.push_back(key2); // Can't re-use sig keys.push_back(key2); keys.push_back(key2); // Can't re-use sig
CScript badsig1 = sign_multisig(scriptPubKey23, keys, txTo23); CScript badsig1 = sign_multisig(scriptPubKey23, keys, txTo23);
BOOST_CHECK(!VerifyScript(badsig1, scriptPubKey23, flags, SignatureChecker(txTo23, 0))); BOOST_CHECK(!VerifyScript(badsig1, scriptPubKey23, flags, SignatureChecker(txTo23, 0), &err));
BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_EVAL_FALSE, ScriptErrorString(err));
keys.clear(); keys.clear();
keys.push_back(key2); keys.push_back(key1); // sigs must be in correct order keys.push_back(key2); keys.push_back(key1); // sigs must be in correct order
CScript badsig2 = sign_multisig(scriptPubKey23, keys, txTo23); CScript badsig2 = sign_multisig(scriptPubKey23, keys, txTo23);
BOOST_CHECK(!VerifyScript(badsig2, scriptPubKey23, flags, SignatureChecker(txTo23, 0))); BOOST_CHECK(!VerifyScript(badsig2, scriptPubKey23, flags, SignatureChecker(txTo23, 0), &err));
BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_EVAL_FALSE, ScriptErrorString(err));
keys.clear(); keys.clear();
keys.push_back(key3); keys.push_back(key2); // sigs must be in correct order keys.push_back(key3); keys.push_back(key2); // sigs must be in correct order
CScript badsig3 = sign_multisig(scriptPubKey23, keys, txTo23); CScript badsig3 = sign_multisig(scriptPubKey23, keys, txTo23);
BOOST_CHECK(!VerifyScript(badsig3, scriptPubKey23, flags, SignatureChecker(txTo23, 0))); BOOST_CHECK(!VerifyScript(badsig3, scriptPubKey23, flags, SignatureChecker(txTo23, 0), &err));
BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_EVAL_FALSE, ScriptErrorString(err));
keys.clear(); keys.clear();
keys.push_back(key4); keys.push_back(key2); // sigs must match pubkeys keys.push_back(key4); keys.push_back(key2); // sigs must match pubkeys
CScript badsig4 = sign_multisig(scriptPubKey23, keys, txTo23); CScript badsig4 = sign_multisig(scriptPubKey23, keys, txTo23);
BOOST_CHECK(!VerifyScript(badsig4, scriptPubKey23, flags, SignatureChecker(txTo23, 0))); BOOST_CHECK(!VerifyScript(badsig4, scriptPubKey23, flags, SignatureChecker(txTo23, 0), &err));
BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_EVAL_FALSE, ScriptErrorString(err));
keys.clear(); keys.clear();
keys.push_back(key1); keys.push_back(key4); // sigs must match pubkeys keys.push_back(key1); keys.push_back(key4); // sigs must match pubkeys
CScript badsig5 = sign_multisig(scriptPubKey23, keys, txTo23); CScript badsig5 = sign_multisig(scriptPubKey23, keys, txTo23);
BOOST_CHECK(!VerifyScript(badsig5, scriptPubKey23, flags, SignatureChecker(txTo23, 0))); BOOST_CHECK(!VerifyScript(badsig5, scriptPubKey23, flags, SignatureChecker(txTo23, 0), &err));
BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_EVAL_FALSE, ScriptErrorString(err));
keys.clear(); // Must have signatures keys.clear(); // Must have signatures
CScript badsig6 = sign_multisig(scriptPubKey23, keys, txTo23); CScript badsig6 = sign_multisig(scriptPubKey23, keys, txTo23);
BOOST_CHECK(!VerifyScript(badsig6, scriptPubKey23, flags, SignatureChecker(txTo23, 0))); BOOST_CHECK(!VerifyScript(badsig6, scriptPubKey23, flags, SignatureChecker(txTo23, 0), &err));
BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_INVALID_STACK_OPERATION, ScriptErrorString(err));
} }
BOOST_AUTO_TEST_CASE(script_combineSigs) BOOST_AUTO_TEST_CASE(script_combineSigs)
@ -833,11 +856,13 @@ BOOST_AUTO_TEST_CASE(script_combineSigs)
BOOST_AUTO_TEST_CASE(script_standard_push) BOOST_AUTO_TEST_CASE(script_standard_push)
{ {
ScriptError err;
for (int i=0; i<67000; i++) { for (int i=0; i<67000; i++) {
CScript script; CScript script;
script << i; script << i;
BOOST_CHECK_MESSAGE(script.IsPushOnly(), "Number " << i << " is not pure push."); BOOST_CHECK_MESSAGE(script.IsPushOnly(), "Number " << i << " is not pure push.");
BOOST_CHECK_MESSAGE(VerifyScript(script, CScript() << OP_1, SCRIPT_VERIFY_MINIMALDATA, BaseSignatureChecker()), "Number " << i << " push is not minimal data."); BOOST_CHECK_MESSAGE(VerifyScript(script, CScript() << OP_1, SCRIPT_VERIFY_MINIMALDATA, BaseSignatureChecker(), &err), "Number " << i << " push is not minimal data.");
BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err));
} }
for (unsigned int i=0; i<=MAX_SCRIPT_ELEMENT_SIZE; i++) { for (unsigned int i=0; i<=MAX_SCRIPT_ELEMENT_SIZE; i++) {
@ -845,7 +870,8 @@ BOOST_AUTO_TEST_CASE(script_standard_push)
CScript script; CScript script;
script << data; script << data;
BOOST_CHECK_MESSAGE(script.IsPushOnly(), "Length " << i << " is not pure push."); BOOST_CHECK_MESSAGE(script.IsPushOnly(), "Length " << i << " is not pure push.");
BOOST_CHECK_MESSAGE(VerifyScript(script, CScript() << OP_1, SCRIPT_VERIFY_MINIMALDATA, BaseSignatureChecker()), "Length " << i << " push is not minimal data."); BOOST_CHECK_MESSAGE(VerifyScript(script, CScript() << OP_1, SCRIPT_VERIFY_MINIMALDATA, BaseSignatureChecker(), &err), "Length " << i << " push is not minimal data.");
BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err));
} }
} }

View file

@ -10,6 +10,7 @@
#include "keystore.h" #include "keystore.h"
#include "main.h" #include "main.h"
#include "script/script.h" #include "script/script.h"
#include "script/script_error.h"
#include "core_io.h" #include "core_io.h"
#include <map> #include <map>
@ -86,6 +87,7 @@ BOOST_AUTO_TEST_CASE(tx_valid)
// verifyFlags is a comma separated list of script verification flags to apply, or "NONE" // verifyFlags is a comma separated list of script verification flags to apply, or "NONE"
Array tests = read_json(std::string(json_tests::tx_valid, json_tests::tx_valid + sizeof(json_tests::tx_valid))); Array tests = read_json(std::string(json_tests::tx_valid, json_tests::tx_valid + sizeof(json_tests::tx_valid)));
ScriptError err;
BOOST_FOREACH(Value& tv, tests) BOOST_FOREACH(Value& tv, tests)
{ {
Array test = tv.get_array(); Array test = tv.get_array();
@ -142,8 +144,9 @@ BOOST_AUTO_TEST_CASE(tx_valid)
unsigned int verify_flags = ParseScriptFlags(test[2].get_str()); unsigned int verify_flags = ParseScriptFlags(test[2].get_str());
BOOST_CHECK_MESSAGE(VerifyScript(tx.vin[i].scriptSig, mapprevOutScriptPubKeys[tx.vin[i].prevout], BOOST_CHECK_MESSAGE(VerifyScript(tx.vin[i].scriptSig, mapprevOutScriptPubKeys[tx.vin[i].prevout],
verify_flags, SignatureChecker(tx, i)), verify_flags, SignatureChecker(tx, i), &err),
strTest); strTest);
BOOST_CHECK_MESSAGE(err == SCRIPT_ERR_OK, ScriptErrorString(err));
} }
} }
} }
@ -160,6 +163,7 @@ BOOST_AUTO_TEST_CASE(tx_invalid)
// verifyFlags is a comma separated list of script verification flags to apply, or "NONE" // verifyFlags is a comma separated list of script verification flags to apply, or "NONE"
Array tests = read_json(std::string(json_tests::tx_invalid, json_tests::tx_invalid + sizeof(json_tests::tx_invalid))); Array tests = read_json(std::string(json_tests::tx_invalid, json_tests::tx_invalid + sizeof(json_tests::tx_invalid)));
ScriptError err;
BOOST_FOREACH(Value& tv, tests) BOOST_FOREACH(Value& tv, tests)
{ {
Array test = tv.get_array(); Array test = tv.get_array();
@ -215,10 +219,10 @@ BOOST_AUTO_TEST_CASE(tx_invalid)
unsigned int verify_flags = ParseScriptFlags(test[2].get_str()); unsigned int verify_flags = ParseScriptFlags(test[2].get_str());
fValid = VerifyScript(tx.vin[i].scriptSig, mapprevOutScriptPubKeys[tx.vin[i].prevout], fValid = VerifyScript(tx.vin[i].scriptSig, mapprevOutScriptPubKeys[tx.vin[i].prevout],
verify_flags, SignatureChecker(tx, i)); verify_flags, SignatureChecker(tx, i), &err);
} }
BOOST_CHECK_MESSAGE(!fValid, strTest); BOOST_CHECK_MESSAGE(!fValid, strTest);
BOOST_CHECK_MESSAGE(err != SCRIPT_ERR_OK, ScriptErrorString(err));
} }
} }
} }