src/wallet/scriptpubkeyman.cpp
IsMineResult IsMineInner(const LegacyScriptPubKeyMan& keystore, const CScript& scriptPubKey, IsMineSigVersion sigversion, bool recurse_scripthash=true)
{
    IsMineResult ret = IsMineResult::NO;

    std::vector<valtype> vSolutions;
    txnouttype whichType = Solver(scriptPubKey, vSolutions);

    CKeyID keyID;
    switch (whichType)
    {
    case TX_NONSTANDARD:
    case TX_NULL_DATA:
    case TX_WITNESS_UNKNOWN:
        break;
    case TX_PUBKEY:
        keyID = CPubKey(vSolutions[0]).GetID();
        if (!PermitsUncompressed(sigversion) && vSolutions[0].size() != 33) {
            return IsMineResult::INVALID;
        }
        if (keystore.HaveKey(keyID)) {
            ret = std::max(ret, IsMineResult::SPENDABLE);
        }
        break;
    case TX_WITNESS_V0_KEYHASH:
    {
        if (sigversion == IsMineSigVersion::WITNESS_V0) {
            // P2WPKH inside P2WSH is invalid.
            return IsMineResult::INVALID;
        }
        if (sigversion == IsMineSigVersion::TOP && !keystore.HaveCScript(CScriptID(CScript() << OP_0 << vSolutions[0]))) {
            // We do not support bare witness outputs unless the P2SH version of it would be
            // acceptable as well. This protects against matching before segwit activates.
            // This also applies to the P2WSH case.
            break;
        }
        ret = std::max(ret, IsMineInner(keystore, GetScriptForDestination(PKHash(uint160(vSolutions[0]))), IsMineSigVersion::WITNESS_V0));
        break;
    }
    case TX_PUBKEYHASH:
        keyID = CKeyID(uint160(vSolutions[0]));
        if (!PermitsUncompressed(sigversion)) {
            CPubKey pubkey;
            if (keystore.GetPubKey(keyID, pubkey) && !pubkey.IsCompressed()) {
                return IsMineResult::INVALID;
            }
        }
        if (keystore.HaveKey(keyID)) {
            ret = std::max(ret, IsMineResult::SPENDABLE);
        }
        break;
    case TX_SCRIPTHASH:
    {
        if (sigversion != IsMineSigVersion::TOP) {
            // P2SH inside P2WSH or P2SH is invalid.
            return IsMineResult::INVALID;
        }
        CScriptID scriptID = CScriptID(uint160(vSolutions[0]));
        CScript subscript;
        if (keystore.GetCScript(scriptID, subscript)) {
            ret = std::max(ret, recurse_scripthash ? IsMineInner(keystore, subscript, IsMineSigVersion::P2SH) : IsMineResult::SPENDABLE);
        }
        break;
    }
    case TX_WITNESS_V0_SCRIPTHASH:
    {
        if (sigversion == IsMineSigVersion::WITNESS_V0) {
            // P2WSH inside P2WSH is invalid.
            return IsMineResult::INVALID;
        }
        if (sigversion == IsMineSigVersion::TOP && !keystore.HaveCScript(CScriptID(CScript() << OP_0 << vSolutions[0]))) {
            break;
        }
        uint160 hash;
        CRIPEMD160().Write(&vSolutions[0][0], vSolutions[0].size()).Finalize(hash.begin());
        CScriptID scriptID = CScriptID(hash);
        CScript subscript;
        if (keystore.GetCScript(scriptID, subscript)) {
            ret = std::max(ret, recurse_scripthash ? IsMineInner(keystore, subscript, IsMineSigVersion::WITNESS_V0) : IsMineResult::SPENDABLE);
        }
        break;
    }

    case TX_MULTISIG:
    {
        // Never treat bare multisig outputs as ours (they can still be made watchonly-though)
        if (sigversion == IsMineSigVersion::TOP) {
            break;
        }

        // Only consider transactions "mine" if we own ALL the
        // keys involved. Multi-signature transactions that are
        // partially owned (somebody else has a key that can spend
        // them) enable spend-out-from-under-you attacks, especially
        // in shared-wallet situations.
        std::vector<valtype> keys(vSolutions.begin()+1, vSolutions.begin()+vSolutions.size()-1);
        if (!PermitsUncompressed(sigversion)) {
            for (size_t i = 0; i < keys.size(); i++) {
                if (keys[i].size() != 33) {
                    return IsMineResult::INVALID;
                }
            }
        }
        if (HaveKeys(keys, keystore)) {
            ret = std::max(ret, IsMineResult::SPENDABLE);
        }
        break;
    }

    default:
        break;
    }

    if (ret == IsMineResult::NO && keystore.HaveWatchOnly(scriptPubKey)) {
        ret = std::max(ret, IsMineResult::WATCH_ONLY);
    }
    return ret;
}
//! Recursively solve script and return spendable/watchonly/invalid status.
//!
//! @param keystore            legacy key and script store
//! @param script              script to solve
//! @param sigversion          script type (top-level / redeemscript / witnessscript)
//! @param recurse_scripthash  whether to recurse into nested p2sh and p2wsh
//!                            scripts or simply treat any script that has been
//!                            stored in the keystore as spendable
Recursively solve script and return spendable/watchonly/invalid status.
Recursively solve script and return spendable / watchonly / invalid status .
IsMineResult IsMineInner(const LegacyScriptPubKeyMan& keystore, const CScript& scriptPubKey, IsMineSigVersion sigversion, bool recurse_scripthash=true)
{
    IsMineResult ret = IsMineResult::NO;
    std::vector<valtype> vSolutions;
    txnouttype whichType = Solver(scriptPubKey, vSolutions);
    CKeyID keyID;
    switch (whichType)
    {
    case TX_NONSTANDARD:
    case TX_NULL_DATA:
    case TX_WITNESS_UNKNOWN:
        break;
    case TX_PUBKEY:
        keyID = CPubKey(vSolutions[0]).GetID();
        if (!PermitsUncompressed(sigversion) && vSolutions[0].size() != 33) {
            return IsMineResult::INVALID;
        }
        if (keystore.HaveKey(keyID)) {
            ret = std::max(ret, IsMineResult::SPENDABLE);
        }
        break;
    case TX_WITNESS_V0_KEYHASH:
    {
        if (sigversion == IsMineSigVersion::WITNESS_V0) {
            return IsMineResult::INVALID;
        }
        if (sigversion == IsMineSigVersion::TOP && !keystore.HaveCScript(CScriptID(CScript() << OP_0 << vSolutions[0]))) {
            break;
        }
        ret = std::max(ret, IsMineInner(keystore, GetScriptForDestination(PKHash(uint160(vSolutions[0]))), IsMineSigVersion::WITNESS_V0));
        break;
    }
    case TX_PUBKEYHASH:
        keyID = CKeyID(uint160(vSolutions[0]));
        if (!PermitsUncompressed(sigversion)) {
            CPubKey pubkey;
            if (keystore.GetPubKey(keyID, pubkey) && !pubkey.IsCompressed()) {
                return IsMineResult::INVALID;
            }
        }
        if (keystore.HaveKey(keyID)) {
            ret = std::max(ret, IsMineResult::SPENDABLE);
        }
        break;
    case TX_SCRIPTHASH:
    {
        if (sigversion != IsMineSigVersion::TOP) {
            return IsMineResult::INVALID;
        }
        CScriptID scriptID = CScriptID(uint160(vSolutions[0]));
        CScript subscript;
        if (keystore.GetCScript(scriptID, subscript)) {
            ret = std::max(ret, recurse_scripthash ? IsMineInner(keystore, subscript, IsMineSigVersion::P2SH) : IsMineResult::SPENDABLE);
        }
        break;
    }
    case TX_WITNESS_V0_SCRIPTHASH:
    {
        if (sigversion == IsMineSigVersion::WITNESS_V0) {
            return IsMineResult::INVALID;
        }
        if (sigversion == IsMineSigVersion::TOP && !keystore.HaveCScript(CScriptID(CScript() << OP_0 << vSolutions[0]))) {
            break;
        }
        uint160 hash;
        CRIPEMD160().Write(&vSolutions[0][0], vSolutions[0].size()).Finalize(hash.begin());
        CScriptID scriptID = CScriptID(hash);
        CScript subscript;
        if (keystore.GetCScript(scriptID, subscript)) {
            ret = std::max(ret, recurse_scripthash ? IsMineInner(keystore, subscript, IsMineSigVersion::WITNESS_V0) : IsMineResult::SPENDABLE);
        }
        break;
    }
    case TX_MULTISIG:
    {
        if (sigversion == IsMineSigVersion::TOP) {
            break;
        }
        std::vector<valtype> keys(vSolutions.begin()+1, vSolutions.begin()+vSolutions.size()-1);
        if (!PermitsUncompressed(sigversion)) {
            for (size_t i = 0; i < keys.size(); i++) {
                if (keys[i].size() != 33) {
                    return IsMineResult::INVALID;
                }
            }
        }
        if (HaveKeys(keys, keystore)) {
            ret = std::max(ret, IsMineResult::SPENDABLE);
        }
        break;
    }
    default:
        break;
    }
    if (ret == IsMineResult::NO && keystore.HaveWatchOnly(scriptPubKey)) {
        ret = std::max(ret, IsMineResult::WATCH_ONLY);
    }
    return ret;
}
IsMineResult IsMineInner ( const LegacyScriptPubKeyMan & keystore , const CScript & scriptPubKey , IsMineSigVersion sigversion , bool recurse_scripthash = true ) { IsMineResult ret = IsMineResult :: NO ; std :: vector < valtype > vSolutions ; txnouttype whichType = Solver ( scriptPubKey , vSolutions ) ; CKeyID keyID ; switch ( whichType ) { case TX_NONSTANDARD : case TX_NULL_DATA : case TX_WITNESS_UNKNOWN : break ; case TX_PUBKEY : keyID = CPubKey ( vSolutions [ 0 ] ) . GetID ( ) ; if ( ! PermitsUncompressed ( sigversion ) && vSolutions [ 0 ] . size ( ) != 33 ) { return IsMineResult :: INVALID ; } if ( keystore . HaveKey ( keyID ) ) { ret = std :: max ( ret , IsMineResult :: SPENDABLE ) ; } break ; case TX_WITNESS_V0_KEYHASH : { if ( sigversion == IsMineSigVersion :: WITNESS_V0 ) { return IsMineResult :: INVALID ; } if ( sigversion == IsMineSigVersion :: TOP && ! keystore . HaveCScript ( CScriptID ( CScript ( ) << OP_0 << vSolutions [ 0 ] ) ) ) { break ; } ret = std :: max ( ret , IsMineInner ( keystore , GetScriptForDestination ( PKHash ( uint160 ( vSolutions [ 0 ] ) ) ) , IsMineSigVersion :: WITNESS_V0 ) ) ; break ; } case TX_PUBKEYHASH : keyID = CKeyID ( uint160 ( vSolutions [ 0 ] ) ) ; if ( ! PermitsUncompressed ( sigversion ) ) { CPubKey pubkey ; if ( keystore . GetPubKey ( keyID , pubkey ) && ! pubkey . IsCompressed ( ) ) { return IsMineResult :: INVALID ; } } if ( keystore . HaveKey ( keyID ) ) { ret = std :: max ( ret , IsMineResult :: SPENDABLE ) ; } break ; case TX_SCRIPTHASH : { if ( sigversion != IsMineSigVersion :: TOP ) { return IsMineResult :: INVALID ; } CScriptID scriptID = CScriptID ( uint160 ( vSolutions [ 0 ] ) ) ; CScript subscript ; if ( keystore . GetCScript ( scriptID , subscript ) ) { ret = std :: max ( ret , recurse_scripthash ? IsMineInner ( keystore , subscript , IsMineSigVersion :: P2SH ) : IsMineResult :: SPENDABLE ) ; } break ; } case TX_WITNESS_V0_SCRIPTHASH : { if ( sigversion == IsMineSigVersion :: WITNESS_V0 ) { return IsMineResult :: INVALID ; } if ( sigversion == IsMineSigVersion :: TOP && ! keystore . HaveCScript ( CScriptID ( CScript ( ) << OP_0 << vSolutions [ 0 ] ) ) ) { break ; } uint160 hash ; CRIPEMD160 ( ) . Write ( & vSolutions [ 0 ] [ 0 ] , vSolutions [ 0 ] . size ( ) ) . Finalize ( hash . begin ( ) ) ; CScriptID scriptID = CScriptID ( hash ) ; CScript subscript ; if ( keystore . GetCScript ( scriptID , subscript ) ) { ret = std :: max ( ret , recurse_scripthash ? IsMineInner ( keystore , subscript , IsMineSigVersion :: WITNESS_V0 ) : IsMineResult :: SPENDABLE ) ; } break ; } case TX_MULTISIG : { if ( sigversion == IsMineSigVersion :: TOP ) { break ; } std :: vector < valtype > keys ( vSolutions . begin ( ) + 1 , vSolutions . begin ( ) + vSolutions . size ( ) - 1 ) ; if ( ! PermitsUncompressed ( sigversion ) ) { for ( size_t i = 0 ; i < keys . size ( ) ; i ++ ) { if ( keys [ i ] . size ( ) != 33 ) { return IsMineResult :: INVALID ; } } } if ( HaveKeys ( keys , keystore ) ) { ret = std :: max ( ret , IsMineResult :: SPENDABLE ) ; } break ; } default : break ; } if ( ret == IsMineResult :: NO && keystore . HaveWatchOnly ( scriptPubKey ) ) { ret = std :: max ( ret , IsMineResult :: WATCH_ONLY ) ; } return ret ; }
Recursively solve script and return spendable/watchonly/invalid status.
Recursively solve script and return spendable / watchonly / invalid status .
// P2WPKH inside P2WSH is invalid. // We do not support bare witness outputs unless the P2SH version of it would be // acceptable as well. This protects against matching before segwit activates. // This also applies to the P2WSH case. // P2SH inside P2WSH or P2SH is invalid. // P2WSH inside P2WSH is invalid. // Never treat bare multisig outputs as ours (they can still be made watchonly-though) // Only consider transactions "mine" if we own ALL the // keys involved. Multi-signature transactions that are // partially owned (somebody else has a key that can spend // them) enable spend-out-from-under-you attacks, especially // in shared-wallet situations.