Recursively solve script and return spendable/watchonly/invalid status. @param keystore legacy key and script store @param scriptPubKey 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
| 97 | //! scripts or simply treat any script that has been |
| 98 | //! stored in the keystore as spendable |
| 99 | IsMineResult IsMineInner(const LegacyScriptPubKeyMan& keystore, const CScript& scriptPubKey, IsMineSigVersion sigversion, bool recurse_scripthash=true) |
| 100 | { |
| 101 | IsMineResult ret = IsMineResult::NO; |
| 102 | |
| 103 | std::vector<valtype> vSolutions; |
| 104 | TxoutType whichType = Solver(scriptPubKey, vSolutions); |
| 105 | |
| 106 | CKeyID keyID; |
| 107 | switch (whichType) { |
| 108 | case TxoutType::NONSTANDARD: |
| 109 | case TxoutType::NULL_DATA: |
| 110 | case TxoutType::WITNESS_UNKNOWN: |
| 111 | case TxoutType::WITNESS_V1_TAPROOT: |
| 112 | case TxoutType::FEE: |
| 113 | break; |
| 114 | case TxoutType::PUBKEY: |
| 115 | keyID = CPubKey(vSolutions[0]).GetID(); |
| 116 | if (!PermitsUncompressed(sigversion) && vSolutions[0].size() != 33) { |
| 117 | return IsMineResult::INVALID; |
| 118 | } |
| 119 | if (keystore.HaveKey(keyID)) { |
| 120 | ret = std::max(ret, IsMineResult::SPENDABLE); |
| 121 | } |
| 122 | break; |
| 123 | case TxoutType::WITNESS_V0_KEYHASH: |
| 124 | { |
| 125 | if (sigversion == IsMineSigVersion::WITNESS_V0) { |
| 126 | // P2WPKH inside P2WSH is invalid. |
| 127 | return IsMineResult::INVALID; |
| 128 | } |
| 129 | if (sigversion == IsMineSigVersion::TOP && !keystore.HaveCScript(CScriptID(CScript() << OP_0 << vSolutions[0]))) { |
| 130 | // We do not support bare witness outputs unless the P2SH version of it would be |
| 131 | // acceptable as well. This protects against matching before segwit activates. |
| 132 | // This also applies to the P2WSH case. |
| 133 | break; |
| 134 | } |
| 135 | ret = std::max(ret, IsMineInner(keystore, GetScriptForDestination(PKHash(CKeyID(uint160(vSolutions[0])))), IsMineSigVersion::WITNESS_V0)); |
| 136 | break; |
| 137 | } |
| 138 | case TxoutType::PUBKEYHASH: |
| 139 | keyID = CKeyID(uint160(vSolutions[0])); |
| 140 | if (!PermitsUncompressed(sigversion)) { |
| 141 | CPubKey pubkey; |
| 142 | if (keystore.GetPubKey(keyID, pubkey) && !pubkey.IsCompressed()) { |
| 143 | return IsMineResult::INVALID; |
| 144 | } |
| 145 | } |
| 146 | if (keystore.HaveKey(keyID)) { |
| 147 | ret = std::max(ret, IsMineResult::SPENDABLE); |
| 148 | } |
| 149 | break; |
| 150 | case TxoutType::SCRIPTHASH: |
| 151 | { |
| 152 | if (sigversion != IsMineSigVersion::TOP) { |
| 153 | // P2SH inside P2WSH or P2SH is invalid. |
| 154 | return IsMineResult::INVALID; |
| 155 | } |
| 156 | CScriptID scriptID = CScriptID(uint160(vSolutions[0])); |
no test coverage detected