Browse Source

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)
0.10
Wladimir J. van der Laan 10 years ago
parent
commit
8adf457047
No known key found for this signature in database
GPG Key ID: 74810B012346C9A6
  1. 2
      src/Makefile.am
  2. 297
      src/script/interpreter.cpp
  3. 6
      src/script/interpreter.h
  4. 67
      src/script/script_error.cpp
  5. 53
      src/script/script_error.h
  6. 37
      src/test/multisig_tests.cpp
  7. 19
      src/test/script_P2SH_tests.cpp
  8. 66
      src/test/script_tests.cpp
  9. 10
      src/test/transaction_tests.cpp

2
src/Makefile.am

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

297
src/script/interpreter.cpp

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

6
src/script/interpreter.h

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

67
src/script/script_error.cpp

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

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

37
src/test/multisig_tests.cpp

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

19
src/test/script_P2SH_tests.cpp

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

66
src/test/script_tests.cpp

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

10
src/test/transaction_tests.cpp

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

Loading…
Cancel
Save