@@ -964,6 +964,12 @@ static std::string RecurseImportData(const CScript& script, ImportData& import_d
964964 }
965965}
966966
967+ static UniValue ProcessImportLegacy (ImportData& import_data, std::map<CKeyID, CPubKey>& pubkey_map, std::map<CKeyID, CKey>& privkey_map, std::set<CScript>& script_pub_keys, bool & have_solving_data, const UniValue& data)
968+ {
969+ UniValue warnings (UniValue::VARR);
970+ return warnings;
971+ }
972+
967973static UniValue ProcessImport (CWallet * const pwallet, const UniValue& data, const int64_t timestamp) EXCLUSIVE_LOCKS_REQUIRED(pwallet->cs_wallet)
968974{
969975 UniValue warnings (UniValue::VARR);
@@ -983,141 +989,143 @@ static UniValue ProcessImport(CWallet * const pwallet, const UniValue& data, con
983989 std::set<CScript> script_pub_keys;
984990 bool have_solving_data;
985991
986- // First ensure scriptPubKey has either a script or JSON with "address" string
987- const UniValue& scriptPubKey = data[" scriptPubKey" ];
988- bool isScript = scriptPubKey.getType () == UniValue::VSTR;
989- if (!isScript && !(scriptPubKey.getType () == UniValue::VOBJ && scriptPubKey.exists (" address" ))) {
990- throw JSONRPCError (RPC_INVALID_PARAMETER, " scriptPubKey must be string with script or JSON with address string" );
992+ warnings = ProcessImportLegacy (import_data, pubkey_map, privkey_map, script_pub_keys, have_solving_data, data);
993+
994+ // First ensure scriptPubKey has either a script or JSON with "address" string
995+ const UniValue& scriptPubKey = data[" scriptPubKey" ];
996+ bool isScript = scriptPubKey.getType () == UniValue::VSTR;
997+ if (!isScript && !(scriptPubKey.getType () == UniValue::VOBJ && scriptPubKey.exists (" address" ))) {
998+ throw JSONRPCError (RPC_INVALID_PARAMETER, " scriptPubKey must be string with script or JSON with address string" );
999+ }
1000+ const std::string& output = isScript ? scriptPubKey.get_str () : scriptPubKey[" address" ].get_str ();
1001+
1002+ // Optional fields.
1003+ const std::string& strRedeemScript = data.exists (" redeemscript" ) ? data[" redeemscript" ].get_str () : " " ;
1004+ const std::string& witness_script_hex = data.exists (" witnessscript" ) ? data[" witnessscript" ].get_str () : " " ;
1005+ const UniValue& pubKeys = data.exists (" pubkeys" ) ? data[" pubkeys" ].get_array () : UniValue ();
1006+ const UniValue& keys = data.exists (" keys" ) ? data[" keys" ].get_array () : UniValue ();
1007+ const bool watchOnly = data.exists (" watchonly" ) ? data[" watchonly" ].get_bool () : false ;
1008+
1009+ // If private keys are disabled, abort if private keys are being imported
1010+ if (pwallet->IsWalletFlagSet (WALLET_FLAG_DISABLE_PRIVATE_KEYS) && !keys.isNull ()) {
1011+ throw JSONRPCError (RPC_WALLET_ERROR, " Cannot import private keys to a wallet with private keys disabled" );
1012+ }
1013+
1014+ // Generate the script and destination for the scriptPubKey provided
1015+ CScript script;
1016+ CTxDestination dest;
1017+ if (!isScript) {
1018+ dest = DecodeDestination (output);
1019+ if (!IsValidDestination (dest)) {
1020+ throw JSONRPCError (RPC_INVALID_ADDRESS_OR_KEY, " Invalid address \" " + output + " \" " );
9911021 }
992- const std::string& output = isScript ? scriptPubKey.get_str () : scriptPubKey[" address" ].get_str ();
993-
994- // Optional fields.
995- const std::string& strRedeemScript = data.exists (" redeemscript" ) ? data[" redeemscript" ].get_str () : " " ;
996- const std::string& witness_script_hex = data.exists (" witnessscript" ) ? data[" witnessscript" ].get_str () : " " ;
997- const UniValue& pubKeys = data.exists (" pubkeys" ) ? data[" pubkeys" ].get_array () : UniValue ();
998- const UniValue& keys = data.exists (" keys" ) ? data[" keys" ].get_array () : UniValue ();
999- const bool watchOnly = data.exists (" watchonly" ) ? data[" watchonly" ].get_bool () : false ;
1000-
1001- // If private keys are disabled, abort if private keys are being imported
1002- if (pwallet->IsWalletFlagSet (WALLET_FLAG_DISABLE_PRIVATE_KEYS) && !keys.isNull ()) {
1003- throw JSONRPCError (RPC_WALLET_ERROR, " Cannot import private keys to a wallet with private keys disabled" );
1022+ script = GetScriptForDestination (dest);
1023+ } else {
1024+ if (!IsHex (output)) {
1025+ throw JSONRPCError (RPC_INVALID_ADDRESS_OR_KEY, " Invalid scriptPubKey \" " + output + " \" " );
10041026 }
1005-
1006- // Generate the script and destination for the scriptPubKey provided
1007- CScript script;
1008- CTxDestination dest;
1009- if (!isScript) {
1010- dest = DecodeDestination (output);
1011- if (!IsValidDestination (dest)) {
1012- throw JSONRPCError (RPC_INVALID_ADDRESS_OR_KEY, " Invalid address \" " + output + " \" " );
1013- }
1014- script = GetScriptForDestination (dest);
1015- } else {
1016- if (!IsHex (output)) {
1017- throw JSONRPCError (RPC_INVALID_ADDRESS_OR_KEY, " Invalid scriptPubKey \" " + output + " \" " );
1018- }
1019- std::vector<unsigned char > vData (ParseHex (output));
1020- script = CScript (vData.begin (), vData.end ());
1021- if (!ExtractDestination (script, dest) && !internal) {
1022- throw JSONRPCError (RPC_INVALID_PARAMETER, " Internal must be set to true for nonstandard scriptPubKey imports." );
1023- }
1027+ std::vector<unsigned char > vData (ParseHex (output));
1028+ script = CScript (vData.begin (), vData.end ());
1029+ if (!ExtractDestination (script, dest) && !internal) {
1030+ throw JSONRPCError (RPC_INVALID_PARAMETER, " Internal must be set to true for nonstandard scriptPubKey imports." );
10241031 }
1025- script_pub_keys.emplace (script);
1032+ }
1033+ script_pub_keys.emplace (script);
10261034
1027- // Parse all arguments
1028- if (strRedeemScript.size ()) {
1029- if (!IsHex (strRedeemScript)) {
1030- throw JSONRPCError (RPC_INVALID_ADDRESS_OR_KEY, " Invalid redeem script \" " + strRedeemScript + " \" : must be hex string" );
1031- }
1032- auto parsed_redeemscript = ParseHex (strRedeemScript);
1033- import_data.redeemscript = MakeUnique<CScript>(parsed_redeemscript.begin (), parsed_redeemscript.end ());
1035+ // Parse all arguments
1036+ if (strRedeemScript.size ()) {
1037+ if (!IsHex (strRedeemScript)) {
1038+ throw JSONRPCError (RPC_INVALID_ADDRESS_OR_KEY, " Invalid redeem script \" " + strRedeemScript + " \" : must be hex string" );
10341039 }
1035- if (witness_script_hex. size ()) {
1036- if (! IsHex (witness_script_hex)) {
1037- throw JSONRPCError (RPC_INVALID_ADDRESS_OR_KEY, " Invalid witness script \" " + witness_script_hex + " \" : must be hex string " );
1038- }
1039- auto parsed_witnessscript = ParseHex ( witness_script_hex);
1040- import_data. witnessscript = MakeUnique<CScript>(parsed_witnessscript. begin (), parsed_witnessscript. end () );
1040+ auto parsed_redeemscript = ParseHex (strRedeemScript);
1041+ import_data. redeemscript = MakeUnique<CScript>(parsed_redeemscript. begin (), parsed_redeemscript. end ());
1042+ }
1043+ if (witness_script_hex. size ()) {
1044+ if (! IsHex ( witness_script_hex)) {
1045+ throw JSONRPCError (RPC_INVALID_ADDRESS_OR_KEY, " Invalid witness script \" " + witness_script_hex + " \" : must be hex string " );
10411046 }
1042- for (size_t i = 0 ; i < pubKeys.size (); ++i) {
1043- const auto & str = pubKeys[i].get_str ();
1044- if (!IsHex (str)) {
1045- throw JSONRPCError (RPC_INVALID_ADDRESS_OR_KEY, " Pubkey \" " + str + " \" must be a hex string" );
1046- }
1047- auto parsed_pubkey = ParseHex (str);
1048- CPubKey pubkey (parsed_pubkey.begin (), parsed_pubkey.end ());
1049- if (!pubkey.IsFullyValid ()) {
1050- throw JSONRPCError (RPC_INVALID_ADDRESS_OR_KEY, " Pubkey \" " + str + " \" is not a valid public key" );
1051- }
1052- pubkey_map.emplace (pubkey.GetID (), pubkey);
1047+ auto parsed_witnessscript = ParseHex (witness_script_hex);
1048+ import_data.witnessscript = MakeUnique<CScript>(parsed_witnessscript.begin (), parsed_witnessscript.end ());
1049+ }
1050+ for (size_t i = 0 ; i < pubKeys.size (); ++i) {
1051+ const auto & str = pubKeys[i].get_str ();
1052+ if (!IsHex (str)) {
1053+ throw JSONRPCError (RPC_INVALID_ADDRESS_OR_KEY, " Pubkey \" " + str + " \" must be a hex string" );
10531054 }
1054- for (size_t i = 0 ; i < keys.size (); ++i) {
1055- const auto & str = keys[i].get_str ();
1056- CKey key = DecodeSecret (str);
1057- if (!key.IsValid ()) {
1058- throw JSONRPCError (RPC_INVALID_ADDRESS_OR_KEY, " Invalid private key encoding" );
1059- }
1060- CPubKey pubkey = key.GetPubKey ();
1061- CKeyID id = pubkey.GetID ();
1062- if (pubkey_map.count (id)) {
1063- pubkey_map.erase (id);
1064- }
1065- privkey_map.emplace (id, key);
1055+ auto parsed_pubkey = ParseHex (str);
1056+ CPubKey pubkey (parsed_pubkey.begin (), parsed_pubkey.end ());
1057+ if (!pubkey.IsFullyValid ()) {
1058+ throw JSONRPCError (RPC_INVALID_ADDRESS_OR_KEY, " Pubkey \" " + str + " \" is not a valid public key" );
10661059 }
1060+ pubkey_map.emplace (pubkey.GetID (), pubkey);
1061+ }
1062+ for (size_t i = 0 ; i < keys.size (); ++i) {
1063+ const auto & str = keys[i].get_str ();
1064+ CKey key = DecodeSecret (str);
1065+ if (!key.IsValid ()) {
1066+ throw JSONRPCError (RPC_INVALID_ADDRESS_OR_KEY, " Invalid private key encoding" );
1067+ }
1068+ CPubKey pubkey = key.GetPubKey ();
1069+ CKeyID id = pubkey.GetID ();
1070+ if (pubkey_map.count (id)) {
1071+ pubkey_map.erase (id);
1072+ }
1073+ privkey_map.emplace (id, key);
1074+ }
10671075
10681076
1069- // Verify and process input data
1070- have_solving_data = import_data.redeemscript || import_data.witnessscript || pubkey_map.size () || privkey_map.size ();
1071- if (have_solving_data) {
1072- // Match up data in import_data with the scriptPubKey in script.
1073- auto error = RecurseImportData (script, import_data, ScriptContext::TOP);
1077+ // Verify and process input data
1078+ have_solving_data = import_data.redeemscript || import_data.witnessscript || pubkey_map.size () || privkey_map.size ();
1079+ if (have_solving_data) {
1080+ // Match up data in import_data with the scriptPubKey in script.
1081+ auto error = RecurseImportData (script, import_data, ScriptContext::TOP);
10741082
1075- // Verify whether the watchonly option corresponds to the availability of private keys.
1076- bool spendable = std::all_of (import_data.used_keys .begin (), import_data.used_keys .end (), [&](const std::pair<CKeyID, bool >& used_key){ return privkey_map.count (used_key.first ) > 0 ; });
1077- if (!watchOnly && !spendable) {
1078- warnings.push_back (" Some private keys are missing, outputs will be considered watchonly. If this is intentional, specify the watchonly flag." );
1079- }
1080- if (watchOnly && spendable) {
1081- warnings.push_back (" All private keys are provided, outputs will be considered spendable. If this is intentional, do not specify the watchonly flag." );
1082- }
1083+ // Verify whether the watchonly option corresponds to the availability of private keys.
1084+ bool spendable = std::all_of (import_data.used_keys .begin (), import_data.used_keys .end (), [&](const std::pair<CKeyID, bool >& used_key){ return privkey_map.count (used_key.first ) > 0 ; });
1085+ if (!watchOnly && !spendable) {
1086+ warnings.push_back (" Some private keys are missing, outputs will be considered watchonly. If this is intentional, specify the watchonly flag." );
1087+ }
1088+ if (watchOnly && spendable) {
1089+ warnings.push_back (" All private keys are provided, outputs will be considered spendable. If this is intentional, do not specify the watchonly flag." );
1090+ }
10831091
1084- // Check that all required keys for solvability are provided.
1085- if (error.empty ()) {
1086- for (const auto & require_key : import_data.used_keys ) {
1087- if (!require_key.second ) continue ; // Not a required key
1088- if (pubkey_map.count (require_key.first ) == 0 && privkey_map.count (require_key.first ) == 0 ) {
1089- error = " some required keys are missing" ;
1090- }
1092+ // Check that all required keys for solvability are provided.
1093+ if (error.empty ()) {
1094+ for (const auto & require_key : import_data.used_keys ) {
1095+ if (!require_key.second ) continue ; // Not a required key
1096+ if (pubkey_map.count (require_key.first ) == 0 && privkey_map.count (require_key.first ) == 0 ) {
1097+ error = " some required keys are missing" ;
10911098 }
10921099 }
1100+ }
10931101
1094- if (!error.empty ()) {
1095- warnings.push_back (" Importing as non-solvable: " + error + " . If this is intentional, don't provide any keys, pubkeys, witnessscript, or redeemscript." );
1096- import_data = ImportData ();
1097- pubkey_map.clear ();
1098- privkey_map.clear ();
1099- have_solving_data = false ;
1100- } else {
1101- // RecurseImportData() removes any relevant redeemscript/witnessscript from import_data, so we can use that to discover if a superfluous one was provided.
1102- if (import_data.redeemscript ) warnings.push_back (" Ignoring redeemscript as this is not a P2SH script." );
1103- if (import_data.witnessscript ) warnings.push_back (" Ignoring witnessscript as this is not a (P2SH-)P2WSH script." );
1104- for (auto it = privkey_map.begin (); it != privkey_map.end (); ) {
1105- auto oldit = it++;
1106- if (import_data.used_keys .count (oldit->first ) == 0 ) {
1107- warnings.push_back (" Ignoring irrelevant private key." );
1108- privkey_map.erase (oldit);
1109- }
1102+ if (!error.empty ()) {
1103+ warnings.push_back (" Importing as non-solvable: " + error + " . If this is intentional, don't provide any keys, pubkeys, witnessscript, or redeemscript." );
1104+ import_data = ImportData ();
1105+ pubkey_map.clear ();
1106+ privkey_map.clear ();
1107+ have_solving_data = false ;
1108+ } else {
1109+ // RecurseImportData() removes any relevant redeemscript/witnessscript from import_data, so we can use that to discover if a superfluous one was provided.
1110+ if (import_data.redeemscript ) warnings.push_back (" Ignoring redeemscript as this is not a P2SH script." );
1111+ if (import_data.witnessscript ) warnings.push_back (" Ignoring witnessscript as this is not a (P2SH-)P2WSH script." );
1112+ for (auto it = privkey_map.begin (); it != privkey_map.end (); ) {
1113+ auto oldit = it++;
1114+ if (import_data.used_keys .count (oldit->first ) == 0 ) {
1115+ warnings.push_back (" Ignoring irrelevant private key." );
1116+ privkey_map.erase (oldit);
11101117 }
1111- for ( auto it = pubkey_map. begin (); it != pubkey_map. end (); ) {
1112- auto oldit = it++;
1113- auto key_data_it = import_data. used_keys . find (oldit-> first ) ;
1114- if ( key_data_it == import_data.used_keys .end () || !key_data_it-> second ) {
1115- warnings. push_back ( " Ignoring public key \" " + HexStr (oldit-> first ) + " \" as it doesn't appear inside P2PKH or P2WPKH. " );
1116- pubkey_map. erase (oldit);
1117- }
1118+ }
1119+ for ( auto it = pubkey_map. begin (); it != pubkey_map. end (); ) {
1120+ auto oldit = it++ ;
1121+ auto key_data_it = import_data.used_keys .find (oldit-> first );
1122+ if (key_data_it == import_data. used_keys . end () || !key_data_it-> second ) {
1123+ warnings. push_back ( " Ignoring public key \" " + HexStr (oldit-> first ) + " \" as it doesn't appear inside P2PKH or P2WPKH. " );
1124+ pubkey_map. erase (oldit);
11181125 }
11191126 }
11201127 }
1128+ }
11211129
11221130 // Check whether we have any work to do
11231131 for (const CScript& script : script_pub_keys) {
0 commit comments