26#include <boost/algorithm/string.hpp>
35 std::stringstream ret;
36 for (
const unsigned char c : str) {
37 if (c <= 32 || c >= 128 || c ==
'%') {
38 ret << '%' << HexStr(Span<const unsigned char>(&c, 1));
47 std::stringstream ret;
48 for (
unsigned int pos = 0; pos < str.length(); pos++) {
49 unsigned char c = str[pos];
50 if (c ==
'%' && pos+2 < str.length()) {
51 c = (((str[pos+1]>>6)*9+((str[pos+1]-
'0')&15)) << 4) |
52 ((str[pos+2]>>6)*9+((str[pos+2]-
'0')&15));
62 bool fLabelFound =
false;
64 spk_man->GetKey(keyid, key);
66 const auto* address_book_entry =
wallet.FindAddressBookEntry(dest);
67 if (address_book_entry) {
68 if (!strAddr.empty()) {
86 int64_t scanned_time =
wallet.RescanFromTime(time_begin, reserver, update);
87 if (
wallet.IsAbortingRescan()) {
89 }
else if (scanned_time > time_begin) {
97 "\nAdds a private key (as returned by dumpprivkey) to your wallet. Requires a new wallet backup.\n"
98 "Hint: use importmulti to import more than one private key.\n"
99 "\nNote: This call can take over an hour to complete if rescan is true, during that time, other rpc calls\n"
100 "may report that the imported key exists but related transactions are still missing, leading to temporarily incorrect/bogus balances and unspent outputs until rescan completes.\n"
101 "Note: Use \"getwalletinfo\" to query the scanning progress.\n",
109 "\nDump a private key\n"
111 "\nImport the private key with rescan\n"
113 "\nImport using a label and without rescan\n"
114 +
HelpExampleCli(
"importprivkey",
"\"mykey\" \"testing\" false") +
115 "\nImport using default blank label and without rescan\n"
117 "\nAs a JSON-RPC call\n"
118 +
HelpExampleRpc(
"importprivkey",
"\"mykey\", \"testing\", false")
134 LOCK(pwallet->cs_wallet);
138 std::string strSecret = request.params[0].get_str();
139 std::string strLabel =
"";
140 if (!request.params[1].isNull())
141 strLabel = request.params[1].get_str();
144 if (!request.params[2].isNull())
145 fRescan = request.params[2].get_bool();
147 if (fRescan && pwallet->chain().havePruned()) {
154 if (fRescan && !reserver.
reserve()) {
165 pwallet->MarkDirty();
171 if (!request.params[1].isNull() || !pwallet->FindAddressBookEntry(dest)) {
172 pwallet->SetAddressBook(dest, strLabel,
"receive");
177 if (!pwallet->ImportPrivKeys({{vchAddress, key}}, 1)) {
199 "\nStops current wallet rescan triggered by an RPC call, e.g. by an importprivkey call.\n"
200 "Note: Use \"getwalletinfo\" to query the scanning progress.\n",
204 "\nImport a private key\n"
206 "\nAbort the running wallet rescan\n"
208 "\nAs a JSON-RPC call\n"
216 if (!pwallet->IsScanning() || pwallet->IsAbortingRescan())
return false;
217 pwallet->AbortRescan();
226 "\nAdds an address or script (in hex) that can be watched as if it were in your wallet but cannot be used to spend. Requires a new wallet backup.\n"
227 "\nNote: This call can take over an hour to complete if rescan is true, during that time, other rpc calls\n"
228 "may report that the imported address exists but related transactions are still missing, leading to temporarily incorrect/bogus balances and unspent outputs until rescan completes.\n"
229 "If you have the full public key, you should call importpubkey instead of this.\n"
230 "Hint: use importmulti to import more than one address.\n"
231 "\nNote: If you import a non-standard raw script in hex form, outputs sending to it will be treated\n"
232 "as change, and not show up in many RPCs.\n"
233 "Note: Use \"getwalletinfo\" to query the scanning progress.\n",
242 "\nImport an address with rescan\n"
244 "\nImport using a label without rescan\n"
245 +
HelpExampleCli(
"importaddress",
"\"myaddress\" \"testing\" false") +
246 "\nAs a JSON-RPC call\n"
247 +
HelpExampleRpc(
"importaddress",
"\"myaddress\", \"testing\", false")
256 std::string strLabel;
257 if (!request.params[1].isNull())
258 strLabel = request.params[1].get_str();
262 if (!request.params[2].isNull())
263 fRescan = request.params[2].get_bool();
265 if (fRescan && pwallet->chain().havePruned()) {
273 if (fRescan && !reserver.
reserve()) {
279 if (!request.params[3].isNull())
280 fP2SH = request.params[3].get_bool();
283 LOCK(pwallet->cs_wallet);
294 pwallet->MarkDirty();
297 }
else if (
IsHex(request.params[0].get_str())) {
298 std::vector<unsigned char> data(
ParseHex(request.params[0].get_str()));
299 CScript redeem_script(data.begin(), data.end());
301 std::set<CScript> scripts = {redeem_script};
302 pwallet->ImportScripts(scripts, 0 );
308 pwallet->ImportScriptPubKeys(strLabel, scripts,
false ,
true , 1 );
317 LOCK(pwallet->cs_wallet);
318 pwallet->ReacceptWalletTransactions();
330 "\nImports funds without rescan. Corresponding address or script must previously be included in wallet. Aimed towards pruned wallets. The end-user is responsible to import additional transactions that subsequently spend the imported outputs or rescan after the point in the blockchain the transaction is included.\n",
343 if (!
DecodeHexTx(tx, request.params[0].get_str())) {
353 std::vector<uint256> vMatch;
354 std::vector<unsigned int> vIndex;
359 LOCK(pwallet->cs_wallet);
361 if (!pwallet->chain().findAncestorByHash(pwallet->GetLastBlockHash(), merkleBlock.
header.
GetHash(),
FoundBlock().height(height))) {
365 std::vector<uint256>::const_iterator it;
366 if ((it = std::find(vMatch.begin(), vMatch.end(), hashTx)) == vMatch.end()) {
370 unsigned int txnIndex = vIndex[it - vMatch.begin()];
375 if (pwallet->IsMine(*tx_ref)) {
376 pwallet->AddToWallet(std::move(tx_ref), confirm);
388 "\nDeletes the specified transaction from the wallet. Meant for use with pruned wallets and as a companion to importprunedfunds. This will affect wallet balances.\n",
394 HelpExampleCli(
"removeprunedfunds",
"\"a8d0c0184dde994a09ec054286f1ce581bebf46446a512166eae7628734ea0a5\"") +
395 "\nAs a JSON-RPC call\n"
396 +
HelpExampleRpc(
"removeprunedfunds",
"\"a8d0c0184dde994a09ec054286f1ce581bebf46446a512166eae7628734ea0a5\"")
403 LOCK(pwallet->cs_wallet);
406 std::vector<uint256> vHash;
407 vHash.push_back(hash);
408 std::vector<uint256> vHashOut;
414 if(vHashOut.empty()) {
426 "\nAdds a public key (in hex) that can be watched as if it were in your wallet but cannot be used to spend. Requires a new wallet backup.\n"
427 "Hint: use importmulti to import more than one public key.\n"
428 "\nNote: This call can take over an hour to complete if rescan is true, during that time, other rpc calls\n"
429 "may report that the imported pubkey exists but related transactions are still missing, leading to temporarily incorrect/bogus balances and unspent outputs until rescan completes.\n"
430 "Note: Use \"getwalletinfo\" to query the scanning progress.\n",
438 "\nImport a public key with rescan\n"
440 "\nImport using a label without rescan\n"
441 +
HelpExampleCli(
"importpubkey",
"\"mypubkey\" \"testing\" false") +
442 "\nAs a JSON-RPC call\n"
443 +
HelpExampleRpc(
"importpubkey",
"\"mypubkey\", \"testing\", false")
452 std::string strLabel;
453 if (!request.params[1].isNull())
454 strLabel = request.params[1].get_str();
458 if (!request.params[2].isNull())
459 fRescan = request.params[2].get_bool();
461 if (fRescan && pwallet->chain().havePruned()) {
469 if (fRescan && !reserver.
reserve()) {
473 if (!
IsHex(request.params[0].get_str()))
475 std::vector<unsigned char> data(
ParseHex(request.params[0].get_str()));
481 LOCK(pwallet->cs_wallet);
483 std::set<CScript> script_pub_keys;
488 pwallet->MarkDirty();
490 pwallet->ImportScriptPubKeys(strLabel, script_pub_keys,
true ,
true , 1 );
492 pwallet->ImportPubKeys({pubKey.
GetID()}, {{pubKey.
GetID(), pubKey}} , {} ,
false ,
false , 1 );
498 LOCK(pwallet->cs_wallet);
499 pwallet->ReacceptWalletTransactions();
512 "\nImports keys from a wallet dump file (see dumpwallet). Requires a new wallet backup to include imported keys.\n"
513 "Note: Use \"getwalletinfo\" to query the scanning progress.\n",
519 "\nDump the wallet\n"
521 "\nImport the wallet\n"
523 "\nImport using the json rpc call\n"
533 if (pwallet->chain().havePruned()) {
545 int64_t nTimeBegin = 0;
548 LOCK(pwallet->cs_wallet);
553 file.open(
fs::u8path(request.params[0].get_str()), std::ios::in | std::ios::ate);
554 if (!file.is_open()) {
559 int64_t nFilesize = std::max((int64_t)1, (int64_t)file.tellg());
560 file.seekg(0, file.beg);
564 pwallet->chain().showProgress(
strprintf(
"%s " +
_(
"Importing…").translated, pwallet->GetDisplayName()), 0,
false);
565 std::vector<std::tuple<CKey, int64_t, bool, std::string>> keys;
566 std::vector<std::pair<CScript, int64_t>> scripts;
567 while (file.good()) {
568 pwallet->chain().showProgress(
"", std::max(1, std::min(50, (
int)(((
double)file.tellg() / (
double)nFilesize) * 100))),
false);
570 std::getline(file, line);
571 if (line.empty() || line[0] ==
'#')
574 std::vector<std::string> vstr;
575 boost::split(vstr, line, boost::is_any_of(
" "));
581 std::string strLabel;
583 for (
unsigned int nStr = 2; nStr < vstr.size(); nStr++) {
584 if (vstr[nStr].front() ==
'#')
586 if (vstr[nStr] ==
"change=1")
588 if (vstr[nStr] ==
"reserve=1")
590 if (vstr[nStr].substr(0,6) ==
"label=") {
595 keys.push_back(std::make_tuple(key, nTime, fLabel, strLabel));
596 }
else if(
IsHex(vstr[0])) {
597 std::vector<unsigned char> vData(
ParseHex(vstr[0]));
600 scripts.push_back(std::pair<CScript, int64_t>(script, birth_time));
606 pwallet->chain().showProgress(
"", 100,
false);
609 double total = (double)(keys.size() + scripts.size());
611 for (
const auto& key_tuple : keys) {
612 pwallet->chain().showProgress(
"", std::max(50, std::min(75, (
int)((progress / total) * 100) + 50)),
false);
613 const CKey& key = std::get<0>(key_tuple);
614 int64_t time = std::get<1>(key_tuple);
615 bool has_label = std::get<2>(key_tuple);
616 std::string label = std::get<3>(key_tuple);
624 if (!pwallet->ImportPrivKeys({{keyid, key}}, time)) {
631 pwallet->SetAddressBook(
PKHash(keyid), label,
"receive");
633 nTimeBegin = std::min(nTimeBegin, time);
636 for (
const auto& script_pair : scripts) {
637 pwallet->chain().showProgress(
"", std::max(50, std::min(75, (
int)((progress / total) * 100) + 50)),
false);
638 const CScript& script = script_pair.first;
639 int64_t time = script_pair.second;
641 if (!pwallet->ImportScripts({script}, time)) {
642 pwallet->WalletLogPrintf(
"Error importing script %s\n",
HexStr(script));
647 nTimeBegin = std::min(nTimeBegin, time);
652 pwallet->chain().showProgress(
"", 100,
false);
654 pwallet->chain().showProgress(
"", 100,
false);
656 pwallet->MarkDirty();
669 "\nReveals the private key corresponding to 'address'.\n"
670 "Then the importprivkey can be used with this output\n",
693 std::string strAddress = request.params[0].get_str();
699 if (keyid.IsNull()) {
703 if (!spk_man.
GetKey(keyid, vchSecret)) {
715 "\nDumps all wallet keys in a human-readable format to a server-side file. This does not allow overwriting existing files.\n"
716 "Imported scripts are included in the dumpfile, but corresponding BIP173 addresses, etc. may not be added automatically by importwallet.\n"
717 "Note that if your wallet contains keys which are not derived from your HD seed (e.g. imported keys), these are not covered by\n"
718 "only backing up the seed itself, and must be backed up too (e.g. ensure you back up the whole dumpfile).\n",
742 wallet.BlockUntilSyncedToCurrentChain();
749 filepath = fs::absolute(filepath);
765 std::map<CKeyID, int64_t> mapKeyBirth;
766 wallet.GetKeyBirthTimes(mapKeyBirth);
768 int64_t block_time = 0;
776 std::set<CScriptID> scripts = spk_man.
GetCScripts();
779 std::vector<std::pair<int64_t, CKeyID> > vKeyBirth;
780 for (
const auto& entry : mapKeyBirth) {
781 vKeyBirth.push_back(std::make_pair(entry.second, entry.first));
784 std::sort(vKeyBirth.begin(), vKeyBirth.end());
789 file <<
strprintf(
"# * Best block at time of backup was %i (%s),\n",
wallet.GetLastBlockHeight(),
wallet.GetLastBlockHash().ToString());
798 if (spk_man.
GetKey(seed_id, seed)) {
802 file <<
"# extended private masterkey: " <<
EncodeExtKey(masterKey) <<
"\n\n";
805 for (std::vector<std::pair<int64_t, CKeyID> >::const_iterator it = vKeyBirth.begin(); it != vKeyBirth.end(); it++) {
806 const CKeyID &keyid = it->second;
809 std::string strLabel;
811 if (spk_man.
GetKey(keyid, key)) {
815 }
else if (keyid == seed_id) {
817 }
else if (mapKeyPool.count(keyid)) {
819 }
else if (spk_man.mapKeyMetadata[keyid].hdKeypath ==
"s") {
820 file <<
"inactivehdseed=1";
824 file <<
strprintf(
" # addr=%s%s\n", strAddr, (spk_man.mapKeyMetadata[keyid].has_key_origin ?
" hdkeypath="+
WriteHDKeypath(spk_man.mapKeyMetadata[keyid].key_origin.path) :
""));
828 for (
const CScriptID &scriptid : scripts) {
830 std::string create_time =
"0";
833 auto it = spk_man.m_script_metadata.find(scriptid);
834 if (it != spk_man.m_script_metadata.end()) {
839 file <<
strprintf(
" # addr=%s\n", address);
843 file <<
"# End of dump\n";
878 std::vector<std::vector<unsigned char>> solverdata;
881 switch (script_type) {
898 if (!subscript)
return "missing redeemscript";
899 if (
CScriptID(*subscript) !=
id)
return "redeemScript does not match the scriptPubKey";
904 for (
size_t i = 1; i + 1< solverdata.size(); ++i) {
916 if (!subscript)
return "missing witnessscript";
917 if (
CScriptID(*subscript) !=
id)
return "witnessScript does not match the scriptPubKey or redeemScript";
934 return "unspendable script";
938 return "unrecognized script";
943static 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, std::vector<CKeyID>& ordered_pubkeys)
948 const UniValue& scriptPubKey = data[
"scriptPubKey"];
953 const std::string& output = isScript ? scriptPubKey.
get_str() : scriptPubKey[
"address"].
get_str();
956 const std::string& strRedeemScript = data.
exists(
"redeemscript") ? data[
"redeemscript"].
get_str() :
"";
957 const std::string& witness_script_hex = data.
exists(
"witnessscript") ? data[
"witnessscript"].
get_str() :
"";
960 const bool internal = data.
exists(
"internal") ? data[
"internal"].
get_bool() :
false;
961 const bool watchOnly = data.
exists(
"watchonly") ? data[
"watchonly"].
get_bool() :
false;
963 if (data.
exists(
"range")) {
979 if (!
IsHex(output)) {
982 std::vector<unsigned char> vData(
ParseHex(output));
983 script =
CScript(vData.begin(), vData.end());
989 script_pub_keys.emplace(script);
992 if (strRedeemScript.size()) {
993 if (!
IsHex(strRedeemScript)) {
996 auto parsed_redeemscript =
ParseHex(strRedeemScript);
997 import_data.
redeemscript = std::make_unique<CScript>(parsed_redeemscript.begin(), parsed_redeemscript.end());
999 if (witness_script_hex.size()) {
1000 if (!
IsHex(witness_script_hex)) {
1003 auto parsed_witnessscript =
ParseHex(witness_script_hex);
1004 import_data.
witnessscript = std::make_unique<CScript>(parsed_witnessscript.begin(), parsed_witnessscript.end());
1006 for (
size_t i = 0; i < pubKeys.
size(); ++i) {
1007 const auto& str = pubKeys[i].
get_str();
1011 auto parsed_pubkey =
ParseHex(str);
1012 CPubKey pubkey(parsed_pubkey);
1016 pubkey_map.emplace(pubkey.
GetID(), pubkey);
1017 ordered_pubkeys.push_back(pubkey.
GetID());
1019 for (
size_t i = 0; i < keys.
size(); ++i) {
1020 const auto& str = keys[i].
get_str();
1027 if (pubkey_map.count(
id)) {
1028 pubkey_map.erase(
id);
1030 privkey_map.emplace(
id, key);
1036 if (have_solving_data) {
1041 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; });
1042 if (!watchOnly && !spendable) {
1043 warnings.
push_back(
"Some private keys are missing, outputs will be considered watchonly. If this is intentional, specify the watchonly flag.");
1045 if (watchOnly && spendable) {
1046 warnings.
push_back(
"All private keys are provided, outputs will be considered spendable. If this is intentional, do not specify the watchonly flag.");
1050 if (
error.empty()) {
1051 for (
const auto& require_key : import_data.
used_keys) {
1052 if (!require_key.second)
continue;
1053 if (pubkey_map.count(require_key.first) == 0 && privkey_map.count(require_key.first) == 0) {
1054 error =
"some required keys are missing";
1059 if (!
error.empty()) {
1060 warnings.
push_back(
"Importing as non-solvable: " +
error +
". If this is intentional, don't provide any keys, pubkeys, witnessscript, or redeemscript.");
1063 privkey_map.clear();
1064 have_solving_data =
false;
1067 if (import_data.
redeemscript) warnings.
push_back(
"Ignoring redeemscript as this is not a P2SH script.");
1068 if (import_data.
witnessscript) warnings.
push_back(
"Ignoring witnessscript as this is not a (P2SH-)P2WSH script.");
1069 for (
auto it = privkey_map.begin(); it != privkey_map.end(); ) {
1071 if (import_data.
used_keys.count(oldit->first) == 0) {
1072 warnings.
push_back(
"Ignoring irrelevant private key.");
1073 privkey_map.erase(oldit);
1076 for (
auto it = pubkey_map.begin(); it != pubkey_map.end(); ) {
1078 auto key_data_it = import_data.
used_keys.find(oldit->first);
1079 if (key_data_it == import_data.
used_keys.end() || !key_data_it->second) {
1080 warnings.
push_back(
"Ignoring public key \"" +
HexStr(oldit->first) +
"\" as it doesn't appear inside P2PKH or P2WPKH.");
1081 pubkey_map.erase(oldit);
1090static UniValue ProcessImportDescriptor(
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, std::vector<CKeyID>& ordered_pubkeys)
1094 const std::string& descriptor = data[
"desc"].
get_str();
1097 auto parsed_desc =
Parse(descriptor, keys,
error,
true);
1105 have_solving_data = parsed_desc->IsSolvable();
1106 const bool watch_only = data.
exists(
"watchonly") ? data[
"watchonly"].
get_bool() :
false;
1108 int64_t range_start = 0, range_end = 0;
1109 if (!parsed_desc->IsRange() && data.
exists(
"range")) {
1111 }
else if (parsed_desc->IsRange()) {
1112 if (!data.
exists(
"range")) {
1121 for (
int i = range_start; i <= range_end; ++i) {
1123 std::vector<CScript> scripts_temp;
1124 parsed_desc->Expand(i, keys, scripts_temp, out_keys);
1125 std::copy(scripts_temp.begin(), scripts_temp.end(), std::inserter(script_pub_keys, script_pub_keys.end()));
1126 for (
const auto& key_pair : out_keys.
pubkeys) {
1127 ordered_pubkeys.push_back(key_pair.first);
1130 for (
const auto& x : out_keys.
scripts) {
1134 parsed_desc->ExpandPrivate(i, keys, out_keys);
1136 std::copy(out_keys.
pubkeys.begin(), out_keys.
pubkeys.end(), std::inserter(pubkey_map, pubkey_map.end()));
1137 std::copy(out_keys.
keys.begin(), out_keys.
keys.end(), std::inserter(privkey_map, privkey_map.end()));
1141 for (
size_t i = 0; i < priv_keys.
size(); ++i) {
1142 const auto& str = priv_keys[i].
get_str();
1151 if (!pubkey_map.count(
id)) {
1152 warnings.
push_back(
"Ignoring irrelevant private key.");
1154 privkey_map.emplace(
id, key);
1162 bool spendable = std::all_of(pubkey_map.begin(), pubkey_map.end(),
1163 [&](
const std::pair<CKeyID, CPubKey>& used_key) {
1164 return privkey_map.count(used_key.first) > 0;
1166 [&](
const std::pair<
CKeyID, std::pair<CPubKey, KeyOriginInfo>>& entry) {
1167 return privkey_map.count(entry.first) > 0;
1169 if (!watch_only && !spendable) {
1170 warnings.
push_back(
"Some private keys are missing, outputs will be considered watchonly. If this is intentional, specify the watchonly flag.");
1172 if (watch_only && spendable) {
1173 warnings.
push_back(
"All private keys are provided, outputs will be considered spendable. If this is intentional, do not specify the watchonly flag.");
1185 const bool internal = data.exists(
"internal") ? data[
"internal"].get_bool() :
false;
1187 if (
internal && data.exists(
"label")) {
1190 const std::string& label = data.exists(
"label") ? data[
"label"].get_str() :
"";
1191 const bool add_keypool = data.exists(
"keypool") ? data[
"keypool"].get_bool() :
false;
1199 std::map<CKeyID, CPubKey> pubkey_map;
1200 std::map<CKeyID, CKey> privkey_map;
1201 std::set<CScript> script_pub_keys;
1202 std::vector<CKeyID> ordered_pubkeys;
1203 bool have_solving_data;
1205 if (data.exists(
"scriptPubKey") && data.exists(
"desc")) {
1207 }
else if (data.exists(
"scriptPubKey")) {
1208 warnings =
ProcessImportLegacy(import_data, pubkey_map, privkey_map, script_pub_keys, have_solving_data, data, ordered_pubkeys);
1209 }
else if (data.exists(
"desc")) {
1210 warnings =
ProcessImportDescriptor(import_data, pubkey_map, privkey_map, script_pub_keys, have_solving_data, data, ordered_pubkeys);
1221 for (
const CScript& script : script_pub_keys) {
1232 if (!
wallet.ImportPrivKeys(privkey_map, timestamp)) {
1235 if (!
wallet.ImportPubKeys(ordered_pubkeys, pubkey_map, import_data.
key_origins, add_keypool,
internal, timestamp)) {
1238 if (!
wallet.ImportScriptPubKeys(label, script_pub_keys, have_solving_data, !
internal, timestamp)) {
1245 result.
pushKV(
"error", e);
1251 if (warnings.
size()) result.
pushKV(
"warnings", warnings);
1257 if (data.
exists(
"timestamp")) {
1258 const UniValue& timestamp = data[
"timestamp"];
1259 if (timestamp.
isNum()) {
1261 }
else if (timestamp.
isStr() && timestamp.
get_str() ==
"now") {
1272 "\nImport addresses/scripts (with private or public keys, redeem script (P2SH)), optionally rescanning the blockchain from the earliest creation time of the imported scripts. Requires a new wallet backup.\n"
1273 "If an address/script is imported without all of the private keys required to spend from that address, it will be watchonly. The 'watchonly' option must be set to true in this case or a warning will be returned.\n"
1274 "Conversely, if all the private keys are provided and the address/script is spendable, the watchonly option must be set to false, or a warning will be returned.\n"
1275 "\nNote: This call can take over an hour to complete if rescan is true, during that time, other rpc calls\n"
1276 "may report that the imported keys, addresses or scripts exist but related transactions are still missing.\n"
1277 "Note: Use \"getwalletinfo\" to query the scanning progress.\n",
1285 "", {
"\"<script>\" | { \"address\":\"<address>\" }",
"string / json"}
1288 " or the string \"now\" to substitute the current synced blockchain time. The timestamp of the oldest\n"
1289 " key will determine how far back blockchain rescans need to begin for missing wallet transactions.\n"
1290 " \"now\" can be specified to bypass scanning, for keys which are known to never have been used, and\n"
1291 " 0 can be specified to scan the entire blockchain. Blocks up to 2 hours before the earliest key\n"
1292 " creation time of all keys being imported by the importmulti call will be scanned.",
1293 "", {
"timestamp | \"now\"",
"integer / string"}
1297 {
"pubkeys",
RPCArg::Type::ARR,
RPCArg::Default{
UniValue::VARR},
"Array of strings giving pubkeys to import. They must occur in P2PKH or P2WPKH scripts. They are not required when the private key is also provided (see the \"keys\" argument).",
1311 {
"keypool",
RPCArg::Type::BOOL,
RPCArg::Default{
false},
"Stating whether imported public keys should be added to the keypool for when users request new addresses. Only allowed when wallet private keys are disabled"},
1323 RPCResult::Type::ARR,
"",
"Response is an array with the same size as the input that has the execution result",
1340 HelpExampleCli(
"importmulti",
"'[{ \"scriptPubKey\": { \"address\": \"<my address>\" }, \"timestamp\":1455191478 }, "
1341 "{ \"scriptPubKey\": { \"address\": \"<my 2nd address>\" }, \"label\": \"example 2\", \"timestamp\": 1455191480 }]'") +
1342 HelpExampleCli(
"importmulti",
"'[{ \"scriptPubKey\": { \"address\": \"<my address>\" }, \"timestamp\":1455191478 }]' '{ \"rescan\": false}'")
1349 RPCTypeCheck(mainRequest.params, {UniValue::VARR, UniValue::VOBJ});
1353 const UniValue& requests = mainRequest.params[0];
1356 bool fRescan =
true;
1358 if (!mainRequest.params[1].isNull()) {
1359 const UniValue& options = mainRequest.params[1];
1361 if (options.
exists(
"rescan")) {
1362 fRescan = options[
"rescan"].
get_bool();
1367 if (fRescan && !reserver.
reserve()) {
1372 bool fRunScan =
false;
1373 int64_t nLowestTimestamp = 0;
1376 LOCK(pwallet->cs_wallet);
1380 CHECK_NONFATAL(pwallet->chain().findBlock(pwallet->GetLastBlockHash(),
FoundBlock().time(nLowestTimestamp).mtpTime(now)));
1385 const int64_t minimumTimestamp = 1;
1397 if (result[
"success"].get_bool()) {
1402 if (timestamp < nLowestTimestamp) {
1403 nLowestTimestamp = timestamp;
1407 if (fRescan && fRunScan && requests.
size()) {
1408 int64_t scannedTime = pwallet->RescanFromTime(nLowestTimestamp, reserver,
true );
1410 LOCK(pwallet->cs_wallet);
1411 pwallet->ReacceptWalletTransactions();
1414 if (pwallet->IsAbortingRescan()) {
1417 if (scannedTime > nLowestTimestamp) {
1418 std::vector<UniValue> results = response.
getValues();
1427 if (scannedTime <=
GetImportTimestamp(request, now) || results.at(i).exists(
"error")) {
1436 strprintf(
"Rescan failed for key with creation timestamp %d. There was an error reading a "
1437 "block from time %d, which is after or within %d seconds of key creation, and "
1438 "could contain transactions pertaining to the key. As a result, transactions "
1439 "and coins using this key may not appear in the wallet. This error could be "
1440 "caused by pruning or data corruption (see bitcoind log for details) and could "
1441 "be dealt with by downloading and rescanning the relevant blocks (see -reindex "
1442 "option and rescanblockchain RPC).",
1462 if (!data.exists(
"desc")) {
1466 const std::string& descriptor = data[
"desc"].get_str();
1467 const bool active = data.exists(
"active") ? data[
"active"].get_bool() :
false;
1468 const bool internal = data.exists(
"internal") ? data[
"internal"].get_bool() :
false;
1469 const std::string& label = data.exists(
"label") ? data[
"label"].get_str() :
"";
1474 auto parsed_desc =
Parse(descriptor, keys,
error,
true);
1480 int64_t range_start = 0, range_end = 1, next_index = 0;
1481 if (!parsed_desc->IsRange() && data.exists(
"range")) {
1483 }
else if (parsed_desc->IsRange()) {
1484 if (data.exists(
"range")) {
1486 range_start = range.first;
1487 range_end = range.second + 1;
1489 warnings.
push_back(
"Range not given, using default keypool range");
1493 next_index = range_start;
1495 if (data.exists(
"next_index")) {
1496 next_index = data[
"next_index"].get_int64();
1498 if (next_index < range_start || next_index >= range_end) {
1505 if (active && !parsed_desc->IsRange()) {
1510 if (data.exists(
"range") && data.exists(
"label")) {
1515 if (
internal && data.exists(
"label")) {
1520 if (active && !parsed_desc->IsSingleType()) {
1531 std::vector<CScript> scripts;
1532 if (!parsed_desc->Expand(0, keys, scripts, expand_keys)) {
1533 throw JSONRPCError(
RPC_WALLET_ERROR,
"Cannot expand descriptor. Probably because of hardened derivations without private keys provided");
1535 parsed_desc->ExpandPrivate(0, keys, expand_keys);
1538 bool have_all_privkeys = !expand_keys.
keys.empty();
1539 for (
const auto& entry : expand_keys.
origins) {
1540 const CKeyID& key_id = entry.first;
1542 if (!expand_keys.
GetKey(key_id, key)) {
1543 have_all_privkeys =
false;
1552 if (std::holds_alternative<WitnessV1Taproot>(dest)) {
1554 if (!
wallet.chain().isTaprootActive()) {
1562 if (keys.
keys.empty()) {
1565 if (!have_all_privkeys) {
1566 warnings.
push_back(
"Not all private keys provided. Some wallet functionality may return unexpected errors");
1570 WalletDescriptor w_desc(std::move(parsed_desc), timestamp, range_start, range_end, next_index);
1573 auto existing_spk_manager =
wallet.GetDescriptorScriptPubKeyMan(w_desc);
1574 if (existing_spk_manager) {
1575 if (!existing_spk_manager->CanUpdateToWalletDescriptor(w_desc,
error)) {
1581 auto spk_manager =
wallet.AddWalletDescriptor(w_desc, keys, label,
internal);
1582 if (spk_manager ==
nullptr) {
1589 warnings.
push_back(
"Unknown output type, cannot set descriptor to active.");
1591 wallet.AddActiveScriptPubKeyMan(spk_manager->GetID(), *w_desc.
descriptor->GetOutputType(),
internal);
1595 wallet.DeactivateScriptPubKeyMan(spk_manager->GetID(), *w_desc.
descriptor->GetOutputType(),
internal);
1602 result.
pushKV(
"error", e);
1604 if (warnings.
size()) result.
pushKV(
"warnings", warnings);
1611 "\nImport descriptors. This will trigger a rescan of the blockchain based on the earliest timestamp of all descriptors being imported. Requires a new wallet backup.\n"
1612 "\nNote: This call can take over an hour to complete if using an early timestamp; during that time, other rpc calls\n"
1613 "may report that the imported keys, addresses or scripts exist but related transactions are still missing.\n",
1624 " Use the string \"now\" to substitute the current synced blockchain time.\n"
1625 " \"now\" can be specified to bypass scanning, for outputs which are known to never have been used, and\n"
1626 " 0 can be specified to scan the entire blockchain. Blocks up to 2 hours before the earliest timestamp\n"
1627 " of all descriptors being imported will be scanned.",
1628 "", {
"timestamp | \"now\"",
"integer / string"}
1638 RPCResult::Type::ARR,
"",
"Response is an array with the same size as the input that has the execution result",
1655 HelpExampleCli(
"importdescriptors",
"'[{ \"desc\": \"<my descriptor>\", \"timestamp\":1455191478, \"internal\": true }, "
1656 "{ \"desc\": \"<my desccriptor 2>\", \"label\": \"example 2\", \"timestamp\": 1455191480 }]'") +
1657 HelpExampleCli(
"importdescriptors",
"'[{ \"desc\": \"<my descriptor>\", \"timestamp\":1455191478, \"active\": true, \"range\": [0,100], \"label\": \"<my bech32 wallet>\" }]'")
1669 RPCTypeCheck(main_request.params, {UniValue::VARR, UniValue::VOBJ});
1676 const UniValue& requests = main_request.params[0];
1677 const int64_t minimum_timestamp = 1;
1679 int64_t lowest_timestamp = 0;
1680 bool rescan =
false;
1683 LOCK(pwallet->cs_wallet);
1686 CHECK_NONFATAL(pwallet->chain().findBlock(pwallet->GetLastBlockHash(),
FoundBlock().time(lowest_timestamp).mtpTime(now)));
1691 const int64_t timestamp = std::max(
GetImportTimestamp(request, now), minimum_timestamp);
1695 if (lowest_timestamp > timestamp ) {
1696 lowest_timestamp = timestamp;
1700 if (!rescan && result[
"success"].get_bool()) {
1704 pwallet->ConnectScriptPubKeyManNotifiers();
1709 int64_t scanned_time = pwallet->RescanFromTime(lowest_timestamp, reserver,
true );
1711 LOCK(pwallet->cs_wallet);
1712 pwallet->ReacceptWalletTransactions();
1715 if (pwallet->IsAbortingRescan()) {
1719 if (scanned_time > lowest_timestamp) {
1720 std::vector<UniValue> results = response.
getValues();
1725 for (
unsigned int i = 0; i < requests.
size(); ++i) {
1732 if (scanned_time <=
GetImportTimestamp(request, now) || results.at(i).exists(
"error")) {
1741 strprintf(
"Rescan failed for descriptor with timestamp %d. There was an error reading a "
1742 "block from time %d, which is after or within %d seconds of key creation, and "
1743 "could contain transactions pertaining to the desc. As a result, transactions "
1744 "and coins using this desc may not appear in the wallet. This error could be "
1745 "caused by pruning or data corruption (see bitcoind log for details) and could "
1746 "be dealt with by downloading and rescanning the relevant blocks (see -reindex "
1747 "option and rescanblockchain RPC).",
1764 "\nList descriptors imported into a descriptor-enabled wallet.\n",
1776 {
RPCResult::Type::BOOL,
"internal",
true,
"Whether this is an internal or external descriptor; defined only for active descriptors"},
1781 {
RPCResult::Type::NUM,
"next",
true,
"The next index to generate addresses from; defined only for ranged descriptors"},
1798 const bool priv = !request.params[0].isNull() && request.params[0].get_bool();
1806 const auto active_spk_mans =
wallet->GetActiveScriptPubKeyMans();
1807 for (
const auto& spk_man :
wallet->GetAllScriptPubKeyMans()) {
1809 if (!desc_spk_man) {
1813 LOCK(desc_spk_man->cs_desc_man);
1814 const auto& wallet_descriptor = desc_spk_man->GetWalletDescriptor();
1815 std::string descriptor;
1817 if (!desc_spk_man->GetDescriptorString(descriptor, priv)) {
1820 spk.
pushKV(
"desc", descriptor);
1821 spk.
pushKV(
"timestamp", wallet_descriptor.creation_time);
1822 const bool active = active_spk_mans.count(desc_spk_man) != 0;
1823 spk.
pushKV(
"active", active);
1824 const auto& type = wallet_descriptor.descriptor->GetOutputType();
1825 if (active && type) {
1826 spk.
pushKV(
"internal",
wallet->GetScriptPubKeyMan(*type,
true) == desc_spk_man);
1828 if (wallet_descriptor.descriptor->IsRange()) {
1830 range.
push_back(wallet_descriptor.range_start);
1831 range.
push_back(wallet_descriptor.range_end - 1);
1832 spk.
pushKV(
"range", range);
1833 spk.
pushKV(
"next", wallet_descriptor.next_index);
1840 response.
pushKV(
"descriptors", descriptors);
std::string WriteHDKeypath(const std::vector< uint32_t > &keypath)
Write HD keypaths as strings.
static constexpr int64_t TIMESTAMP_WINDOW
Timestamp window used as a grace period by code that compares external timestamps (such as timestamps...
#define CHECK_NONFATAL(condition)
Throw a NonFatalCheckError when the condition evaluates to false.
int64_t GetIntArg(const std::string &strArg, int64_t nDefault) const
Return integer argument or default value.
Double ended buffer combining vector and stream-like interfaces.
CKeyID seed_id
seed hash160
An encapsulated private key.
bool IsValid() const
Check whether this private key is valid.
CPubKey GetPubKey() const
Compute the public key from a private key.
bool VerifyPubKey(const CPubKey &vchPubKey) const
Verify thoroughly whether a private key and a public key match.
A reference to a CKey: the Hash160 of its serialized public key.
Used to relay blocks as header + vector<merkle branch> to filtered nodes.
CBlockHeader header
Public only for unit testing.
uint256 ExtractMatches(std::vector< uint256 > &vMatch, std::vector< unsigned int > &vnIndex)
extract the matching txid's represented by this partial merkle tree and their respective indices with...
An encapsulated public key.
bool IsCompressed() const
Check whether this is a compressed public key.
CKeyID GetID() const
Get the KeyID of this public key (hash of its serialization)
bool IsFullyValid() const
fully validate whether this is a valid public key (more expensive than IsValid())
A hasher class for RIPEMD-160.
CRIPEMD160 & Write(const unsigned char *data, size_t len)
void Finalize(unsigned char hash[OUTPUT_SIZE])
Serialized script, used inside transaction inputs and outputs.
A reference to a CScript: the Hash160 of its serialization (see script.h)
A CWallet maintains a set of transactions and balances, and provides the ability to create new transa...
virtual bool GetCScript(const CScriptID &hash, CScript &redeemScriptOut) const override
virtual std::set< CScriptID > GetCScripts() const
RecursiveMutex cs_KeyStore
const CHDChain & GetHDChain() const
bool GetKey(const CKeyID &address, CKey &keyOut) const override
const std::map< CKeyID, int64_t > & GetAllReserveKeys() const
const std::string & get_str() const
enum VType getType() const
int64_t get_int64() const
const std::vector< UniValue > & getValues() const
bool push_back(const UniValue &val)
const UniValue & get_array() const
bool exists(const std::string &key) const
bool pushKV(const std::string &key, const UniValue &val)
Descriptor with some wallet metadata.
std::shared_ptr< Descriptor > descriptor
RAII object to check and reserve a wallet rescan.
static constexpr unsigned int size()
Path class wrapper to prepare application code for transition from boost::filesystem library to std::...
std::string u8string() const
Helper for findBlock to selectively return pieces of block data.
iterator insert(iterator pos, const T &value)
std::string FormatFullVersion()
bool DecodeHexTx(CMutableTransaction &tx, const std::string &hex_tx, bool try_no_witness=false, bool try_witness=true)
std::unique_ptr< Descriptor > Parse(const std::string &descriptor, FlatSigningProvider &out, std::string &error, bool require_checksum)
Parse a descriptor string.
@ WITNESS_V0
Witness v0 (P2WPKH and P2WSH); see BIP 141.
std::string EncodeExtKey(const CExtKey &key)
std::string EncodeSecret(const CKey &key)
std::string EncodeDestination(const CTxDestination &dest)
CKey DecodeSecret(const std::string &str)
CTxDestination DecodeDestination(const std::string &str, std::string &error_msg)
static path u8path(const std::string &string)
static bool exists(const path &p)
CTxDestination GetDestinationForKey(const CPubKey &key, OutputType type)
Get a destination of the requested type (if possible) to the specified key.
std::optional< OutputType > OutputTypeFromDestination(const CTxDestination &dest)
Get the OutputType for a CTxDestination.
std::vector< CTxDestination > GetAllDestinationsForKey(const CPubKey &key)
Get all destinations (potentially) supported by the wallet for the given key.
static CTransactionRef MakeTransactionRef(Tx &&txIn)
std::shared_ptr< const CTransaction > CTransactionRef
UniValue JSONRPCError(int code, const std::string &message)
@ RPC_MISC_ERROR
General application defined errors.
@ RPC_TYPE_ERROR
Unexpected type was passed as parameter.
@ RPC_INVALID_PARAMETER
Invalid, missing or duplicate parameter.
@ RPC_WALLET_ERROR
Wallet errors.
@ RPC_DESERIALIZATION_ERROR
Error parsing or validating structure in raw format.
@ RPC_INVALID_ADDRESS_OR_KEY
Invalid address or key.
std::vector< unsigned char > ParseHexV(const UniValue &v, std::string strName)
void RPCTypeCheck(const UniValue ¶ms, const std::list< UniValueType > &typesExpected, bool fAllowNull)
Type-check arguments; throws JSONRPCError if wrong type given.
std::pair< int64_t, int64_t > ParseDescriptorRange(const UniValue &value)
Parse a JSON range specified as int64, or [int64, int64].
std::string HelpExampleCli(const std::string &methodname, const std::string &args)
std::string HelpExampleRpc(const std::string &methodname, const std::string &args)
const std::string UNIX_EPOCH_TIME
String used to describe UNIX epoch time in documentation, factored out to a constant for consistency.
uint256 ParseHashV(const UniValue &v, std::string strName)
Utilities: convert hex-encoded Values (throws error if not hex).
RPCHelpMan importprivkey()
static const int64_t TIMESTAMP_MIN
RPCHelpMan importdescriptors()
RPCHelpMan listdescriptors()
static void RescanWallet(CWallet &wallet, const WalletRescanReserver &reserver, int64_t time_begin=TIMESTAMP_MIN, bool update=true)
static std::string RecurseImportData(const CScript &script, ImportData &import_data, const ScriptContext script_ctx)
RPCHelpMan importaddress()
static UniValue ProcessImport(CWallet &wallet, const UniValue &data, const int64_t timestamp) EXCLUSIVE_LOCKS_REQUIRED(wallet.cs_wallet)
RPCHelpMan importwallet()
static bool GetWalletAddressesForKey(LegacyScriptPubKeyMan *spk_man, const CWallet &wallet, const CKeyID &keyid, std::string &strAddr, std::string &strLabel) EXCLUSIVE_LOCKS_REQUIRED(wallet.cs_wallet)
RPCHelpMan importpubkey()
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, std::vector< CKeyID > &ordered_pubkeys)
static std::string EncodeDumpString(const std::string &str)
static std::string DecodeDumpString(const std::string &str)
RPCHelpMan importprunedfunds()
static UniValue ProcessImportDescriptor(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, std::vector< CKeyID > &ordered_pubkeys)
@ TOP
Top-level scriptPubKey.
@ WITNESS_V0
P2WSH witnessScript.
static UniValue ProcessDescriptorImport(CWallet &wallet, const UniValue &data, const int64_t timestamp) EXCLUSIVE_LOCKS_REQUIRED(wallet.cs_wallet)
RPCHelpMan removeprunedfunds()
static int64_t GetImportTimestamp(const UniValue &data, int64_t now)
std::shared_ptr< CWallet > GetWalletForJSONRPCRequest(const JSONRPCRequest &request)
Figures out what wallet, if any, to use for a JSONRPCRequest.
void EnsureWalletIsUnlocked(const CWallet &wallet)
LegacyScriptPubKeyMan & EnsureLegacyScriptPubKeyMan(CWallet &wallet, bool also_create)
static const unsigned int DEFAULT_KEYPOOL_SIZE
Default for -keypool.
CKeyID GetKeyForDestination(const SigningProvider &store, const CTxDestination &dest)
Return the CKeyID of the key involved in a script (if there is a unique one).
TxoutType Solver(const CScript &scriptPubKey, std::vector< std::vector< unsigned char > > &vSolutionsRet)
Parse a scriptPubKey and identify script type for standard scripts.
bool ExtractDestination(const CScript &scriptPubKey, CTxDestination &addressRet)
Parse a standard scriptPubKey for the destination address.
bool IsValidDestination(const CTxDestination &dest)
Check whether a CTxDestination is a CNoDestination.
CScript GetScriptForDestination(const CTxDestination &dest)
Generate a Bitcoin scriptPubKey for the given CTxDestination.
@ WITNESS_UNKNOWN
Only for Witness versions not already defined above.
@ NULL_DATA
unspendable OP_RETURN script that carries data
std::variant< CNoDestination, PKHash, ScriptHash, WitnessV0ScriptHash, WitnessV0KeyHash, WitnessV1Taproot, WitnessUnknown > CTxDestination
A txout script template with a specific destination.
std::string HexStr(const Span< const uint8_t > s)
Convert a span of bytes to a lower-case hexadecimal string.
std::vector< unsigned char > ParseHex(const char *psz)
bool IsHex(const std::string &str)
void SetSeed(Span< const uint8_t > seed)
A mutable version of CTransaction.
uint256 GetHash() const
Compute the hash of this CMutableTransaction.
Confirmation includes tx status and a triplet of {block height/block hash/tx index in block} at which...
std::map< CKeyID, std::pair< CPubKey, KeyOriginInfo > > origins
bool GetKey(const CKeyID &keyid, CKey &key) const override
std::map< CKeyID, CPubKey > pubkeys
std::map< CKeyID, CKey > keys
std::map< CScriptID, CScript > scripts
std::unique_ptr< CScript > redeemscript
Provided redeemScript; will be moved to import_scripts if relevant.
std::map< CKeyID, bool > used_keys
Import these private keys if available (the value indicates whether if the key is required for solvab...
std::set< CScript > import_scripts
std::unique_ptr< CScript > witnessscript
Provided witnessScript; will be moved to import_scripts if relevant.
std::map< CKeyID, std::pair< CPubKey, KeyOriginInfo > > key_origins
@ RANGE
Special type that is a NUM or [NUM,NUM].
@ STR_HEX
Special type that is a STR with only hex chars.
@ OMITTED_NAMED_ARG
Optional arg that is a named argument and has a default value of null.
@ OMITTED
Optional argument with default value omitted because they are implicitly clear.
@ ELISION
Special type to denote elision (...)
@ ARR_FIXED
Special array that has a fixed number of entries.
bool error(const char *fmt, const Args &... args)
#define EXCLUSIVE_LOCKS_REQUIRED(...)
int64_t ParseISO8601DateTime(const std::string &str)
int64_t GetTime()
DEPRECATED Use either GetTimeSeconds (not mockable) or GetTime<T> (mockable)
std::string FormatISO8601DateTime(int64_t nTime)
ISO 8601 formatting is preferred.
bilingual_str _(const char *psz)
Translation function.
const UniValue NullUniValue
const char * uvTypeName(UniValue::VType t)
static const int PROTOCOL_VERSION
network protocol versioning
@ WALLET_FLAG_DISABLE_PRIVATE_KEYS
@ WALLET_FLAG_DESCRIPTORS
Indicate that this wallet supports DescriptorScriptPubKeyMan.