r1
This commit is contained in:
@@ -0,0 +1,98 @@
|
||||
// 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 "bitcoinconsensus.h"
|
||||
|
||||
#include "primitives/transaction.h"
|
||||
#include "script/interpreter.h"
|
||||
#include "version.h"
|
||||
|
||||
namespace {
|
||||
|
||||
/** A class that deserializes a single CTransaction one time. */
|
||||
class TxInputStream
|
||||
{
|
||||
public:
|
||||
TxInputStream(int nTypeIn, int nVersionIn, const unsigned char *txTo, size_t txToLen) :
|
||||
m_type(nTypeIn),
|
||||
m_version(nVersionIn),
|
||||
m_data(txTo),
|
||||
m_remaining(txToLen)
|
||||
{}
|
||||
|
||||
TxInputStream& read(char* pch, size_t nSize)
|
||||
{
|
||||
if (nSize > m_remaining)
|
||||
throw std::ios_base::failure(std::string(__func__) + ": end of data");
|
||||
|
||||
if (pch == NULL)
|
||||
throw std::ios_base::failure(std::string(__func__) + ": bad destination buffer");
|
||||
|
||||
if (m_data == NULL)
|
||||
throw std::ios_base::failure(std::string(__func__) + ": bad source buffer");
|
||||
|
||||
memcpy(pch, m_data, nSize);
|
||||
m_remaining -= nSize;
|
||||
m_data += nSize;
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
TxInputStream& operator>>(T& obj)
|
||||
{
|
||||
::Unserialize(*this, obj, m_type, m_version);
|
||||
return *this;
|
||||
}
|
||||
|
||||
private:
|
||||
const int m_type;
|
||||
const int m_version;
|
||||
const unsigned char* m_data;
|
||||
size_t m_remaining;
|
||||
};
|
||||
|
||||
inline int set_error(bitcoinconsensus_error* ret, bitcoinconsensus_error serror)
|
||||
{
|
||||
if (ret)
|
||||
*ret = serror;
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct ECCryptoClosure
|
||||
{
|
||||
ECCVerifyHandle handle;
|
||||
};
|
||||
|
||||
ECCryptoClosure instance_of_eccryptoclosure;
|
||||
|
||||
} // anon namespace
|
||||
|
||||
int bitcoinconsensus_verify_script(const unsigned char *scriptPubKey, unsigned int scriptPubKeyLen,
|
||||
const unsigned char *txTo , unsigned int txToLen,
|
||||
unsigned int nIn, unsigned int flags, bitcoinconsensus_error* err)
|
||||
{
|
||||
try {
|
||||
TxInputStream stream(SER_NETWORK, PROTOCOL_VERSION, txTo, txToLen);
|
||||
CTransaction tx;
|
||||
stream >> tx;
|
||||
if (nIn >= tx.vin.size())
|
||||
return set_error(err, bitcoinconsensus_ERR_TX_INDEX);
|
||||
if (tx.GetSerializeSize(SER_NETWORK, PROTOCOL_VERSION) != txToLen)
|
||||
return set_error(err, bitcoinconsensus_ERR_TX_SIZE_MISMATCH);
|
||||
|
||||
// Regardless of the verification result, the tx did not error.
|
||||
set_error(err, bitcoinconsensus_ERR_OK);
|
||||
|
||||
return VerifyScript(tx.vin[nIn].scriptSig, CScript(scriptPubKey, scriptPubKey + scriptPubKeyLen), flags, TransactionSignatureChecker(&tx, nIn), NULL);
|
||||
} catch (const std::exception&) {
|
||||
return set_error(err, bitcoinconsensus_ERR_TX_DESERIALIZE); // Error deserializing
|
||||
}
|
||||
}
|
||||
|
||||
unsigned int bitcoinconsensus_version()
|
||||
{
|
||||
// Just use the API version for now
|
||||
return BITCOINCONSENSUS_API_VER;
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
// 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_BITCOINCONSENSUS_H
|
||||
#define BITCOIN_BITCOINCONSENSUS_H
|
||||
|
||||
#if defined(BUILD_BITCOIN_INTERNAL) && defined(HAVE_CONFIG_H)
|
||||
#include "config/agrarian-config.h"
|
||||
#if defined(_WIN32)
|
||||
#if defined(DLL_EXPORT)
|
||||
#if defined(HAVE_FUNC_ATTRIBUTE_DLLEXPORT)
|
||||
#define EXPORT_SYMBOL __declspec(dllexport)
|
||||
#else
|
||||
#define EXPORT_SYMBOL
|
||||
#endif
|
||||
#endif
|
||||
#elif defined(HAVE_FUNC_ATTRIBUTE_VISIBILITY)
|
||||
#define EXPORT_SYMBOL __attribute__ ((visibility ("default")))
|
||||
#endif
|
||||
#elif defined(MSC_VER) && !defined(STATIC_LIBBITCOINCONSENSUS)
|
||||
#define EXPORT_SYMBOL __declspec(dllimport)
|
||||
#endif
|
||||
|
||||
#ifndef EXPORT_SYMBOL
|
||||
#define EXPORT_SYMBOL
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define BITCOINCONSENSUS_API_VER 0
|
||||
|
||||
typedef enum bitcoinconsensus_error_t
|
||||
{
|
||||
bitcoinconsensus_ERR_OK = 0,
|
||||
bitcoinconsensus_ERR_TX_INDEX,
|
||||
bitcoinconsensus_ERR_TX_SIZE_MISMATCH,
|
||||
bitcoinconsensus_ERR_TX_DESERIALIZE,
|
||||
} bitcoinconsensus_error;
|
||||
|
||||
/** Script verification flags */
|
||||
enum
|
||||
{
|
||||
bitcoinconsensus_SCRIPT_FLAGS_VERIFY_NONE = 0,
|
||||
bitcoinconsensus_SCRIPT_FLAGS_VERIFY_P2SH = (1U << 0), // evaluate P2SH (BIP16) subscripts
|
||||
bitcoinconsensus_SCRIPT_FLAGS_VERIFY_DERSIG = (1U << 2), // enforce strict DER (BIP66) compliance
|
||||
};
|
||||
|
||||
/// Returns 1 if the input nIn of the serialized transaction pointed to by
|
||||
/// txTo correctly spends the scriptPubKey pointed to by scriptPubKey under
|
||||
/// the additional constraints specified by flags.
|
||||
/// If not NULL, err will contain an error/success code for the operation
|
||||
EXPORT_SYMBOL int bitcoinconsensus_verify_script(const unsigned char *scriptPubKey, unsigned int scriptPubKeyLen,
|
||||
const unsigned char *txTo , unsigned int txToLen,
|
||||
unsigned int nIn, unsigned int flags, bitcoinconsensus_error* err);
|
||||
|
||||
EXPORT_SYMBOL unsigned int bitcoinconsensus_version();
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
#undef EXPORT_SYMBOL
|
||||
|
||||
#endif // BITCOIN_BITCOINCONSENSUS_H
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,131 @@
|
||||
// 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_INTERPRETER_H
|
||||
#define BITCOIN_SCRIPT_INTERPRETER_H
|
||||
|
||||
#include "script_error.h"
|
||||
#include "primitives/transaction.h"
|
||||
|
||||
#include <vector>
|
||||
#include <stdint.h>
|
||||
#include <string>
|
||||
|
||||
class CPubKey;
|
||||
class CScript;
|
||||
class CTransaction;
|
||||
class uint256;
|
||||
|
||||
/** Signature hash types/flags */
|
||||
enum
|
||||
{
|
||||
SIGHASH_ALL = 1,
|
||||
SIGHASH_NONE = 2,
|
||||
SIGHASH_SINGLE = 3,
|
||||
SIGHASH_ANYONECANPAY = 0x80,
|
||||
};
|
||||
|
||||
/** Script verification flags */
|
||||
enum
|
||||
{
|
||||
SCRIPT_VERIFY_NONE = 0,
|
||||
|
||||
// Evaluate P2SH subscripts (softfork safe, BIP16).
|
||||
SCRIPT_VERIFY_P2SH = (1U << 0),
|
||||
|
||||
// Passing a non-strict-DER signature or one with undefined hashtype to a checksig operation causes script failure.
|
||||
// Evaluating a pubkey that is not (0x04 + 64 bytes) or (0x02 or 0x03 + 32 bytes) by checksig causes script failure.
|
||||
// (softfork safe, but not used or intended as a consensus rule).
|
||||
SCRIPT_VERIFY_STRICTENC = (1U << 1),
|
||||
|
||||
// Passing a non-strict-DER signature to a checksig operation causes script failure (softfork safe, BIP62 rule 1)
|
||||
SCRIPT_VERIFY_DERSIG = (1U << 2),
|
||||
|
||||
// Passing a non-strict-DER signature or one with S > order/2 to a checksig operation causes script failure
|
||||
// (softfork safe, BIP62 rule 5).
|
||||
SCRIPT_VERIFY_LOW_S = (1U << 3),
|
||||
|
||||
// verify dummy stack item consumed by CHECKMULTISIG is of zero-length (softfork safe, BIP62 rule 7).
|
||||
SCRIPT_VERIFY_NULLDUMMY = (1U << 4),
|
||||
|
||||
// Using a non-push operator in the scriptSig causes script failure (softfork safe, BIP62 rule 2).
|
||||
SCRIPT_VERIFY_SIGPUSHONLY = (1U << 5),
|
||||
|
||||
// Require minimal encodings for all push operations (OP_0... OP_16, OP_1NEGATE where possible, direct
|
||||
// pushes up to 75 bytes, OP_PUSHDATA up to 255 bytes, OP_PUSHDATA2 for anything larger). Evaluating
|
||||
// any other push causes the script to fail (BIP62 rule 3).
|
||||
// In addition, whenever a stack element is interpreted as a number, it must be of minimal length (BIP62 rule 4).
|
||||
// (softfork safe)
|
||||
SCRIPT_VERIFY_MINIMALDATA = (1U << 6),
|
||||
|
||||
// Discourage use of NOPs reserved for upgrades (NOP1-10)
|
||||
//
|
||||
// Provided so that nodes can avoid accepting or mining transactions
|
||||
// containing executed NOP's whose meaning may change after a soft-fork,
|
||||
// thus rendering the script invalid; with this flag set executing
|
||||
// discouraged NOPs fails the script. This verification flag will never be
|
||||
// a mandatory flag applied to scripts in a block. NOPs that are not
|
||||
// executed, e.g. within an unexecuted IF ENDIF block, are *not* rejected.
|
||||
SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS = (1U << 7),
|
||||
|
||||
// Require that only a single stack element remains after evaluation. This changes the success criterion from
|
||||
// "At least one stack element must remain, and when interpreted as a boolean, it must be true" to
|
||||
// "Exactly one stack element must remain, and when interpreted as a boolean, it must be true".
|
||||
// (softfork safe, BIP62 rule 6)
|
||||
// Note: CLEANSTACK should never be used without P2SH.
|
||||
SCRIPT_VERIFY_CLEANSTACK = (1U << 8),
|
||||
|
||||
// Verify CHECKLOCKTIMEVERIFY
|
||||
//
|
||||
// See BIP65 for details.
|
||||
SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY = (1U << 9)
|
||||
};
|
||||
|
||||
uint256 SignatureHash(const CScript &scriptCode, const CTransaction& txTo, unsigned int nIn, int nHashType);
|
||||
|
||||
class BaseSignatureChecker
|
||||
{
|
||||
public:
|
||||
virtual bool CheckSig(const std::vector<unsigned char>& scriptSig, const std::vector<unsigned char>& vchPubKey, const CScript& scriptCode) const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
virtual bool CheckLockTime(const CScriptNum& nLockTime) const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
virtual ~BaseSignatureChecker() {}
|
||||
};
|
||||
|
||||
class TransactionSignatureChecker : public BaseSignatureChecker
|
||||
{
|
||||
private:
|
||||
const CTransaction* txTo;
|
||||
unsigned int nIn;
|
||||
|
||||
protected:
|
||||
virtual bool VerifySignature(const std::vector<unsigned char>& vchSig, const CPubKey& vchPubKey, const uint256& sighash) const;
|
||||
|
||||
public:
|
||||
TransactionSignatureChecker(const CTransaction* txToIn, unsigned int nInIn) : txTo(txToIn), nIn(nInIn) {}
|
||||
bool CheckSig(const std::vector<unsigned char>& scriptSig, const std::vector<unsigned char>& vchPubKey, const CScript& scriptCode) const;
|
||||
bool CheckLockTime(const CScriptNum& nLockTime) const;
|
||||
};
|
||||
|
||||
class MutableTransactionSignatureChecker : public TransactionSignatureChecker
|
||||
{
|
||||
private:
|
||||
const CTransaction txTo;
|
||||
|
||||
public:
|
||||
MutableTransactionSignatureChecker(const CMutableTransaction* txToIn, unsigned int nInIn) : TransactionSignatureChecker(&txTo, nInIn), txTo(*txToIn) {}
|
||||
};
|
||||
|
||||
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, ScriptError* error = NULL);
|
||||
|
||||
#endif // BITCOIN_SCRIPT_INTERPRETER_H
|
||||
@@ -0,0 +1,321 @@
|
||||
// Copyright (c) 2009-2010 Satoshi Nakamoto
|
||||
// Copyright (c) 2009-2014 The Bitcoin developers
|
||||
// Copyright (c) 2017-2019 The PIVX developers
|
||||
// Distributed under the MIT software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#include "script.h"
|
||||
#include "tinyformat.h"
|
||||
#include "utilstrencodings.h"
|
||||
|
||||
namespace {
|
||||
inline std::string ValueString(const std::vector<unsigned char>& vch)
|
||||
{
|
||||
if (vch.size() <= 4)
|
||||
return strprintf("%d", CScriptNum(vch, false).getint());
|
||||
else
|
||||
return HexStr(vch);
|
||||
}
|
||||
} // anon namespace
|
||||
|
||||
using namespace std;
|
||||
|
||||
const char* GetOpName(opcodetype opcode)
|
||||
{
|
||||
switch (opcode)
|
||||
{
|
||||
// push value
|
||||
case OP_0 : return "0";
|
||||
case OP_PUSHDATA1 : return "OP_PUSHDATA1";
|
||||
case OP_PUSHDATA2 : return "OP_PUSHDATA2";
|
||||
case OP_PUSHDATA4 : return "OP_PUSHDATA4";
|
||||
case OP_1NEGATE : return "-1";
|
||||
case OP_RESERVED : return "OP_RESERVED";
|
||||
case OP_1 : return "1";
|
||||
case OP_2 : return "2";
|
||||
case OP_3 : return "3";
|
||||
case OP_4 : return "4";
|
||||
case OP_5 : return "5";
|
||||
case OP_6 : return "6";
|
||||
case OP_7 : return "7";
|
||||
case OP_8 : return "8";
|
||||
case OP_9 : return "9";
|
||||
case OP_10 : return "10";
|
||||
case OP_11 : return "11";
|
||||
case OP_12 : return "12";
|
||||
case OP_13 : return "13";
|
||||
case OP_14 : return "14";
|
||||
case OP_15 : return "15";
|
||||
case OP_16 : return "16";
|
||||
|
||||
// control
|
||||
case OP_NOP : return "OP_NOP";
|
||||
case OP_VER : return "OP_VER";
|
||||
case OP_IF : return "OP_IF";
|
||||
case OP_NOTIF : return "OP_NOTIF";
|
||||
case OP_VERIF : return "OP_VERIF";
|
||||
case OP_VERNOTIF : return "OP_VERNOTIF";
|
||||
case OP_ELSE : return "OP_ELSE";
|
||||
case OP_ENDIF : return "OP_ENDIF";
|
||||
case OP_VERIFY : return "OP_VERIFY";
|
||||
case OP_RETURN : return "OP_RETURN";
|
||||
|
||||
// stack ops
|
||||
case OP_TOALTSTACK : return "OP_TOALTSTACK";
|
||||
case OP_FROMALTSTACK : return "OP_FROMALTSTACK";
|
||||
case OP_2DROP : return "OP_2DROP";
|
||||
case OP_2DUP : return "OP_2DUP";
|
||||
case OP_3DUP : return "OP_3DUP";
|
||||
case OP_2OVER : return "OP_2OVER";
|
||||
case OP_2ROT : return "OP_2ROT";
|
||||
case OP_2SWAP : return "OP_2SWAP";
|
||||
case OP_IFDUP : return "OP_IFDUP";
|
||||
case OP_DEPTH : return "OP_DEPTH";
|
||||
case OP_DROP : return "OP_DROP";
|
||||
case OP_DUP : return "OP_DUP";
|
||||
case OP_NIP : return "OP_NIP";
|
||||
case OP_OVER : return "OP_OVER";
|
||||
case OP_PICK : return "OP_PICK";
|
||||
case OP_ROLL : return "OP_ROLL";
|
||||
case OP_ROT : return "OP_ROT";
|
||||
case OP_SWAP : return "OP_SWAP";
|
||||
case OP_TUCK : return "OP_TUCK";
|
||||
|
||||
// splice ops
|
||||
case OP_CAT : return "OP_CAT";
|
||||
case OP_SUBSTR : return "OP_SUBSTR";
|
||||
case OP_LEFT : return "OP_LEFT";
|
||||
case OP_RIGHT : return "OP_RIGHT";
|
||||
case OP_SIZE : return "OP_SIZE";
|
||||
|
||||
// bit logic
|
||||
case OP_INVERT : return "OP_INVERT";
|
||||
case OP_AND : return "OP_AND";
|
||||
case OP_OR : return "OP_OR";
|
||||
case OP_XOR : return "OP_XOR";
|
||||
case OP_EQUAL : return "OP_EQUAL";
|
||||
case OP_EQUALVERIFY : return "OP_EQUALVERIFY";
|
||||
case OP_RESERVED1 : return "OP_RESERVED1";
|
||||
case OP_RESERVED2 : return "OP_RESERVED2";
|
||||
|
||||
// numeric
|
||||
case OP_1ADD : return "OP_1ADD";
|
||||
case OP_1SUB : return "OP_1SUB";
|
||||
case OP_2MUL : return "OP_2MUL";
|
||||
case OP_2DIV : return "OP_2DIV";
|
||||
case OP_NEGATE : return "OP_NEGATE";
|
||||
case OP_ABS : return "OP_ABS";
|
||||
case OP_NOT : return "OP_NOT";
|
||||
case OP_0NOTEQUAL : return "OP_0NOTEQUAL";
|
||||
case OP_ADD : return "OP_ADD";
|
||||
case OP_SUB : return "OP_SUB";
|
||||
case OP_MUL : return "OP_MUL";
|
||||
case OP_DIV : return "OP_DIV";
|
||||
case OP_MOD : return "OP_MOD";
|
||||
case OP_LSHIFT : return "OP_LSHIFT";
|
||||
case OP_RSHIFT : return "OP_RSHIFT";
|
||||
case OP_BOOLAND : return "OP_BOOLAND";
|
||||
case OP_BOOLOR : return "OP_BOOLOR";
|
||||
case OP_NUMEQUAL : return "OP_NUMEQUAL";
|
||||
case OP_NUMEQUALVERIFY : return "OP_NUMEQUALVERIFY";
|
||||
case OP_NUMNOTEQUAL : return "OP_NUMNOTEQUAL";
|
||||
case OP_LESSTHAN : return "OP_LESSTHAN";
|
||||
case OP_GREATERTHAN : return "OP_GREATERTHAN";
|
||||
case OP_LESSTHANOREQUAL : return "OP_LESSTHANOREQUAL";
|
||||
case OP_GREATERTHANOREQUAL : return "OP_GREATERTHANOREQUAL";
|
||||
case OP_MIN : return "OP_MIN";
|
||||
case OP_MAX : return "OP_MAX";
|
||||
case OP_WITHIN : return "OP_WITHIN";
|
||||
|
||||
// crypto
|
||||
case OP_RIPEMD160 : return "OP_RIPEMD160";
|
||||
case OP_SHA1 : return "OP_SHA1";
|
||||
case OP_SHA256 : return "OP_SHA256";
|
||||
case OP_HASH160 : return "OP_HASH160";
|
||||
case OP_HASH256 : return "OP_HASH256";
|
||||
case OP_CODESEPARATOR : return "OP_CODESEPARATOR";
|
||||
case OP_CHECKSIG : return "OP_CHECKSIG";
|
||||
case OP_CHECKSIGVERIFY : return "OP_CHECKSIGVERIFY";
|
||||
case OP_CHECKMULTISIG : return "OP_CHECKMULTISIG";
|
||||
case OP_CHECKMULTISIGVERIFY : return "OP_CHECKMULTISIGVERIFY";
|
||||
|
||||
// expanson
|
||||
case OP_NOP1 : return "OP_NOP1";
|
||||
case OP_NOP2 : return "OP_NOP2";
|
||||
case OP_NOP3 : return "OP_NOP3";
|
||||
case OP_NOP4 : return "OP_NOP4";
|
||||
case OP_NOP5 : return "OP_NOP5";
|
||||
case OP_NOP6 : return "OP_NOP6";
|
||||
case OP_NOP7 : return "OP_NOP7";
|
||||
case OP_NOP8 : return "OP_NOP8";
|
||||
case OP_NOP9 : return "OP_NOP9";
|
||||
case OP_NOP10 : return "OP_NOP10";
|
||||
|
||||
// zerocoin
|
||||
case OP_ZEROCOINMINT : return "OP_ZEROCOINMINT";
|
||||
case OP_ZEROCOINSPEND : return "OP_ZEROCOINSPEND";
|
||||
case OP_ZEROCOINPUBLICSPEND : return "OP_ZEROCOINPUBLICSPEND";
|
||||
|
||||
case OP_INVALIDOPCODE : return "OP_INVALIDOPCODE";
|
||||
|
||||
// Note:
|
||||
// The template matching params OP_SMALLINTEGER/etc are defined in opcodetype enum
|
||||
// as kind of implementation hack, they are *NOT* real opcodes. If found in real
|
||||
// Script, just let the default: case deal with them.
|
||||
|
||||
default:
|
||||
return "OP_UNKNOWN";
|
||||
}
|
||||
}
|
||||
|
||||
unsigned int CScript::GetSigOpCount(bool fAccurate) const
|
||||
{
|
||||
unsigned int n = 0;
|
||||
const_iterator pc = begin();
|
||||
opcodetype lastOpcode = OP_INVALIDOPCODE;
|
||||
while (pc < end())
|
||||
{
|
||||
opcodetype opcode;
|
||||
if (!GetOp(pc, opcode))
|
||||
break;
|
||||
if (opcode == OP_CHECKSIG || opcode == OP_CHECKSIGVERIFY)
|
||||
n++;
|
||||
else if (opcode == OP_CHECKMULTISIG || opcode == OP_CHECKMULTISIGVERIFY)
|
||||
{
|
||||
if (fAccurate && lastOpcode >= OP_1 && lastOpcode <= OP_16)
|
||||
n += DecodeOP_N(lastOpcode);
|
||||
else
|
||||
n += 20;
|
||||
}
|
||||
lastOpcode = opcode;
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
unsigned int CScript::GetSigOpCount(const CScript& scriptSig) const
|
||||
{
|
||||
if (!IsPayToScriptHash())
|
||||
return GetSigOpCount(true);
|
||||
|
||||
// This is a pay-to-script-hash scriptPubKey;
|
||||
// get the last item that the scriptSig
|
||||
// pushes onto the stack:
|
||||
const_iterator pc = scriptSig.begin();
|
||||
vector<unsigned char> data;
|
||||
while (pc < scriptSig.end())
|
||||
{
|
||||
opcodetype opcode;
|
||||
if (!scriptSig.GetOp(pc, opcode, data))
|
||||
return 0;
|
||||
if (opcode > OP_16)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/// ... and return its opcount:
|
||||
CScript subscript(data.begin(), data.end());
|
||||
return subscript.GetSigOpCount(true);
|
||||
}
|
||||
|
||||
bool CScript::IsNormalPaymentScript() const
|
||||
{
|
||||
if(this->size() != 25) return false;
|
||||
|
||||
std::string str;
|
||||
opcodetype opcode;
|
||||
const_iterator pc = begin();
|
||||
int i = 0;
|
||||
while (pc < end())
|
||||
{
|
||||
GetOp(pc, opcode);
|
||||
|
||||
if( i == 0 && opcode != OP_DUP) return false;
|
||||
else if(i == 1 && opcode != OP_HASH160) return false;
|
||||
else if(i == 3 && opcode != OP_EQUALVERIFY) return false;
|
||||
else if(i == 4 && opcode != OP_CHECKSIG) return false;
|
||||
else if(i == 5) return false;
|
||||
|
||||
i++;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CScript::IsPayToScriptHash() const
|
||||
{
|
||||
// Extra-fast test for pay-to-script-hash CScripts:
|
||||
return (this->size() == 23 &&
|
||||
this->at(0) == OP_HASH160 &&
|
||||
this->at(1) == 0x14 &&
|
||||
this->at(22) == OP_EQUAL);
|
||||
}
|
||||
|
||||
bool CScript::StartsWithOpcode(const opcodetype opcode) const
|
||||
{
|
||||
return (!this->empty() && this->at(0) == opcode);
|
||||
}
|
||||
|
||||
bool CScript::IsZerocoinMint() const
|
||||
{
|
||||
return StartsWithOpcode(OP_ZEROCOINMINT);
|
||||
}
|
||||
|
||||
bool CScript::IsZerocoinSpend() const
|
||||
{
|
||||
return StartsWithOpcode(OP_ZEROCOINSPEND);
|
||||
}
|
||||
|
||||
bool CScript::IsZerocoinPublicSpend() const
|
||||
{
|
||||
return StartsWithOpcode(OP_ZEROCOINPUBLICSPEND);
|
||||
}
|
||||
|
||||
bool CScript::IsPushOnly(const_iterator pc) const
|
||||
{
|
||||
while (pc < end())
|
||||
{
|
||||
opcodetype opcode;
|
||||
if (!GetOp(pc, opcode))
|
||||
return false;
|
||||
// Note that IsPushOnly() *does* consider OP_RESERVED to be a
|
||||
// push-type opcode, however execution of OP_RESERVED fails, so
|
||||
// it's not relevant to P2SH/BIP62 as the scriptSig would fail prior to
|
||||
// the P2SH special validation code being executed.
|
||||
if (opcode > OP_16)
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CScript::IsPushOnly() const
|
||||
{
|
||||
return this->IsPushOnly(begin());
|
||||
}
|
||||
|
||||
std::string CScript::ToString() const
|
||||
{
|
||||
std::string str;
|
||||
opcodetype opcode;
|
||||
std::vector<unsigned char> vch;
|
||||
const_iterator pc = begin();
|
||||
while (pc < end())
|
||||
{
|
||||
if (!str.empty())
|
||||
str += " ";
|
||||
if (!GetOp(pc, opcode, vch))
|
||||
{
|
||||
str += "[error]";
|
||||
return str;
|
||||
}
|
||||
if (0 <= opcode && opcode <= OP_PUSHDATA4) {
|
||||
str += ValueString(vch);
|
||||
} else {
|
||||
str += GetOpName(opcode);
|
||||
if (opcode == OP_ZEROCOINSPEND) {
|
||||
//Zerocoinspend has no further op codes.
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
return str;
|
||||
}
|
||||
@@ -0,0 +1,629 @@
|
||||
// Copyright (c) 2009-2010 Satoshi Nakamoto
|
||||
// Copyright (c) 2009-2014 The Bitcoin developers
|
||||
// Copyright (c) 2014-2015 The Dash developers
|
||||
// Copyright (c) 2016-2019 The PIVX developers
|
||||
// Distributed under the MIT software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#ifndef BITCOIN_SCRIPT_SCRIPT_H
|
||||
#define BITCOIN_SCRIPT_SCRIPT_H
|
||||
|
||||
#include <assert.h>
|
||||
#include <climits>
|
||||
#include <limits>
|
||||
#include "pubkey.h"
|
||||
#include <stdexcept>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
typedef std::vector<unsigned char> valtype;
|
||||
|
||||
static const unsigned int MAX_SCRIPT_ELEMENT_SIZE = 520; // bytes
|
||||
|
||||
// Threshold for nLockTime: below this value it is interpreted as block number,
|
||||
// otherwise as UNIX timestamp.
|
||||
static const unsigned int LOCKTIME_THRESHOLD = 500000000; // Tue Nov 5 00:53:20 1985 UTC
|
||||
|
||||
template <typename T>
|
||||
std::vector<unsigned char> ToByteVector(const T& in)
|
||||
{
|
||||
return std::vector<unsigned char>(in.begin(), in.end());
|
||||
}
|
||||
|
||||
/** Script opcodes */
|
||||
enum opcodetype
|
||||
{
|
||||
// push value
|
||||
OP_0 = 0x00,
|
||||
OP_FALSE = OP_0,
|
||||
OP_PUSHDATA1 = 0x4c,
|
||||
OP_PUSHDATA2 = 0x4d,
|
||||
OP_PUSHDATA4 = 0x4e,
|
||||
OP_1NEGATE = 0x4f,
|
||||
OP_RESERVED = 0x50,
|
||||
OP_1 = 0x51,
|
||||
OP_TRUE=OP_1,
|
||||
OP_2 = 0x52,
|
||||
OP_3 = 0x53,
|
||||
OP_4 = 0x54,
|
||||
OP_5 = 0x55,
|
||||
OP_6 = 0x56,
|
||||
OP_7 = 0x57,
|
||||
OP_8 = 0x58,
|
||||
OP_9 = 0x59,
|
||||
OP_10 = 0x5a,
|
||||
OP_11 = 0x5b,
|
||||
OP_12 = 0x5c,
|
||||
OP_13 = 0x5d,
|
||||
OP_14 = 0x5e,
|
||||
OP_15 = 0x5f,
|
||||
OP_16 = 0x60,
|
||||
|
||||
// control
|
||||
OP_NOP = 0x61,
|
||||
OP_VER = 0x62,
|
||||
OP_IF = 0x63,
|
||||
OP_NOTIF = 0x64,
|
||||
OP_VERIF = 0x65,
|
||||
OP_VERNOTIF = 0x66,
|
||||
OP_ELSE = 0x67,
|
||||
OP_ENDIF = 0x68,
|
||||
OP_VERIFY = 0x69,
|
||||
OP_RETURN = 0x6a,
|
||||
|
||||
// stack ops
|
||||
OP_TOALTSTACK = 0x6b,
|
||||
OP_FROMALTSTACK = 0x6c,
|
||||
OP_2DROP = 0x6d,
|
||||
OP_2DUP = 0x6e,
|
||||
OP_3DUP = 0x6f,
|
||||
OP_2OVER = 0x70,
|
||||
OP_2ROT = 0x71,
|
||||
OP_2SWAP = 0x72,
|
||||
OP_IFDUP = 0x73,
|
||||
OP_DEPTH = 0x74,
|
||||
OP_DROP = 0x75,
|
||||
OP_DUP = 0x76,
|
||||
OP_NIP = 0x77,
|
||||
OP_OVER = 0x78,
|
||||
OP_PICK = 0x79,
|
||||
OP_ROLL = 0x7a,
|
||||
OP_ROT = 0x7b,
|
||||
OP_SWAP = 0x7c,
|
||||
OP_TUCK = 0x7d,
|
||||
|
||||
// splice ops
|
||||
OP_CAT = 0x7e,
|
||||
OP_SUBSTR = 0x7f,
|
||||
OP_LEFT = 0x80,
|
||||
OP_RIGHT = 0x81,
|
||||
OP_SIZE = 0x82,
|
||||
|
||||
// bit logic
|
||||
OP_INVERT = 0x83,
|
||||
OP_AND = 0x84,
|
||||
OP_OR = 0x85,
|
||||
OP_XOR = 0x86,
|
||||
OP_EQUAL = 0x87,
|
||||
OP_EQUALVERIFY = 0x88,
|
||||
OP_RESERVED1 = 0x89,
|
||||
OP_RESERVED2 = 0x8a,
|
||||
|
||||
// numeric
|
||||
OP_1ADD = 0x8b,
|
||||
OP_1SUB = 0x8c,
|
||||
OP_2MUL = 0x8d,
|
||||
OP_2DIV = 0x8e,
|
||||
OP_NEGATE = 0x8f,
|
||||
OP_ABS = 0x90,
|
||||
OP_NOT = 0x91,
|
||||
OP_0NOTEQUAL = 0x92,
|
||||
|
||||
OP_ADD = 0x93,
|
||||
OP_SUB = 0x94,
|
||||
OP_MUL = 0x95,
|
||||
OP_DIV = 0x96,
|
||||
OP_MOD = 0x97,
|
||||
OP_LSHIFT = 0x98,
|
||||
OP_RSHIFT = 0x99,
|
||||
|
||||
OP_BOOLAND = 0x9a,
|
||||
OP_BOOLOR = 0x9b,
|
||||
OP_NUMEQUAL = 0x9c,
|
||||
OP_NUMEQUALVERIFY = 0x9d,
|
||||
OP_NUMNOTEQUAL = 0x9e,
|
||||
OP_LESSTHAN = 0x9f,
|
||||
OP_GREATERTHAN = 0xa0,
|
||||
OP_LESSTHANOREQUAL = 0xa1,
|
||||
OP_GREATERTHANOREQUAL = 0xa2,
|
||||
OP_MIN = 0xa3,
|
||||
OP_MAX = 0xa4,
|
||||
|
||||
OP_WITHIN = 0xa5,
|
||||
|
||||
// crypto
|
||||
OP_RIPEMD160 = 0xa6,
|
||||
OP_SHA1 = 0xa7,
|
||||
OP_SHA256 = 0xa8,
|
||||
OP_HASH160 = 0xa9,
|
||||
OP_HASH256 = 0xaa,
|
||||
OP_CODESEPARATOR = 0xab,
|
||||
OP_CHECKSIG = 0xac,
|
||||
OP_CHECKSIGVERIFY = 0xad,
|
||||
OP_CHECKMULTISIG = 0xae,
|
||||
OP_CHECKMULTISIGVERIFY = 0xaf,
|
||||
|
||||
// expansion
|
||||
OP_NOP1 = 0xb0,
|
||||
OP_NOP2 = 0xb1,
|
||||
OP_CHECKLOCKTIMEVERIFY = OP_NOP2,
|
||||
OP_NOP3 = 0xb2,
|
||||
OP_NOP4 = 0xb3,
|
||||
OP_NOP5 = 0xb4,
|
||||
OP_NOP6 = 0xb5,
|
||||
OP_NOP7 = 0xb6,
|
||||
OP_NOP8 = 0xb7,
|
||||
OP_NOP9 = 0xb8,
|
||||
OP_NOP10 = 0xb9,
|
||||
|
||||
// zerocoin
|
||||
OP_ZEROCOINMINT = 0xc1,
|
||||
OP_ZEROCOINSPEND = 0xc2,
|
||||
OP_ZEROCOINPUBLICSPEND = 0xc3,
|
||||
|
||||
// template matching params
|
||||
OP_SMALLINTEGER = 0xfa,
|
||||
OP_PUBKEYS = 0xfb,
|
||||
OP_PUBKEYHASH = 0xfd,
|
||||
OP_PUBKEY = 0xfe,
|
||||
|
||||
OP_INVALIDOPCODE = 0xff,
|
||||
};
|
||||
|
||||
const char* GetOpName(opcodetype opcode);
|
||||
|
||||
class scriptnum_error : public std::runtime_error
|
||||
{
|
||||
public:
|
||||
explicit scriptnum_error(const std::string& str) : std::runtime_error(str) {}
|
||||
};
|
||||
|
||||
class CScriptNum
|
||||
{
|
||||
/**
|
||||
* Numeric opcodes (OP_1ADD, etc) are restricted to operating on 4-byte integers.
|
||||
* The semantics are subtle, though: operands must be in the range [-2^31 +1...2^31 -1],
|
||||
* but results may overflow (and are valid as long as they are not used in a subsequent
|
||||
* numeric operation). CScriptNum enforces those semantics by storing results as
|
||||
* an int64 and allowing out-of-range values to be returned as a vector of bytes but
|
||||
* throwing an exception if arithmetic is done or the result is interpreted as an integer.
|
||||
*/
|
||||
public:
|
||||
|
||||
explicit CScriptNum(const int64_t& n)
|
||||
{
|
||||
m_value = n;
|
||||
}
|
||||
|
||||
static const size_t nDefaultMaxNumSize = 4;
|
||||
|
||||
explicit CScriptNum(const std::vector<unsigned char>& vch, bool fRequireMinimal,
|
||||
const size_t nMaxNumSize = nDefaultMaxNumSize)
|
||||
{
|
||||
if (vch.size() > nMaxNumSize) {
|
||||
throw scriptnum_error("script number overflow");
|
||||
}
|
||||
if (fRequireMinimal && vch.size() > 0) {
|
||||
// Check that the number is encoded with the minimum possible
|
||||
// number of bytes.
|
||||
//
|
||||
// If the most-significant-byte - excluding the sign bit - is zero
|
||||
// then we're not minimal. Note how this test also rejects the
|
||||
// negative-zero encoding, 0x80.
|
||||
if ((vch.back() & 0x7f) == 0) {
|
||||
// One exception: if there's more than one byte and the most
|
||||
// significant bit of the second-most-significant-byte is set
|
||||
// it would conflict with the sign bit. An example of this case
|
||||
// is +-255, which encode to 0xff00 and 0xff80 respectively.
|
||||
// (big-endian).
|
||||
if (vch.size() <= 1 || (vch[vch.size() - 2] & 0x80) == 0) {
|
||||
throw scriptnum_error("non-minimally encoded script number");
|
||||
}
|
||||
}
|
||||
}
|
||||
m_value = set_vch(vch);
|
||||
}
|
||||
|
||||
inline bool operator==(const int64_t& rhs) const { return m_value == rhs; }
|
||||
inline bool operator!=(const int64_t& rhs) const { return m_value != rhs; }
|
||||
inline bool operator<=(const int64_t& rhs) const { return m_value <= rhs; }
|
||||
inline bool operator< (const int64_t& rhs) const { return m_value < rhs; }
|
||||
inline bool operator>=(const int64_t& rhs) const { return m_value >= rhs; }
|
||||
inline bool operator> (const int64_t& rhs) const { return m_value > rhs; }
|
||||
|
||||
inline bool operator==(const CScriptNum& rhs) const { return operator==(rhs.m_value); }
|
||||
inline bool operator!=(const CScriptNum& rhs) const { return operator!=(rhs.m_value); }
|
||||
inline bool operator<=(const CScriptNum& rhs) const { return operator<=(rhs.m_value); }
|
||||
inline bool operator< (const CScriptNum& rhs) const { return operator< (rhs.m_value); }
|
||||
inline bool operator>=(const CScriptNum& rhs) const { return operator>=(rhs.m_value); }
|
||||
inline bool operator> (const CScriptNum& rhs) const { return operator> (rhs.m_value); }
|
||||
|
||||
inline CScriptNum operator+( const int64_t& rhs) const { return CScriptNum(m_value + rhs);}
|
||||
inline CScriptNum operator-( const int64_t& rhs) const { return CScriptNum(m_value - rhs);}
|
||||
inline CScriptNum operator+( const CScriptNum& rhs) const { return operator+(rhs.m_value); }
|
||||
inline CScriptNum operator-( const CScriptNum& rhs) const { return operator-(rhs.m_value); }
|
||||
|
||||
inline CScriptNum& operator+=( const CScriptNum& rhs) { return operator+=(rhs.m_value); }
|
||||
inline CScriptNum& operator-=( const CScriptNum& rhs) { return operator-=(rhs.m_value); }
|
||||
|
||||
inline CScriptNum operator-() const
|
||||
{
|
||||
assert(m_value != std::numeric_limits<int64_t>::min());
|
||||
return CScriptNum(-m_value);
|
||||
}
|
||||
|
||||
inline CScriptNum& operator=( const int64_t& rhs)
|
||||
{
|
||||
m_value = rhs;
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline CScriptNum& operator+=( const int64_t& rhs)
|
||||
{
|
||||
assert(rhs == 0 || (rhs > 0 && m_value <= std::numeric_limits<int64_t>::max() - rhs) ||
|
||||
(rhs < 0 && m_value >= std::numeric_limits<int64_t>::min() - rhs));
|
||||
m_value += rhs;
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline CScriptNum& operator-=( const int64_t& rhs)
|
||||
{
|
||||
assert(rhs == 0 || (rhs > 0 && m_value >= std::numeric_limits<int64_t>::min() + rhs) ||
|
||||
(rhs < 0 && m_value <= std::numeric_limits<int64_t>::max() + rhs));
|
||||
m_value -= rhs;
|
||||
return *this;
|
||||
}
|
||||
|
||||
int getint() const
|
||||
{
|
||||
if (m_value > std::numeric_limits<int>::max())
|
||||
return std::numeric_limits<int>::max();
|
||||
else if (m_value < std::numeric_limits<int>::min())
|
||||
return std::numeric_limits<int>::min();
|
||||
return m_value;
|
||||
}
|
||||
|
||||
std::vector<unsigned char> getvch() const
|
||||
{
|
||||
return serialize(m_value);
|
||||
}
|
||||
|
||||
static std::vector<unsigned char> serialize(const int64_t& value)
|
||||
{
|
||||
if(value == 0)
|
||||
return std::vector<unsigned char>();
|
||||
|
||||
std::vector<unsigned char> result;
|
||||
const bool neg = value < 0;
|
||||
uint64_t absvalue = neg ? -value : value;
|
||||
|
||||
while(absvalue)
|
||||
{
|
||||
result.push_back(absvalue & 0xff);
|
||||
absvalue >>= 8;
|
||||
}
|
||||
|
||||
// - If the most significant byte is >= 0x80 and the value is positive, push a
|
||||
// new zero-byte to make the significant byte < 0x80 again.
|
||||
|
||||
// - If the most significant byte is >= 0x80 and the value is negative, push a
|
||||
// new 0x80 byte that will be popped off when converting to an integral.
|
||||
|
||||
// - If the most significant byte is < 0x80 and the value is negative, add
|
||||
// 0x80 to it, since it will be subtracted and interpreted as a negative when
|
||||
// converting to an integral.
|
||||
|
||||
if (result.back() & 0x80)
|
||||
result.push_back(neg ? 0x80 : 0);
|
||||
else if (neg)
|
||||
result.back() |= 0x80;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private:
|
||||
static int64_t set_vch(const std::vector<unsigned char>& vch)
|
||||
{
|
||||
if (vch.empty())
|
||||
return 0;
|
||||
|
||||
int64_t result = 0;
|
||||
for (size_t i = 0; i != vch.size(); ++i)
|
||||
result |= static_cast<int64_t>(vch[i]) << 8*i;
|
||||
|
||||
// If the input vector's most significant byte is 0x80, remove it from
|
||||
// the result's msb and return a negative.
|
||||
if (vch.back() & 0x80)
|
||||
return -((int64_t)(result & ~(0x80ULL << (8 * (vch.size() - 1)))));
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
int64_t m_value;
|
||||
};
|
||||
|
||||
/** Serialized script, used inside transaction inputs and outputs */
|
||||
class CScript : public std::vector<unsigned char>
|
||||
{
|
||||
protected:
|
||||
CScript& push_int64(int64_t n)
|
||||
{
|
||||
if (n == -1 || (n >= 1 && n <= 16))
|
||||
{
|
||||
push_back(n + (OP_1 - 1));
|
||||
}
|
||||
else if (n == 0)
|
||||
{
|
||||
push_back(OP_0);
|
||||
}
|
||||
else
|
||||
{
|
||||
*this << CScriptNum::serialize(n);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
public:
|
||||
CScript() { }
|
||||
CScript(const CScript& b) : std::vector<unsigned char>(b.begin(), b.end()) { }
|
||||
CScript(const_iterator pbegin, const_iterator pend) : std::vector<unsigned char>(pbegin, pend) { }
|
||||
CScript(const unsigned char* pbegin, const unsigned char* pend) : std::vector<unsigned char>(pbegin, pend) { }
|
||||
|
||||
CScript& operator+=(const CScript& b)
|
||||
{
|
||||
insert(end(), b.begin(), b.end());
|
||||
return *this;
|
||||
}
|
||||
|
||||
friend CScript operator+(const CScript& a, const CScript& b)
|
||||
{
|
||||
CScript ret = a;
|
||||
ret += b;
|
||||
return ret;
|
||||
}
|
||||
|
||||
CScript(int64_t b) { operator<<(b); }
|
||||
|
||||
explicit CScript(opcodetype b) { operator<<(b); }
|
||||
explicit CScript(const CScriptNum& b) { operator<<(b); }
|
||||
explicit CScript(const std::vector<unsigned char>& b) { operator<<(b); }
|
||||
|
||||
|
||||
CScript& operator<<(int64_t b) { return push_int64(b); }
|
||||
|
||||
CScript& operator<<(opcodetype opcode)
|
||||
{
|
||||
if (opcode < 0 || opcode > 0xff)
|
||||
throw std::runtime_error("CScript::operator<<() : invalid opcode");
|
||||
insert(end(), (unsigned char)opcode);
|
||||
return *this;
|
||||
}
|
||||
|
||||
CScript& operator<<(const CScriptNum& b)
|
||||
{
|
||||
*this << b.getvch();
|
||||
return *this;
|
||||
}
|
||||
|
||||
CScript& operator<<(const std::vector<unsigned char>& b)
|
||||
{
|
||||
if (b.size() < OP_PUSHDATA1)
|
||||
{
|
||||
insert(end(), (unsigned char)b.size());
|
||||
}
|
||||
else if (b.size() <= 0xff)
|
||||
{
|
||||
insert(end(), OP_PUSHDATA1);
|
||||
insert(end(), (unsigned char)b.size());
|
||||
}
|
||||
else if (b.size() <= 0xffff)
|
||||
{
|
||||
insert(end(), OP_PUSHDATA2);
|
||||
unsigned short nSize = b.size();
|
||||
insert(end(), (unsigned char*)&nSize, (unsigned char*)&nSize + sizeof(nSize));
|
||||
}
|
||||
else
|
||||
{
|
||||
insert(end(), OP_PUSHDATA4);
|
||||
unsigned int nSize = b.size();
|
||||
insert(end(), (unsigned char*)&nSize, (unsigned char*)&nSize + sizeof(nSize));
|
||||
}
|
||||
insert(end(), b.begin(), b.end());
|
||||
return *this;
|
||||
}
|
||||
|
||||
CScript& operator<<(const CScript& b)
|
||||
{
|
||||
// I'm not sure if this should push the script or concatenate scripts.
|
||||
// If there's ever a use for pushing a script onto a script, delete this member fn
|
||||
assert(!"Warning: Pushing a CScript onto a CScript with << is probably not intended, use + to concatenate!");
|
||||
return *this;
|
||||
}
|
||||
|
||||
CScript& operator<<(const CPubKey& key)
|
||||
{
|
||||
std::vector<unsigned char> vchKey = key.Raw();
|
||||
return (*this) << vchKey;
|
||||
}
|
||||
|
||||
|
||||
bool GetOp(iterator& pc, opcodetype& opcodeRet, std::vector<unsigned char>& vchRet)
|
||||
{
|
||||
// Wrapper so it can be called with either iterator or const_iterator
|
||||
const_iterator pc2 = pc;
|
||||
bool fRet = GetOp2(pc2, opcodeRet, &vchRet);
|
||||
pc = begin() + (pc2 - begin());
|
||||
return fRet;
|
||||
}
|
||||
|
||||
bool GetOp(iterator& pc, opcodetype& opcodeRet)
|
||||
{
|
||||
const_iterator pc2 = pc;
|
||||
bool fRet = GetOp2(pc2, opcodeRet, NULL);
|
||||
pc = begin() + (pc2 - begin());
|
||||
return fRet;
|
||||
}
|
||||
|
||||
bool GetOp(const_iterator& pc, opcodetype& opcodeRet, std::vector<unsigned char>& vchRet) const
|
||||
{
|
||||
return GetOp2(pc, opcodeRet, &vchRet);
|
||||
}
|
||||
|
||||
bool GetOp(const_iterator& pc, opcodetype& opcodeRet) const
|
||||
{
|
||||
return GetOp2(pc, opcodeRet, NULL);
|
||||
}
|
||||
|
||||
bool GetOp2(const_iterator& pc, opcodetype& opcodeRet, std::vector<unsigned char>* pvchRet) const
|
||||
{
|
||||
opcodeRet = OP_INVALIDOPCODE;
|
||||
if (pvchRet)
|
||||
pvchRet->clear();
|
||||
if (pc >= end())
|
||||
return false;
|
||||
|
||||
// Read instruction
|
||||
if (end() - pc < 1)
|
||||
return false;
|
||||
unsigned int opcode = *pc++;
|
||||
|
||||
// Immediate operand
|
||||
if (opcode <= OP_PUSHDATA4)
|
||||
{
|
||||
unsigned int nSize = 0;
|
||||
if (opcode < OP_PUSHDATA1)
|
||||
{
|
||||
nSize = opcode;
|
||||
}
|
||||
else if (opcode == OP_PUSHDATA1)
|
||||
{
|
||||
if (end() - pc < 1)
|
||||
return false;
|
||||
nSize = *pc++;
|
||||
}
|
||||
else if (opcode == OP_PUSHDATA2)
|
||||
{
|
||||
if (end() - pc < 2)
|
||||
return false;
|
||||
nSize = 0;
|
||||
memcpy(&nSize, &pc[0], 2);
|
||||
pc += 2;
|
||||
}
|
||||
else if (opcode == OP_PUSHDATA4)
|
||||
{
|
||||
if (end() - pc < 4)
|
||||
return false;
|
||||
memcpy(&nSize, &pc[0], 4);
|
||||
pc += 4;
|
||||
}
|
||||
if (end() - pc < 0 || (unsigned int)(end() - pc) < nSize)
|
||||
return false;
|
||||
if (pvchRet)
|
||||
pvchRet->assign(pc, pc + nSize);
|
||||
pc += nSize;
|
||||
}
|
||||
|
||||
opcodeRet = (opcodetype)opcode;
|
||||
return true;
|
||||
}
|
||||
|
||||
/** Encode/decode small integers: */
|
||||
static int DecodeOP_N(opcodetype opcode)
|
||||
{
|
||||
if (opcode == OP_0)
|
||||
return 0;
|
||||
assert(opcode >= OP_1 && opcode <= OP_16);
|
||||
return (int)opcode - (int)(OP_1 - 1);
|
||||
}
|
||||
static opcodetype EncodeOP_N(int n)
|
||||
{
|
||||
assert(n >= 0 && n <= 16);
|
||||
if (n == 0)
|
||||
return OP_0;
|
||||
return (opcodetype)(OP_1+n-1);
|
||||
}
|
||||
|
||||
int FindAndDelete(const CScript& b)
|
||||
{
|
||||
int nFound = 0;
|
||||
if (b.empty())
|
||||
return nFound;
|
||||
iterator pc = begin();
|
||||
opcodetype opcode;
|
||||
do
|
||||
{
|
||||
while (end() - pc >= (long)b.size() && memcmp(&pc[0], &b[0], b.size()) == 0)
|
||||
{
|
||||
pc = erase(pc, pc + b.size());
|
||||
++nFound;
|
||||
}
|
||||
}
|
||||
while (GetOp(pc, opcode));
|
||||
return nFound;
|
||||
}
|
||||
int Find(opcodetype op) const
|
||||
{
|
||||
int nFound = 0;
|
||||
opcodetype opcode;
|
||||
for (const_iterator pc = begin(); pc != end() && GetOp(pc, opcode);)
|
||||
if (opcode == op)
|
||||
++nFound;
|
||||
return nFound;
|
||||
}
|
||||
|
||||
/**
|
||||
* Pre-version-0.6, Bitcoin always counted CHECKMULTISIGs
|
||||
* as 20 sigops. With pay-to-script-hash, that changed:
|
||||
* CHECKMULTISIGs serialized in scriptSigs are
|
||||
* counted more accurately, assuming they are of the form
|
||||
* ... OP_N CHECKMULTISIG ...
|
||||
*/
|
||||
unsigned int GetSigOpCount(bool fAccurate) const;
|
||||
|
||||
/**
|
||||
* Accurately count sigOps, including sigOps in
|
||||
* pay-to-script-hash transactions:
|
||||
*/
|
||||
unsigned int GetSigOpCount(const CScript& scriptSig) const;
|
||||
|
||||
bool IsNormalPaymentScript() const;
|
||||
bool IsPayToScriptHash() const;
|
||||
bool StartsWithOpcode(const opcodetype opcode) const;
|
||||
bool IsZerocoinMint() const;
|
||||
bool IsZerocoinSpend() const;
|
||||
bool IsZerocoinPublicSpend() const;
|
||||
|
||||
/** Called by IsStandardTx and P2SH/BIP62 VerifyScript (which makes it consensus-critical). */
|
||||
bool IsPushOnly(const_iterator pc) const;
|
||||
bool IsPushOnly() const;
|
||||
|
||||
/**
|
||||
* Returns whether the script is guaranteed to fail at execution,
|
||||
* regardless of the initial stack. This allows outputs to be pruned
|
||||
* instantly when entering the UTXO set.
|
||||
*/
|
||||
bool IsUnspendable() const
|
||||
{
|
||||
return (size() > 0 && *begin() == OP_RETURN);
|
||||
}
|
||||
|
||||
std::string ToString() const;
|
||||
void clear()
|
||||
{
|
||||
// The default std::vector::clear() does not release memory.
|
||||
std::vector<unsigned char>().swap(*this);
|
||||
}
|
||||
};
|
||||
|
||||
#endif // BITCOIN_SCRIPT_SCRIPT_H
|
||||
@@ -0,0 +1,75 @@
|
||||
// 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_NEGATIVE_LOCKTIME:
|
||||
return "Negative locktime";
|
||||
case SCRIPT_ERR_UNSATISFIED_LOCKTIME:
|
||||
return "Locktime requirement not satisfied";
|
||||
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_DISCOURAGE_UPGRADABLE_NOPS:
|
||||
return "NOPx reserved for soft-fork upgrades";
|
||||
case SCRIPT_ERR_PUBKEYTYPE:
|
||||
return "Public key is neither compressed or uncompressed";
|
||||
case SCRIPT_ERR_UNKNOWN_ERROR:
|
||||
case SCRIPT_ERR_ERROR_COUNT:
|
||||
default: break;
|
||||
}
|
||||
return "unknown error";
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
// 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_SCRIPT_ERROR_H
|
||||
#define BITCOIN_SCRIPT_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,
|
||||
|
||||
/* OP_CHECKLOCKTIMEVERIFY */
|
||||
SCRIPT_ERR_NEGATIVE_LOCKTIME,
|
||||
SCRIPT_ERR_UNSATISFIED_LOCKTIME,
|
||||
|
||||
/* 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_PUBKEYTYPE,
|
||||
|
||||
/* softfork safeness */
|
||||
SCRIPT_ERR_DISCOURAGE_UPGRADABLE_NOPS,
|
||||
|
||||
SCRIPT_ERR_ERROR_COUNT
|
||||
} ScriptError;
|
||||
|
||||
#define SCRIPT_ERR_LAST SCRIPT_ERR_ERROR_COUNT
|
||||
|
||||
const char* ScriptErrorString(const ScriptError error);
|
||||
|
||||
#endif // BITCOIN_SCRIPT_SCRIPT_ERROR_H
|
||||
@@ -0,0 +1,88 @@
|
||||
// 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 "sigcache.h"
|
||||
|
||||
#include "pubkey.h"
|
||||
#include "random.h"
|
||||
#include "uint256.h"
|
||||
#include "util.h"
|
||||
|
||||
#include <boost/thread.hpp>
|
||||
#include <boost/tuple/tuple_comparison.hpp>
|
||||
|
||||
namespace {
|
||||
|
||||
/**
|
||||
* Valid signature cache, to avoid doing expensive ECDSA signature checking
|
||||
* twice for every transaction (once when accepted into memory pool, and
|
||||
* again when accepted into the block chain)
|
||||
*/
|
||||
class CSignatureCache
|
||||
{
|
||||
private:
|
||||
//! sigdata_type is (signature hash, signature, public key):
|
||||
typedef boost::tuple<uint256, std::vector<unsigned char>, CPubKey> sigdata_type;
|
||||
std::set< sigdata_type> setValid;
|
||||
boost::shared_mutex cs_sigcache;
|
||||
|
||||
public:
|
||||
bool
|
||||
Get(const uint256 &hash, const std::vector<unsigned char>& vchSig, const CPubKey& pubKey)
|
||||
{
|
||||
boost::shared_lock<boost::shared_mutex> lock(cs_sigcache);
|
||||
|
||||
sigdata_type k(hash, vchSig, pubKey);
|
||||
std::set<sigdata_type>::iterator mi = setValid.find(k);
|
||||
if (mi != setValid.end())
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
void Set(const uint256 &hash, const std::vector<unsigned char>& vchSig, const CPubKey& pubKey)
|
||||
{
|
||||
// DoS prevention: limit cache size to less than 10MB
|
||||
// (~200 bytes per cache entry times 50,000 entries)
|
||||
// Since there are a maximum of 20,000 signature operations per block
|
||||
// 50,000 is a reasonable default.
|
||||
int64_t nMaxCacheSize = GetArg("-maxsigcachesize", 50000);
|
||||
if (nMaxCacheSize <= 0) return;
|
||||
|
||||
boost::unique_lock<boost::shared_mutex> lock(cs_sigcache);
|
||||
|
||||
while (static_cast<int64_t>(setValid.size()) > nMaxCacheSize)
|
||||
{
|
||||
// Evict a random entry. Random because that helps
|
||||
// foil would-be DoS attackers who might try to pre-generate
|
||||
// and re-use a set of valid signatures just-slightly-greater
|
||||
// than our cache size.
|
||||
uint256 randomHash = GetRandHash();
|
||||
std::set<sigdata_type>::iterator it = setValid.lower_bound(sigdata_type(randomHash));
|
||||
if (it == setValid.end())
|
||||
it = setValid.begin();
|
||||
setValid.erase(*it);
|
||||
}
|
||||
|
||||
sigdata_type k(hash, vchSig, pubKey);
|
||||
setValid.insert(k);
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
bool CachingTransactionSignatureChecker::VerifySignature(const std::vector<unsigned char>& vchSig, const CPubKey& pubkey, const uint256& sighash) const
|
||||
{
|
||||
static CSignatureCache signatureCache;
|
||||
|
||||
if (signatureCache.Get(sighash, vchSig, pubkey))
|
||||
return true;
|
||||
|
||||
if (!TransactionSignatureChecker::VerifySignature(vchSig, pubkey, sighash))
|
||||
return false;
|
||||
|
||||
if (store)
|
||||
signatureCache.Set(sighash, vchSig, pubkey);
|
||||
return true;
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
// 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_SIGCACHE_H
|
||||
#define BITCOIN_SCRIPT_SIGCACHE_H
|
||||
|
||||
#include "script/interpreter.h"
|
||||
|
||||
#include <vector>
|
||||
|
||||
class CPubKey;
|
||||
|
||||
class CachingTransactionSignatureChecker : public TransactionSignatureChecker
|
||||
{
|
||||
private:
|
||||
bool store;
|
||||
|
||||
public:
|
||||
CachingTransactionSignatureChecker(const CTransaction* txToIn, unsigned int nInIn, bool storeIn=true) : TransactionSignatureChecker(txToIn, nInIn), store(storeIn) {}
|
||||
|
||||
bool VerifySignature(const std::vector<unsigned char>& vchSig, const CPubKey& vchPubKey, const uint256& sighash) const;
|
||||
};
|
||||
|
||||
#endif // BITCOIN_SCRIPT_SIGCACHE_H
|
||||
@@ -0,0 +1,279 @@
|
||||
// Copyright (c) 2009-2010 Satoshi Nakamoto
|
||||
// Copyright (c) 2009-2014 The Bitcoin developers
|
||||
// Copyright (c) 2016-2019 The PIVX developers
|
||||
// Distributed under the MIT software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#include "script/sign.h"
|
||||
|
||||
#include "primitives/transaction.h"
|
||||
#include "key.h"
|
||||
#include "keystore.h"
|
||||
#include "script/standard.h"
|
||||
#include "uint256.h"
|
||||
#include "util.h"
|
||||
|
||||
|
||||
using namespace std;
|
||||
|
||||
typedef vector<unsigned char> valtype;
|
||||
|
||||
bool Sign1(const CKeyID& address, const CKeyStore& keystore, uint256 hash, int nHashType, CScript& scriptSigRet)
|
||||
{
|
||||
CKey key;
|
||||
if (!keystore.GetKey(address, key))
|
||||
return false;
|
||||
|
||||
vector<unsigned char> vchSig;
|
||||
if (!key.Sign(hash, vchSig))
|
||||
return false;
|
||||
vchSig.push_back((unsigned char)nHashType);
|
||||
scriptSigRet << vchSig;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SignN(const vector<valtype>& multisigdata, const CKeyStore& keystore, uint256 hash, int nHashType, CScript& scriptSigRet)
|
||||
{
|
||||
int nSigned = 0;
|
||||
int nRequired = multisigdata.front()[0];
|
||||
for (unsigned int i = 1; i < multisigdata.size()-1 && nSigned < nRequired; i++)
|
||||
{
|
||||
const valtype& pubkey = multisigdata[i];
|
||||
CKeyID keyID = CPubKey(pubkey).GetID();
|
||||
if (Sign1(keyID, keystore, hash, nHashType, scriptSigRet))
|
||||
++nSigned;
|
||||
}
|
||||
return nSigned==nRequired;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sign scriptPubKey with private keys stored in keystore, given transaction hash and hash type.
|
||||
* Signatures are returned in scriptSigRet (or returns false if scriptPubKey can't be signed),
|
||||
* unless whichTypeRet is TX_SCRIPTHASH, in which case scriptSigRet is the redemption script.
|
||||
* Returns false if scriptPubKey could not be completely satisfied.
|
||||
*/
|
||||
bool Solver(const CKeyStore& keystore, const CScript& scriptPubKey, uint256 hash, int nHashType,
|
||||
CScript& scriptSigRet, txnouttype& whichTypeRet)
|
||||
{
|
||||
scriptSigRet.clear();
|
||||
|
||||
vector<valtype> vSolutions;
|
||||
if (!Solver(scriptPubKey, whichTypeRet, vSolutions))
|
||||
{
|
||||
LogPrintf("*** solver solver failed \n");
|
||||
return false;
|
||||
}
|
||||
|
||||
CKeyID keyID;
|
||||
switch (whichTypeRet)
|
||||
{
|
||||
case TX_NONSTANDARD:
|
||||
case TX_NULL_DATA:
|
||||
{
|
||||
LogPrintf("*** null data \n");
|
||||
return false;
|
||||
}
|
||||
case TX_ZEROCOINMINT:
|
||||
return false;
|
||||
case TX_PUBKEY:
|
||||
keyID = CPubKey(vSolutions[0]).GetID();
|
||||
if(!Sign1(keyID, keystore, hash, nHashType, scriptSigRet))
|
||||
{
|
||||
LogPrintf("*** Sign1 failed \n");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
case TX_PUBKEYHASH:
|
||||
keyID = CKeyID(uint160(vSolutions[0]));
|
||||
if (!Sign1(keyID, keystore, hash, nHashType, scriptSigRet))
|
||||
{
|
||||
LogPrintf("*** solver failed to sign \n");
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
CPubKey vch;
|
||||
keystore.GetPubKey(keyID, vch);
|
||||
scriptSigRet << ToByteVector(vch);
|
||||
}
|
||||
return true;
|
||||
case TX_SCRIPTHASH:
|
||||
return keystore.GetCScript(uint160(vSolutions[0]), scriptSigRet);
|
||||
|
||||
case TX_MULTISIG:
|
||||
scriptSigRet << OP_0; // workaround CHECKMULTISIG bug
|
||||
return (SignN(vSolutions, keystore, hash, nHashType, scriptSigRet));
|
||||
}
|
||||
LogPrintf("*** solver no case met \n");
|
||||
return false;
|
||||
}
|
||||
|
||||
bool SignSignature(const CKeyStore &keystore, const CScript& fromPubKey, CMutableTransaction& txTo, unsigned int nIn, int nHashType)
|
||||
{
|
||||
assert(nIn < txTo.vin.size());
|
||||
CTxIn& txin = txTo.vin[nIn];
|
||||
|
||||
// Leave out the signature from the hash, since a signature can't sign itself.
|
||||
// The checksig op will also drop the signatures from its hash.
|
||||
uint256 hash = SignatureHash(fromPubKey, txTo, nIn, nHashType);
|
||||
|
||||
txnouttype whichType;
|
||||
if (!Solver(keystore, fromPubKey, hash, nHashType, txin.scriptSig, whichType))
|
||||
return false;
|
||||
|
||||
if (whichType == TX_SCRIPTHASH)
|
||||
{
|
||||
// Solver returns the subscript that need to be evaluated;
|
||||
// the final scriptSig is the signatures from that
|
||||
// and then the serialized subscript:
|
||||
CScript subscript = txin.scriptSig;
|
||||
|
||||
// Recompute txn hash using subscript in place of scriptPubKey:
|
||||
uint256 hash2 = SignatureHash(subscript, txTo, nIn, nHashType);
|
||||
|
||||
txnouttype subType;
|
||||
bool fSolved =
|
||||
Solver(keystore, subscript, hash2, nHashType, txin.scriptSig, subType) && subType != TX_SCRIPTHASH;
|
||||
// Append serialized subscript whether or not it is completely signed:
|
||||
txin.scriptSig << static_cast<valtype>(subscript);
|
||||
if (!fSolved) return false;
|
||||
}
|
||||
|
||||
// Test solution
|
||||
return VerifyScript(txin.scriptSig, fromPubKey, STANDARD_SCRIPT_VERIFY_FLAGS, MutableTransactionSignatureChecker(&txTo, nIn));
|
||||
}
|
||||
|
||||
bool SignSignature(const CKeyStore &keystore, const CTransaction& txFrom, CMutableTransaction& txTo, unsigned int nIn, int nHashType)
|
||||
{
|
||||
assert(nIn < txTo.vin.size());
|
||||
CTxIn& txin = txTo.vin[nIn];
|
||||
assert(txin.prevout.n < txFrom.vout.size());
|
||||
const CTxOut& txout = txFrom.vout[txin.prevout.n];
|
||||
|
||||
return SignSignature(keystore, txout.scriptPubKey, txTo, nIn, nHashType);
|
||||
}
|
||||
|
||||
static CScript PushAll(const vector<valtype>& values)
|
||||
{
|
||||
CScript result;
|
||||
for (const valtype& v : values)
|
||||
result << v;
|
||||
return result;
|
||||
}
|
||||
|
||||
static CScript CombineMultisig(const CScript& scriptPubKey, const CTransaction& txTo, unsigned int nIn,
|
||||
const vector<valtype>& vSolutions,
|
||||
const vector<valtype>& sigs1, const vector<valtype>& sigs2)
|
||||
{
|
||||
// Combine all the signatures we've got:
|
||||
set<valtype> allsigs;
|
||||
for (const valtype& v : sigs1)
|
||||
{
|
||||
if (!v.empty())
|
||||
allsigs.insert(v);
|
||||
}
|
||||
for (const valtype& v : sigs2)
|
||||
{
|
||||
if (!v.empty())
|
||||
allsigs.insert(v);
|
||||
}
|
||||
|
||||
// Build a map of pubkey -> signature by matching sigs to pubkeys:
|
||||
assert(vSolutions.size() > 1);
|
||||
unsigned int nSigsRequired = vSolutions.front()[0];
|
||||
unsigned int nPubKeys = vSolutions.size()-2;
|
||||
map<valtype, valtype> sigs;
|
||||
for (const valtype& sig : allsigs)
|
||||
{
|
||||
for (unsigned int i = 0; i < nPubKeys; i++)
|
||||
{
|
||||
const valtype& pubkey = vSolutions[i+1];
|
||||
if (sigs.count(pubkey))
|
||||
continue; // Already got a sig for this pubkey
|
||||
|
||||
if (TransactionSignatureChecker(&txTo, nIn).CheckSig(sig, pubkey, scriptPubKey))
|
||||
{
|
||||
sigs[pubkey] = sig;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Now build a merged CScript:
|
||||
unsigned int nSigsHave = 0;
|
||||
CScript result; result << OP_0; // pop-one-too-many workaround
|
||||
for (unsigned int i = 0; i < nPubKeys && nSigsHave < nSigsRequired; i++)
|
||||
{
|
||||
if (sigs.count(vSolutions[i+1]))
|
||||
{
|
||||
result << sigs[vSolutions[i+1]];
|
||||
++nSigsHave;
|
||||
}
|
||||
}
|
||||
// Fill any missing with OP_0:
|
||||
for (unsigned int i = nSigsHave; i < nSigsRequired; i++)
|
||||
result << OP_0;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static CScript CombineSignatures(const CScript& scriptPubKey, const CTransaction& txTo, unsigned int nIn,
|
||||
const txnouttype txType, const vector<valtype>& vSolutions,
|
||||
vector<valtype>& sigs1, vector<valtype>& sigs2)
|
||||
{
|
||||
switch (txType)
|
||||
{
|
||||
case TX_NONSTANDARD:
|
||||
case TX_NULL_DATA:
|
||||
case TX_ZEROCOINMINT:
|
||||
// Don't know anything about this, assume bigger one is correct:
|
||||
if (sigs1.size() >= sigs2.size())
|
||||
return PushAll(sigs1);
|
||||
return PushAll(sigs2);
|
||||
case TX_PUBKEY:
|
||||
case TX_PUBKEYHASH:
|
||||
// Signatures are bigger than placeholders or empty scripts:
|
||||
if (sigs1.empty() || sigs1[0].empty())
|
||||
return PushAll(sigs2);
|
||||
return PushAll(sigs1);
|
||||
case TX_SCRIPTHASH:
|
||||
if (sigs1.empty() || sigs1.back().empty())
|
||||
return PushAll(sigs2);
|
||||
else if (sigs2.empty() || sigs2.back().empty())
|
||||
return PushAll(sigs1);
|
||||
else
|
||||
{
|
||||
// Recur to combine:
|
||||
valtype spk = sigs1.back();
|
||||
CScript pubKey2(spk.begin(), spk.end());
|
||||
|
||||
txnouttype txType2;
|
||||
vector<vector<unsigned char> > vSolutions2;
|
||||
Solver(pubKey2, txType2, vSolutions2);
|
||||
sigs1.pop_back();
|
||||
sigs2.pop_back();
|
||||
CScript result = CombineSignatures(pubKey2, txTo, nIn, txType2, vSolutions2, sigs1, sigs2);
|
||||
result << spk;
|
||||
return result;
|
||||
}
|
||||
case TX_MULTISIG:
|
||||
return CombineMultisig(scriptPubKey, txTo, nIn, vSolutions, sigs1, sigs2);
|
||||
}
|
||||
|
||||
return CScript();
|
||||
}
|
||||
|
||||
CScript CombineSignatures(const CScript& scriptPubKey, const CTransaction& txTo, unsigned int nIn,
|
||||
const CScript& scriptSig1, const CScript& scriptSig2)
|
||||
{
|
||||
txnouttype txType;
|
||||
vector<vector<unsigned char> > vSolutions;
|
||||
Solver(scriptPubKey, txType, vSolutions);
|
||||
|
||||
vector<valtype> stack1;
|
||||
EvalScript(stack1, scriptSig1, SCRIPT_VERIFY_STRICTENC, BaseSignatureChecker());
|
||||
vector<valtype> stack2;
|
||||
EvalScript(stack2, scriptSig2, SCRIPT_VERIFY_STRICTENC, BaseSignatureChecker());
|
||||
|
||||
return CombineSignatures(scriptPubKey, txTo, nIn, txType, vSolutions, stack1, stack2);
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
// Copyright (c) 2009-2010 Satoshi Nakamoto
|
||||
// Copyright (c) 2009-2014 The Bitcoin developers
|
||||
// Copyright (c) 2016-2018 The PIVX developers
|
||||
// Distributed under the MIT software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#ifndef BITCOIN_SCRIPT_SIGN_H
|
||||
#define BITCOIN_SCRIPT_SIGN_H
|
||||
|
||||
#include "script/interpreter.h"
|
||||
#include "key.h"
|
||||
#include "keystore.h"
|
||||
#include "script/standard.h"
|
||||
|
||||
class CKeyStore;
|
||||
class CScript;
|
||||
class CTransaction;
|
||||
|
||||
struct CMutableTransaction;
|
||||
|
||||
bool Sign1(const CKeyID& address, const CKeyStore& keystore, uint256 hash, int nHashType, CScript& scriptSigRet);
|
||||
bool SignSignature(const CKeyStore& keystore, const CScript& fromPubKey, CMutableTransaction& txTo, unsigned int nIn, int nHashType=SIGHASH_ALL);
|
||||
bool SignSignature(const CKeyStore& keystore, const CTransaction& txFrom, CMutableTransaction& txTo, unsigned int nIn, int nHashType=SIGHASH_ALL);
|
||||
|
||||
/**
|
||||
* Given two sets of signatures for scriptPubKey, possibly with OP_0 placeholders,
|
||||
* combine them intelligently and return the result.
|
||||
*/
|
||||
CScript CombineSignatures(const CScript& scriptPubKey, const CTransaction& txTo, unsigned int nIn, const CScript& scriptSig1, const CScript& scriptSig2);
|
||||
|
||||
#endif // BITCOIN_SCRIPT_SIGN_H
|
||||
@@ -0,0 +1,330 @@
|
||||
// Copyright (c) 2009-2010 Satoshi Nakamoto
|
||||
// Copyright (c) 2009-2014 The Bitcoin developers
|
||||
// Copyright (c) 2017-2019 The PIVX developers
|
||||
// Distributed under the MIT software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#include "script/standard.h"
|
||||
|
||||
#include "pubkey.h"
|
||||
#include "script/script.h"
|
||||
#include "util.h"
|
||||
#include "utilstrencodings.h"
|
||||
|
||||
|
||||
using namespace std;
|
||||
|
||||
typedef vector<unsigned char> valtype;
|
||||
|
||||
unsigned nMaxDatacarrierBytes = MAX_OP_RETURN_RELAY;
|
||||
|
||||
CScriptID::CScriptID(const CScript& in) : uint160(Hash160(in.begin(), in.end())) {}
|
||||
|
||||
const char* GetTxnOutputType(txnouttype t)
|
||||
{
|
||||
switch (t)
|
||||
{
|
||||
case TX_NONSTANDARD: return "nonstandard";
|
||||
case TX_PUBKEY: return "pubkey";
|
||||
case TX_PUBKEYHASH: return "pubkeyhash";
|
||||
case TX_SCRIPTHASH: return "scripthash";
|
||||
case TX_MULTISIG: return "multisig";
|
||||
case TX_NULL_DATA: return "nulldata";
|
||||
case TX_ZEROCOINMINT: return "zerocoinmint";
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return public keys or hashes from scriptPubKey, for 'standard' transaction types.
|
||||
*/
|
||||
bool Solver(const CScript& scriptPubKey, txnouttype& typeRet, vector<vector<unsigned char> >& vSolutionsRet)
|
||||
{
|
||||
// Templates
|
||||
static multimap<txnouttype, CScript> mTemplates;
|
||||
if (mTemplates.empty())
|
||||
{
|
||||
// Standard tx, sender provides pubkey, receiver adds signature
|
||||
mTemplates.insert(make_pair(TX_PUBKEY, CScript() << OP_PUBKEY << OP_CHECKSIG));
|
||||
|
||||
// Bitcoin address tx, sender provides hash of pubkey, receiver provides signature and pubkey
|
||||
mTemplates.insert(make_pair(TX_PUBKEYHASH, CScript() << OP_DUP << OP_HASH160 << OP_PUBKEYHASH << OP_EQUALVERIFY << OP_CHECKSIG));
|
||||
|
||||
// Sender provides N pubkeys, receivers provides M signatures
|
||||
mTemplates.insert(make_pair(TX_MULTISIG, CScript() << OP_SMALLINTEGER << OP_PUBKEYS << OP_SMALLINTEGER << OP_CHECKMULTISIG));
|
||||
}
|
||||
|
||||
// Shortcut for pay-to-script-hash, which are more constrained than the other types:
|
||||
// it is always OP_HASH160 20 [20 byte hash] OP_EQUAL
|
||||
if (scriptPubKey.IsPayToScriptHash())
|
||||
{
|
||||
typeRet = TX_SCRIPTHASH;
|
||||
vector<unsigned char> hashBytes(scriptPubKey.begin()+2, scriptPubKey.begin()+22);
|
||||
vSolutionsRet.push_back(hashBytes);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Zerocoin
|
||||
if (scriptPubKey.IsZerocoinMint()) {
|
||||
typeRet = TX_ZEROCOINMINT;
|
||||
if(scriptPubKey.size() > 150) return false;
|
||||
vector<unsigned char> hashBytes(scriptPubKey.begin()+2, scriptPubKey.end());
|
||||
vSolutionsRet.push_back(hashBytes);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Provably prunable, data-carrying output
|
||||
//
|
||||
// So long as script passes the IsUnspendable() test and all but the first
|
||||
// byte passes the IsPushOnly() test we don't care what exactly is in the
|
||||
// script.
|
||||
if (scriptPubKey.size() >= 1 && scriptPubKey[0] == OP_RETURN && scriptPubKey.IsPushOnly(scriptPubKey.begin()+1)) {
|
||||
typeRet = TX_NULL_DATA;
|
||||
return true;
|
||||
}
|
||||
|
||||
// Scan templates
|
||||
const CScript& script1 = scriptPubKey;
|
||||
for (const PAIRTYPE(txnouttype, CScript)& tplate : mTemplates)
|
||||
{
|
||||
const CScript& script2 = tplate.second;
|
||||
vSolutionsRet.clear();
|
||||
|
||||
opcodetype opcode1, opcode2;
|
||||
vector<unsigned char> vch1, vch2;
|
||||
|
||||
// Compare
|
||||
CScript::const_iterator pc1 = script1.begin();
|
||||
CScript::const_iterator pc2 = script2.begin();
|
||||
while (true)
|
||||
{
|
||||
if (pc1 == script1.end() && pc2 == script2.end())
|
||||
{
|
||||
// Found a match
|
||||
typeRet = tplate.first;
|
||||
if (typeRet == TX_MULTISIG)
|
||||
{
|
||||
// Additional checks for TX_MULTISIG:
|
||||
unsigned char m = vSolutionsRet.front()[0];
|
||||
unsigned char n = vSolutionsRet.back()[0];
|
||||
if (m < 1 || n < 1 || m > n || vSolutionsRet.size()-2 != n)
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
if (!script1.GetOp(pc1, opcode1, vch1))
|
||||
break;
|
||||
if (!script2.GetOp(pc2, opcode2, vch2))
|
||||
break;
|
||||
|
||||
// Template matching opcodes:
|
||||
if (opcode2 == OP_PUBKEYS)
|
||||
{
|
||||
while (vch1.size() >= 33 && vch1.size() <= 65)
|
||||
{
|
||||
vSolutionsRet.push_back(vch1);
|
||||
if (!script1.GetOp(pc1, opcode1, vch1))
|
||||
break;
|
||||
}
|
||||
if (!script2.GetOp(pc2, opcode2, vch2))
|
||||
break;
|
||||
// Normal situation is to fall through
|
||||
// to other if/else statements
|
||||
}
|
||||
|
||||
if (opcode2 == OP_PUBKEY)
|
||||
{
|
||||
if (vch1.size() < 33 || vch1.size() > 65)
|
||||
break;
|
||||
vSolutionsRet.push_back(vch1);
|
||||
}
|
||||
else if (opcode2 == OP_PUBKEYHASH)
|
||||
{
|
||||
if (vch1.size() != sizeof(uint160))
|
||||
break;
|
||||
vSolutionsRet.push_back(vch1);
|
||||
}
|
||||
else if (opcode2 == OP_SMALLINTEGER)
|
||||
{ // Single-byte small integer pushed onto vSolutions
|
||||
if (opcode1 == OP_0 ||
|
||||
(opcode1 >= OP_1 && opcode1 <= OP_16))
|
||||
{
|
||||
char n = (char)CScript::DecodeOP_N(opcode1);
|
||||
vSolutionsRet.push_back(valtype(1, n));
|
||||
}
|
||||
else
|
||||
break;
|
||||
}
|
||||
else if (opcode1 != opcode2 || vch1 != vch2)
|
||||
{
|
||||
// Others must match exactly
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
vSolutionsRet.clear();
|
||||
typeRet = TX_NONSTANDARD;
|
||||
return false;
|
||||
}
|
||||
|
||||
int ScriptSigArgsExpected(txnouttype t, const std::vector<std::vector<unsigned char> >& vSolutions)
|
||||
{
|
||||
switch (t)
|
||||
{
|
||||
case TX_NONSTANDARD:
|
||||
case TX_NULL_DATA:
|
||||
case TX_ZEROCOINMINT:
|
||||
return -1;
|
||||
case TX_PUBKEY:
|
||||
return 1;
|
||||
case TX_PUBKEYHASH:
|
||||
return 2;
|
||||
case TX_MULTISIG:
|
||||
if (vSolutions.size() < 1 || vSolutions[0].size() < 1)
|
||||
return -1;
|
||||
return vSolutions[0][0] + 1;
|
||||
case TX_SCRIPTHASH:
|
||||
return 1; // doesn't include args needed by the script
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
bool IsStandard(const CScript& scriptPubKey, txnouttype& whichType)
|
||||
{
|
||||
vector<valtype> vSolutions;
|
||||
if (!Solver(scriptPubKey, whichType, vSolutions))
|
||||
return false;
|
||||
|
||||
if (whichType == TX_MULTISIG)
|
||||
{
|
||||
unsigned char m = vSolutions.front()[0];
|
||||
unsigned char n = vSolutions.back()[0];
|
||||
// Support up to x-of-3 multisig txns as standard
|
||||
if (n < 1 || n > 3)
|
||||
return false;
|
||||
if (m < 1 || m > n)
|
||||
return false;
|
||||
} else if (whichType == TX_NULL_DATA &&
|
||||
(!GetBoolArg("-datacarrier", true) || scriptPubKey.size() > nMaxDatacarrierBytes))
|
||||
return false;
|
||||
|
||||
return whichType != TX_NONSTANDARD;
|
||||
}
|
||||
|
||||
bool ExtractDestination(const CScript& scriptPubKey, CTxDestination& addressRet)
|
||||
{
|
||||
vector<valtype> vSolutions;
|
||||
txnouttype whichType;
|
||||
if (!Solver(scriptPubKey, whichType, vSolutions))
|
||||
return false;
|
||||
|
||||
if (whichType == TX_PUBKEY)
|
||||
{
|
||||
CPubKey pubKey(vSolutions[0]);
|
||||
if (!pubKey.IsValid())
|
||||
return false;
|
||||
|
||||
addressRet = pubKey.GetID();
|
||||
return true;
|
||||
}
|
||||
else if (whichType == TX_PUBKEYHASH)
|
||||
{
|
||||
addressRet = CKeyID(uint160(vSolutions[0]));
|
||||
return true;
|
||||
}
|
||||
else if (whichType == TX_SCRIPTHASH)
|
||||
{
|
||||
addressRet = CScriptID(uint160(vSolutions[0]));
|
||||
return true;
|
||||
}
|
||||
// Multisig txns have more than one address...
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ExtractDestinations(const CScript& scriptPubKey, txnouttype& typeRet, vector<CTxDestination>& addressRet, int& nRequiredRet)
|
||||
{
|
||||
addressRet.clear();
|
||||
typeRet = TX_NONSTANDARD;
|
||||
vector<valtype> vSolutions;
|
||||
if (!Solver(scriptPubKey, typeRet, vSolutions))
|
||||
return false;
|
||||
if (typeRet == TX_NULL_DATA){
|
||||
// This is data, not addresses
|
||||
return false;
|
||||
}
|
||||
|
||||
if (typeRet == TX_MULTISIG)
|
||||
{
|
||||
nRequiredRet = vSolutions.front()[0];
|
||||
for (unsigned int i = 1; i < vSolutions.size()-1; i++)
|
||||
{
|
||||
CPubKey pubKey(vSolutions[i]);
|
||||
if (!pubKey.IsValid())
|
||||
continue;
|
||||
|
||||
CTxDestination address = pubKey.GetID();
|
||||
addressRet.push_back(address);
|
||||
}
|
||||
|
||||
if (addressRet.empty())
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
nRequiredRet = 1;
|
||||
CTxDestination address;
|
||||
if (!ExtractDestination(scriptPubKey, address))
|
||||
return false;
|
||||
addressRet.push_back(address);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
class CScriptVisitor : public boost::static_visitor<bool>
|
||||
{
|
||||
private:
|
||||
CScript *script;
|
||||
public:
|
||||
CScriptVisitor(CScript *scriptin) { script = scriptin; }
|
||||
|
||||
bool operator()(const CNoDestination &dest) const {
|
||||
script->clear();
|
||||
return false;
|
||||
}
|
||||
|
||||
bool operator()(const CKeyID &keyID) const {
|
||||
script->clear();
|
||||
*script << OP_DUP << OP_HASH160 << ToByteVector(keyID) << OP_EQUALVERIFY << OP_CHECKSIG;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool operator()(const CScriptID &scriptID) const {
|
||||
script->clear();
|
||||
*script << OP_HASH160 << ToByteVector(scriptID) << OP_EQUAL;
|
||||
return true;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
CScript GetScriptForDestination(const CTxDestination& dest)
|
||||
{
|
||||
CScript script;
|
||||
|
||||
boost::apply_visitor(CScriptVisitor(&script), dest);
|
||||
return script;
|
||||
}
|
||||
|
||||
CScript GetScriptForMultisig(int nRequired, const std::vector<CPubKey>& keys)
|
||||
{
|
||||
CScript script;
|
||||
|
||||
script << CScript::EncodeOP_N(nRequired);
|
||||
for (const CPubKey& key : keys)
|
||||
script << ToByteVector(key);
|
||||
script << CScript::EncodeOP_N(keys.size()) << OP_CHECKMULTISIG;
|
||||
return script;
|
||||
}
|
||||
@@ -0,0 +1,96 @@
|
||||
// Copyright (c) 2009-2010 Satoshi Nakamoto
|
||||
// Copyright (c) 2009-2014 The Bitcoin developers
|
||||
// Copyright (c) 2017-2018 The PIVX developers
|
||||
// Distributed under the MIT software license, see the accompanying
|
||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
#ifndef BITCOIN_SCRIPT_STANDARD_H
|
||||
#define BITCOIN_SCRIPT_STANDARD_H
|
||||
|
||||
#include "script/interpreter.h"
|
||||
#include "uint256.h"
|
||||
|
||||
#include <boost/variant.hpp>
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
class CKeyID;
|
||||
class CScript;
|
||||
|
||||
/** A reference to a CScript: the Hash160 of its serialization (see script.h) */
|
||||
class CScriptID : public uint160
|
||||
{
|
||||
public:
|
||||
CScriptID() : uint160() {}
|
||||
CScriptID(const CScript& in);
|
||||
CScriptID(const uint160& in) : uint160(in) {}
|
||||
};
|
||||
|
||||
static const unsigned int MAX_OP_RETURN_RELAY = 83; //!< bytes (+1 for OP_RETURN, +2 for the pushdata opcodes)
|
||||
extern unsigned nMaxDatacarrierBytes;
|
||||
|
||||
/**
|
||||
* Mandatory script verification flags that all new blocks must comply with for
|
||||
* them to be valid. (but old blocks may not comply with) Currently just P2SH,
|
||||
* but in the future other flags may be added, such as a soft-fork to enforce
|
||||
* strict DER encoding.
|
||||
*
|
||||
* Failing one of these tests may trigger a DoS ban - see CheckInputs() for
|
||||
* details.
|
||||
*/
|
||||
static const unsigned int MANDATORY_SCRIPT_VERIFY_FLAGS = SCRIPT_VERIFY_P2SH;
|
||||
|
||||
/**
|
||||
* Standard script verification flags that standard transactions will comply
|
||||
* with. However scripts violating these flags may still be present in valid
|
||||
* blocks and we must accept those blocks.
|
||||
*/
|
||||
static const unsigned int STANDARD_SCRIPT_VERIFY_FLAGS = MANDATORY_SCRIPT_VERIFY_FLAGS |
|
||||
SCRIPT_VERIFY_DERSIG |
|
||||
SCRIPT_VERIFY_STRICTENC |
|
||||
SCRIPT_VERIFY_MINIMALDATA |
|
||||
SCRIPT_VERIFY_NULLDUMMY |
|
||||
SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_NOPS;
|
||||
|
||||
/** For convenience, standard but not mandatory verify flags. */
|
||||
static const unsigned int STANDARD_NOT_MANDATORY_VERIFY_FLAGS = STANDARD_SCRIPT_VERIFY_FLAGS & ~MANDATORY_SCRIPT_VERIFY_FLAGS;
|
||||
|
||||
enum txnouttype
|
||||
{
|
||||
TX_NONSTANDARD,
|
||||
// 'standard' transaction types:
|
||||
TX_PUBKEY,
|
||||
TX_PUBKEYHASH,
|
||||
TX_SCRIPTHASH,
|
||||
TX_MULTISIG,
|
||||
TX_NULL_DATA,
|
||||
TX_ZEROCOINMINT,
|
||||
};
|
||||
|
||||
class CNoDestination {
|
||||
public:
|
||||
friend bool operator==(const CNoDestination &a, const CNoDestination &b) { return true; }
|
||||
friend bool operator<(const CNoDestination &a, const CNoDestination &b) { return true; }
|
||||
};
|
||||
|
||||
/**
|
||||
* A txout script template with a specific destination. It is either:
|
||||
* * CNoDestination: no destination set
|
||||
* * CKeyID: TX_PUBKEYHASH destination
|
||||
* * CScriptID: TX_SCRIPTHASH destination
|
||||
* A CTxDestination is the internal data type encoded in a CBitcoinAddress
|
||||
*/
|
||||
typedef boost::variant<CNoDestination, CKeyID, CScriptID> CTxDestination;
|
||||
|
||||
const char* GetTxnOutputType(txnouttype t);
|
||||
|
||||
bool Solver(const CScript& scriptPubKey, txnouttype& typeRet, std::vector<std::vector<unsigned char> >& vSolutionsRet);
|
||||
int ScriptSigArgsExpected(txnouttype t, const std::vector<std::vector<unsigned char> >& vSolutions);
|
||||
bool IsStandard(const CScript& scriptPubKey, txnouttype& whichType);
|
||||
bool ExtractDestination(const CScript& scriptPubKey, CTxDestination& addressRet);
|
||||
bool ExtractDestinations(const CScript& scriptPubKey, txnouttype& typeRet, std::vector<CTxDestination>& addressRet, int& nRequiredRet);
|
||||
|
||||
CScript GetScriptForDestination(const CTxDestination& dest);
|
||||
CScript GetScriptForMultisig(int nRequired, const std::vector<CPubKey>& keys);
|
||||
|
||||
#endif // BITCOIN_SCRIPT_STANDARD_H
|
||||
Reference in New Issue
Block a user