03914234b3
NOP1 to NOP10 are reserved for future soft-fork upgrades. In the event
of an upgrade such NOPs have *VERIFY behavior, meaning that if their
arguments are not correct the script fails. Discouraging these NOPs by
rejecting transactions containing them from the mempool ensures that
we'll never accept transactions, nor mine blocks, with scripts that are
now invalid according to the majority of hashing power even if we're not
yet upgraded. Previously this wasn't an issue as the IsStandard() rules
didn't allow upgradable NOPs anyway, but 7f3b4e95
relaxed the
IsStandard() rules for P2SH redemptions allowing any redeemScript to be
spent.
We *do* allow upgradable NOPs in scripts so long as they are not
executed. This is harmless as there is no opportunity for the script to
be invalid post-upgrade.
1128 lines
41 KiB
C++
1128 lines
41 KiB
C++
// 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 "interpreter.h"
|
|
|
|
#include "core/transaction.h"
|
|
#include "crypto/ripemd160.h"
|
|
#include "crypto/sha1.h"
|
|
#include "crypto/sha2.h"
|
|
#include "eccryptoverify.h"
|
|
#include "pubkey.h"
|
|
#include "script/script.h"
|
|
#include "uint256.h"
|
|
|
|
using namespace std;
|
|
|
|
typedef vector<unsigned char> valtype;
|
|
static const valtype vchFalse(0);
|
|
static const valtype vchZero(0);
|
|
static const valtype vchTrue(1, 1);
|
|
static const CScriptNum bnZero(0);
|
|
static const CScriptNum bnOne(1);
|
|
static const CScriptNum bnFalse(0);
|
|
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)
|
|
{
|
|
for (unsigned int i = 0; i < vch.size(); i++)
|
|
{
|
|
if (vch[i] != 0)
|
|
{
|
|
// Can be negative zero
|
|
if (i == vch.size()-1 && vch[i] == 0x80)
|
|
return false;
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* Script is a stack machine (like Forth) that evaluates a predicate
|
|
* returning a bool indicating valid or not. There are no loops.
|
|
*/
|
|
#define stacktop(i) (stack.at(stack.size()+(i)))
|
|
#define altstacktop(i) (altstack.at(altstack.size()+(i)))
|
|
static inline void popstack(vector<valtype>& stack)
|
|
{
|
|
if (stack.empty())
|
|
throw runtime_error("popstack() : stack empty");
|
|
stack.pop_back();
|
|
}
|
|
|
|
bool static IsCompressedOrUncompressedPubKey(const valtype &vchPubKey) {
|
|
if (vchPubKey.size() < 33) {
|
|
// Non-canonical public key: too short
|
|
return false;
|
|
}
|
|
if (vchPubKey[0] == 0x04) {
|
|
if (vchPubKey.size() != 65) {
|
|
// Non-canonical public key: invalid length for uncompressed key
|
|
return false;
|
|
}
|
|
} else if (vchPubKey[0] == 0x02 || vchPubKey[0] == 0x03) {
|
|
if (vchPubKey.size() != 33) {
|
|
// Non-canonical public key: invalid length for compressed key
|
|
return false;
|
|
}
|
|
} else {
|
|
// Non-canonical public key: neither compressed nor uncompressed
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* A canonical signature exists of: <30> <total len> <02> <len R> <R> <02> <len S> <S> <hashtype>
|
|
* Where R and S are not negative (their first byte has its highest bit not set), and not
|
|
* excessively padded (do not start with a 0 byte, unless an otherwise negative number follows,
|
|
* in which case a single 0 byte is necessary and even required).
|
|
*
|
|
* See https://bitcointalk.org/index.php?topic=8392.msg127623#msg127623
|
|
*/
|
|
bool static IsDERSignature(const valtype &vchSig) {
|
|
|
|
if (vchSig.size() < 9) {
|
|
// Non-canonical signature: too short
|
|
return false;
|
|
}
|
|
if (vchSig.size() > 73) {
|
|
// Non-canonical signature: too long
|
|
return false;
|
|
}
|
|
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];
|
|
if (5 + nLenR >= vchSig.size()) {
|
|
// Non-canonical signature: S length misplaced
|
|
return false;
|
|
}
|
|
unsigned int nLenS = vchSig[5+nLenR];
|
|
if ((unsigned long)(nLenR+nLenS+7) != vchSig.size()) {
|
|
// Non-canonical signature: R+S length mismatch
|
|
return false;
|
|
}
|
|
|
|
const unsigned char *R = &vchSig[4];
|
|
if (R[-2] != 0x02) {
|
|
// Non-canonical signature: R value type mismatch
|
|
return false;
|
|
}
|
|
if (nLenR == 0) {
|
|
// Non-canonical signature: R length is zero
|
|
return false;
|
|
}
|
|
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];
|
|
if (S[-2] != 0x02) {
|
|
// Non-canonical signature: S value type mismatch
|
|
return false;
|
|
}
|
|
if (nLenS == 0) {
|
|
// Non-canonical signature: S length is zero
|
|
return false;
|
|
}
|
|
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;
|
|
}
|
|
|
|
bool static IsLowDERSignature(const valtype &vchSig, ScriptError* serror) {
|
|
if (!IsDERSignature(vchSig)) {
|
|
return set_error(serror, SCRIPT_ERR_SIG_DER);
|
|
}
|
|
unsigned int nLenR = vchSig[3];
|
|
unsigned int nLenS = vchSig[5+nLenR];
|
|
const unsigned char *S = &vchSig[6+nLenR];
|
|
// If the S value is above the order of the curve divided by two, its
|
|
// complement modulo the order could have been used instead, which is
|
|
// one byte shorter when encoded correctly.
|
|
if (!eccrypto::CheckSignatureElement(S, nLenS, true))
|
|
return set_error(serror, SCRIPT_ERR_SIG_HIGH_S);
|
|
|
|
return true;
|
|
}
|
|
|
|
bool static IsDefinedHashtypeSignature(const valtype &vchSig) {
|
|
if (vchSig.size() == 0) {
|
|
return false;
|
|
}
|
|
unsigned char nHashType = vchSig[vchSig.size() - 1] & (~(SIGHASH_ANYONECANPAY));
|
|
if (nHashType < SIGHASH_ALL || nHashType > SIGHASH_SINGLE)
|
|
return false;
|
|
|
|
return true;
|
|
}
|
|
|
|
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)) {
|
|
return set_error(serror, SCRIPT_ERR_SIG_DER);
|
|
} else if ((flags & SCRIPT_VERIFY_LOW_S) != 0 && !IsLowDERSignature(vchSig, serror)) {
|
|
// serror is set
|
|
return false;
|
|
} else if ((flags & SCRIPT_VERIFY_STRICTENC) != 0 && !IsDefinedHashtypeSignature(vchSig)) {
|
|
return set_error(serror, SCRIPT_ERR_SIG_HASHTYPE);
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool static CheckPubKeyEncoding(const valtype &vchSig, unsigned int flags) {
|
|
if ((flags & SCRIPT_VERIFY_STRICTENC) != 0 && !IsCompressedOrUncompressedPubKey(vchSig)) {
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool static CheckMinimalPush(const valtype& data, opcodetype opcode) {
|
|
if (data.size() == 0) {
|
|
// Could have used OP_0.
|
|
return opcode == OP_0;
|
|
} else if (data.size() == 1 && data[0] >= 1 && data[0] <= 16) {
|
|
// Could have used OP_1 .. OP_16.
|
|
return opcode == OP_1 + (data[0] - 1);
|
|
} else if (data.size() == 1 && data[0] == 0x81) {
|
|
// Could have used OP_1NEGATE.
|
|
return opcode == OP_1NEGATE;
|
|
} else if (data.size() <= 75) {
|
|
// Could have used a direct push (opcode indicating number of bytes pushed + those bytes).
|
|
return opcode == data.size();
|
|
} else if (data.size() <= 255) {
|
|
// Could have used OP_PUSHDATA.
|
|
return opcode == OP_PUSHDATA1;
|
|
} else if (data.size() <= 65535) {
|
|
// Could have used OP_PUSHDATA2.
|
|
return opcode == OP_PUSHDATA2;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
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 pend = script.end();
|
|
CScript::const_iterator pbegincodehash = script.begin();
|
|
opcodetype opcode;
|
|
valtype vchPushValue;
|
|
vector<bool> vfExec;
|
|
vector<valtype> altstack;
|
|
set_error(serror, SCRIPT_ERR_UNKNOWN_ERROR);
|
|
if (script.size() > 10000)
|
|
return set_error(serror, SCRIPT_ERR_SCRIPT_SIZE);
|
|
int nOpCount = 0;
|
|
bool fRequireMinimal = (flags & SCRIPT_VERIFY_MINIMALDATA) != 0;
|
|
|
|
try
|
|
{
|
|
while (pc < pend)
|
|
{
|
|
bool fExec = !count(vfExec.begin(), vfExec.end(), false);
|
|
|
|
//
|
|
// Read instruction
|
|
//
|
|
if (!script.GetOp(pc, opcode, vchPushValue))
|
|
return set_error(serror, SCRIPT_ERR_BAD_OPCODE);
|
|
if (vchPushValue.size() > MAX_SCRIPT_ELEMENT_SIZE)
|
|
return set_error(serror, SCRIPT_ERR_PUSH_SIZE);
|
|
|
|
// Note how OP_RESERVED does not count towards the opcode limit.
|
|
if (opcode > OP_16 && ++nOpCount > 201)
|
|
return set_error(serror, SCRIPT_ERR_OP_COUNT);
|
|
|
|
if (opcode == OP_CAT ||
|
|
opcode == OP_SUBSTR ||
|
|
opcode == OP_LEFT ||
|
|
opcode == OP_RIGHT ||
|
|
opcode == OP_INVERT ||
|
|
opcode == OP_AND ||
|
|
opcode == OP_OR ||
|
|
opcode == OP_XOR ||
|
|
opcode == OP_2MUL ||
|
|
opcode == OP_2DIV ||
|
|
opcode == OP_MUL ||
|
|
opcode == OP_DIV ||
|
|
opcode == OP_MOD ||
|
|
opcode == OP_LSHIFT ||
|
|
opcode == OP_RSHIFT)
|
|
return set_error(serror, SCRIPT_ERR_DISABLED_OPCODE); // Disabled opcodes.
|
|
|
|
if (fExec && 0 <= opcode && opcode <= OP_PUSHDATA4) {
|
|
if (fRequireMinimal && !CheckMinimalPush(vchPushValue, opcode)) {
|
|
return set_error(serror, SCRIPT_ERR_MINIMALDATA);
|
|
}
|
|
stack.push_back(vchPushValue);
|
|
} else if (fExec || (OP_IF <= opcode && opcode <= OP_ENDIF))
|
|
switch (opcode)
|
|
{
|
|
//
|
|
// Push value
|
|
//
|
|
case OP_1NEGATE:
|
|
case OP_1:
|
|
case OP_2:
|
|
case OP_3:
|
|
case OP_4:
|
|
case OP_5:
|
|
case OP_6:
|
|
case OP_7:
|
|
case OP_8:
|
|
case OP_9:
|
|
case OP_10:
|
|
case OP_11:
|
|
case OP_12:
|
|
case OP_13:
|
|
case OP_14:
|
|
case OP_15:
|
|
case OP_16:
|
|
{
|
|
// ( -- value)
|
|
CScriptNum bn((int)opcode - (int)(OP_1 - 1));
|
|
stack.push_back(bn.getvch());
|
|
// The result of these opcodes should always be the minimal way to push the data
|
|
// they push, so no need for a CheckMinimalPush here.
|
|
}
|
|
break;
|
|
|
|
|
|
//
|
|
// Control
|
|
//
|
|
case OP_NOP:
|
|
break;
|
|
|
|
case OP_NOP1: case OP_NOP2: case OP_NOP3: case OP_NOP4: case OP_NOP5:
|
|
case OP_NOP6: case OP_NOP7: case OP_NOP8: case OP_NOP9: case OP_NOP10:
|
|
{
|
|
if (flags & SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS)
|
|
return set_error(serror, SCRIPT_ERR_DISCOURAGE_UPGRADABLE_NOPS);
|
|
}
|
|
break;
|
|
|
|
case OP_IF:
|
|
case OP_NOTIF:
|
|
{
|
|
// <expression> if [statements] [else [statements]] endif
|
|
bool fValue = false;
|
|
if (fExec)
|
|
{
|
|
if (stack.size() < 1)
|
|
return set_error(serror, SCRIPT_ERR_UNBALANCED_CONDITIONAL);
|
|
valtype& vch = stacktop(-1);
|
|
fValue = CastToBool(vch);
|
|
if (opcode == OP_NOTIF)
|
|
fValue = !fValue;
|
|
popstack(stack);
|
|
}
|
|
vfExec.push_back(fValue);
|
|
}
|
|
break;
|
|
|
|
case OP_ELSE:
|
|
{
|
|
if (vfExec.empty())
|
|
return set_error(serror, SCRIPT_ERR_UNBALANCED_CONDITIONAL);
|
|
vfExec.back() = !vfExec.back();
|
|
}
|
|
break;
|
|
|
|
case OP_ENDIF:
|
|
{
|
|
if (vfExec.empty())
|
|
return set_error(serror, SCRIPT_ERR_UNBALANCED_CONDITIONAL);
|
|
vfExec.pop_back();
|
|
}
|
|
break;
|
|
|
|
case OP_VERIFY:
|
|
{
|
|
// (true -- ) or
|
|
// (false -- false) and return
|
|
if (stack.size() < 1)
|
|
return set_error(serror, SCRIPT_ERR_INVALID_STACK_OPERATION);
|
|
bool fValue = CastToBool(stacktop(-1));
|
|
if (fValue)
|
|
popstack(stack);
|
|
else
|
|
return set_error(serror, SCRIPT_ERR_VERIFY);
|
|
}
|
|
break;
|
|
|
|
case OP_RETURN:
|
|
{
|
|
return set_error(serror, SCRIPT_ERR_OP_RETURN);
|
|
}
|
|
break;
|
|
|
|
|
|
//
|
|
// Stack ops
|
|
//
|
|
case OP_TOALTSTACK:
|
|
{
|
|
if (stack.size() < 1)
|
|
return set_error(serror, SCRIPT_ERR_INVALID_STACK_OPERATION);
|
|
altstack.push_back(stacktop(-1));
|
|
popstack(stack);
|
|
}
|
|
break;
|
|
|
|
case OP_FROMALTSTACK:
|
|
{
|
|
if (altstack.size() < 1)
|
|
return set_error(serror, SCRIPT_ERR_INVALID_ALTSTACK_OPERATION);
|
|
stack.push_back(altstacktop(-1));
|
|
popstack(altstack);
|
|
}
|
|
break;
|
|
|
|
case OP_2DROP:
|
|
{
|
|
// (x1 x2 -- )
|
|
if (stack.size() < 2)
|
|
return set_error(serror, SCRIPT_ERR_INVALID_STACK_OPERATION);
|
|
popstack(stack);
|
|
popstack(stack);
|
|
}
|
|
break;
|
|
|
|
case OP_2DUP:
|
|
{
|
|
// (x1 x2 -- x1 x2 x1 x2)
|
|
if (stack.size() < 2)
|
|
return set_error(serror, SCRIPT_ERR_INVALID_STACK_OPERATION);
|
|
valtype vch1 = stacktop(-2);
|
|
valtype vch2 = stacktop(-1);
|
|
stack.push_back(vch1);
|
|
stack.push_back(vch2);
|
|
}
|
|
break;
|
|
|
|
case OP_3DUP:
|
|
{
|
|
// (x1 x2 x3 -- x1 x2 x3 x1 x2 x3)
|
|
if (stack.size() < 3)
|
|
return set_error(serror, SCRIPT_ERR_INVALID_STACK_OPERATION);
|
|
valtype vch1 = stacktop(-3);
|
|
valtype vch2 = stacktop(-2);
|
|
valtype vch3 = stacktop(-1);
|
|
stack.push_back(vch1);
|
|
stack.push_back(vch2);
|
|
stack.push_back(vch3);
|
|
}
|
|
break;
|
|
|
|
case OP_2OVER:
|
|
{
|
|
// (x1 x2 x3 x4 -- x1 x2 x3 x4 x1 x2)
|
|
if (stack.size() < 4)
|
|
return set_error(serror, SCRIPT_ERR_INVALID_STACK_OPERATION);
|
|
valtype vch1 = stacktop(-4);
|
|
valtype vch2 = stacktop(-3);
|
|
stack.push_back(vch1);
|
|
stack.push_back(vch2);
|
|
}
|
|
break;
|
|
|
|
case OP_2ROT:
|
|
{
|
|
// (x1 x2 x3 x4 x5 x6 -- x3 x4 x5 x6 x1 x2)
|
|
if (stack.size() < 6)
|
|
return set_error(serror, SCRIPT_ERR_INVALID_STACK_OPERATION);
|
|
valtype vch1 = stacktop(-6);
|
|
valtype vch2 = stacktop(-5);
|
|
stack.erase(stack.end()-6, stack.end()-4);
|
|
stack.push_back(vch1);
|
|
stack.push_back(vch2);
|
|
}
|
|
break;
|
|
|
|
case OP_2SWAP:
|
|
{
|
|
// (x1 x2 x3 x4 -- x3 x4 x1 x2)
|
|
if (stack.size() < 4)
|
|
return set_error(serror, SCRIPT_ERR_INVALID_STACK_OPERATION);
|
|
swap(stacktop(-4), stacktop(-2));
|
|
swap(stacktop(-3), stacktop(-1));
|
|
}
|
|
break;
|
|
|
|
case OP_IFDUP:
|
|
{
|
|
// (x - 0 | x x)
|
|
if (stack.size() < 1)
|
|
return set_error(serror, SCRIPT_ERR_INVALID_STACK_OPERATION);
|
|
valtype vch = stacktop(-1);
|
|
if (CastToBool(vch))
|
|
stack.push_back(vch);
|
|
}
|
|
break;
|
|
|
|
case OP_DEPTH:
|
|
{
|
|
// -- stacksize
|
|
CScriptNum bn(stack.size());
|
|
stack.push_back(bn.getvch());
|
|
}
|
|
break;
|
|
|
|
case OP_DROP:
|
|
{
|
|
// (x -- )
|
|
if (stack.size() < 1)
|
|
return set_error(serror, SCRIPT_ERR_INVALID_STACK_OPERATION);
|
|
popstack(stack);
|
|
}
|
|
break;
|
|
|
|
case OP_DUP:
|
|
{
|
|
// (x -- x x)
|
|
if (stack.size() < 1)
|
|
return set_error(serror, SCRIPT_ERR_INVALID_STACK_OPERATION);
|
|
valtype vch = stacktop(-1);
|
|
stack.push_back(vch);
|
|
}
|
|
break;
|
|
|
|
case OP_NIP:
|
|
{
|
|
// (x1 x2 -- x2)
|
|
if (stack.size() < 2)
|
|
return set_error(serror, SCRIPT_ERR_INVALID_STACK_OPERATION);
|
|
stack.erase(stack.end() - 2);
|
|
}
|
|
break;
|
|
|
|
case OP_OVER:
|
|
{
|
|
// (x1 x2 -- x1 x2 x1)
|
|
if (stack.size() < 2)
|
|
return set_error(serror, SCRIPT_ERR_INVALID_STACK_OPERATION);
|
|
valtype vch = stacktop(-2);
|
|
stack.push_back(vch);
|
|
}
|
|
break;
|
|
|
|
case OP_PICK:
|
|
case OP_ROLL:
|
|
{
|
|
// (xn ... x2 x1 x0 n - xn ... x2 x1 x0 xn)
|
|
// (xn ... x2 x1 x0 n - ... x2 x1 x0 xn)
|
|
if (stack.size() < 2)
|
|
return set_error(serror, SCRIPT_ERR_INVALID_STACK_OPERATION);
|
|
int n = CScriptNum(stacktop(-1), fRequireMinimal).getint();
|
|
popstack(stack);
|
|
if (n < 0 || n >= (int)stack.size())
|
|
return set_error(serror, SCRIPT_ERR_INVALID_STACK_OPERATION);
|
|
valtype vch = stacktop(-n-1);
|
|
if (opcode == OP_ROLL)
|
|
stack.erase(stack.end()-n-1);
|
|
stack.push_back(vch);
|
|
}
|
|
break;
|
|
|
|
case OP_ROT:
|
|
{
|
|
// (x1 x2 x3 -- x2 x3 x1)
|
|
// x2 x1 x3 after first swap
|
|
// x2 x3 x1 after second swap
|
|
if (stack.size() < 3)
|
|
return set_error(serror, SCRIPT_ERR_INVALID_STACK_OPERATION);
|
|
swap(stacktop(-3), stacktop(-2));
|
|
swap(stacktop(-2), stacktop(-1));
|
|
}
|
|
break;
|
|
|
|
case OP_SWAP:
|
|
{
|
|
// (x1 x2 -- x2 x1)
|
|
if (stack.size() < 2)
|
|
return set_error(serror, SCRIPT_ERR_INVALID_STACK_OPERATION);
|
|
swap(stacktop(-2), stacktop(-1));
|
|
}
|
|
break;
|
|
|
|
case OP_TUCK:
|
|
{
|
|
// (x1 x2 -- x2 x1 x2)
|
|
if (stack.size() < 2)
|
|
return set_error(serror, SCRIPT_ERR_INVALID_STACK_OPERATION);
|
|
valtype vch = stacktop(-1);
|
|
stack.insert(stack.end()-2, vch);
|
|
}
|
|
break;
|
|
|
|
|
|
case OP_SIZE:
|
|
{
|
|
// (in -- in size)
|
|
if (stack.size() < 1)
|
|
return set_error(serror, SCRIPT_ERR_INVALID_STACK_OPERATION);
|
|
CScriptNum bn(stacktop(-1).size());
|
|
stack.push_back(bn.getvch());
|
|
}
|
|
break;
|
|
|
|
|
|
//
|
|
// Bitwise logic
|
|
//
|
|
case OP_EQUAL:
|
|
case OP_EQUALVERIFY:
|
|
//case OP_NOTEQUAL: // use OP_NUMNOTEQUAL
|
|
{
|
|
// (x1 x2 - bool)
|
|
if (stack.size() < 2)
|
|
return set_error(serror, SCRIPT_ERR_INVALID_STACK_OPERATION);
|
|
valtype& vch1 = stacktop(-2);
|
|
valtype& vch2 = stacktop(-1);
|
|
bool fEqual = (vch1 == vch2);
|
|
// OP_NOTEQUAL is disabled because it would be too easy to say
|
|
// something like n != 1 and have some wiseguy pass in 1 with extra
|
|
// zero bytes after it (numerically, 0x01 == 0x0001 == 0x000001)
|
|
//if (opcode == OP_NOTEQUAL)
|
|
// fEqual = !fEqual;
|
|
popstack(stack);
|
|
popstack(stack);
|
|
stack.push_back(fEqual ? vchTrue : vchFalse);
|
|
if (opcode == OP_EQUALVERIFY)
|
|
{
|
|
if (fEqual)
|
|
popstack(stack);
|
|
else
|
|
return set_error(serror, SCRIPT_ERR_EQUALVERIFY);
|
|
}
|
|
}
|
|
break;
|
|
|
|
|
|
//
|
|
// Numeric
|
|
//
|
|
case OP_1ADD:
|
|
case OP_1SUB:
|
|
case OP_NEGATE:
|
|
case OP_ABS:
|
|
case OP_NOT:
|
|
case OP_0NOTEQUAL:
|
|
{
|
|
// (in -- out)
|
|
if (stack.size() < 1)
|
|
return set_error(serror, SCRIPT_ERR_INVALID_STACK_OPERATION);
|
|
CScriptNum bn(stacktop(-1), fRequireMinimal);
|
|
switch (opcode)
|
|
{
|
|
case OP_1ADD: bn += bnOne; break;
|
|
case OP_1SUB: bn -= bnOne; break;
|
|
case OP_NEGATE: bn = -bn; break;
|
|
case OP_ABS: if (bn < bnZero) bn = -bn; break;
|
|
case OP_NOT: bn = (bn == bnZero); break;
|
|
case OP_0NOTEQUAL: bn = (bn != bnZero); break;
|
|
default: assert(!"invalid opcode"); break;
|
|
}
|
|
popstack(stack);
|
|
stack.push_back(bn.getvch());
|
|
}
|
|
break;
|
|
|
|
case OP_ADD:
|
|
case OP_SUB:
|
|
case OP_BOOLAND:
|
|
case OP_BOOLOR:
|
|
case OP_NUMEQUAL:
|
|
case OP_NUMEQUALVERIFY:
|
|
case OP_NUMNOTEQUAL:
|
|
case OP_LESSTHAN:
|
|
case OP_GREATERTHAN:
|
|
case OP_LESSTHANOREQUAL:
|
|
case OP_GREATERTHANOREQUAL:
|
|
case OP_MIN:
|
|
case OP_MAX:
|
|
{
|
|
// (x1 x2 -- out)
|
|
if (stack.size() < 2)
|
|
return set_error(serror, SCRIPT_ERR_INVALID_STACK_OPERATION);
|
|
CScriptNum bn1(stacktop(-2), fRequireMinimal);
|
|
CScriptNum bn2(stacktop(-1), fRequireMinimal);
|
|
CScriptNum bn(0);
|
|
switch (opcode)
|
|
{
|
|
case OP_ADD:
|
|
bn = bn1 + bn2;
|
|
break;
|
|
|
|
case OP_SUB:
|
|
bn = bn1 - bn2;
|
|
break;
|
|
|
|
case OP_BOOLAND: bn = (bn1 != bnZero && bn2 != bnZero); break;
|
|
case OP_BOOLOR: bn = (bn1 != bnZero || bn2 != bnZero); break;
|
|
case OP_NUMEQUAL: bn = (bn1 == bn2); break;
|
|
case OP_NUMEQUALVERIFY: bn = (bn1 == bn2); break;
|
|
case OP_NUMNOTEQUAL: bn = (bn1 != bn2); break;
|
|
case OP_LESSTHAN: bn = (bn1 < bn2); break;
|
|
case OP_GREATERTHAN: bn = (bn1 > bn2); break;
|
|
case OP_LESSTHANOREQUAL: bn = (bn1 <= bn2); break;
|
|
case OP_GREATERTHANOREQUAL: bn = (bn1 >= bn2); break;
|
|
case OP_MIN: bn = (bn1 < bn2 ? bn1 : bn2); break;
|
|
case OP_MAX: bn = (bn1 > bn2 ? bn1 : bn2); break;
|
|
default: assert(!"invalid opcode"); break;
|
|
}
|
|
popstack(stack);
|
|
popstack(stack);
|
|
stack.push_back(bn.getvch());
|
|
|
|
if (opcode == OP_NUMEQUALVERIFY)
|
|
{
|
|
if (CastToBool(stacktop(-1)))
|
|
popstack(stack);
|
|
else
|
|
return set_error(serror, SCRIPT_ERR_NUMEQUALVERIFY);
|
|
}
|
|
}
|
|
break;
|
|
|
|
case OP_WITHIN:
|
|
{
|
|
// (x min max -- out)
|
|
if (stack.size() < 3)
|
|
return set_error(serror, SCRIPT_ERR_INVALID_STACK_OPERATION);
|
|
CScriptNum bn1(stacktop(-3), fRequireMinimal);
|
|
CScriptNum bn2(stacktop(-2), fRequireMinimal);
|
|
CScriptNum bn3(stacktop(-1), fRequireMinimal);
|
|
bool fValue = (bn2 <= bn1 && bn1 < bn3);
|
|
popstack(stack);
|
|
popstack(stack);
|
|
popstack(stack);
|
|
stack.push_back(fValue ? vchTrue : vchFalse);
|
|
}
|
|
break;
|
|
|
|
|
|
//
|
|
// Crypto
|
|
//
|
|
case OP_RIPEMD160:
|
|
case OP_SHA1:
|
|
case OP_SHA256:
|
|
case OP_HASH160:
|
|
case OP_HASH256:
|
|
{
|
|
// (in -- hash)
|
|
if (stack.size() < 1)
|
|
return set_error(serror, SCRIPT_ERR_INVALID_STACK_OPERATION);
|
|
valtype& vch = stacktop(-1);
|
|
valtype vchHash((opcode == OP_RIPEMD160 || opcode == OP_SHA1 || opcode == OP_HASH160) ? 20 : 32);
|
|
if (opcode == OP_RIPEMD160)
|
|
CRIPEMD160().Write(begin_ptr(vch), vch.size()).Finalize(begin_ptr(vchHash));
|
|
else if (opcode == OP_SHA1)
|
|
CSHA1().Write(begin_ptr(vch), vch.size()).Finalize(begin_ptr(vchHash));
|
|
else if (opcode == OP_SHA256)
|
|
CSHA256().Write(begin_ptr(vch), vch.size()).Finalize(begin_ptr(vchHash));
|
|
else if (opcode == OP_HASH160)
|
|
CHash160().Write(begin_ptr(vch), vch.size()).Finalize(begin_ptr(vchHash));
|
|
else if (opcode == OP_HASH256)
|
|
CHash256().Write(begin_ptr(vch), vch.size()).Finalize(begin_ptr(vchHash));
|
|
popstack(stack);
|
|
stack.push_back(vchHash);
|
|
}
|
|
break;
|
|
|
|
case OP_CODESEPARATOR:
|
|
{
|
|
// Hash starts after the code separator
|
|
pbegincodehash = pc;
|
|
}
|
|
break;
|
|
|
|
case OP_CHECKSIG:
|
|
case OP_CHECKSIGVERIFY:
|
|
{
|
|
// (sig pubkey -- bool)
|
|
if (stack.size() < 2)
|
|
return set_error(serror, SCRIPT_ERR_INVALID_STACK_OPERATION);
|
|
|
|
valtype& vchSig = stacktop(-2);
|
|
valtype& vchPubKey = stacktop(-1);
|
|
|
|
// Subset of script starting at the most recent codeseparator
|
|
CScript scriptCode(pbegincodehash, pend);
|
|
|
|
// Drop the signature, since there's no way for a signature to sign itself
|
|
scriptCode.FindAndDelete(CScript(vchSig));
|
|
|
|
if (!CheckSignatureEncoding(vchSig, flags, serror)) {
|
|
//serror is set
|
|
return false;
|
|
}
|
|
bool fSuccess = CheckPubKeyEncoding(vchPubKey, flags) && checker.CheckSig(vchSig, vchPubKey, scriptCode);
|
|
|
|
popstack(stack);
|
|
popstack(stack);
|
|
stack.push_back(fSuccess ? vchTrue : vchFalse);
|
|
if (opcode == OP_CHECKSIGVERIFY)
|
|
{
|
|
if (fSuccess)
|
|
popstack(stack);
|
|
else
|
|
return set_error(serror, SCRIPT_ERR_CHECKSIGVERIFY);
|
|
}
|
|
}
|
|
break;
|
|
|
|
case OP_CHECKMULTISIG:
|
|
case OP_CHECKMULTISIGVERIFY:
|
|
{
|
|
// ([sig ...] num_of_signatures [pubkey ...] num_of_pubkeys -- bool)
|
|
|
|
int i = 1;
|
|
if ((int)stack.size() < i)
|
|
return set_error(serror, SCRIPT_ERR_INVALID_STACK_OPERATION);
|
|
|
|
int nKeysCount = CScriptNum(stacktop(-i), fRequireMinimal).getint();
|
|
if (nKeysCount < 0 || nKeysCount > 20)
|
|
return set_error(serror, SCRIPT_ERR_PUBKEY_COUNT);
|
|
nOpCount += nKeysCount;
|
|
if (nOpCount > 201)
|
|
return set_error(serror, SCRIPT_ERR_OP_COUNT);
|
|
int ikey = ++i;
|
|
i += nKeysCount;
|
|
if ((int)stack.size() < i)
|
|
return set_error(serror, SCRIPT_ERR_INVALID_STACK_OPERATION);
|
|
|
|
int nSigsCount = CScriptNum(stacktop(-i), fRequireMinimal).getint();
|
|
if (nSigsCount < 0 || nSigsCount > nKeysCount)
|
|
return set_error(serror, SCRIPT_ERR_SIG_COUNT);
|
|
int isig = ++i;
|
|
i += nSigsCount;
|
|
if ((int)stack.size() < i)
|
|
return set_error(serror, SCRIPT_ERR_INVALID_STACK_OPERATION);
|
|
|
|
// Subset of script starting at the most recent codeseparator
|
|
CScript scriptCode(pbegincodehash, pend);
|
|
|
|
// Drop the signatures, since there's no way for a signature to sign itself
|
|
for (int k = 0; k < nSigsCount; k++)
|
|
{
|
|
valtype& vchSig = stacktop(-isig-k);
|
|
scriptCode.FindAndDelete(CScript(vchSig));
|
|
}
|
|
|
|
bool fSuccess = true;
|
|
while (fSuccess && nSigsCount > 0)
|
|
{
|
|
valtype& vchSig = stacktop(-isig);
|
|
valtype& vchPubKey = stacktop(-ikey);
|
|
|
|
if (!CheckSignatureEncoding(vchSig, flags, serror)) {
|
|
// serror is set
|
|
return false;
|
|
}
|
|
|
|
// Check signature
|
|
bool fOk = CheckPubKeyEncoding(vchPubKey, flags) && checker.CheckSig(vchSig, vchPubKey, scriptCode);
|
|
|
|
if (fOk) {
|
|
isig++;
|
|
nSigsCount--;
|
|
}
|
|
ikey++;
|
|
nKeysCount--;
|
|
|
|
// If there are more signatures left than keys left,
|
|
// then too many signatures have failed
|
|
if (nSigsCount > nKeysCount)
|
|
fSuccess = false;
|
|
}
|
|
|
|
// Clean up stack of actual arguments
|
|
while (i-- > 1)
|
|
popstack(stack);
|
|
|
|
// A bug causes CHECKMULTISIG to consume one extra argument
|
|
// whose contents were not checked in any way.
|
|
//
|
|
// Unfortunately this is a potential source of mutability,
|
|
// so optionally verify it is exactly equal to zero prior
|
|
// to removing it from the stack.
|
|
if (stack.size() < 1)
|
|
return set_error(serror, SCRIPT_ERR_INVALID_STACK_OPERATION);
|
|
if ((flags & SCRIPT_VERIFY_NULLDUMMY) && stacktop(-1).size())
|
|
return set_error(serror, SCRIPT_ERR_SIG_NULLDUMMY);
|
|
popstack(stack);
|
|
|
|
stack.push_back(fSuccess ? vchTrue : vchFalse);
|
|
|
|
if (opcode == OP_CHECKMULTISIGVERIFY)
|
|
{
|
|
if (fSuccess)
|
|
popstack(stack);
|
|
else
|
|
return set_error(serror, SCRIPT_ERR_CHECKMULTISIGVERIFY);
|
|
}
|
|
}
|
|
break;
|
|
|
|
default:
|
|
return set_error(serror, SCRIPT_ERR_BAD_OPCODE);
|
|
}
|
|
|
|
// Size limits
|
|
if (stack.size() + altstack.size() > 1000)
|
|
return set_error(serror, SCRIPT_ERR_STACK_SIZE);
|
|
}
|
|
}
|
|
catch (...)
|
|
{
|
|
return set_error(serror, SCRIPT_ERR_UNKNOWN_ERROR);
|
|
}
|
|
|
|
if (!vfExec.empty())
|
|
return set_error(serror, SCRIPT_ERR_UNBALANCED_CONDITIONAL);
|
|
|
|
return set_success(serror);
|
|
}
|
|
|
|
namespace {
|
|
|
|
/**
|
|
* Wrapper that serializes like CTransaction, but with the modifications
|
|
* required for the signature hash done in-place
|
|
*/
|
|
class CTransactionSignatureSerializer {
|
|
private:
|
|
const CTransaction &txTo; //! reference to the spending transaction (the one being serialized)
|
|
const CScript &scriptCode; //! output script being consumed
|
|
const unsigned int nIn; //! input index of txTo being signed
|
|
const bool fAnyoneCanPay; //! whether the hashtype has the SIGHASH_ANYONECANPAY flag set
|
|
const bool fHashSingle; //! whether the hashtype is SIGHASH_SINGLE
|
|
const bool fHashNone; //! whether the hashtype is SIGHASH_NONE
|
|
|
|
public:
|
|
CTransactionSignatureSerializer(const CTransaction &txToIn, const CScript &scriptCodeIn, unsigned int nInIn, int nHashTypeIn) :
|
|
txTo(txToIn), scriptCode(scriptCodeIn), nIn(nInIn),
|
|
fAnyoneCanPay(!!(nHashTypeIn & SIGHASH_ANYONECANPAY)),
|
|
fHashSingle((nHashTypeIn & 0x1f) == SIGHASH_SINGLE),
|
|
fHashNone((nHashTypeIn & 0x1f) == SIGHASH_NONE) {}
|
|
|
|
/** Serialize the passed scriptCode, skipping OP_CODESEPARATORs */
|
|
template<typename S>
|
|
void SerializeScriptCode(S &s, int nType, int nVersion) const {
|
|
CScript::const_iterator it = scriptCode.begin();
|
|
CScript::const_iterator itBegin = it;
|
|
opcodetype opcode;
|
|
unsigned int nCodeSeparators = 0;
|
|
while (scriptCode.GetOp(it, opcode)) {
|
|
if (opcode == OP_CODESEPARATOR)
|
|
nCodeSeparators++;
|
|
}
|
|
::WriteCompactSize(s, scriptCode.size() - nCodeSeparators);
|
|
it = itBegin;
|
|
while (scriptCode.GetOp(it, opcode)) {
|
|
if (opcode == OP_CODESEPARATOR) {
|
|
s.write((char*)&itBegin[0], it-itBegin-1);
|
|
itBegin = it;
|
|
}
|
|
}
|
|
if (itBegin != scriptCode.end())
|
|
s.write((char*)&itBegin[0], it-itBegin);
|
|
}
|
|
|
|
/** Serialize an input of txTo */
|
|
template<typename S>
|
|
void SerializeInput(S &s, unsigned int nInput, int nType, int nVersion) const {
|
|
// In case of SIGHASH_ANYONECANPAY, only the input being signed is serialized
|
|
if (fAnyoneCanPay)
|
|
nInput = nIn;
|
|
// Serialize the prevout
|
|
::Serialize(s, txTo.vin[nInput].prevout, nType, nVersion);
|
|
// Serialize the script
|
|
if (nInput != nIn)
|
|
// Blank out other inputs' signatures
|
|
::Serialize(s, CScript(), nType, nVersion);
|
|
else
|
|
SerializeScriptCode(s, nType, nVersion);
|
|
// Serialize the nSequence
|
|
if (nInput != nIn && (fHashSingle || fHashNone))
|
|
// let the others update at will
|
|
::Serialize(s, (int)0, nType, nVersion);
|
|
else
|
|
::Serialize(s, txTo.vin[nInput].nSequence, nType, nVersion);
|
|
}
|
|
|
|
/** Serialize an output of txTo */
|
|
template<typename S>
|
|
void SerializeOutput(S &s, unsigned int nOutput, int nType, int nVersion) const {
|
|
if (fHashSingle && nOutput != nIn)
|
|
// Do not lock-in the txout payee at other indices as txin
|
|
::Serialize(s, CTxOut(), nType, nVersion);
|
|
else
|
|
::Serialize(s, txTo.vout[nOutput], nType, nVersion);
|
|
}
|
|
|
|
/** Serialize txTo */
|
|
template<typename S>
|
|
void Serialize(S &s, int nType, int nVersion) const {
|
|
// Serialize nVersion
|
|
::Serialize(s, txTo.nVersion, nType, nVersion);
|
|
// Serialize vin
|
|
unsigned int nInputs = fAnyoneCanPay ? 1 : txTo.vin.size();
|
|
::WriteCompactSize(s, nInputs);
|
|
for (unsigned int nInput = 0; nInput < nInputs; nInput++)
|
|
SerializeInput(s, nInput, nType, nVersion);
|
|
// Serialize vout
|
|
unsigned int nOutputs = fHashNone ? 0 : (fHashSingle ? nIn+1 : txTo.vout.size());
|
|
::WriteCompactSize(s, nOutputs);
|
|
for (unsigned int nOutput = 0; nOutput < nOutputs; nOutput++)
|
|
SerializeOutput(s, nOutput, nType, nVersion);
|
|
// Serialize nLockTime
|
|
::Serialize(s, txTo.nLockTime, nType, nVersion);
|
|
}
|
|
};
|
|
|
|
} // anon namespace
|
|
|
|
uint256 SignatureHash(const CScript& scriptCode, const CTransaction& txTo, unsigned int nIn, int nHashType)
|
|
{
|
|
if (nIn >= txTo.vin.size()) {
|
|
// nIn out of range
|
|
return 1;
|
|
}
|
|
|
|
// Check for invalid use of SIGHASH_SINGLE
|
|
if ((nHashType & 0x1f) == SIGHASH_SINGLE) {
|
|
if (nIn >= txTo.vout.size()) {
|
|
// nOut out of range
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
// Wrapper to serialize only the necessary parts of the transaction being signed
|
|
CTransactionSignatureSerializer txTmp(txTo, scriptCode, nIn, nHashType);
|
|
|
|
// Serialize and hash
|
|
CHashWriter ss(SER_GETHASH, 0);
|
|
ss << txTmp << nHashType;
|
|
return ss.GetHash();
|
|
}
|
|
|
|
bool SignatureChecker::VerifySignature(const std::vector<unsigned char>& vchSig, const CPubKey& pubkey, const uint256& sighash) const
|
|
{
|
|
return pubkey.Verify(sighash, vchSig);
|
|
}
|
|
|
|
bool SignatureChecker::CheckSig(const vector<unsigned char>& vchSigIn, const vector<unsigned char>& vchPubKey, const CScript& scriptCode) const
|
|
{
|
|
CPubKey pubkey(vchPubKey);
|
|
if (!pubkey.IsValid())
|
|
return false;
|
|
|
|
// Hash type is one byte tacked on to the end of the signature
|
|
vector<unsigned char> vchSig(vchSigIn);
|
|
if (vchSig.empty())
|
|
return false;
|
|
int nHashType = vchSig.back();
|
|
vchSig.pop_back();
|
|
|
|
uint256 sighash = SignatureHash(scriptCode, txTo, nIn, nHashType);
|
|
|
|
if (!VerifySignature(vchSig, pubkey, sighash))
|
|
return false;
|
|
|
|
return true;
|
|
}
|
|
|
|
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()) {
|
|
return set_error(serror, SCRIPT_ERR_SIG_PUSHONLY);
|
|
}
|
|
|
|
vector<vector<unsigned char> > stack, stackCopy;
|
|
if (!EvalScript(stack, scriptSig, flags, checker, serror))
|
|
// serror is set
|
|
return false;
|
|
if (flags & SCRIPT_VERIFY_P2SH)
|
|
stackCopy = stack;
|
|
if (!EvalScript(stack, scriptPubKey, flags, checker, serror))
|
|
// serror is set
|
|
return false;
|
|
if (stack.empty())
|
|
return set_error(serror, SCRIPT_ERR_EVAL_FALSE);
|
|
|
|
if (CastToBool(stack.back()) == false)
|
|
return set_error(serror, SCRIPT_ERR_EVAL_FALSE);
|
|
|
|
// Additional validation for spend-to-script-hash transactions:
|
|
if ((flags & SCRIPT_VERIFY_P2SH) && scriptPubKey.IsPayToScriptHash())
|
|
{
|
|
// scriptSig must be literals-only or validation fails
|
|
if (!scriptSig.IsPushOnly())
|
|
return set_error(serror, SCRIPT_ERR_SIG_PUSHONLY);
|
|
|
|
// stackCopy cannot be empty here, because if it was the
|
|
// P2SH HASH <> EQUAL scriptPubKey would be evaluated with
|
|
// an empty stack and the EvalScript above would return false.
|
|
assert(!stackCopy.empty());
|
|
|
|
const valtype& pubKeySerialized = stackCopy.back();
|
|
CScript pubKey2(pubKeySerialized.begin(), pubKeySerialized.end());
|
|
popstack(stackCopy);
|
|
|
|
if (!EvalScript(stackCopy, pubKey2, flags, checker, serror))
|
|
// serror is set
|
|
return false;
|
|
if (stackCopy.empty())
|
|
return set_error(serror, SCRIPT_ERR_EVAL_FALSE);
|
|
if (!CastToBool(stackCopy.back()))
|
|
return set_error(serror, SCRIPT_ERR_EVAL_FALSE);
|
|
else
|
|
return set_success(serror);
|
|
}
|
|
|
|
return set_success(serror);
|
|
}
|