25 #include <boost/algorithm/string.hpp> 34 std::stringstream ret;
35 for (
const unsigned char c : str) {
36 if (c <= 32 || c >= 128 || c ==
'%') {
37 ret << '%' << HexStr(Span<const unsigned char>(&c, 1));
46 std::stringstream ret;
47 for (
unsigned int pos = 0; pos < str.length(); pos++) {
48 unsigned char c = str[pos];
49 if (c ==
'%' && pos+2 < str.length()) {
50 c = (((str[pos+1]>>6)*9+((str[pos+1]-
'0')&15)) << 4) |
51 ((str[pos+2]>>6)*9+((str[pos+2]-
'0')&15));
61 bool fLabelFound =
false;
63 spk_man->GetKey(keyid, key);
65 const auto* address_book_entry =
wallet.FindAddressBookEntry(dest);
66 if (address_book_entry) {
67 if (!strAddr.empty()) {
85 int64_t scanned_time =
wallet.RescanFromTime(time_begin, reserver, update);
86 if (
wallet.IsAbortingRescan()) {
88 }
else if (scanned_time > time_begin) {
96 "\nAdds a private key (as returned by dumpprivkey) to your wallet. Requires a new wallet backup.\n" 97 "Hint: use importmulti to import more than one private key.\n" 98 "\nNote: This call can take over an hour to complete if rescan is true, during that time, other rpc calls\n" 99 "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" 100 "Note: Use \"getwalletinfo\" to query the scanning progress.\n",
108 "\nDump a private key\n" 110 "\nImport the private key with rescan\n" 112 "\nImport using a label and without rescan\n" 113 +
HelpExampleCli(
"importprivkey",
"\"mykey\" \"testing\" false") +
114 "\nImport using default blank label and without rescan\n" 116 "\nAs a JSON-RPC call\n" 117 +
HelpExampleRpc(
"importprivkey",
"\"mykey\", \"testing\", false")
133 LOCK(pwallet->cs_wallet);
137 std::string strSecret = request.params[0].get_str();
138 std::string strLabel =
"";
139 if (!request.params[1].isNull())
140 strLabel = request.params[1].get_str();
143 if (!request.params[2].isNull())
144 fRescan = request.params[2].get_bool();
146 if (fRescan && pwallet->chain().havePruned()) {
153 if (fRescan && !reserver.
reserve()) {
164 pwallet->MarkDirty();
170 if (!request.params[1].isNull() || !pwallet->FindAddressBookEntry(dest)) {
171 pwallet->SetAddressBook(dest, strLabel,
"receive");
176 if (!pwallet->ImportPrivKeys({{vchAddress, key}}, 1)) {
198 "\nStops current wallet rescan triggered by an RPC call, e.g. by an importprivkey call.\n" 199 "Note: Use \"getwalletinfo\" to query the scanning progress.\n",
203 "\nImport a private key\n" 205 "\nAbort the running wallet rescan\n" 207 "\nAs a JSON-RPC call\n" 215 if (!pwallet->IsScanning() || pwallet->IsAbortingRescan())
return false;
216 pwallet->AbortRescan();
225 "\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" 226 "\nNote: This call can take over an hour to complete if rescan is true, during that time, other rpc calls\n" 227 "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" 228 "If you have the full public key, you should call importpubkey instead of this.\n" 229 "Hint: use importmulti to import more than one address.\n" 230 "\nNote: If you import a non-standard raw script in hex form, outputs sending to it will be treated\n" 231 "as change, and not show up in many RPCs.\n" 232 "Note: Use \"getwalletinfo\" to query the scanning progress.\n",
241 "\nImport an address with rescan\n" 243 "\nImport using a label without rescan\n" 244 +
HelpExampleCli(
"importaddress",
"\"myaddress\" \"testing\" false") +
245 "\nAs a JSON-RPC call\n" 246 +
HelpExampleRpc(
"importaddress",
"\"myaddress\", \"testing\", false")
255 std::string strLabel;
256 if (!request.params[1].isNull())
257 strLabel = request.params[1].get_str();
261 if (!request.params[2].isNull())
262 fRescan = request.params[2].get_bool();
264 if (fRescan && pwallet->chain().havePruned()) {
272 if (fRescan && !reserver.
reserve()) {
278 if (!request.params[3].isNull())
279 fP2SH = request.params[3].get_bool();
282 LOCK(pwallet->cs_wallet);
293 pwallet->MarkDirty();
296 }
else if (
IsHex(request.params[0].get_str())) {
297 std::vector<unsigned char> data(
ParseHex(request.params[0].get_str()));
298 CScript redeem_script(data.begin(), data.end());
300 std::set<CScript> scripts = {redeem_script};
301 pwallet->ImportScripts(scripts, 0 );
307 pwallet->ImportScriptPubKeys(strLabel, scripts,
false ,
true , 1 );
316 LOCK(pwallet->cs_wallet);
317 pwallet->ReacceptWalletTransactions();
329 "\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",
342 if (!
DecodeHexTx(tx, request.params[0].get_str())) {
352 std::vector<uint256> vMatch;
353 std::vector<unsigned int> vIndex;
354 if (merkleBlock.txn.ExtractMatches(vMatch, vIndex) != merkleBlock.header.hashMerkleRoot) {
358 LOCK(pwallet->cs_wallet);
360 if (!pwallet->chain().findAncestorByHash(pwallet->GetLastBlockHash(), merkleBlock.header.GetHash(),
FoundBlock().
height(height))) {
364 std::vector<uint256>::const_iterator it;
365 if ((it = std::find(vMatch.begin(), vMatch.end(), hashTx)) == vMatch.end()) {
369 unsigned int txnIndex = vIndex[it - vMatch.begin()];
374 if (pwallet->IsMine(*tx_ref)) {
375 pwallet->AddToWallet(std::move(tx_ref), confirm);
387 "\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",
393 HelpExampleCli(
"removeprunedfunds",
"\"a8d0c0184dde994a09ec054286f1ce581bebf46446a512166eae7628734ea0a5\"") +
394 "\nAs a JSON-RPC call\n" 395 +
HelpExampleRpc(
"removeprunedfunds",
"\"a8d0c0184dde994a09ec054286f1ce581bebf46446a512166eae7628734ea0a5\"")
402 LOCK(pwallet->cs_wallet);
405 std::vector<uint256> vHash;
406 vHash.push_back(hash);
407 std::vector<uint256> vHashOut;
413 if(vHashOut.empty()) {
425 "\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" 426 "Hint: use importmulti to import more than one public key.\n" 427 "\nNote: This call can take over an hour to complete if rescan is true, during that time, other rpc calls\n" 428 "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" 429 "Note: Use \"getwalletinfo\" to query the scanning progress.\n",
437 "\nImport a public key with rescan\n" 439 "\nImport using a label without rescan\n" 440 +
HelpExampleCli(
"importpubkey",
"\"mypubkey\" \"testing\" false") +
441 "\nAs a JSON-RPC call\n" 442 +
HelpExampleRpc(
"importpubkey",
"\"mypubkey\", \"testing\", false")
451 std::string strLabel;
452 if (!request.params[1].isNull())
453 strLabel = request.params[1].get_str();
457 if (!request.params[2].isNull())
458 fRescan = request.params[2].get_bool();
460 if (fRescan && pwallet->chain().havePruned()) {
468 if (fRescan && !reserver.
reserve()) {
472 if (!
IsHex(request.params[0].get_str()))
474 std::vector<unsigned char> data(
ParseHex(request.params[0].get_str()));
480 LOCK(pwallet->cs_wallet);
482 std::set<CScript> script_pub_keys;
487 pwallet->MarkDirty();
489 pwallet->ImportScriptPubKeys(strLabel, script_pub_keys,
true ,
true , 1 );
491 pwallet->ImportPubKeys({pubKey.
GetID()}, {{pubKey.
GetID(), pubKey}} , {} ,
false ,
false , 1 );
497 LOCK(pwallet->cs_wallet);
498 pwallet->ReacceptWalletTransactions();
511 "\nImports keys from a wallet dump file (see dumpwallet). Requires a new wallet backup to include imported keys.\n" 512 "Note: Use \"getwalletinfo\" to query the scanning progress.\n",
518 "\nDump the wallet\n" 520 "\nImport the wallet\n" 522 "\nImport using the json rpc call\n" 532 if (pwallet->chain().havePruned()) {
544 int64_t nTimeBegin = 0;
547 LOCK(pwallet->cs_wallet);
552 file.open(request.params[0].get_str(), std::ios::in | std::ios::ate);
553 if (!file.is_open()) {
558 int64_t nFilesize = std::max((int64_t)1, (int64_t)file.tellg());
559 file.seekg(0, file.beg);
563 pwallet->chain().showProgress(
strprintf(
"%s " +
_(
"Importing…").translated, pwallet->GetDisplayName()), 0,
false);
564 std::vector<std::tuple<CKey, int64_t, bool, std::string>> keys;
565 std::vector<std::pair<CScript, int64_t>> scripts;
566 while (file.good()) {
567 pwallet->chain().showProgress(
"", std::max(1, std::min(50, (
int)(((
double)file.tellg() / (double)nFilesize) * 100))),
false);
569 std::getline(file, line);
570 if (line.empty() || line[0] ==
'#')
573 std::vector<std::string> vstr;
574 boost::split(vstr, line, boost::is_any_of(
" "));
580 std::string strLabel;
582 for (
unsigned int nStr = 2; nStr < vstr.size(); nStr++) {
583 if (vstr[nStr].front() ==
'#')
585 if (vstr[nStr] ==
"change=1")
587 if (vstr[nStr] ==
"reserve=1")
589 if (vstr[nStr].substr(0,6) ==
"label=") {
594 keys.push_back(std::make_tuple(key, nTime, fLabel, strLabel));
595 }
else if(
IsHex(vstr[0])) {
596 std::vector<unsigned char> vData(
ParseHex(vstr[0]));
599 scripts.push_back(std::pair<CScript, int64_t>(script, birth_time));
605 pwallet->chain().showProgress(
"", 100,
false);
608 double total = (double)(keys.size() + scripts.size());
610 for (
const auto& key_tuple : keys) {
611 pwallet->chain().showProgress(
"", std::max(50, std::min(75, (
int)((progress / total) * 100) + 50)),
false);
612 const CKey& key = std::get<0>(key_tuple);
613 int64_t time = std::get<1>(key_tuple);
614 bool has_label = std::get<2>(key_tuple);
615 std::string label = std::get<3>(key_tuple);
619 CKeyID keyid = pubkey.GetID();
623 if (!pwallet->ImportPrivKeys({{keyid, key}}, time)) {
630 pwallet->SetAddressBook(
PKHash(keyid), label,
"receive");
632 nTimeBegin = std::min(nTimeBegin, time);
635 for (
const auto& script_pair : scripts) {
636 pwallet->chain().showProgress(
"", std::max(50, std::min(75, (
int)((progress / total) * 100) + 50)),
false);
637 const CScript& script = script_pair.first;
638 int64_t time = script_pair.second;
640 if (!pwallet->ImportScripts({script}, time)) {
641 pwallet->WalletLogPrintf(
"Error importing script %s\n",
HexStr(script));
646 nTimeBegin = std::min(nTimeBegin, time);
651 pwallet->chain().showProgress(
"", 100,
false);
653 pwallet->chain().showProgress(
"", 100,
false);
655 pwallet->MarkDirty();
668 "\nReveals the private key corresponding to 'address'.\n" 669 "Then the importprivkey can be used with this output\n",
692 std::string strAddress = request.params[0].get_str();
698 if (keyid.IsNull()) {
702 if (!spk_man.
GetKey(keyid, vchSecret)) {
714 "\nDumps all wallet keys in a human-readable format to a server-side file. This does not allow overwriting existing files.\n" 715 "Imported scripts are included in the dumpfile, but corresponding BIP173 addresses, etc. may not be added automatically by importwallet.\n" 716 "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" 717 "only backing up the seed itself, and must be backed up too (e.g. ensure you back up the whole dumpfile).\n",
741 wallet.BlockUntilSyncedToCurrentChain();
747 fs::path filepath = request.params[0].get_str();
748 filepath = fs::absolute(filepath);
755 if (fs::exists(filepath)) {
764 std::map<CKeyID, int64_t> mapKeyBirth;
765 wallet.GetKeyBirthTimes(mapKeyBirth);
767 int64_t block_time = 0;
775 std::set<CScriptID> scripts = spk_man.
GetCScripts();
778 std::vector<std::pair<int64_t, CKeyID> > vKeyBirth;
779 for (
const auto& entry : mapKeyBirth) {
780 vKeyBirth.push_back(std::make_pair(entry.second, entry.first));
783 std::sort(vKeyBirth.begin(), vKeyBirth.end());
788 file <<
strprintf(
"# * Best block at time of backup was %i (%s),\n",
wallet.GetLastBlockHeight(),
wallet.GetLastBlockHash().ToString());
797 if (spk_man.
GetKey(seed_id, seed)) {
801 file <<
"# extended private masterkey: " <<
EncodeExtKey(masterKey) <<
"\n\n";
804 for (std::vector<std::pair<int64_t, CKeyID> >::const_iterator it = vKeyBirth.begin(); it != vKeyBirth.end(); it++) {
805 const CKeyID &keyid = it->second;
808 std::string strLabel;
810 if (spk_man.
GetKey(keyid, key)) {
814 }
else if (keyid == seed_id) {
816 }
else if (mapKeyPool.count(keyid)) {
818 }
else if (spk_man.mapKeyMetadata[keyid].hdKeypath ==
"s") {
819 file <<
"inactivehdseed=1";
823 file <<
strprintf(
" # addr=%s%s\n", strAddr, (spk_man.mapKeyMetadata[keyid].has_key_origin ?
" hdkeypath="+
WriteHDKeypath(spk_man.mapKeyMetadata[keyid].key_origin.path) :
""));
827 for (
const CScriptID &scriptid : scripts) {
829 std::string create_time =
"0";
832 auto it = spk_man.m_script_metadata.find(scriptid);
833 if (it != spk_man.m_script_metadata.end()) {
838 file <<
strprintf(
" # addr=%s\n", address);
842 file <<
"# End of dump\n";
846 reply.
pushKV(
"filename", filepath.string());
877 std::vector<std::vector<unsigned char>> solverdata;
880 switch (script_type) {
897 if (!subscript)
return "missing redeemscript";
898 if (
CScriptID(*subscript) !=
id)
return "redeemScript does not match the scriptPubKey";
903 for (
size_t i = 1; i + 1< solverdata.size(); ++i) {
915 if (!subscript)
return "missing witnessscript";
916 if (
CScriptID(*subscript) !=
id)
return "witnessScript does not match the scriptPubKey or redeemScript";
933 return "unspendable script";
937 return "unrecognized script";
942 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)
947 const UniValue& scriptPubKey = data[
"scriptPubKey"];
952 const std::string& output = isScript ? scriptPubKey.
get_str() : scriptPubKey[
"address"].
get_str();
955 const std::string& strRedeemScript = data.
exists(
"redeemscript") ? data[
"redeemscript"].
get_str() :
"";
956 const std::string& witness_script_hex = data.
exists(
"witnessscript") ? data[
"witnessscript"].
get_str() :
"";
959 const bool internal = data.
exists(
"internal") ? data[
"internal"].
get_bool() :
false;
960 const bool watchOnly = data.
exists(
"watchonly") ? data[
"watchonly"].
get_bool() :
false;
962 if (data.
exists(
"range")) {
978 if (!
IsHex(output)) {
981 std::vector<unsigned char> vData(
ParseHex(output));
982 script =
CScript(vData.begin(), vData.end());
988 script_pub_keys.emplace(script);
991 if (strRedeemScript.size()) {
992 if (!
IsHex(strRedeemScript)) {
995 auto parsed_redeemscript =
ParseHex(strRedeemScript);
996 import_data.
redeemscript = std::make_unique<CScript>(parsed_redeemscript.begin(), parsed_redeemscript.end());
998 if (witness_script_hex.size()) {
999 if (!
IsHex(witness_script_hex)) {
1002 auto parsed_witnessscript =
ParseHex(witness_script_hex);
1003 import_data.
witnessscript = std::make_unique<CScript>(parsed_witnessscript.begin(), parsed_witnessscript.end());
1005 for (
size_t i = 0; i < pubKeys.
size(); ++i) {
1006 const auto& str = pubKeys[i].
get_str();
1010 auto parsed_pubkey =
ParseHex(str);
1011 CPubKey pubkey(parsed_pubkey);
1015 pubkey_map.emplace(pubkey.
GetID(), pubkey);
1016 ordered_pubkeys.push_back(pubkey.
GetID());
1018 for (
size_t i = 0; i < keys.
size(); ++i) {
1019 const auto& str = keys[i].
get_str();
1026 if (pubkey_map.count(
id)) {
1027 pubkey_map.erase(
id);
1029 privkey_map.emplace(
id, key);
1035 if (have_solving_data) {
1040 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; });
1041 if (!watchOnly && !spendable) {
1042 warnings.
push_back(
"Some private keys are missing, outputs will be considered watchonly. If this is intentional, specify the watchonly flag.");
1044 if (watchOnly && spendable) {
1045 warnings.
push_back(
"All private keys are provided, outputs will be considered spendable. If this is intentional, do not specify the watchonly flag.");
1049 if (
error.empty()) {
1050 for (
const auto& require_key : import_data.
used_keys) {
1051 if (!require_key.second)
continue;
1052 if (pubkey_map.count(require_key.first) == 0 && privkey_map.count(require_key.first) == 0) {
1053 error =
"some required keys are missing";
1058 if (!
error.empty()) {
1059 warnings.
push_back(
"Importing as non-solvable: " +
error +
". If this is intentional, don't provide any keys, pubkeys, witnessscript, or redeemscript.");
1062 privkey_map.clear();
1063 have_solving_data =
false;
1066 if (import_data.
redeemscript) warnings.
push_back(
"Ignoring redeemscript as this is not a P2SH script.");
1067 if (import_data.
witnessscript) warnings.
push_back(
"Ignoring witnessscript as this is not a (P2SH-)P2WSH script.");
1068 for (
auto it = privkey_map.begin(); it != privkey_map.end(); ) {
1070 if (import_data.
used_keys.count(oldit->first) == 0) {
1071 warnings.
push_back(
"Ignoring irrelevant private key.");
1072 privkey_map.erase(oldit);
1075 for (
auto it = pubkey_map.begin(); it != pubkey_map.end(); ) {
1077 auto key_data_it = import_data.
used_keys.find(oldit->first);
1078 if (key_data_it == import_data.
used_keys.end() || !key_data_it->second) {
1079 warnings.
push_back(
"Ignoring public key \"" +
HexStr(oldit->first) +
"\" as it doesn't appear inside P2PKH or P2WPKH.");
1080 pubkey_map.erase(oldit);
1089 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)
1093 const std::string& descriptor = data[
"desc"].
get_str();
1096 auto parsed_desc =
Parse(descriptor, keys,
error,
true);
1104 have_solving_data = parsed_desc->IsSolvable();
1105 const bool watch_only = data.
exists(
"watchonly") ? data[
"watchonly"].
get_bool() :
false;
1107 int64_t range_start = 0, range_end = 0;
1108 if (!parsed_desc->IsRange() && data.
exists(
"range")) {
1110 }
else if (parsed_desc->IsRange()) {
1111 if (!data.
exists(
"range")) {
1120 for (
int i = range_start; i <= range_end; ++i) {
1122 std::vector<CScript> scripts_temp;
1123 parsed_desc->Expand(i, keys, scripts_temp, out_keys);
1124 std::copy(scripts_temp.begin(), scripts_temp.end(), std::inserter(script_pub_keys, script_pub_keys.end()));
1125 for (
const auto& key_pair : out_keys.
pubkeys) {
1126 ordered_pubkeys.push_back(key_pair.first);
1129 for (
const auto& x : out_keys.
scripts) {
1133 parsed_desc->ExpandPrivate(i, keys, out_keys);
1135 std::copy(out_keys.
pubkeys.begin(), out_keys.
pubkeys.end(), std::inserter(pubkey_map, pubkey_map.end()));
1136 std::copy(out_keys.
keys.begin(), out_keys.
keys.end(), std::inserter(privkey_map, privkey_map.end()));
1140 for (
size_t i = 0; i < priv_keys.
size(); ++i) {
1141 const auto& str = priv_keys[i].
get_str();
1150 if (!pubkey_map.count(
id)) {
1151 warnings.
push_back(
"Ignoring irrelevant private key.");
1153 privkey_map.emplace(
id, key);
1161 bool spendable = std::all_of(pubkey_map.begin(), pubkey_map.end(),
1162 [&](
const std::pair<CKeyID, CPubKey>& used_key) {
1163 return privkey_map.count(used_key.first) > 0;
1165 [&](
const std::pair<CKeyID, std::pair<CPubKey, KeyOriginInfo>>& entry) {
1166 return privkey_map.count(entry.first) > 0;
1168 if (!watch_only && !spendable) {
1169 warnings.
push_back(
"Some private keys are missing, outputs will be considered watchonly. If this is intentional, specify the watchonly flag.");
1171 if (watch_only && spendable) {
1172 warnings.
push_back(
"All private keys are provided, outputs will be considered spendable. If this is intentional, do not specify the watchonly flag.");
1184 const bool internal = data.exists(
"internal") ? data[
"internal"].get_bool() :
false;
1186 if (
internal && data.exists(
"label")) {
1189 const std::string& label = data.exists(
"label") ? data[
"label"].get_str() :
"";
1190 const bool add_keypool = data.exists(
"keypool") ? data[
"keypool"].get_bool() :
false;
1198 std::map<CKeyID, CPubKey> pubkey_map;
1199 std::map<CKeyID, CKey> privkey_map;
1200 std::set<CScript> script_pub_keys;
1201 std::vector<CKeyID> ordered_pubkeys;
1202 bool have_solving_data;
1204 if (data.exists(
"scriptPubKey") && data.exists(
"desc")) {
1206 }
else if (data.exists(
"scriptPubKey")) {
1207 warnings =
ProcessImportLegacy(import_data, pubkey_map, privkey_map, script_pub_keys, have_solving_data, data, ordered_pubkeys);
1208 }
else if (data.exists(
"desc")) {
1209 warnings =
ProcessImportDescriptor(import_data, pubkey_map, privkey_map, script_pub_keys, have_solving_data, data, ordered_pubkeys);
1220 for (
const CScript& script : script_pub_keys) {
1231 if (!
wallet.ImportPrivKeys(privkey_map, timestamp)) {
1234 if (!
wallet.ImportPubKeys(ordered_pubkeys, pubkey_map, import_data.
key_origins, add_keypool,
internal, timestamp)) {
1237 if (!
wallet.ImportScriptPubKeys(label, script_pub_keys, have_solving_data, !
internal, timestamp)) {
1244 result.
pushKV(
"error", e);
1250 if (warnings.
size()) result.
pushKV(
"warnings", warnings);
1256 if (data.
exists(
"timestamp")) {
1257 const UniValue& timestamp = data[
"timestamp"];
1258 if (timestamp.
isNum()) {
1260 }
else if (timestamp.
isStr() && timestamp.
get_str() ==
"now") {
1271 "\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" 1272 "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" 1273 "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" 1274 "\nNote: This call can take over an hour to complete if rescan is true, during that time, other rpc calls\n" 1275 "may report that the imported keys, addresses or scripts exist but related transactions are still missing.\n" 1276 "Note: Use \"getwalletinfo\" to query the scanning progress.\n",
1284 "", {
"\"<script>\" | { \"address\":\"<address>\" }",
"string / json"}
1287 " or the string \"now\" to substitute the current synced blockchain time. The timestamp of the oldest\n" 1288 " key will determine how far back blockchain rescans need to begin for missing wallet transactions.\n" 1289 " \"now\" can be specified to bypass scanning, for keys which are known to never have been used, and\n" 1290 " 0 can be specified to scan the entire blockchain. Blocks up to 2 hours before the earliest key\n" 1291 " creation time of all keys being imported by the importmulti call will be scanned.",
1292 "", {
"timestamp | \"now\"",
"integer / string"}
1296 {
"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).",
1310 {
"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"},
1322 RPCResult::Type::ARR,
"",
"Response is an array with the same size as the input that has the execution result",
1339 HelpExampleCli(
"importmulti",
"'[{ \"scriptPubKey\": { \"address\": \"<my address>\" }, \"timestamp\":1455191478 }, " 1340 "{ \"scriptPubKey\": { \"address\": \"<my 2nd address>\" }, \"label\": \"example 2\", \"timestamp\": 1455191480 }]'") +
1341 HelpExampleCli(
"importmulti",
"'[{ \"scriptPubKey\": { \"address\": \"<my address>\" }, \"timestamp\":1455191478 }]' '{ \"rescan\": false}'")
1348 RPCTypeCheck(mainRequest.params, {UniValue::VARR, UniValue::VOBJ});
1352 const UniValue& requests = mainRequest.params[0];
1355 bool fRescan =
true;
1357 if (!mainRequest.params[1].isNull()) {
1358 const UniValue& options = mainRequest.params[1];
1360 if (options.
exists(
"rescan")) {
1361 fRescan = options[
"rescan"].
get_bool();
1366 if (fRescan && !reserver.
reserve()) {
1371 bool fRunScan =
false;
1372 int64_t nLowestTimestamp = 0;
1375 LOCK(pwallet->cs_wallet);
1384 const int64_t minimumTimestamp = 1;
1396 if (result[
"success"].get_bool()) {
1401 if (timestamp < nLowestTimestamp) {
1402 nLowestTimestamp = timestamp;
1406 if (fRescan && fRunScan && requests.
size()) {
1407 int64_t scannedTime = pwallet->RescanFromTime(nLowestTimestamp, reserver,
true );
1409 LOCK(pwallet->cs_wallet);
1410 pwallet->ReacceptWalletTransactions();
1413 if (pwallet->IsAbortingRescan()) {
1416 if (scannedTime > nLowestTimestamp) {
1417 std::vector<UniValue> results = response.
getValues();
1426 if (scannedTime <=
GetImportTimestamp(request, now) || results.at(i).exists(
"error")) {
1435 strprintf(
"Rescan failed for key with creation timestamp %d. There was an error reading a " 1436 "block from time %d, which is after or within %d seconds of key creation, and " 1437 "could contain transactions pertaining to the key. As a result, transactions " 1438 "and coins using this key may not appear in the wallet. This error could be " 1439 "caused by pruning or data corruption (see bitcoind log for details) and could " 1440 "be dealt with by downloading and rescanning the relevant blocks (see -reindex " 1441 "and -rescan options).",
1461 if (!data.exists(
"desc")) {
1465 const std::string& descriptor = data[
"desc"].get_str();
1466 const bool active = data.exists(
"active") ? data[
"active"].get_bool() :
false;
1467 const bool internal = data.exists(
"internal") ? data[
"internal"].get_bool() :
false;
1468 const std::string& label = data.exists(
"label") ? data[
"label"].get_str() :
"";
1473 auto parsed_desc =
Parse(descriptor, keys,
error,
true);
1479 int64_t range_start = 0, range_end = 1, next_index = 0;
1480 if (!parsed_desc->IsRange() && data.exists(
"range")) {
1482 }
else if (parsed_desc->IsRange()) {
1483 if (data.exists(
"range")) {
1485 range_start = range.first;
1486 range_end = range.second + 1;
1488 warnings.
push_back(
"Range not given, using default keypool range");
1492 next_index = range_start;
1494 if (data.exists(
"next_index")) {
1495 next_index = data[
"next_index"].get_int64();
1497 if (next_index < range_start || next_index >= range_end) {
1504 if (active && !parsed_desc->IsRange()) {
1509 if (data.exists(
"range") && data.exists(
"label")) {
1514 if (
internal && data.exists(
"label")) {
1519 if (active && !parsed_desc->IsSingleType()) {
1530 std::vector<CScript> scripts;
1531 if (!parsed_desc->Expand(0, keys, scripts, expand_keys)) {
1532 throw JSONRPCError(
RPC_WALLET_ERROR,
"Cannot expand descriptor. Probably because of hardened derivations without private keys provided");
1534 parsed_desc->ExpandPrivate(0, keys, expand_keys);
1537 bool have_all_privkeys = !expand_keys.
keys.empty();
1538 for (
const auto& entry : expand_keys.
origins) {
1539 const CKeyID& key_id = entry.first;
1541 if (!expand_keys.
GetKey(key_id, key)) {
1542 have_all_privkeys =
false;
1551 if (std::holds_alternative<WitnessV1Taproot>(dest)) {
1553 if (!
wallet.chain().isTaprootActive()) {
1561 if (keys.
keys.empty()) {
1564 if (!have_all_privkeys) {
1565 warnings.
push_back(
"Not all private keys provided. Some wallet functionality may return unexpected errors");
1569 WalletDescriptor w_desc(std::move(parsed_desc), timestamp, range_start, range_end, next_index);
1572 auto existing_spk_manager =
wallet.GetDescriptorScriptPubKeyMan(w_desc);
1573 if (existing_spk_manager) {
1574 if (!existing_spk_manager->CanUpdateToWalletDescriptor(w_desc,
error)) {
1580 auto spk_manager =
wallet.AddWalletDescriptor(w_desc, keys, label,
internal);
1581 if (spk_manager ==
nullptr) {
1588 warnings.
push_back(
"Unknown output type, cannot set descriptor to active.");
1590 wallet.AddActiveScriptPubKeyMan(spk_manager->GetID(), *w_desc.
descriptor->GetOutputType(),
internal);
1594 wallet.DeactivateScriptPubKeyMan(spk_manager->GetID(), *w_desc.
descriptor->GetOutputType(),
internal);
1601 result.
pushKV(
"error", e);
1603 if (warnings.
size()) result.
pushKV(
"warnings", warnings);
1610 "\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" 1611 "\nNote: This call can take over an hour to complete if using an early timestamp; during that time, other rpc calls\n" 1612 "may report that the imported keys, addresses or scripts exist but related transactions are still missing.\n",
1623 " Use the string \"now\" to substitute the current synced blockchain time.\n" 1624 " \"now\" can be specified to bypass scanning, for outputs which are known to never have been used, and\n" 1625 " 0 can be specified to scan the entire blockchain. Blocks up to 2 hours before the earliest timestamp\n" 1626 " of all descriptors being imported will be scanned.",
1627 "", {
"timestamp | \"now\"",
"integer / string"}
1637 RPCResult::Type::ARR,
"",
"Response is an array with the same size as the input that has the execution result",
1654 HelpExampleCli(
"importdescriptors",
"'[{ \"desc\": \"<my descriptor>\", \"timestamp\":1455191478, \"internal\": true }, " 1655 "{ \"desc\": \"<my desccriptor 2>\", \"label\": \"example 2\", \"timestamp\": 1455191480 }]'") +
1656 HelpExampleCli(
"importdescriptors",
"'[{ \"desc\": \"<my descriptor>\", \"timestamp\":1455191478, \"active\": true, \"range\": [0,100], \"label\": \"<my bech32 wallet>\" }]'")
1668 RPCTypeCheck(main_request.params, {UniValue::VARR, UniValue::VOBJ});
1675 const UniValue& requests = main_request.params[0];
1676 const int64_t minimum_timestamp = 1;
1678 int64_t lowest_timestamp = 0;
1679 bool rescan =
false;
1682 LOCK(pwallet->cs_wallet);
1690 const int64_t timestamp = std::max(
GetImportTimestamp(request, now), minimum_timestamp);
1694 if (lowest_timestamp > timestamp ) {
1695 lowest_timestamp = timestamp;
1699 if (!rescan && result[
"success"].get_bool()) {
1703 pwallet->ConnectScriptPubKeyManNotifiers();
1708 int64_t scanned_time = pwallet->RescanFromTime(lowest_timestamp, reserver,
true );
1710 LOCK(pwallet->cs_wallet);
1711 pwallet->ReacceptWalletTransactions();
1714 if (pwallet->IsAbortingRescan()) {
1718 if (scanned_time > lowest_timestamp) {
1719 std::vector<UniValue> results = response.
getValues();
1724 for (
unsigned int i = 0; i < requests.
size(); ++i) {
1731 if (scanned_time <=
GetImportTimestamp(request, now) || results.at(i).exists(
"error")) {
1740 strprintf(
"Rescan failed for descriptor with timestamp %d. There was an error reading a " 1741 "block from time %d, which is after or within %d seconds of key creation, and " 1742 "could contain transactions pertaining to the desc. As a result, transactions " 1743 "and coins using this desc may not appear in the wallet. This error could be " 1744 "caused by pruning or data corruption (see bitcoind log for details) and could " 1745 "be dealt with by downloading and rescanning the relevant blocks (see -reindex " 1746 "and -rescan options).",
1763 "\nList descriptors imported into a descriptor-enabled wallet.",
1773 {
RPCResult::Type::BOOL,
"internal",
true,
"Whether this is an internal or external descriptor; defined only for active descriptors"},
1778 {
RPCResult::Type::NUM,
"next",
true,
"The next index to generate addresses from; defined only for ranged descriptors"},
1797 const auto active_spk_mans =
wallet->GetActiveScriptPubKeyMans();
1798 for (
const auto& spk_man :
wallet->GetAllScriptPubKeyMans()) {
1800 if (!desc_spk_man) {
1804 LOCK(desc_spk_man->cs_desc_man);
1805 const auto& wallet_descriptor = desc_spk_man->GetWalletDescriptor();
1806 std::string descriptor;
1807 if (!desc_spk_man->GetDescriptorString(descriptor)) {
1810 spk.
pushKV(
"desc", descriptor);
1811 spk.
pushKV(
"timestamp", wallet_descriptor.creation_time);
1812 const bool active = active_spk_mans.count(desc_spk_man) != 0;
1813 spk.
pushKV(
"active", active);
1814 const auto& type = wallet_descriptor.descriptor->GetOutputType();
1815 if (active && type) {
1816 spk.
pushKV(
"internal",
wallet->GetScriptPubKeyMan(*type,
true) == desc_spk_man);
1818 if (wallet_descriptor.descriptor->IsRange()) {
1820 range.
push_back(wallet_descriptor.range_start);
1821 range.
push_back(wallet_descriptor.range_end - 1);
1822 spk.
pushKV(
"range", range);
1823 spk.
pushKV(
"next", wallet_descriptor.next_index);
1830 response.
pushKV(
"descriptors", descriptors);
std::shared_ptr< const CTransaction > CTransactionRef
static std::string EncodeDumpString(const std::string &str)
std::unique_ptr< CScript > witnessscript
Provided witnessScript; will be moved to import_scripts if relevant.
Witness v0 (P2WPKH and P2WSH); see BIP 141.
Helper for findBlock to selectively return pieces of block data.
const CHDChain & GetHDChain() const
void RPCTypeCheck(const UniValue ¶ms, const std::list< UniValueType > &typesExpected, bool fAllowNull)
Type-check arguments; throws JSONRPCError if wrong type given.
const std::vector< UniValue > & getValues() const
bool ExtractDestination(const CScript &scriptPubKey, CTxDestination &addressRet)
Parse a standard scriptPubKey for the destination address.
virtual bool GetCScript(const CScriptID &hash, CScript &redeemScriptOut) const override
std::shared_ptr< Descriptor > descriptor
iterator insert(iterator pos, const T &value)
void EnsureWalletIsUnlocked(const CWallet &wallet)
RecursiveMutex cs_KeyStore
bool VerifyPubKey(const CPubKey &vchPubKey) const
Verify thoroughly whether a private key and a public key match.
CPubKey GetPubKey() const
Compute the public key from a private key.
static UniValue ProcessImport(CWallet &wallet, const UniValue &data, const int64_t timestamp) EXCLUSIVE_LOCKS_REQUIRED(wallet.cs_wallet)
std::map< CKeyID, CKey > keys
static constexpr unsigned int size()
std::vector< unsigned char > ParseHexV(const UniValue &v, std::string strName)
LegacyScriptPubKeyMan & EnsureLegacyScriptPubKeyMan(CWallet &wallet, bool also_create)
const std::string UNIX_EPOCH_TIME
String used to describe UNIX epoch time in documentation, factored out to a constant for consistency...
#define CHECK_NONFATAL(condition)
Throw a NonFatalCheckError when the condition evaluates to false.
std::vector< unsigned char > ParseHex(const char *psz)
bool IsValidDestination(const CTxDestination &dest)
Check whether a CTxDestination is a CNoDestination.
virtual std::set< CScriptID > GetCScripts() const
std::map< CKeyID, std::pair< CPubKey, KeyOriginInfo > > origins
std::string FormatISO8601DateTime(int64_t nTime)
ISO 8601 formatting is preferred.
const std::string & get_str() const
enum VType getType() const
CKeyID GetKeyForDestination(const SigningProvider &store, const CTxDestination &dest)
Return the CKeyID of the key involved in a script (if there is a unique one).
const UniValue & get_array() const
CTxDestination DecodeDestination(const std::string &str, std::string &error_msg)
Double ended buffer combining vector and stream-like interfaces.
int64_t get_int64() const
static bool GetWalletAddressesForKey(LegacyScriptPubKeyMan *spk_man, const CWallet &wallet, const CKeyID &keyid, std::string &strAddr, std::string &strLabel) EXCLUSIVE_LOCKS_REQUIRED(wallet.cs_wallet)
const unsigned char * begin() const
int64_t ParseISO8601DateTime(const std::string &str)
static constexpr int64_t TIMESTAMP_WINDOW
Timestamp window used as a grace period by code that compares external timestamps (such as timestamps...
unspendable OP_RETURN script that carries data
CKeyID GetID() const
Get the KeyID of this public key (hash of its serialization)
const std::map< CKeyID, int64_t > & GetAllReserveKeys() const
Invalid, missing or duplicate parameter.
std::vector< CTxDestination > GetAllDestinationsForKey(const CPubKey &key)
Get all destinations (potentially) supported by the wallet for the given key.
RPCHelpMan removeprunedfunds()
std::unique_ptr< Descriptor > Parse(const std::string &descriptor, FlatSigningProvider &out, std::string &error, bool require_checksum)
Parse a descriptor string.
static std::string RecurseImportData(const CScript &script, ImportData &import_data, const ScriptContext script_ctx)
Special type that is a STR with only hex chars.
const char * uvTypeName(UniValue::VType t)
Used to relay blocks as header + vector<merkle branch> to filtered nodes.
UniValue JSONRPCError(int code, const std::string &message)
bool push_back(const UniValue &val)
std::map< CKeyID, std::pair< CPubKey, KeyOriginInfo > > key_origins
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)
bool IsFullyValid() const
fully validate whether this is a valid public key (more expensive than IsValid()) ...
RPCHelpMan listdescriptors()
std::map< CScriptID, CScript > scripts
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)
static const unsigned int DEFAULT_KEYPOOL_SIZE
Default for -keypool.
bool exists(const std::string &key) const
bilingual_str _(const char *psz)
Translation function.
std::map< CKeyID, bool > used_keys
Import these private keys if available (the value indicates whether if the key is required for solvab...
static const int64_t TIMESTAMP_MIN
Special array that has a fixed number of entries.
An encapsulated public key.
std::string HelpExampleRpc(const std::string &methodname, const std::string &args)
bool IsHex(const std::string &str)
std::map< CKeyID, CPubKey > pubkeys
static std::string DecodeDumpString(const std::string &str)
Unexpected type was passed as parameter.
RPCHelpMan importprivkey()
static UniValue ProcessDescriptorImport(CWallet &wallet, const UniValue &data, const int64_t timestamp) EXCLUSIVE_LOCKS_REQUIRED(wallet.cs_wallet)
bool GetKey(const CKeyID &address, CKey &keyOut) const override
RPCHelpMan importwallet()
std::variant< CNoDestination, PKHash, ScriptHash, WitnessV0ScriptHash, WitnessV0KeyHash, WitnessV1Taproot, WitnessUnknown > CTxDestination
A txout script template with a specific destination.
General application defined errors.
bool pushKV(const std::string &key, const UniValue &val)
unsigned int size() const
Simple read-only vector-like interface.
static void RescanWallet(CWallet &wallet, const WalletRescanReserver &reserver, int64_t time_begin=TIMESTAMP_MIN, bool update=true)
CScript GetScriptForDestination(const CTxDestination &dest)
Generate a Bitcoin scriptPubKey for the given CTxDestination.
Descriptor with some wallet metadata.
std::set< CScript > import_scripts
std::shared_ptr< CWallet > GetWalletForJSONRPCRequest(const JSONRPCRequest &request)
Figures out what wallet, if any, to use for a JSONRPCRequest.
void SetSeed(const unsigned char *seed, unsigned int nSeedLen)
std::string HexStr(const Span< const uint8_t > s)
Convert a span of bytes to a lower-case hexadecimal string.
RPCHelpMan importaddress()
Optional arg that is a named argument and has a default value of null.
RAII object to check and reserve a wallet rescan.
static CTransactionRef MakeTransactionRef(Tx &&txIn)
CRIPEMD160 & Write(const unsigned char *data, size_t len)
std::unique_ptr< CScript > redeemscript
Provided redeemScript; will be moved to import_scripts if relevant.
Special type that is a NUM or [NUM,NUM].
Optional argument with default value omitted because they are implicitly clear.
#define EXCLUSIVE_LOCKS_REQUIRED(...)
bool GetKey(const CKeyID &keyid, CKey &key) const override
RPCHelpMan importdescriptors()
uint256 GetHash() const
Compute the hash of this CMutableTransaction.
Serialized script, used inside transaction inputs and outputs.
static const int PROTOCOL_VERSION
network protocol versioning
std::string WriteHDKeypath(const std::vector< uint32_t > &keypath)
Write HD keypaths as strings.
std::string GetArg(const std::string &strArg, const std::string &strDefault) const
Return string argument or default value.
A reference to a CKey: the Hash160 of its serialized public key.
TxoutType Solver(const CScript &scriptPubKey, std::vector< std::vector< unsigned char >> &vSolutionsRet)
Parse a scriptPubKey and identify script type for standard scripts.
bool DecodeHexTx(CMutableTransaction &tx, const std::string &hex_tx, bool try_no_witness=false, bool try_witness=true)
Only for Witness versions not already defined above.
A CWallet maintains a set of transactions and balances, and provides the ability to create new transa...
const UniValue NullUniValue
RPCHelpMan importprunedfunds()
CTxDestination GetDestinationForKey(const CPubKey &key, OutputType type)
Get a destination of the requested type (if possible) to the specified key.
std::pair< int64_t, int64_t > ParseDescriptorRange(const UniValue &value)
Parse a JSON range specified as int64, or [int64, int64].
A reference to a CScript: the Hash160 of its serialization (see script.h)
std::string HelpExampleCli(const std::string &methodname, const std::string &args)
std::string EncodeDestination(const CTxDestination &dest)
A mutable version of CTransaction.
FoundBlock & height(int &height)
An encapsulated private key.
FoundBlock & mtpTime(int64_t &mtp_time)
uint256 ParseHashV(const UniValue &v, std::string strName)
Utilities: convert hex-encoded Values (throws error if not hex).
std::optional< OutputType > OutputTypeFromDestination(const CTxDestination &dest)
Get the OutputType for a CTxDestination.
static int64_t GetImportTimestamp(const UniValue &data, int64_t now)
CKey DecodeSecret(const std::string &str)
Confirmation includes tx status and a triplet of {block height/block hash/tx index in block} at which...
Indicate that this wallet supports DescriptorScriptPubKeyMan.
CKeyID seed_id
seed hash160
int64_t GetTime()
Return system time (or mocked time, if set)
std::string EncodeSecret(const CKey &key)
bool error(const char *fmt, const Args &... args)
const std::string CLIENT_BUILD
RPCHelpMan importpubkey()
std::string EncodeExtKey(const CExtKey &key)
FoundBlock & time(int64_t &time)
Error parsing or validating structure in raw format.
A hasher class for RIPEMD-160.
Special type to denote elision (...)
bool IsValid() const
Check whether this private key is valid.
bool IsCompressed() const
Check whether this is a compressed public key.