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:
commit
8adf457047
9 changed files with 400 additions and 157 deletions
|
@ -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.
|
||||||
|
|
|
@ -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,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
Normal file
67
src/script/script_error.cpp
Normal 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
53
src/script/script_error.h
Normal 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
|
|
@ -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));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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,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…
Reference in a new issue