Analyse the provided scriptPubKey, determining which keys and which redeem scripts from the ImportData struct are needed to spend it, and mark them as used. Returns an error string, or the empty string for success.
| 871 | // Analyse the provided scriptPubKey, determining which keys and which redeem scripts from the ImportData struct are needed to spend it, and mark them as used. |
| 872 | // Returns an error string, or the empty string for success. |
| 873 | static std::string RecurseImportData(const CScript& script, ImportData& import_data, const ScriptContext script_ctx) |
| 874 | { |
| 875 | // Use Solver to obtain script type and parsed pubkeys or hashes: |
| 876 | std::vector<std::vector<unsigned char>> solverdata; |
| 877 | TxoutType script_type = Solver(script, solverdata); |
| 878 | |
| 879 | switch (script_type) { |
| 880 | case TxoutType::PUBKEY: { |
| 881 | CPubKey pubkey(solverdata[0]); |
| 882 | import_data.used_keys.emplace(pubkey.GetID(), false); |
| 883 | return ""; |
| 884 | } |
| 885 | case TxoutType::PUBKEYHASH: { |
| 886 | CKeyID id = CKeyID(uint160(solverdata[0])); |
| 887 | import_data.used_keys[id] = true; |
| 888 | return ""; |
| 889 | } |
| 890 | case TxoutType::SCRIPTHASH: { |
| 891 | if (script_ctx == ScriptContext::P2SH) throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Trying to nest P2SH inside another P2SH"); |
| 892 | if (script_ctx == ScriptContext::WITNESS_V0) throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Trying to nest P2SH inside a P2WSH"); |
| 893 | CHECK_NONFATAL(script_ctx == ScriptContext::TOP); |
| 894 | CScriptID id = CScriptID(uint160(solverdata[0])); |
| 895 | auto subscript = std::move(import_data.redeemscript); // Remove redeemscript from import_data to check for superfluous script later. |
| 896 | if (!subscript) return "missing redeemscript"; |
| 897 | if (CScriptID(*subscript) != id) return "redeemScript does not match the scriptPubKey"; |
| 898 | import_data.import_scripts.emplace(*subscript); |
| 899 | return RecurseImportData(*subscript, import_data, ScriptContext::P2SH); |
| 900 | } |
| 901 | case TxoutType::MULTISIG: { |
| 902 | for (size_t i = 1; i + 1< solverdata.size(); ++i) { |
| 903 | CPubKey pubkey(solverdata[i]); |
| 904 | import_data.used_keys.emplace(pubkey.GetID(), false); |
| 905 | } |
| 906 | return ""; |
| 907 | } |
| 908 | case TxoutType::WITNESS_V0_SCRIPTHASH: { |
| 909 | if (script_ctx == ScriptContext::WITNESS_V0) throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Trying to nest P2WSH inside another P2WSH"); |
| 910 | uint256 fullid(solverdata[0]); |
| 911 | CScriptID id; |
| 912 | CRIPEMD160().Write(fullid.begin(), fullid.size()).Finalize(id.begin()); |
| 913 | auto subscript = std::move(import_data.witnessscript); // Remove redeemscript from import_data to check for superfluous script later. |
| 914 | if (!subscript) return "missing witnessscript"; |
| 915 | if (CScriptID(*subscript) != id) return "witnessScript does not match the scriptPubKey or redeemScript"; |
| 916 | if (script_ctx == ScriptContext::TOP) { |
| 917 | import_data.import_scripts.emplace(script); // Special rule for IsMine: native P2WSH requires the TOP script imported (see script/ismine.cpp) |
| 918 | } |
| 919 | import_data.import_scripts.emplace(*subscript); |
| 920 | return RecurseImportData(*subscript, import_data, ScriptContext::WITNESS_V0); |
| 921 | } |
| 922 | case TxoutType::WITNESS_V0_KEYHASH: { |
| 923 | if (script_ctx == ScriptContext::WITNESS_V0) throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Trying to nest P2WPKH inside P2WSH"); |
| 924 | CKeyID id = CKeyID(uint160(solverdata[0])); |
| 925 | import_data.used_keys[id] = true; |
| 926 | if (script_ctx == ScriptContext::TOP) { |
| 927 | import_data.import_scripts.emplace(script); // Special rule for IsMine: native P2WPKH requires the TOP script imported (see script/ismine.cpp) |
| 928 | } |
| 929 | return ""; |
| 930 | } |
no test coverage detected