29 #include <boost/algorithm/string.hpp>
39 std::stringstream ret;
40 for (
const unsigned char c : str) {
41 if (c <= 32 || c >= 128 || c ==
'%') {
42 ret <<
'%' <<
HexStr({&c, 1});
51 std::stringstream ret;
52 for (
unsigned int pos = 0; pos < str.length(); pos++) {
53 unsigned char c = str[pos];
54 if (c ==
'%' && pos+2 < str.length()) {
55 c = (((str[pos+1]>>6)*9+((str[pos+1]-
'0')&15)) << 4) |
56 ((str[pos+2]>>6)*9+((str[pos+2]-
'0')&15));
66 bool fLabelFound =
false;
68 spk_man->GetKey(keyid, key);
70 const auto* address_book_entry =
wallet.FindAddressBookEntry(dest);
71 if (address_book_entry) {
72 if (!strAddr.empty()) {
90 int64_t scanned_time =
wallet.RescanFromTime(time_begin, reserver, update);
91 if (
wallet.IsAbortingRescan()) {
93 }
else if (scanned_time > time_begin) {
101 "\nAdds a private key (as returned by dumpprivkey) to your wallet. Requires a new wallet backup.\n"
102 "Hint: use importmulti to import more than one private key.\n"
103 "\nNote: This call can take over an hour to complete if rescan is true, during that time, other rpc calls\n"
104 "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"
105 "Note: Use \"getwalletinfo\" to query the scanning progress.\n",
113 "\nDump a private key\n"
115 "\nImport the private key with rescan\n"
117 "\nImport using a label and without rescan\n"
118 +
HelpExampleCli(
"importprivkey",
"\"mykey\" \"testing\" false") +
119 "\nImport using default blank label and without rescan\n"
121 "\nAs a JSON-RPC call\n"
122 +
HelpExampleRpc(
"importprivkey",
"\"mykey\", \"testing\", false")
138 LOCK(pwallet->cs_wallet);
142 std::string strSecret = request.params[0].get_str();
143 std::string strLabel =
"";
144 if (!request.params[1].isNull())
145 strLabel = request.params[1].get_str();
148 if (!request.params[2].isNull())
149 fRescan = request.params[2].get_bool();
151 if (fRescan && pwallet->chain().havePruned()) {
158 if (fRescan && !reserver.
reserve()) {
169 pwallet->MarkDirty();
175 if (!request.params[1].isNull() || !pwallet->FindAddressBookEntry(dest)) {
176 pwallet->SetAddressBook(dest, strLabel,
"receive");
181 if (!pwallet->ImportPrivKeys({{vchAddress, key}}, 1)) {
203 "\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"
204 "\nNote: This call can take over an hour to complete if rescan is true, during that time, other rpc calls\n"
205 "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"
206 "If you have the full public key, you should call importpubkey instead of this.\n"
207 "Hint: use importmulti to import more than one address.\n"
208 "\nNote: If you import a non-standard raw script in hex form, outputs sending to it will be treated\n"
209 "as change, and not show up in many RPCs.\n"
210 "Note: Use \"getwalletinfo\" to query the scanning progress.\n",
219 "\nImport an address with rescan\n"
221 "\nImport using a label without rescan\n"
222 +
HelpExampleCli(
"importaddress",
"\"myaddress\" \"testing\" false") +
223 "\nAs a JSON-RPC call\n"
224 +
HelpExampleRpc(
"importaddress",
"\"myaddress\", \"testing\", false")
233 std::string strLabel;
234 if (!request.params[1].isNull())
235 strLabel = request.params[1].get_str();
239 if (!request.params[2].isNull())
240 fRescan = request.params[2].get_bool();
242 if (fRescan && pwallet->chain().havePruned()) {
250 if (fRescan && !reserver.
reserve()) {
256 if (!request.params[3].isNull())
257 fP2SH = request.params[3].get_bool();
260 LOCK(pwallet->cs_wallet);
271 pwallet->MarkDirty();
274 }
else if (
IsHex(request.params[0].get_str())) {
275 std::vector<unsigned char> data(
ParseHex(request.params[0].get_str()));
276 CScript redeem_script(data.begin(), data.end());
278 std::set<CScript> scripts = {redeem_script};
279 pwallet->ImportScripts(scripts, 0 );
285 pwallet->ImportScriptPubKeys(strLabel, scripts,
false ,
true , 1 );
294 LOCK(pwallet->cs_wallet);
295 pwallet->ReacceptWalletTransactions();
307 "\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",
320 if (!
DecodeHexTx(tx, request.params[0].get_str())) {
330 std::vector<uint256> vMatch;
331 std::vector<unsigned int> vIndex;
332 if (merkleBlock.txn.ExtractMatches(vMatch, vIndex) != merkleBlock.header.hashMerkleRoot) {
336 LOCK(pwallet->cs_wallet);
338 if (!pwallet->chain().findAncestorByHash(pwallet->GetLastBlockHash(), merkleBlock.header.GetHash(),
FoundBlock().height(height))) {
342 std::vector<uint256>::const_iterator it;
343 if ((it = std::find(vMatch.begin(), vMatch.end(), hashTx)) == vMatch.end()) {
347 unsigned int txnIndex = vIndex[it - vMatch.begin()];
350 if (pwallet->IsMine(*tx_ref)) {
351 pwallet->AddToWallet(std::move(tx_ref),
TxStateConfirmed{merkleBlock.header.GetHash(), height,
static_cast<int>(txnIndex)});
363 "\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",
369 HelpExampleCli(
"removeprunedfunds",
"\"a8d0c0184dde994a09ec054286f1ce581bebf46446a512166eae7628734ea0a5\"") +
370 "\nAs a JSON-RPC call\n"
371 +
HelpExampleRpc(
"removeprunedfunds",
"\"a8d0c0184dde994a09ec054286f1ce581bebf46446a512166eae7628734ea0a5\"")
378 LOCK(pwallet->cs_wallet);
381 std::vector<uint256> vHash;
382 vHash.push_back(hash);
383 std::vector<uint256> vHashOut;
385 if (pwallet->ZapSelectTx(vHash, vHashOut) != DBErrors::LOAD_OK) {
389 if(vHashOut.empty()) {
401 "\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"
402 "Hint: use importmulti to import more than one public key.\n"
403 "\nNote: This call can take over an hour to complete if rescan is true, during that time, other rpc calls\n"
404 "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"
405 "Note: Use \"getwalletinfo\" to query the scanning progress.\n",
413 "\nImport a public key with rescan\n"
415 "\nImport using a label without rescan\n"
416 +
HelpExampleCli(
"importpubkey",
"\"mypubkey\" \"testing\" false") +
417 "\nAs a JSON-RPC call\n"
418 +
HelpExampleRpc(
"importpubkey",
"\"mypubkey\", \"testing\", false")
427 std::string strLabel;
428 if (!request.params[1].isNull())
429 strLabel = request.params[1].get_str();
433 if (!request.params[2].isNull())
434 fRescan = request.params[2].get_bool();
436 if (fRescan && pwallet->chain().havePruned()) {
444 if (fRescan && !reserver.
reserve()) {
448 if (!
IsHex(request.params[0].get_str()))
450 std::vector<unsigned char> data(
ParseHex(request.params[0].get_str()));
456 LOCK(pwallet->cs_wallet);
458 std::set<CScript> script_pub_keys;
463 pwallet->MarkDirty();
465 pwallet->ImportScriptPubKeys(strLabel, script_pub_keys,
true ,
true , 1 );
467 pwallet->ImportPubKeys({pubKey.
GetID()}, {{pubKey.
GetID(), pubKey}} , {} ,
false ,
false , 1 );
473 LOCK(pwallet->cs_wallet);
474 pwallet->ReacceptWalletTransactions();
487 "\nImports keys from a wallet dump file (see dumpwallet). Requires a new wallet backup to include imported keys.\n"
488 "Note: Use \"getwalletinfo\" to query the scanning progress.\n",
494 "\nDump the wallet\n"
496 "\nImport the wallet\n"
498 "\nImport using the json rpc call\n"
508 if (pwallet->chain().havePruned()) {
520 int64_t nTimeBegin = 0;
523 LOCK(pwallet->cs_wallet);
528 file.open(fs::u8path(request.params[0].get_str()), std::ios::in | std::ios::ate);
529 if (!file.is_open()) {
534 int64_t nFilesize = std::max((int64_t)1, (int64_t)file.tellg());
535 file.seekg(0, file.beg);
539 pwallet->chain().showProgress(
strprintf(
"%s " +
_(
"Importing…").translated, pwallet->GetDisplayName()), 0,
false);
540 std::vector<std::tuple<CKey, int64_t, bool, std::string>> keys;
541 std::vector<std::pair<CScript, int64_t>> scripts;
542 while (file.good()) {
543 pwallet->chain().showProgress(
"", std::max(1, std::min(50, (
int)(((
double)file.tellg() / (
double)nFilesize) * 100))),
false);
545 std::getline(file, line);
546 if (line.empty() || line[0] ==
'#')
549 std::vector<std::string> vstr;
550 boost::split(vstr, line, boost::is_any_of(
" "));
556 std::string strLabel;
558 for (
unsigned int nStr = 2; nStr < vstr.size(); nStr++) {
559 if (vstr[nStr].front() ==
'#')
561 if (vstr[nStr] ==
"change=1")
563 if (vstr[nStr] ==
"reserve=1")
565 if (vstr[nStr].substr(0,6) ==
"label=") {
570 keys.push_back(std::make_tuple(key, nTime, fLabel, strLabel));
571 }
else if(
IsHex(vstr[0])) {
572 std::vector<unsigned char> vData(
ParseHex(vstr[0]));
575 scripts.push_back(std::pair<CScript, int64_t>(script, birth_time));
581 pwallet->chain().showProgress(
"", 100,
false);
584 double total = (double)(keys.size() + scripts.size());
586 for (
const auto& key_tuple : keys) {
587 pwallet->chain().showProgress(
"", std::max(50, std::min(75, (
int)((progress / total) * 100) + 50)),
false);
588 const CKey& key = std::get<0>(key_tuple);
589 int64_t time = std::get<1>(key_tuple);
590 bool has_label = std::get<2>(key_tuple);
591 std::string label = std::get<3>(key_tuple);
599 if (!pwallet->ImportPrivKeys({{keyid, key}}, time)) {
606 pwallet->SetAddressBook(
PKHash(keyid), label,
"receive");
608 nTimeBegin = std::min(nTimeBegin, time);
611 for (
const auto& script_pair : scripts) {
612 pwallet->chain().showProgress(
"", std::max(50, std::min(75, (
int)((progress / total) * 100) + 50)),
false);
613 const CScript& script = script_pair.first;
614 int64_t time = script_pair.second;
616 if (!pwallet->ImportScripts({script}, time)) {
617 pwallet->WalletLogPrintf(
"Error importing script %s\n",
HexStr(script));
622 nTimeBegin = std::min(nTimeBegin, time);
627 pwallet->chain().showProgress(
"", 100,
false);
629 pwallet->chain().showProgress(
"", 100,
false);
631 pwallet->MarkDirty();
644 "\nReveals the private key corresponding to 'address'.\n"
645 "Then the importprivkey can be used with this output\n",
668 std::string strAddress = request.params[0].get_str();
674 if (keyid.IsNull()) {
678 if (!spk_man.
GetKey(keyid, vchSecret)) {
690 "\nDumps all wallet keys in a human-readable format to a server-side file. This does not allow overwriting existing files.\n"
691 "Imported scripts are included in the dumpfile, but corresponding BIP173 addresses, etc. may not be added automatically by importwallet.\n"
692 "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"
693 "only backing up the seed itself, and must be backed up too (e.g. ensure you back up the whole dumpfile).\n",
717 wallet.BlockUntilSyncedToCurrentChain();
723 fs::path filepath = fs::u8path(request.params[0].get_str());
740 std::map<CKeyID, int64_t> mapKeyBirth;
741 wallet.GetKeyBirthTimes(mapKeyBirth);
743 int64_t block_time = 0;
751 std::set<CScriptID> scripts = spk_man.
GetCScripts();
754 std::vector<std::pair<int64_t, CKeyID> > vKeyBirth;
755 for (
const auto& entry : mapKeyBirth) {
756 vKeyBirth.push_back(std::make_pair(entry.second, entry.first));
759 std::sort(vKeyBirth.begin(), vKeyBirth.end());
764 file <<
strprintf(
"# * Best block at time of backup was %i (%s),\n",
wallet.GetLastBlockHeight(),
wallet.GetLastBlockHash().ToString());
773 if (spk_man.
GetKey(seed_id, seed)) {
777 file <<
"# extended private masterkey: " <<
EncodeExtKey(masterKey) <<
"\n\n";
780 for (std::vector<std::pair<int64_t, CKeyID> >::const_iterator it = vKeyBirth.begin(); it != vKeyBirth.end(); it++) {
781 const CKeyID &keyid = it->second;
784 std::string strLabel;
786 if (spk_man.
GetKey(keyid, key)) {
788 const auto it{spk_man.mapKeyMetadata.find(keyid)};
789 if (it != spk_man.mapKeyMetadata.end()) metadata = it->second;
793 }
else if (keyid == seed_id) {
795 }
else if (mapKeyPool.count(keyid)) {
798 file <<
"inactivehdseed=1";
806 for (
const CScriptID &scriptid : scripts) {
808 std::string create_time =
"0";
811 auto it = spk_man.m_script_metadata.find(scriptid);
812 if (it != spk_man.m_script_metadata.end()) {
817 file <<
strprintf(
" # addr=%s\n", address);
821 file <<
"# End of dump\n";
825 reply.
pushKV(
"filename", filepath.u8string());
856 std::vector<std::vector<unsigned char>> solverdata;
859 switch (script_type) {
876 if (!subscript)
return "missing redeemscript";
877 if (
CScriptID(*subscript) !=
id)
return "redeemScript does not match the scriptPubKey";
882 for (
size_t i = 1; i + 1< solverdata.size(); ++i) {
894 if (!subscript)
return "missing witnessscript";
895 if (
CScriptID(*subscript) !=
id)
return "witnessScript does not match the scriptPubKey or redeemScript";
896 if (script_ctx == ScriptContext::TOP) {
906 if (script_ctx == ScriptContext::TOP) {
912 return "unspendable script";
916 return "unrecognized script";
921 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)
926 const UniValue& scriptPubKey = data[
"scriptPubKey"];
931 const std::string& output = isScript ? scriptPubKey.
get_str() : scriptPubKey[
"address"].
get_str();
934 const std::string& strRedeemScript = data.
exists(
"redeemscript") ? data[
"redeemscript"].
get_str() :
"";
935 const std::string& witness_script_hex = data.
exists(
"witnessscript") ? data[
"witnessscript"].
get_str() :
"";
938 const bool internal = data.
exists(
"internal") ? data[
"internal"].
get_bool() :
false;
939 const bool watchOnly = data.
exists(
"watchonly") ? data[
"watchonly"].
get_bool() :
false;
941 if (data.
exists(
"range")) {
957 if (!
IsHex(output)) {
960 std::vector<unsigned char> vData(
ParseHex(output));
961 script =
CScript(vData.begin(), vData.end());
967 script_pub_keys.emplace(script);
970 if (strRedeemScript.size()) {
971 if (!
IsHex(strRedeemScript)) {
974 auto parsed_redeemscript =
ParseHex(strRedeemScript);
975 import_data.
redeemscript = std::make_unique<CScript>(parsed_redeemscript.begin(), parsed_redeemscript.end());
977 if (witness_script_hex.size()) {
978 if (!
IsHex(witness_script_hex)) {
981 auto parsed_witnessscript =
ParseHex(witness_script_hex);
982 import_data.
witnessscript = std::make_unique<CScript>(parsed_witnessscript.begin(), parsed_witnessscript.end());
984 for (
size_t i = 0; i < pubKeys.
size(); ++i) {
985 const auto& str = pubKeys[i].
get_str();
994 pubkey_map.emplace(pubkey.
GetID(), pubkey);
995 ordered_pubkeys.push_back(pubkey.
GetID());
997 for (
size_t i = 0; i < keys.
size(); ++i) {
998 const auto& str = keys[i].
get_str();
1005 if (pubkey_map.count(
id)) {
1006 pubkey_map.erase(
id);
1008 privkey_map.emplace(
id, key);
1014 if (have_solving_data) {
1019 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; });
1020 if (!watchOnly && !spendable) {
1021 warnings.
push_back(
"Some private keys are missing, outputs will be considered watchonly. If this is intentional, specify the watchonly flag.");
1023 if (watchOnly && spendable) {
1024 warnings.
push_back(
"All private keys are provided, outputs will be considered spendable. If this is intentional, do not specify the watchonly flag.");
1028 if (
error.empty()) {
1029 for (
const auto& require_key : import_data.
used_keys) {
1030 if (!require_key.second)
continue;
1031 if (pubkey_map.count(require_key.first) == 0 && privkey_map.count(require_key.first) == 0) {
1032 error =
"some required keys are missing";
1037 if (!
error.empty()) {
1038 warnings.
push_back(
"Importing as non-solvable: " +
error +
". If this is intentional, don't provide any keys, pubkeys, witnessscript, or redeemscript.");
1041 privkey_map.clear();
1042 have_solving_data =
false;
1045 if (import_data.
redeemscript) warnings.
push_back(
"Ignoring redeemscript as this is not a P2SH script.");
1046 if (import_data.
witnessscript) warnings.
push_back(
"Ignoring witnessscript as this is not a (P2SH-)P2WSH script.");
1047 for (
auto it = privkey_map.begin(); it != privkey_map.end(); ) {
1049 if (import_data.
used_keys.count(oldit->first) == 0) {
1050 warnings.
push_back(
"Ignoring irrelevant private key.");
1051 privkey_map.erase(oldit);
1054 for (
auto it = pubkey_map.begin(); it != pubkey_map.end(); ) {
1056 auto key_data_it = import_data.
used_keys.find(oldit->first);
1057 if (key_data_it == import_data.
used_keys.end() || !key_data_it->second) {
1058 warnings.
push_back(
"Ignoring public key \"" +
HexStr(oldit->first) +
"\" as it doesn't appear inside P2PKH or P2WPKH.");
1059 pubkey_map.erase(oldit);
1068 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)
1072 const std::string& descriptor = data[
"desc"].
get_str();
1075 auto parsed_desc =
Parse(descriptor, keys,
error,
true);
1083 have_solving_data = parsed_desc->IsSolvable();
1084 const bool watch_only = data.
exists(
"watchonly") ? data[
"watchonly"].
get_bool() :
false;
1086 int64_t range_start = 0, range_end = 0;
1087 if (!parsed_desc->IsRange() && data.
exists(
"range")) {
1089 }
else if (parsed_desc->IsRange()) {
1090 if (!data.
exists(
"range")) {
1099 for (
int i = range_start; i <= range_end; ++i) {
1101 std::vector<CScript> scripts_temp;
1102 parsed_desc->Expand(i, keys, scripts_temp, out_keys);
1103 std::copy(scripts_temp.begin(), scripts_temp.end(), std::inserter(script_pub_keys, script_pub_keys.end()));
1104 for (
const auto& key_pair : out_keys.
pubkeys) {
1105 ordered_pubkeys.push_back(key_pair.first);
1108 for (
const auto& x : out_keys.
scripts) {
1112 parsed_desc->ExpandPrivate(i, keys, out_keys);
1114 std::copy(out_keys.
pubkeys.begin(), out_keys.
pubkeys.end(), std::inserter(pubkey_map, pubkey_map.end()));
1115 std::copy(out_keys.
keys.begin(), out_keys.
keys.end(), std::inserter(privkey_map, privkey_map.end()));
1119 for (
size_t i = 0; i < priv_keys.
size(); ++i) {
1120 const auto& str = priv_keys[i].
get_str();
1129 if (!pubkey_map.count(
id)) {
1130 warnings.
push_back(
"Ignoring irrelevant private key.");
1132 privkey_map.emplace(
id, key);
1140 bool spendable = std::all_of(pubkey_map.begin(), pubkey_map.end(),
1141 [&](
const std::pair<CKeyID, CPubKey>& used_key) {
1142 return privkey_map.count(used_key.first) > 0;
1144 [&](
const std::pair<
CKeyID, std::pair<CPubKey, KeyOriginInfo>>& entry) {
1145 return privkey_map.count(entry.first) > 0;
1147 if (!watch_only && !spendable) {
1148 warnings.
push_back(
"Some private keys are missing, outputs will be considered watchonly. If this is intentional, specify the watchonly flag.");
1150 if (watch_only && spendable) {
1151 warnings.
push_back(
"All private keys are provided, outputs will be considered spendable. If this is intentional, do not specify the watchonly flag.");
1163 const bool internal = data.exists(
"internal") ? data[
"internal"].get_bool() :
false;
1165 if (
internal && data.exists(
"label")) {
1168 const std::string& label = data.exists(
"label") ? data[
"label"].get_str() :
"";
1169 const bool add_keypool = data.exists(
"keypool") ? data[
"keypool"].get_bool() :
false;
1177 std::map<CKeyID, CPubKey> pubkey_map;
1178 std::map<CKeyID, CKey> privkey_map;
1179 std::set<CScript> script_pub_keys;
1180 std::vector<CKeyID> ordered_pubkeys;
1181 bool have_solving_data;
1183 if (data.exists(
"scriptPubKey") && data.exists(
"desc")) {
1185 }
else if (data.exists(
"scriptPubKey")) {
1186 warnings =
ProcessImportLegacy(import_data, pubkey_map, privkey_map, script_pub_keys, have_solving_data, data, ordered_pubkeys);
1187 }
else if (data.exists(
"desc")) {
1188 warnings =
ProcessImportDescriptor(import_data, pubkey_map, privkey_map, script_pub_keys, have_solving_data, data, ordered_pubkeys);
1199 for (
const CScript& script : script_pub_keys) {
1210 if (!
wallet.ImportPrivKeys(privkey_map, timestamp)) {
1213 if (!
wallet.ImportPubKeys(ordered_pubkeys, pubkey_map, import_data.
key_origins, add_keypool,
internal, timestamp)) {
1216 if (!
wallet.ImportScriptPubKeys(label, script_pub_keys, have_solving_data, !
internal, timestamp)) {
1223 result.
pushKV(
"error", e);
1229 if (warnings.
size()) result.
pushKV(
"warnings", warnings);
1235 if (data.
exists(
"timestamp")) {
1236 const UniValue& timestamp = data[
"timestamp"];
1237 if (timestamp.
isNum()) {
1239 }
else if (timestamp.
isStr() && timestamp.
get_str() ==
"now") {
1250 "\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"
1251 "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"
1252 "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"
1253 "\nNote: This call can take over an hour to complete if rescan is true, during that time, other rpc calls\n"
1254 "may report that the imported keys, addresses or scripts exist but related transactions are still missing.\n"
1255 "Note: Use \"getwalletinfo\" to query the scanning progress.\n",
1263 "", {
"\"<script>\" | { \"address\":\"<address>\" }",
"string / json"}
1266 " or the string \"now\" to substitute the current synced blockchain time. The timestamp of the oldest\n"
1267 " key will determine how far back blockchain rescans need to begin for missing wallet transactions.\n"
1268 " \"now\" can be specified to bypass scanning, for keys which are known to never have been used, and\n"
1269 " 0 can be specified to scan the entire blockchain. Blocks up to 2 hours before the earliest key\n"
1270 " creation time of all keys being imported by the importmulti call will be scanned.",
1271 "", {
"timestamp | \"now\"",
"integer / string"}
1275 {
"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).",
1289 {
"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"},
1301 RPCResult::Type::ARR,
"",
"Response is an array with the same size as the input that has the execution result",
1318 HelpExampleCli(
"importmulti",
"'[{ \"scriptPubKey\": { \"address\": \"<my address>\" }, \"timestamp\":1455191478 }, "
1319 "{ \"scriptPubKey\": { \"address\": \"<my 2nd address>\" }, \"label\": \"example 2\", \"timestamp\": 1455191480 }]'") +
1320 HelpExampleCli(
"importmulti",
"'[{ \"scriptPubKey\": { \"address\": \"<my address>\" }, \"timestamp\":1455191478 }]' '{ \"rescan\": false}'")
1330 wallet.BlockUntilSyncedToCurrentChain();
1332 RPCTypeCheck(mainRequest.params, {UniValue::VARR, UniValue::VOBJ});
1336 const UniValue& requests = mainRequest.params[0];
1339 bool fRescan =
true;
1341 if (!mainRequest.params[1].isNull()) {
1342 const UniValue& options = mainRequest.params[1];
1344 if (options.
exists(
"rescan")) {
1345 fRescan = options[
"rescan"].
get_bool();
1350 if (fRescan && !reserver.
reserve()) {
1355 bool fRunScan =
false;
1356 int64_t nLowestTimestamp = 0;
1359 LOCK(pwallet->cs_wallet);
1363 CHECK_NONFATAL(pwallet->chain().findBlock(pwallet->GetLastBlockHash(),
FoundBlock().time(nLowestTimestamp).mtpTime(now)));
1368 const int64_t minimumTimestamp = 1;
1380 if (result[
"success"].get_bool()) {
1385 if (timestamp < nLowestTimestamp) {
1386 nLowestTimestamp = timestamp;
1390 if (fRescan && fRunScan && requests.
size()) {
1391 int64_t scannedTime = pwallet->RescanFromTime(nLowestTimestamp, reserver,
true );
1393 LOCK(pwallet->cs_wallet);
1394 pwallet->ReacceptWalletTransactions();
1397 if (pwallet->IsAbortingRescan()) {
1400 if (scannedTime > nLowestTimestamp) {
1401 std::vector<UniValue> results = response.
getValues();
1410 if (scannedTime <=
GetImportTimestamp(request, now) || results.at(i).exists(
"error")) {
1419 strprintf(
"Rescan failed for key with creation timestamp %d. There was an error reading a "
1420 "block from time %d, which is after or within %d seconds of key creation, and "
1421 "could contain transactions pertaining to the key. As a result, transactions "
1422 "and coins using this key may not appear in the wallet. This error could be "
1423 "caused by pruning or data corruption (see bitcoind log for details) and could "
1424 "be dealt with by downloading and rescanning the relevant blocks (see -reindex "
1425 "option and rescanblockchain RPC).",
1445 if (!data.exists(
"desc")) {
1449 const std::string& descriptor = data[
"desc"].get_str();
1450 const bool active = data.exists(
"active") ? data[
"active"].get_bool() :
false;
1451 const bool internal = data.exists(
"internal") ? data[
"internal"].get_bool() :
false;
1452 const std::string& label = data.exists(
"label") ? data[
"label"].get_str() :
"";
1457 auto parsed_desc =
Parse(descriptor, keys,
error,
true);
1463 int64_t range_start = 0, range_end = 1, next_index = 0;
1464 if (!parsed_desc->IsRange() && data.exists(
"range")) {
1466 }
else if (parsed_desc->IsRange()) {
1467 if (data.exists(
"range")) {
1469 range_start = range.first;
1470 range_end = range.second + 1;
1472 warnings.
push_back(
"Range not given, using default keypool range");
1476 next_index = range_start;
1478 if (data.exists(
"next_index")) {
1479 next_index = data[
"next_index"].get_int64();
1481 if (next_index < range_start || next_index >= range_end) {
1488 if (active && !parsed_desc->IsRange()) {
1493 if (data.exists(
"range") && data.exists(
"label")) {
1498 if (
internal && data.exists(
"label")) {
1503 if (active && !parsed_desc->IsSingleType()) {
1514 std::vector<CScript> scripts;
1515 if (!parsed_desc->Expand(0, keys, scripts, expand_keys)) {
1516 throw JSONRPCError(
RPC_WALLET_ERROR,
"Cannot expand descriptor. Probably because of hardened derivations without private keys provided");
1518 parsed_desc->ExpandPrivate(0, keys, expand_keys);
1521 bool have_all_privkeys = !expand_keys.
keys.empty();
1522 for (
const auto& entry : expand_keys.
origins) {
1523 const CKeyID& key_id = entry.first;
1525 if (!expand_keys.
GetKey(key_id, key)) {
1526 have_all_privkeys =
false;
1533 if (keys.
keys.empty()) {
1536 if (!have_all_privkeys) {
1537 warnings.
push_back(
"Not all private keys provided. Some wallet functionality may return unexpected errors");
1541 WalletDescriptor w_desc(std::move(parsed_desc), timestamp, range_start, range_end, next_index);
1544 auto existing_spk_manager =
wallet.GetDescriptorScriptPubKeyMan(w_desc);
1545 if (existing_spk_manager) {
1546 if (!existing_spk_manager->CanUpdateToWalletDescriptor(w_desc,
error)) {
1552 auto spk_manager =
wallet.AddWalletDescriptor(w_desc, keys, label,
internal);
1553 if (spk_manager ==
nullptr) {
1560 warnings.
push_back(
"Unknown output type, cannot set descriptor to active.");
1562 wallet.AddActiveScriptPubKeyMan(spk_manager->GetID(), *w_desc.
descriptor->GetOutputType(),
internal);
1566 wallet.DeactivateScriptPubKeyMan(spk_manager->GetID(), *w_desc.
descriptor->GetOutputType(),
internal);
1573 result.
pushKV(
"error", e);
1575 if (warnings.
size()) result.
pushKV(
"warnings", warnings);
1582 "\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"
1583 "\nNote: This call can take over an hour to complete if using an early timestamp; during that time, other rpc calls\n"
1584 "may report that the imported keys, addresses or scripts exist but related transactions are still missing.\n",
1595 " Use the string \"now\" to substitute the current synced blockchain time.\n"
1596 " \"now\" can be specified to bypass scanning, for outputs which are known to never have been used, and\n"
1597 " 0 can be specified to scan the entire blockchain. Blocks up to 2 hours before the earliest timestamp\n"
1598 " of all descriptors being imported will be scanned.",
1599 "", {
"timestamp | \"now\"",
"integer / string"}
1609 RPCResult::Type::ARR,
"",
"Response is an array with the same size as the input that has the execution result",
1626 HelpExampleCli(
"importdescriptors",
"'[{ \"desc\": \"<my descriptor>\", \"timestamp\":1455191478, \"internal\": true }, "
1627 "{ \"desc\": \"<my desccriptor 2>\", \"label\": \"example 2\", \"timestamp\": 1455191480 }]'") +
1628 HelpExampleCli(
"importdescriptors",
"'[{ \"desc\": \"<my descriptor>\", \"timestamp\":1455191478, \"active\": true, \"range\": [0,100], \"label\": \"<my bech32 wallet>\" }]'")
1638 wallet.BlockUntilSyncedToCurrentChain();
1645 RPCTypeCheck(main_request.params, {UniValue::VARR, UniValue::VOBJ});
1652 const UniValue& requests = main_request.params[0];
1653 const int64_t minimum_timestamp = 1;
1655 int64_t lowest_timestamp = 0;
1656 bool rescan =
false;
1659 LOCK(pwallet->cs_wallet);
1662 CHECK_NONFATAL(pwallet->chain().findBlock(pwallet->GetLastBlockHash(),
FoundBlock().time(lowest_timestamp).mtpTime(now)));
1667 const int64_t timestamp = std::max(
GetImportTimestamp(request, now), minimum_timestamp);
1671 if (lowest_timestamp > timestamp ) {
1672 lowest_timestamp = timestamp;
1676 if (!rescan && result[
"success"].get_bool()) {
1680 pwallet->ConnectScriptPubKeyManNotifiers();
1685 int64_t scanned_time = pwallet->RescanFromTime(lowest_timestamp, reserver,
true );
1687 LOCK(pwallet->cs_wallet);
1688 pwallet->ReacceptWalletTransactions();
1691 if (pwallet->IsAbortingRescan()) {
1695 if (scanned_time > lowest_timestamp) {
1696 std::vector<UniValue> results = response.
getValues();
1701 for (
unsigned int i = 0; i < requests.
size(); ++i) {
1708 if (scanned_time <=
GetImportTimestamp(request, now) || results.at(i).exists(
"error")) {
1717 strprintf(
"Rescan failed for descriptor with timestamp %d. There was an error reading a "
1718 "block from time %d, which is after or within %d seconds of key creation, and "
1719 "could contain transactions pertaining to the desc. As a result, transactions "
1720 "and coins using this desc may not appear in the wallet. This error could be "
1721 "caused by pruning or data corruption (see bitcoind log for details) and could "
1722 "be dealt with by downloading and rescanning the relevant blocks (see -reindex "
1723 "option and rescanblockchain RPC).",
1740 "\nList descriptors imported into a descriptor-enabled wallet.\n",
1752 {
RPCResult::Type::BOOL,
"internal",
true,
"Whether this is an internal or external descriptor; defined only for active descriptors"},
1757 {
RPCResult::Type::NUM,
"next",
true,
"The next index to generate addresses from; defined only for ranged descriptors"},
1774 const bool priv = !request.params[0].isNull() && request.params[0].get_bool();
1782 const auto active_spk_mans =
wallet->GetActiveScriptPubKeyMans();
1783 for (
const auto& spk_man :
wallet->GetAllScriptPubKeyMans()) {
1785 if (!desc_spk_man) {
1789 LOCK(desc_spk_man->cs_desc_man);
1790 const auto& wallet_descriptor = desc_spk_man->GetWalletDescriptor();
1791 std::string descriptor;
1793 if (!desc_spk_man->GetDescriptorString(descriptor, priv)) {
1796 spk.
pushKV(
"desc", descriptor);
1797 spk.
pushKV(
"timestamp", wallet_descriptor.creation_time);
1798 spk.
pushKV(
"active", active_spk_mans.count(desc_spk_man) != 0);
1799 const auto internal =
wallet->IsInternalScriptPubKeyMan(desc_spk_man);
1800 if (
internal.has_value()) {
1801 spk.
pushKV(
"internal", *
internal);
1803 if (wallet_descriptor.descriptor->IsRange()) {
1805 range.
push_back(wallet_descriptor.range_start);
1806 range.
push_back(wallet_descriptor.range_end - 1);
1807 spk.
pushKV(
"range", range);
1808 spk.
pushKV(
"next", wallet_descriptor.next_index);
1815 response.
pushKV(
"descriptors", descriptors);
1825 "\nSafely copies current wallet file to destination, which can be a directory or a path with filename.\n",
1841 pwallet->BlockUntilSyncedToCurrentChain();
1843 LOCK(pwallet->cs_wallet);
1845 std::string strDest = request.params[0].get_str();
1846 if (!pwallet->BackupWallet(strDest)) {
1860 "\nRestore and loads a wallet from backup.\n",
1874 HelpExampleCli(
"restorewallet",
"\"testwallet\" \"home\\backups\\backup-file.bak\"")
1875 +
HelpExampleRpc(
"restorewallet",
"\"testwallet\" \"home\\backups\\backup-file.bak\"")
1876 +
HelpExampleCliNamed(
"restorewallet", {{
"wallet_name",
"testwallet"}, {
"backup_file",
"home\\backups\\backup-file.bak\""}, {
"load_on_startup",
true}})
1877 +
HelpExampleRpcNamed(
"restorewallet", {{
"wallet_name",
"testwallet"}, {
"backup_file",
"home\\backups\\backup-file.bak\""}, {
"load_on_startup",
true}})
1884 auto backup_file = fs::u8path(request.params[1].get_str());
1886 std::string wallet_name = request.params[0].get_str();
1888 std::optional<bool> load_on_start = request.params[2].isNull() ? std::nullopt : std::optional<bool>(request.params[2].get_bool());
1892 std::vector<bilingual_str> warnings;