mirror of
https://github.com/cculianu/Fulcrum.git
synced 2026-08-18 13:09:12 +02:00
1698 lines
68 KiB
C++
1698 lines
68 KiB
C++
// Copyright (c) 2009-2010 Satoshi Nakamoto
|
|
// Copyright (c) 2009-2016 The Bitcoin Core developers
|
|
// Copyright (c) 2017-2018 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 "crypto/ripemd160.h"
|
|
#include "crypto/sha1.h"
|
|
#include "crypto/sha256.h"
|
|
#include "transaction.h"
|
|
#include "pubkey.h"
|
|
#include "script.h"
|
|
#include "script_flags.h"
|
|
#include "sigencoding.h"
|
|
#include "uint256.h"
|
|
|
|
#ifdef __clang__
|
|
#pragma clang diagnostic push
|
|
#pragma clang diagnostic ignored "-Wold-style-cast"
|
|
#pragma clang diagnostic ignored "-Wsign-conversion"
|
|
#pragma clang diagnostic ignored "-Wshorten-64-to-32"
|
|
#pragma clang diagnostic ignored "-Wunused-parameter"
|
|
#pragma clang diagnostic ignored "-Wunused-template"
|
|
#pragma clang diagnostic ignored "-Wtautological-unsigned-enum-zero-compare"
|
|
#pragma clang diagnostic ignored "-Wstring-conversion"
|
|
#pragma clang diagnostic ignored "-Wunreachable-code-break"
|
|
#pragma clang diagnostic ignored "-Wcast-qual"
|
|
#endif
|
|
|
|
namespace bitcoin {
|
|
|
|
bool CastToBool(const valtype &vch) {
|
|
for (size_t 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(std::vector<valtype> &stack) {
|
|
if (stack.empty()) {
|
|
throw std::runtime_error("popstack(): stack empty");
|
|
}
|
|
stack.pop_back();
|
|
}
|
|
|
|
static void CleanupScriptCode(CScript &scriptCode,
|
|
const std::vector<uint8_t> &vchSig,
|
|
uint32_t flags) {
|
|
// Drop the signature in scripts when SIGHASH_FORKID is not used.
|
|
SigHashType sigHashType = GetHashType(vchSig);
|
|
if (!(flags & SCRIPT_ENABLE_SIGHASH_FORKID) || !sigHashType.hasForkId()) {
|
|
scriptCode.FindAndDelete(CScript(vchSig));
|
|
}
|
|
}
|
|
|
|
static bool CheckMinimalPush(const valtype &data, opcodetype opcode) {
|
|
if (data.size() == 0) {
|
|
// Could have used OP_0.
|
|
return opcode == OP_0;
|
|
}
|
|
if (data.size() == 1 && data[0] >= 1 && data[0] <= 16) {
|
|
// Could have used OP_1 .. OP_16.
|
|
return opcode == OP_1 + (data[0] - 1);
|
|
}
|
|
if (data.size() == 1 && data[0] == 0x81) {
|
|
// Could have used OP_1NEGATE.
|
|
return opcode == OP_1NEGATE;
|
|
}
|
|
if (data.size() <= 75) {
|
|
// Could have used a direct push (opcode indicating number of bytes
|
|
// pushed + those bytes).
|
|
return opcode == data.size();
|
|
}
|
|
if (data.size() <= 255) {
|
|
// Could have used OP_PUSHDATA.
|
|
return opcode == OP_PUSHDATA1;
|
|
}
|
|
if (data.size() <= 65535) {
|
|
// Could have used OP_PUSHDATA2.
|
|
return opcode == OP_PUSHDATA2;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
static bool IsOpcodeDisabled(opcodetype opcode, uint32_t flags) {
|
|
switch (opcode) {
|
|
case OP_INVERT:
|
|
case OP_2MUL:
|
|
case OP_2DIV:
|
|
case OP_MUL:
|
|
case OP_LSHIFT:
|
|
case OP_RSHIFT:
|
|
// Disabled opcodes.
|
|
return true;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
bool EvalScript(std::vector<valtype> &stack, const CScript &script,
|
|
uint32_t flags, const BaseSignatureChecker &checker,
|
|
ScriptError *serror) {
|
|
static const CScriptNum bnZero(0);
|
|
static const CScriptNum bnOne(1);
|
|
static const valtype vchFalse(0);
|
|
static const valtype vchTrue(1, 1);
|
|
|
|
CScript::const_iterator pc = script.begin();
|
|
CScript::const_iterator pend = script.end();
|
|
CScript::const_iterator pbegincodehash = script.begin();
|
|
opcodetype opcode;
|
|
valtype vchPushValue;
|
|
std::vector<bool> vfExec;
|
|
std::vector<valtype> altstack;
|
|
set_error(serror, SCRIPT_ERR_UNKNOWN_ERROR);
|
|
if (script.size() > MAX_SCRIPT_SIZE) {
|
|
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 > MAX_OPS_PER_SCRIPT) {
|
|
return set_error(serror, SCRIPT_ERR_OP_COUNT);
|
|
}
|
|
|
|
// Some opcodes are disabled.
|
|
if (IsOpcodeDisabled(opcode, flags)) {
|
|
return set_error(serror, SCRIPT_ERR_DISABLED_OPCODE);
|
|
}
|
|
|
|
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_CHECKLOCKTIMEVERIFY: {
|
|
if (!(flags & SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY)) {
|
|
// not enabled; treat as a NOP2
|
|
if (flags &
|
|
SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS) {
|
|
return set_error(
|
|
serror,
|
|
SCRIPT_ERR_DISCOURAGE_UPGRADABLE_NOPS);
|
|
}
|
|
break;
|
|
}
|
|
|
|
if (stack.size() < 1) {
|
|
return set_error(
|
|
serror, SCRIPT_ERR_INVALID_STACK_OPERATION);
|
|
}
|
|
|
|
// Note that elsewhere numeric opcodes are limited to
|
|
// operands in the range -2**31+1 to 2**31-1, however it
|
|
// is legal for opcodes to produce results exceeding
|
|
// that range. This limitation is implemented by
|
|
// CScriptNum's default 4-byte limit.
|
|
//
|
|
// If we kept to that limit we'd have a year 2038
|
|
// problem, even though the nLockTime field in
|
|
// transactions themselves is uint32 which only becomes
|
|
// meaningless after the year 2106.
|
|
//
|
|
// Thus as a special case we tell CScriptNum to accept
|
|
// up to 5-byte bignums, which are good until 2**39-1,
|
|
// well beyond the 2**32-1 limit of the nLockTime field
|
|
// itself.
|
|
const CScriptNum nLockTime(stacktop(-1),
|
|
fRequireMinimal, 5);
|
|
|
|
// In the rare event that the argument may be < 0 due to
|
|
// some arithmetic being done first, you can always use
|
|
// 0 MAX CHECKLOCKTIMEVERIFY.
|
|
if (nLockTime < 0) {
|
|
return set_error(serror,
|
|
SCRIPT_ERR_NEGATIVE_LOCKTIME);
|
|
}
|
|
|
|
// Actually compare the specified lock time with the
|
|
// transaction.
|
|
if (!checker.CheckLockTime(nLockTime)) {
|
|
return set_error(serror,
|
|
SCRIPT_ERR_UNSATISFIED_LOCKTIME);
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
case OP_CHECKSEQUENCEVERIFY: {
|
|
if (!(flags & SCRIPT_VERIFY_CHECKSEQUENCEVERIFY)) {
|
|
// not enabled; treat as a NOP3
|
|
if (flags &
|
|
SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS) {
|
|
return set_error(
|
|
serror,
|
|
SCRIPT_ERR_DISCOURAGE_UPGRADABLE_NOPS);
|
|
}
|
|
break;
|
|
}
|
|
|
|
if (stack.size() < 1) {
|
|
return set_error(
|
|
serror, SCRIPT_ERR_INVALID_STACK_OPERATION);
|
|
}
|
|
|
|
// nSequence, like nLockTime, is a 32-bit unsigned
|
|
// integer field. See the comment in CHECKLOCKTIMEVERIFY
|
|
// regarding 5-byte numeric operands.
|
|
const CScriptNum nSequence(stacktop(-1),
|
|
fRequireMinimal, 5);
|
|
|
|
// In the rare event that the argument may be < 0 due to
|
|
// some arithmetic being done first, you can always use
|
|
// 0 MAX CHECKSEQUENCEVERIFY.
|
|
if (nSequence < 0) {
|
|
return set_error(serror,
|
|
SCRIPT_ERR_NEGATIVE_LOCKTIME);
|
|
}
|
|
|
|
// To provide for future soft-fork extensibility, if the
|
|
// operand has the disabled lock-time flag set,
|
|
// CHECKSEQUENCEVERIFY behaves as a NOP.
|
|
if ((nSequence &
|
|
CTxIn::SEQUENCE_LOCKTIME_DISABLE_FLAG) != 0) {
|
|
break;
|
|
}
|
|
|
|
// Compare the specified sequence number with the input.
|
|
if (!checker.CheckSequence(nSequence)) {
|
|
return set_error(serror,
|
|
SCRIPT_ERR_UNSATISFIED_LOCKTIME);
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
case OP_NOP1:
|
|
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);
|
|
if (flags & SCRIPT_VERIFY_MINIMALIF) {
|
|
if (vch.size() > 1) {
|
|
return set_error(serror,
|
|
SCRIPT_ERR_MINIMALIF);
|
|
}
|
|
if (vch.size() == 1 && vch[0] != 1) {
|
|
return set_error(serror,
|
|
SCRIPT_ERR_MINIMALIF);
|
|
}
|
|
}
|
|
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_AND:
|
|
case OP_OR:
|
|
case OP_XOR: {
|
|
// (x1 x2 - out)
|
|
if (stack.size() < 2) {
|
|
return set_error(
|
|
serror, SCRIPT_ERR_INVALID_STACK_OPERATION);
|
|
}
|
|
valtype &vch1 = stacktop(-2);
|
|
valtype &vch2 = stacktop(-1);
|
|
|
|
// Inputs must be the same size
|
|
if (vch1.size() != vch2.size()) {
|
|
return set_error(serror,
|
|
SCRIPT_ERR_INVALID_OPERAND_SIZE);
|
|
}
|
|
|
|
// To avoid allocating, we modify vch1 in place.
|
|
switch (opcode) {
|
|
case OP_AND:
|
|
for (size_t i = 0; i < vch1.size(); ++i) {
|
|
vch1[i] &= vch2[i];
|
|
}
|
|
break;
|
|
case OP_OR:
|
|
for (size_t i = 0; i < vch1.size(); ++i) {
|
|
vch1[i] |= vch2[i];
|
|
}
|
|
break;
|
|
case OP_XOR:
|
|
for (size_t i = 0; i < vch1.size(); ++i) {
|
|
vch1[i] ^= vch2[i];
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
// And pop vch2.
|
|
popstack(stack);
|
|
} break;
|
|
|
|
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_DIV:
|
|
case OP_MOD:
|
|
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_DIV:
|
|
// denominator must not be 0
|
|
if (bn2 == 0) {
|
|
return set_error(serror,
|
|
SCRIPT_ERR_DIV_BY_ZERO);
|
|
}
|
|
bn = bn1 / bn2;
|
|
break;
|
|
|
|
case OP_MOD:
|
|
// divisor must not be 0
|
|
if (bn2 == 0) {
|
|
return set_error(serror,
|
|
SCRIPT_ERR_MOD_BY_ZERO);
|
|
}
|
|
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(vch.data(), vch.size())
|
|
.Finalize(vchHash.data());
|
|
} else if (opcode == OP_SHA1) {
|
|
CSHA1()
|
|
.Write(vch.data(), vch.size())
|
|
.Finalize(vchHash.data());
|
|
} else if (opcode == OP_SHA256) {
|
|
CSHA256()
|
|
.Write(vch.data(), vch.size())
|
|
.Finalize(vchHash.data());
|
|
} else if (opcode == OP_HASH160) {
|
|
CHash160()
|
|
.Write(vch.data(), vch.size())
|
|
.Finalize(vchHash.data());
|
|
} else if (opcode == OP_HASH256) {
|
|
CHash256()
|
|
.Write(vch.data(), vch.size())
|
|
.Finalize(vchHash.data());
|
|
}
|
|
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);
|
|
|
|
if (!CheckTransactionSignatureEncoding(vchSig, flags,
|
|
serror) ||
|
|
!CheckPubKeyEncoding(vchPubKey, flags, serror)) {
|
|
// serror is set
|
|
return false;
|
|
}
|
|
|
|
// Subset of script starting at the most recent
|
|
// codeseparator
|
|
CScript scriptCode(pbegincodehash, pend);
|
|
|
|
// Remove signature for pre-fork scripts
|
|
CleanupScriptCode(scriptCode, vchSig, flags);
|
|
|
|
bool fSuccess = checker.CheckSig(vchSig, vchPubKey,
|
|
scriptCode, flags);
|
|
|
|
if (!fSuccess && (flags & SCRIPT_VERIFY_NULLFAIL) &&
|
|
vchSig.size()) {
|
|
return set_error(serror, SCRIPT_ERR_SIG_NULLFAIL);
|
|
}
|
|
|
|
popstack(stack);
|
|
popstack(stack);
|
|
stack.push_back(fSuccess ? vchTrue : vchFalse);
|
|
if (opcode == OP_CHECKSIGVERIFY) {
|
|
if (fSuccess) {
|
|
popstack(stack);
|
|
} else {
|
|
return set_error(serror,
|
|
SCRIPT_ERR_CHECKSIGVERIFY);
|
|
}
|
|
}
|
|
} break;
|
|
|
|
case OP_CHECKDATASIG:
|
|
case OP_CHECKDATASIGVERIFY: {
|
|
// Make sure this remains an error before activation.
|
|
if ((flags & SCRIPT_ENABLE_CHECKDATASIG) == 0) {
|
|
return set_error(serror, SCRIPT_ERR_BAD_OPCODE);
|
|
}
|
|
|
|
// (sig message pubkey -- bool)
|
|
if (stack.size() < 3) {
|
|
return set_error(
|
|
serror, SCRIPT_ERR_INVALID_STACK_OPERATION);
|
|
}
|
|
|
|
valtype &vchSig = stacktop(-3);
|
|
valtype &vchMessage = stacktop(-2);
|
|
valtype &vchPubKey = stacktop(-1);
|
|
|
|
if (!CheckDataSignatureEncoding(vchSig, flags,
|
|
serror) ||
|
|
!CheckPubKeyEncoding(vchPubKey, flags, serror)) {
|
|
// serror is set
|
|
return false;
|
|
}
|
|
|
|
bool fSuccess = false;
|
|
if (vchSig.size()) {
|
|
valtype vchHash(32);
|
|
CSHA256()
|
|
.Write(vchMessage.data(), vchMessage.size())
|
|
.Finalize(vchHash.data());
|
|
fSuccess = checker.VerifySignature(
|
|
vchSig, CPubKey(vchPubKey), uint256(vchHash),
|
|
flags);
|
|
}
|
|
|
|
if (!fSuccess && (flags & SCRIPT_VERIFY_NULLFAIL) &&
|
|
vchSig.size()) {
|
|
return set_error(serror, SCRIPT_ERR_SIG_NULLFAIL);
|
|
}
|
|
|
|
popstack(stack);
|
|
popstack(stack);
|
|
popstack(stack);
|
|
stack.push_back(fSuccess ? vchTrue : vchFalse);
|
|
if (opcode == OP_CHECKDATASIGVERIFY) {
|
|
if (fSuccess) {
|
|
popstack(stack);
|
|
} else {
|
|
return set_error(serror,
|
|
SCRIPT_ERR_CHECKDATASIGVERIFY);
|
|
}
|
|
}
|
|
} 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 > MAX_PUBKEYS_PER_MULTISIG) {
|
|
return set_error(serror, SCRIPT_ERR_PUBKEY_COUNT);
|
|
}
|
|
nOpCount += nKeysCount;
|
|
if (nOpCount > MAX_OPS_PER_SCRIPT) {
|
|
return set_error(serror, SCRIPT_ERR_OP_COUNT);
|
|
}
|
|
int ikey = ++i;
|
|
// ikey2 is the position of last non-signature item in
|
|
// the stack. Top stack item = 1. With
|
|
// SCRIPT_VERIFY_NULLFAIL, this is used for cleanup if
|
|
// operation fails.
|
|
int ikey2 = nKeysCount + 2;
|
|
i += nKeysCount;
|
|
if ((int)stack.size() < i) {
|
|
return set_error(
|
|
serror, SCRIPT_ERR_INVALID_STACK_OPERATION);
|
|
}
|
|
|
|
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);
|
|
|
|
// Remove signature for pre-fork scripts
|
|
for (int k = 0; k < nSigsCount; k++) {
|
|
valtype &vchSig = stacktop(-isig - k);
|
|
CleanupScriptCode(scriptCode, vchSig, flags);
|
|
}
|
|
|
|
bool fSuccess = true;
|
|
while (fSuccess && nSigsCount > 0) {
|
|
valtype &vchSig = stacktop(-isig);
|
|
valtype &vchPubKey = stacktop(-ikey);
|
|
|
|
// Note how this makes the exact order of
|
|
// pubkey/signature evaluation distinguishable by
|
|
// CHECKMULTISIG NOT if the STRICTENC flag is set.
|
|
// See the script_(in)valid tests for details.
|
|
if (!CheckTransactionECDSASignatureEncoding(
|
|
vchSig, flags, serror) ||
|
|
!CheckPubKeyEncoding(vchPubKey, flags,
|
|
serror)) {
|
|
// serror is set
|
|
return false;
|
|
}
|
|
|
|
// Check signature
|
|
bool fOk = checker.CheckSig(vchSig, vchPubKey,
|
|
scriptCode, flags);
|
|
|
|
if (fOk) {
|
|
isig++;
|
|
nSigsCount--;
|
|
}
|
|
ikey++;
|
|
nKeysCount--;
|
|
|
|
// If there are more signatures left than keys left,
|
|
// then too many signatures have failed. Exit early,
|
|
// without checking any further signatures.
|
|
if (nSigsCount > nKeysCount) {
|
|
fSuccess = false;
|
|
}
|
|
}
|
|
|
|
// Clean up stack of actual arguments
|
|
while (i-- > 1) {
|
|
// If the operation failed, we require that all
|
|
// signatures must be empty vector
|
|
if (!fSuccess && (flags & SCRIPT_VERIFY_NULLFAIL) &&
|
|
!ikey2 && stacktop(-1).size()) {
|
|
return set_error(serror,
|
|
SCRIPT_ERR_SIG_NULLFAIL);
|
|
}
|
|
if (ikey2 > 0) {
|
|
ikey2--;
|
|
}
|
|
popstack(stack);
|
|
}
|
|
|
|
// A bug causes CHECKMULTISIG to consume one extra
|
|
// argument whose contents were not checked in any way.
|
|
//
|
|
// 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;
|
|
|
|
//
|
|
// Byte string operations
|
|
//
|
|
case OP_CAT: {
|
|
// (x1 x2 -- out)
|
|
if (stack.size() < 2) {
|
|
return set_error(
|
|
serror, SCRIPT_ERR_INVALID_STACK_OPERATION);
|
|
}
|
|
valtype &vch1 = stacktop(-2);
|
|
valtype &vch2 = stacktop(-1);
|
|
if (vch1.size() + vch2.size() >
|
|
MAX_SCRIPT_ELEMENT_SIZE) {
|
|
return set_error(serror, SCRIPT_ERR_PUSH_SIZE);
|
|
}
|
|
vch1.insert(vch1.end(), vch2.begin(), vch2.end());
|
|
popstack(stack);
|
|
} break;
|
|
|
|
case OP_SPLIT: {
|
|
// (in position -- x1 x2)
|
|
if (stack.size() < 2) {
|
|
return set_error(
|
|
serror, SCRIPT_ERR_INVALID_STACK_OPERATION);
|
|
}
|
|
|
|
const valtype &data = stacktop(-2);
|
|
|
|
// Make sure the split point is apropriate.
|
|
uint64_t position =
|
|
CScriptNum(stacktop(-1), fRequireMinimal).getint();
|
|
if (position > data.size()) {
|
|
return set_error(serror,
|
|
SCRIPT_ERR_INVALID_SPLIT_RANGE);
|
|
}
|
|
|
|
// Prepare the results in their own buffer as `data`
|
|
// will be invalidated.
|
|
valtype n1(data.begin(), data.begin() + position);
|
|
valtype n2(data.begin() + position, data.end());
|
|
|
|
// Replace existing stack values by the new values.
|
|
stacktop(-2) = std::move(n1);
|
|
stacktop(-1) = std::move(n2);
|
|
} break;
|
|
|
|
//
|
|
// Conversion operations
|
|
//
|
|
case OP_NUM2BIN: {
|
|
// (in size -- out)
|
|
if (stack.size() < 2) {
|
|
return set_error(
|
|
serror, SCRIPT_ERR_INVALID_STACK_OPERATION);
|
|
}
|
|
|
|
uint64_t size =
|
|
CScriptNum(stacktop(-1), fRequireMinimal).getint();
|
|
if (size > MAX_SCRIPT_ELEMENT_SIZE) {
|
|
return set_error(serror, SCRIPT_ERR_PUSH_SIZE);
|
|
}
|
|
|
|
popstack(stack);
|
|
valtype &rawnum = stacktop(-1);
|
|
|
|
// Try to see if we can fit that number in the number of
|
|
// byte requested.
|
|
CScriptNum::MinimallyEncode(rawnum);
|
|
if (rawnum.size() > size) {
|
|
// We definitively cannot.
|
|
return set_error(serror,
|
|
SCRIPT_ERR_IMPOSSIBLE_ENCODING);
|
|
}
|
|
|
|
// We already have an element of the right size, we
|
|
// don't need to do anything.
|
|
if (rawnum.size() == size) {
|
|
break;
|
|
}
|
|
|
|
uint8_t signbit = 0x00;
|
|
if (rawnum.size() > 0) {
|
|
signbit = rawnum.back() & 0x80;
|
|
rawnum[rawnum.size() - 1] &= 0x7f;
|
|
}
|
|
|
|
rawnum.reserve(size);
|
|
while (rawnum.size() < size - 1) {
|
|
rawnum.push_back(0x00);
|
|
}
|
|
|
|
rawnum.push_back(signbit);
|
|
} break;
|
|
|
|
case OP_BIN2NUM: {
|
|
// (in -- out)
|
|
if (stack.size() < 1) {
|
|
return set_error(
|
|
serror, SCRIPT_ERR_INVALID_STACK_OPERATION);
|
|
}
|
|
|
|
valtype &n = stacktop(-1);
|
|
CScriptNum::MinimallyEncode(n);
|
|
|
|
// The resulting number must be a valid number.
|
|
if (!CScriptNum::IsMinimallyEncoded(n)) {
|
|
return set_error(serror,
|
|
SCRIPT_ERR_INVALID_NUMBER_RANGE);
|
|
}
|
|
} 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:
|
|
//!< reference to the spending transaction (the one being serialized)
|
|
const CTransaction &txTo;
|
|
//!< output script being consumed
|
|
const CScript &scriptCode;
|
|
//!< input index of txTo being signed
|
|
const unsigned int nIn;
|
|
//!< container for hashtype flags
|
|
const SigHashType sigHashType;
|
|
|
|
public:
|
|
CTransactionSignatureSerializer(const CTransaction &txToIn,
|
|
const CScript &scriptCodeIn,
|
|
unsigned int nInIn,
|
|
SigHashType sigHashTypeIn)
|
|
: txTo(txToIn), scriptCode(scriptCodeIn), nIn(nInIn),
|
|
sigHashType(sigHashTypeIn) {}
|
|
|
|
/** Serialize the passed scriptCode, skipping OP_CODESEPARATORs */
|
|
template <typename S> void SerializeScriptCode(S &s) 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++;
|
|
}
|
|
}
|
|
bitcoin::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) const {
|
|
// In case of SIGHASH_ANYONECANPAY, only the input being signed is
|
|
// serialized
|
|
if (sigHashType.hasAnyoneCanPay()) {
|
|
nInput = nIn;
|
|
}
|
|
// Serialize the prevout
|
|
bitcoin::Serialize(s, txTo.vin[nInput].prevout);
|
|
// Serialize the script
|
|
if (nInput != nIn) {
|
|
// Blank out other inputs' signatures
|
|
bitcoin::Serialize(s, CScript());
|
|
} else {
|
|
SerializeScriptCode(s);
|
|
}
|
|
// Serialize the nSequence
|
|
if (nInput != nIn &&
|
|
(sigHashType.getBaseType() == BaseSigHashType::SINGLE ||
|
|
sigHashType.getBaseType() == BaseSigHashType::NONE)) {
|
|
// let the others update at will
|
|
bitcoin::Serialize(s, (int)0);
|
|
} else {
|
|
bitcoin::Serialize(s, txTo.vin[nInput].nSequence);
|
|
}
|
|
}
|
|
|
|
/** Serialize an output of txTo */
|
|
template <typename S>
|
|
void SerializeOutput(S &s, unsigned int nOutput) const {
|
|
if (sigHashType.getBaseType() == BaseSigHashType::SINGLE &&
|
|
nOutput != nIn) {
|
|
// Do not lock-in the txout payee at other indices as txin
|
|
bitcoin ::Serialize(s, CTxOut());
|
|
} else {
|
|
bitcoin::Serialize(s, txTo.vout[nOutput]);
|
|
}
|
|
}
|
|
|
|
/** Serialize txTo */
|
|
template <typename S> void Serialize(S &s) const {
|
|
// Serialize nVersion
|
|
bitcoin::Serialize(s, txTo.nVersion);
|
|
// Serialize vin
|
|
unsigned int nInputs =
|
|
sigHashType.hasAnyoneCanPay() ? 1 : txTo.vin.size();
|
|
bitcoin::WriteCompactSize(s, nInputs);
|
|
for (unsigned int nInput = 0; nInput < nInputs; nInput++) {
|
|
SerializeInput(s, nInput);
|
|
}
|
|
// Serialize vout
|
|
unsigned int nOutputs =
|
|
(sigHashType.getBaseType() == BaseSigHashType::NONE)
|
|
? 0
|
|
: ((sigHashType.getBaseType() == BaseSigHashType::SINGLE)
|
|
? nIn + 1
|
|
: txTo.vout.size());
|
|
bitcoin::WriteCompactSize(s, nOutputs);
|
|
for (unsigned int nOutput = 0; nOutput < nOutputs; nOutput++) {
|
|
SerializeOutput(s, nOutput);
|
|
}
|
|
// Serialize nLockTime
|
|
bitcoin::Serialize(s, txTo.nLockTime);
|
|
}
|
|
};
|
|
|
|
uint256 GetPrevoutHash(const CTransaction &txTo) {
|
|
CHashWriter ss(SER_GETHASH, 0);
|
|
for (size_t n = 0; n < txTo.vin.size(); n++) {
|
|
ss << txTo.vin[n].prevout;
|
|
}
|
|
return ss.GetHash();
|
|
}
|
|
|
|
uint256 GetSequenceHash(const CTransaction &txTo) {
|
|
CHashWriter ss(SER_GETHASH, 0);
|
|
for (size_t n = 0; n < txTo.vin.size(); n++) {
|
|
ss << txTo.vin[n].nSequence;
|
|
}
|
|
return ss.GetHash();
|
|
}
|
|
|
|
uint256 GetOutputsHash(const CTransaction &txTo) {
|
|
CHashWriter ss(SER_GETHASH, 0);
|
|
for (size_t n = 0; n < txTo.vout.size(); n++) {
|
|
ss << txTo.vout[n];
|
|
}
|
|
return ss.GetHash();
|
|
}
|
|
|
|
} // namespace
|
|
|
|
PrecomputedTransactionData::PrecomputedTransactionData(
|
|
const CTransaction &txTo) {
|
|
hashPrevouts = GetPrevoutHash(txTo);
|
|
hashSequence = GetSequenceHash(txTo);
|
|
hashOutputs = GetOutputsHash(txTo);
|
|
}
|
|
|
|
uint256 SignatureHash(const CScript &scriptCode, const CTransaction &txTo,
|
|
unsigned int nIn, SigHashType sigHashType,
|
|
const Amount amount,
|
|
const PrecomputedTransactionData *cache, uint32_t flags) {
|
|
if (flags & SCRIPT_ENABLE_REPLAY_PROTECTION) {
|
|
// Legacy chain's value for fork id must be of the form 0xffxxxx.
|
|
// By xoring with 0xdead, we ensure that the value will be different
|
|
// from the original one, even if it already starts with 0xff.
|
|
uint32_t newForkValue = sigHashType.getForkValue() ^ 0xdead;
|
|
sigHashType = sigHashType.withForkValue(0xff0000 | newForkValue);
|
|
}
|
|
|
|
if (sigHashType.hasForkId() && (flags & SCRIPT_ENABLE_SIGHASH_FORKID)) {
|
|
uint256 hashPrevouts;
|
|
uint256 hashSequence;
|
|
uint256 hashOutputs;
|
|
|
|
if (!sigHashType.hasAnyoneCanPay()) {
|
|
hashPrevouts = cache ? cache->hashPrevouts : GetPrevoutHash(txTo);
|
|
}
|
|
|
|
if (!sigHashType.hasAnyoneCanPay() &&
|
|
(sigHashType.getBaseType() != BaseSigHashType::SINGLE) &&
|
|
(sigHashType.getBaseType() != BaseSigHashType::NONE)) {
|
|
hashSequence = cache ? cache->hashSequence : GetSequenceHash(txTo);
|
|
}
|
|
|
|
if ((sigHashType.getBaseType() != BaseSigHashType::SINGLE) &&
|
|
(sigHashType.getBaseType() != BaseSigHashType::NONE)) {
|
|
hashOutputs = cache ? cache->hashOutputs : GetOutputsHash(txTo);
|
|
} else if ((sigHashType.getBaseType() == BaseSigHashType::SINGLE) &&
|
|
(nIn < txTo.vout.size())) {
|
|
CHashWriter ss(SER_GETHASH, 0);
|
|
ss << txTo.vout[nIn];
|
|
hashOutputs = ss.GetHash();
|
|
}
|
|
|
|
CHashWriter ss(SER_GETHASH, 0);
|
|
// Version
|
|
ss << txTo.nVersion;
|
|
// Input prevouts/nSequence (none/all, depending on flags)
|
|
ss << hashPrevouts;
|
|
ss << hashSequence;
|
|
// The input being signed (replacing the scriptSig with scriptCode +
|
|
// amount). The prevout may already be contained in hashPrevout, and the
|
|
// nSequence may already be contain in hashSequence.
|
|
ss << txTo.vin[nIn].prevout;
|
|
ss << scriptCode;
|
|
ss << amount;
|
|
ss << txTo.vin[nIn].nSequence;
|
|
// Outputs (none/one/all, depending on flags)
|
|
ss << hashOutputs;
|
|
// Locktime
|
|
ss << txTo.nLockTime;
|
|
// Sighash type
|
|
ss << sigHashType;
|
|
|
|
return ss.GetHash();
|
|
}
|
|
|
|
static const uint256 one(uint256S(
|
|
"0000000000000000000000000000000000000000000000000000000000000001"));
|
|
if (nIn >= txTo.vin.size()) {
|
|
// nIn out of range
|
|
return one;
|
|
}
|
|
|
|
// Check for invalid use of SIGHASH_SINGLE
|
|
if ((sigHashType.getBaseType() == BaseSigHashType::SINGLE) &&
|
|
(nIn >= txTo.vout.size())) {
|
|
// nOut out of range
|
|
return one;
|
|
}
|
|
|
|
// Wrapper to serialize only the necessary parts of the transaction being
|
|
// signed
|
|
CTransactionSignatureSerializer txTmp(txTo, scriptCode, nIn, sigHashType);
|
|
|
|
// Serialize and hash
|
|
CHashWriter ss(SER_GETHASH, 0);
|
|
ss << txTmp << sigHashType;
|
|
return ss.GetHash();
|
|
}
|
|
|
|
bool BaseSignatureChecker::VerifySignature(const std::vector<uint8_t> &vchSig,
|
|
const CPubKey &pubkey,
|
|
const uint256 &sighash,
|
|
uint32_t flags) const {
|
|
if ((flags & SCRIPT_ENABLE_SCHNORR) && (vchSig.size() == 64)) {
|
|
return pubkey.VerifySchnorr(sighash, vchSig);
|
|
} else {
|
|
return pubkey.VerifyECDSA(sighash, vchSig);
|
|
}
|
|
}
|
|
|
|
bool TransactionSignatureChecker::CheckSig(
|
|
const std::vector<uint8_t> &vchSigIn, const std::vector<uint8_t> &vchPubKey,
|
|
const CScript &scriptCode, uint32_t flags) const {
|
|
CPubKey pubkey(vchPubKey);
|
|
if (!pubkey.IsValid()) {
|
|
return false;
|
|
}
|
|
|
|
// Hash type is one byte tacked on to the end of the signature
|
|
std::vector<uint8_t> vchSig(vchSigIn);
|
|
if (vchSig.empty()) {
|
|
return false;
|
|
}
|
|
SigHashType sigHashType = GetHashType(vchSig);
|
|
vchSig.pop_back();
|
|
|
|
uint256 sighash = SignatureHash(scriptCode, *txTo, nIn, sigHashType, amount,
|
|
this->txdata, flags);
|
|
|
|
if (!VerifySignature(vchSig, pubkey, sighash, flags)) {
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool TransactionSignatureChecker::CheckLockTime(
|
|
const CScriptNum &nLockTime) const {
|
|
// There are two kinds of nLockTime: lock-by-blockheight and
|
|
// lock-by-blocktime, distinguished by whether nLockTime <
|
|
// LOCKTIME_THRESHOLD.
|
|
//
|
|
// We want to compare apples to apples, so fail the script unless the type
|
|
// of nLockTime being tested is the same as the nLockTime in the
|
|
// transaction.
|
|
if (!((txTo->nLockTime < LOCKTIME_THRESHOLD &&
|
|
nLockTime < LOCKTIME_THRESHOLD) ||
|
|
(txTo->nLockTime >= LOCKTIME_THRESHOLD &&
|
|
nLockTime >= LOCKTIME_THRESHOLD))) {
|
|
return false;
|
|
}
|
|
|
|
// Now that we know we're comparing apples-to-apples, the comparison is a
|
|
// simple numeric one.
|
|
if (nLockTime > int64_t(txTo->nLockTime)) {
|
|
return false;
|
|
}
|
|
|
|
// Finally the nLockTime feature can be disabled and thus
|
|
// CHECKLOCKTIMEVERIFY bypassed if every txin has been finalized by setting
|
|
// nSequence to maxint. The transaction would be allowed into the
|
|
// blockchain, making the opcode ineffective.
|
|
//
|
|
// Testing if this vin is not final is sufficient to prevent this condition.
|
|
// Alternatively we could test all inputs, but testing just this input
|
|
// minimizes the data required to prove correct CHECKLOCKTIMEVERIFY
|
|
// execution.
|
|
if (CTxIn::SEQUENCE_FINAL == txTo->vin[nIn].nSequence) {
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool TransactionSignatureChecker::CheckSequence(
|
|
const CScriptNum &nSequence) const {
|
|
// Relative lock times are supported by comparing the passed in operand to
|
|
// the sequence number of the input.
|
|
const int64_t txToSequence = int64_t(txTo->vin[nIn].nSequence);
|
|
|
|
// Fail if the transaction's version number is not set high enough to
|
|
// trigger BIP 68 rules.
|
|
if (static_cast<uint32_t>(txTo->nVersion) < 2) {
|
|
return false;
|
|
}
|
|
|
|
// Sequence numbers with their most significant bit set are not consensus
|
|
// constrained. Testing that the transaction's sequence number do not have
|
|
// this bit set prevents using this property to get around a
|
|
// CHECKSEQUENCEVERIFY check.
|
|
if (txToSequence & CTxIn::SEQUENCE_LOCKTIME_DISABLE_FLAG) {
|
|
return false;
|
|
}
|
|
|
|
// Mask off any bits that do not have consensus-enforced meaning before
|
|
// doing the integer comparisons
|
|
const uint32_t nLockTimeMask =
|
|
CTxIn::SEQUENCE_LOCKTIME_TYPE_FLAG | CTxIn::SEQUENCE_LOCKTIME_MASK;
|
|
const int64_t txToSequenceMasked = txToSequence & nLockTimeMask;
|
|
const CScriptNum nSequenceMasked = nSequence & nLockTimeMask;
|
|
|
|
// There are two kinds of nSequence: lock-by-blockheight and
|
|
// lock-by-blocktime, distinguished by whether nSequenceMasked <
|
|
// CTxIn::SEQUENCE_LOCKTIME_TYPE_FLAG.
|
|
//
|
|
// We want to compare apples to apples, so fail the script unless the type
|
|
// of nSequenceMasked being tested is the same as the nSequenceMasked in the
|
|
// transaction.
|
|
if (!((txToSequenceMasked < CTxIn::SEQUENCE_LOCKTIME_TYPE_FLAG &&
|
|
nSequenceMasked < CTxIn::SEQUENCE_LOCKTIME_TYPE_FLAG) ||
|
|
(txToSequenceMasked >= CTxIn::SEQUENCE_LOCKTIME_TYPE_FLAG &&
|
|
nSequenceMasked >= CTxIn::SEQUENCE_LOCKTIME_TYPE_FLAG))) {
|
|
return false;
|
|
}
|
|
|
|
// Now that we know we're comparing apples-to-apples, the comparison is a
|
|
// simple numeric one.
|
|
if (nSequenceMasked > txToSequenceMasked) {
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool VerifyScript(const CScript &scriptSig, const CScript &scriptPubKey,
|
|
uint32_t flags, const BaseSignatureChecker &checker,
|
|
ScriptError *serror) {
|
|
set_error(serror, SCRIPT_ERR_UNKNOWN_ERROR);
|
|
|
|
// If FORKID is enabled, we also ensure strict encoding.
|
|
if (flags & SCRIPT_ENABLE_SIGHASH_FORKID) {
|
|
flags |= SCRIPT_VERIFY_STRICTENC;
|
|
}
|
|
|
|
if ((flags & SCRIPT_VERIFY_SIGPUSHONLY) != 0 && !scriptSig.IsPushOnly()) {
|
|
return set_error(serror, SCRIPT_ERR_SIG_PUSHONLY);
|
|
}
|
|
|
|
std::vector<valtype> 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);
|
|
}
|
|
|
|
// Restore stack.
|
|
swap(stack, stackCopy);
|
|
|
|
// stack 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(!stack.empty());
|
|
|
|
const valtype &pubKeySerialized = stack.back();
|
|
CScript pubKey2(pubKeySerialized.begin(), pubKeySerialized.end());
|
|
popstack(stack);
|
|
|
|
// Bail out early if ALLOW_SEGWIT_RECOVERY is set, the redeem script is
|
|
// a p2sh segwit program and it was the only item pushed into the stack
|
|
if ((flags & SCRIPT_ALLOW_SEGWIT_RECOVERY) != 0 && stack.empty() &&
|
|
pubKey2.IsWitnessProgram()) {
|
|
return set_success(serror);
|
|
}
|
|
|
|
if (!EvalScript(stack, pubKey2, flags, checker, serror)) {
|
|
// serror is set
|
|
return false;
|
|
}
|
|
if (stack.empty()) {
|
|
return set_error(serror, SCRIPT_ERR_EVAL_FALSE);
|
|
}
|
|
if (!CastToBool(stack.back())) {
|
|
return set_error(serror, SCRIPT_ERR_EVAL_FALSE);
|
|
}
|
|
}
|
|
|
|
// The CLEANSTACK check is only performed after potential P2SH evaluation,
|
|
// as the non-P2SH evaluation of a P2SH script will obviously not result in
|
|
// a clean stack (the P2SH inputs remain). The same holds for witness
|
|
// evaluation.
|
|
if ((flags & SCRIPT_VERIFY_CLEANSTACK) != 0) {
|
|
// Disallow CLEANSTACK without P2SH, as otherwise a switch
|
|
// CLEANSTACK->P2SH+CLEANSTACK would be possible, which is not a
|
|
// softfork (and P2SH should be one).
|
|
assert((flags & SCRIPT_VERIFY_P2SH) != 0);
|
|
if (stack.size() != 1) {
|
|
return set_error(serror, SCRIPT_ERR_CLEANSTACK);
|
|
}
|
|
}
|
|
|
|
return set_success(serror);
|
|
}
|
|
|
|
} // end namespace bitcoin
|
|
|
|
#ifdef __clang__
|
|
#pragma clang diagnostic pop
|
|
#endif
|