@@ -964,6 +964,12 @@ static std::string RecurseImportData(const CScript& script, ImportData& import_d
964
964
}
965
965
}
966
966
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
+
967
973
static UniValue ProcessImport (CWallet * const pwallet, const UniValue& data, const int64_t timestamp) EXCLUSIVE_LOCKS_REQUIRED(pwallet->cs_wallet)
968
974
{
969
975
UniValue warnings (UniValue::VARR);
@@ -983,141 +989,143 @@ static UniValue ProcessImport(CWallet * const pwallet, const UniValue& data, con
983
989
std::set<CScript> script_pub_keys;
984
990
bool have_solving_data;
985
991
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 + " \" " );
991
1021
}
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 + " \" " );
1004
1026
}
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." );
1024
1031
}
1025
- script_pub_keys.emplace (script);
1032
+ }
1033
+ script_pub_keys.emplace (script);
1026
1034
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" );
1034
1039
}
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 " );
1041
1046
}
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" );
1053
1054
}
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" );
1066
1059
}
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
+ }
1067
1075
1068
1076
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);
1074
1082
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
+ }
1083
1091
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" ;
1091
1098
}
1092
1099
}
1100
+ }
1093
1101
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);
1110
1117
}
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);
1118
1125
}
1119
1126
}
1120
1127
}
1128
+ }
1121
1129
1122
1130
// Check whether we have any work to do
1123
1131
for (const CScript& script : script_pub_keys) {
0 commit comments