git / moonbite-core / src/script/script.cpp · raw

// Copyright (c) 2009-2010 Satoshi Nakamoto// Copyright (c) 2009-2019 The Bitcoin Core developers// Distributed under the MIT software license, see the accompanying// file COPYING or http://www.opensource.org/licenses/mit-license.php.#include <script/script.h>#include <mw/models/crypto/Hash.h>#include <util/strencodings.h>#include <string>std::string 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";    // expansion    case OP_NOP1                   : return "OP_NOP1";    case OP_CHECKLOCKTIMEVERIFY    : return "OP_CHECKLOCKTIMEVERIFY";    case OP_CHECKSEQUENCEVERIFY    : return "OP_CHECKSEQUENCEVERIFY";    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";    // Opcode added by BIP 342 (Tapscript)    case OP_CHECKSIGADD            : return "OP_CHECKSIGADD";    case OP_INVALIDOPCODE          : return "OP_INVALIDOPCODE";    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 += MAX_PUBKEYS_PER_MULTISIG;        }        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();    std::vector<unsigned char> vData;    while (pc < scriptSig.end())    {        opcodetype opcode;        if (!scriptSig.GetOp(pc, opcode, vData))            return 0;        if (opcode > OP_16)            return 0;    }    /// ... and return its opcount:    CScript subscript(vData.begin(), vData.end());    return subscript.GetSigOpCount(true);}bool CScript::IsPayToScriptHash() const{    // Extra-fast test for pay-to-script-hash CScripts:    return (this->size() == 23 &&            (*this)[0] == OP_HASH160 &&            (*this)[1] == 0x14 &&            (*this)[22] == OP_EQUAL);}bool CScript::IsPayToWitnessScriptHash() const{    // Extra-fast test for pay-to-witness-script-hash CScripts:    return (this->size() == 34 &&            (*this)[0] == OP_0 &&            (*this)[1] == 0x20);}// A witness program is any valid CScript that consists of a 1-byte push opcode// followed by a data push between 2 and 40 bytes.bool CScript::IsWitnessProgram(int& version, std::vector<unsigned char>& program) const{    if (this->size() < 4 || this->size() > 42) {        return false;    }    if ((*this)[0] != OP_0 && ((*this)[0] < OP_1 || (*this)[0] > OP_16)) {        return false;    }    if ((size_t)((*this)[1] + 2) == this->size()) {        version = DecodeOP_N((opcodetype)(*this)[0]);        program = std::vector<unsigned char>(this->begin() + 2, this->end());        return true;    }    return false;}bool CScript::IsMWEBPegin(mw::Hash* const kernel_id) const{    int version;    std::vector<uint8_t> program;    if (IsWitnessProgram(version, program)) {        if (version == MWEB_PEGIN_WITNESS_VERSION && program.size() == WITNESS_MWEB_PEGIN_SIZE) {            if (kernel_id != nullptr) {                *kernel_id = mw::Hash(std::move(program));            }            return true;        }    }    return false;}bool CScript::IsMWEBHogAddr(mw::Hash* const header_hash) const{    int version;    std::vector<uint8_t> program;    if (IsWitnessProgram(version, program)) {        if (version == MWEB_HOG_ADDR_WITNESS_VERSION && program.size() == WITNESS_MWEB_HEADERHASH_SIZE) {            if (header_hash != nullptr) {                *header_hash = mw::Hash(std::move(program));            }            return true;        }    }    return false;}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 CScriptWitness::ToString() const{    std::string ret = "CScriptWitness(";    for (unsigned int i = 0; i < stack.size(); i++) {        if (i) {            ret += ", ";        }        ret += HexStr(stack[i]);    }    return ret + ")";}bool CScript::HasValidOps() const{    CScript::const_iterator it = begin();    while (it < end()) {        opcodetype opcode;        std::vector<unsigned char> item;        if (!GetOp(it, opcode, item) || opcode > MAX_OPCODE || item.size() > MAX_SCRIPT_ELEMENT_SIZE) {            return false;        }    }    return true;}bool GetScriptOp(CScriptBase::const_iterator& pc, CScriptBase::const_iterator end, opcodetype& opcodeRet, std::vector<unsigned char>* pvchRet){    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 = ReadLE16(&pc[0]);            pc += 2;        }        else if (opcode == OP_PUSHDATA4)        {            if (end - pc < 4)                return false;            nSize = ReadLE32(&pc[0]);            pc += 4;        }        if (end - pc < 0 || (unsigned int)(end - pc) < nSize)            return false;        if (pvchRet)            pvchRet->assign(pc, pc + nSize);        pc += nSize;    }    opcodeRet = static_cast<opcodetype>(opcode);    return true;}bool IsOpSuccess(const opcodetype& opcode){    return opcode == 80 || opcode == 98 || (opcode >= 126 && opcode <= 129) ||           (opcode >= 131 && opcode <= 134) || (opcode >= 137 && opcode <= 138) ||           (opcode >= 141 && opcode <= 142) || (opcode >= 149 && opcode <= 153) ||           (opcode >= 187 && opcode <= 254);}