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 = pwallet->FindAddressBookEntry(dest);
66 if (address_book_entry) {
67 if (!strAddr.empty()) {
85 int64_t scanned_time = wallet.
RescanFromTime(time_begin, reserver, update);
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",
103 {
"label",
RPCArg::Type::STR,
"current label if address exists, otherwise \"\"",
"An optional label"},
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")
123 CWallet*
const pwallet = wallet.get();
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();
154 if (fRescan && !reserver.
reserve()) {
161 CPubKey pubkey = key.GetPubKey();
163 CKeyID vchAddress = pubkey.GetID();
182 if (pubkey.IsCompressed()) {
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"
215 CWallet*
const pwallet = wallet.get();
227 "\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"
228 "\nNote: This call can take over an hour to complete if rescan is true, during that time, other rpc calls\n"
229 "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"
230 "If you have the full public key, you should call importpubkey instead of this.\n"
231 "Hint: use importmulti to import more than one address.\n"
232 "\nNote: If you import a non-standard raw script in hex form, outputs sending to it will be treated\n"
233 "as change, and not show up in many RPCs.\n"
234 "Note: Use \"getwalletinfo\" to query the scanning progress.\n",
243 "\nImport an address with rescan\n"
245 "\nImport using a label without rescan\n"
246 +
HelpExampleCli(
"importaddress",
"\"myaddress\" \"testing\" false") +
247 "\nAs a JSON-RPC call\n"
248 +
HelpExampleRpc(
"importaddress",
"\"myaddress\", \"testing\", false")
254 CWallet*
const pwallet = wallet.get();
258 std::string strLabel;
259 if (!request.params[1].isNull())
260 strLabel = request.params[1].get_str();
264 if (!request.params[2].isNull())
265 fRescan = request.params[2].get_bool();
275 if (fRescan && !reserver.
reserve()) {
281 if (!request.params[3].isNull())
282 fP2SH = request.params[3].get_bool();
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};
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",
340 CWallet*
const pwallet = wallet.get();
343 if (!
DecodeHexTx(tx, request.params[0].get_str())) {
353 std::vector<uint256> vMatch;
354 std::vector<unsigned int> vIndex;
355 if (merkleBlock.txn.ExtractMatches(vMatch, vIndex) != merkleBlock.header.hashMerkleRoot) {
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)) {
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\"")
402 CWallet*
const pwallet = wallet.get();
407 std::vector<uint256> vHash;
408 vHash.push_back(hash);
409 std::vector<uint256> vHashOut;
415 if(vHashOut.empty()) {
427 "\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"
428 "Hint: use importmulti to import more than one public key.\n"
429 "\nNote: This call can take over an hour to complete if rescan is true, during that time, other rpc calls\n"
430 "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"
431 "Note: Use \"getwalletinfo\" to query the scanning progress.\n",
439 "\nImport a public key with rescan\n"
441 "\nImport using a label without rescan\n"
442 +
HelpExampleCli(
"importpubkey",
"\"mypubkey\" \"testing\" false") +
443 "\nAs a JSON-RPC call\n"
444 +
HelpExampleRpc(
"importpubkey",
"\"mypubkey\", \"testing\", false")
450 CWallet*
const pwallet = wallet.get();
454 std::string strLabel;
455 if (!request.params[1].isNull())
456 strLabel = request.params[1].get_str();
460 if (!request.params[2].isNull())
461 fRescan = request.params[2].get_bool();
471 if (fRescan && !reserver.
reserve()) {
475 if (!
IsHex(request.params[0].get_str()))
477 std::vector<unsigned char> data(
ParseHex(request.params[0].get_str()));
478 CPubKey pubKey(data.begin(), data.end());
479 if (!pubKey.IsFullyValid())
485 std::set<CScript> script_pub_keys;
494 pwallet->
ImportPubKeys({pubKey.GetID()}, {{pubKey.GetID(), pubKey}} , {} ,
false ,
false , 1 );
514 "\nImports keys from a wallet dump file (see dumpwallet). Requires a new wallet backup to include imported keys.\n"
515 "Note: Use \"getwalletinfo\" to query the scanning progress.\n",
521 "\nDump the wallet\n"
523 "\nImport the wallet\n"
525 "\nImport using the json rpc call\n"
532 CWallet*
const pwallet = wallet.get();
548 int64_t nTimeBegin = 0;
556 file.open(request.params[0].get_str(), std::ios::in | std::ios::ate);
557 if (!file.is_open()) {
562 int64_t nFilesize = std::max((int64_t)1, (int64_t)file.tellg());
563 file.seekg(0, file.beg);
568 std::vector<std::tuple<CKey, int64_t, bool, std::string>> keys;
569 std::vector<std::pair<CScript, int64_t>> scripts;
570 while (file.good()) {
571 pwallet->
chain().
showProgress(
"", std::max(1, std::min(50, (
int)(((
double)file.tellg() / (double)nFilesize) * 100))),
false);
573 std::getline(file, line);
574 if (line.empty() || line[0] ==
'#')
577 std::vector<std::string> vstr;
578 boost::split(vstr, line, boost::is_any_of(
" "));
584 std::string strLabel;
586 for (
unsigned int nStr = 2; nStr < vstr.size(); nStr++) {
587 if (vstr[nStr].front() ==
'#')
589 if (vstr[nStr] ==
"change=1")
591 if (vstr[nStr] ==
"reserve=1")
593 if (vstr[nStr].substr(0,6) ==
"label=") {
598 keys.push_back(std::make_tuple(key, nTime, fLabel, strLabel));
599 }
else if(
IsHex(vstr[0])) {
600 std::vector<unsigned char> vData(
ParseHex(vstr[0]));
603 scripts.push_back(std::pair<CScript, int64_t>(script, birth_time));
612 double total = (double)(keys.size() + scripts.size());
614 for (
const auto& key_tuple : keys) {
615 pwallet->
chain().
showProgress(
"", std::max(50, std::min(75, (
int)((progress / total) * 100) + 50)),
false);
616 const CKey& key = std::get<0>(key_tuple);
617 int64_t time = std::get<1>(key_tuple);
618 bool has_label = std::get<2>(key_tuple);
619 std::string label = std::get<3>(key_tuple);
621 CPubKey pubkey = key.GetPubKey();
623 CKeyID keyid = pubkey.GetID();
636 nTimeBegin = std::min(nTimeBegin, time);
639 for (
const auto& script_pair : scripts) {
640 pwallet->
chain().
showProgress(
"", std::max(50, std::min(75, (
int)((progress / total) * 100) + 50)),
false);
641 const CScript& script = script_pair.first;
642 int64_t time = script_pair.second;
650 nTimeBegin = std::min(nTimeBegin, time);
657 pwallet->chain().showProgress(
"", 100,
false);
659 pwallet->MarkDirty();
672 "\nReveals the private key corresponding to 'address'.\n"
673 "Then the importprivkey can be used with this output\n",
689 const CWallet*
const pwallet = wallet.get();
697 std::string strAddress = request.params[0].get_str();
703 if (keyid.IsNull()) {
707 if (!spk_man.
GetKey(keyid, vchSecret)) {
719 "\nDumps all wallet keys in a human-readable format to a server-side file. This does not allow overwriting existing files.\n"
720 "Imported scripts are included in the dumpfile, but corresponding BIP173 addresses, etc. may not be added automatically by importwallet.\n"
721 "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"
722 "only backing up the seed itself, and must be backed up too (e.g. ensure you back up the whole dumpfile).\n",
746 wallet.BlockUntilSyncedToCurrentChain();
752 fs::path filepath = request.params[0].get_str();
753 filepath = fs::absolute(filepath);
760 if (fs::exists(filepath)) {
769 std::map<CKeyID, int64_t> mapKeyBirth;
773 std::set<CScriptID> scripts = spk_man.
GetCScripts();
776 std::vector<std::pair<int64_t, CKeyID> > vKeyBirth;
777 for (
const auto& entry : mapKeyBirth) {
778 vKeyBirth.push_back(std::make_pair(entry.second, entry.first));
781 std::sort(vKeyBirth.begin(), vKeyBirth.end());
787 int64_t block_time = 0;
797 if (spk_man.
GetKey(seed_id, seed)) {
799 masterKey.
SetSeed(seed.begin(), seed.size());
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++) {
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) {
882 CPubKey pubkey(solverdata[0].begin(), solverdata[0].end());
883 import_data.
used_keys.emplace(pubkey.GetID(),
false);
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) {
904 CPubKey pubkey(solverdata[i].begin(), solverdata[i].end());
905 import_data.
used_keys.emplace(pubkey.GetID(),
false);
915 if (!subscript)
return "missing witnessscript";
916 if (
CScriptID(*subscript) !=
id)
return "witnessScript does not match the scriptPubKey or redeemScript";
933 return "unspendable script";
938 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")) {
975 if (!
IsHex(output)) {
978 std::vector<unsigned char> vData(
ParseHex(output));
979 script =
CScript(vData.begin(), vData.end());
985 script_pub_keys.emplace(script);
988 if (strRedeemScript.size()) {
989 if (!
IsHex(strRedeemScript)) {
992 auto parsed_redeemscript =
ParseHex(strRedeemScript);
993 import_data.
redeemscript = MakeUnique<CScript>(parsed_redeemscript.begin(), parsed_redeemscript.end());
995 if (witness_script_hex.size()) {
996 if (!
IsHex(witness_script_hex)) {
999 auto parsed_witnessscript =
ParseHex(witness_script_hex);
1000 import_data.
witnessscript = MakeUnique<CScript>(parsed_witnessscript.begin(), parsed_witnessscript.end());
1002 for (
size_t i = 0; i < pubKeys.
size(); ++i) {
1003 const auto& str = pubKeys[i].
get_str();
1007 auto parsed_pubkey =
ParseHex(str);
1008 CPubKey pubkey(parsed_pubkey.begin(), parsed_pubkey.end());
1009 if (!pubkey.IsFullyValid()) {
1012 pubkey_map.emplace(pubkey.GetID(), pubkey);
1013 ordered_pubkeys.push_back(pubkey.GetID());
1015 for (
size_t i = 0; i < keys.
size(); ++i) {
1016 const auto& str = keys[i].
get_str();
1018 if (!key.IsValid()) {
1021 CPubKey pubkey = key.GetPubKey();
1022 CKeyID id = pubkey.GetID();
1023 if (pubkey_map.count(
id)) {
1024 pubkey_map.erase(
id);
1026 privkey_map.emplace(
id, key);
1032 if (have_solving_data) {
1037 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; });
1038 if (!watchOnly && !spendable) {
1039 warnings.
push_back(
"Some private keys are missing, outputs will be considered watchonly. If this is intentional, specify the watchonly flag.");
1041 if (watchOnly && spendable) {
1042 warnings.
push_back(
"All private keys are provided, outputs will be considered spendable. If this is intentional, do not specify the watchonly flag.");
1046 if (
error.empty()) {
1047 for (
const auto& require_key : import_data.
used_keys) {
1048 if (!require_key.second)
continue;
1049 if (pubkey_map.count(require_key.first) == 0 && privkey_map.count(require_key.first) == 0) {
1050 error =
"some required keys are missing";
1055 if (!
error.empty()) {
1056 warnings.
push_back(
"Importing as non-solvable: " +
error +
". If this is intentional, don't provide any keys, pubkeys, witnessscript, or redeemscript.");
1059 privkey_map.clear();
1060 have_solving_data =
false;
1063 if (import_data.
redeemscript) warnings.
push_back(
"Ignoring redeemscript as this is not a P2SH script.");
1064 if (import_data.
witnessscript) warnings.
push_back(
"Ignoring witnessscript as this is not a (P2SH-)P2WSH script.");
1065 for (
auto it = privkey_map.begin();
it != privkey_map.end(); ) {
1067 if (import_data.
used_keys.count(oldit->first) == 0) {
1068 warnings.
push_back(
"Ignoring irrelevant private key.");
1069 privkey_map.erase(oldit);
1072 for (
auto it = pubkey_map.begin();
it != pubkey_map.end(); ) {
1074 auto key_data_it = import_data.
used_keys.find(oldit->first);
1075 if (key_data_it == import_data.
used_keys.end() || !key_data_it->second) {
1076 warnings.
push_back(
"Ignoring public key \"" +
HexStr(oldit->first) +
"\" as it doesn't appear inside P2PKH or P2WPKH.");
1077 pubkey_map.erase(oldit);
1086 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)
1090 const std::string& descriptor = data[
"desc"].
get_str();
1093 auto parsed_desc =
Parse(descriptor, keys, error,
true);
1098 have_solving_data = parsed_desc->IsSolvable();
1099 const bool watch_only = data.
exists(
"watchonly") ? data[
"watchonly"].
get_bool() :
false;
1101 int64_t range_start = 0, range_end = 0;
1102 if (!parsed_desc->IsRange() && data.
exists(
"range")) {
1104 }
else if (parsed_desc->IsRange()) {
1105 if (!data.
exists(
"range")) {
1114 for (
int i = range_start; i <= range_end; ++i) {
1116 std::vector<CScript> scripts_temp;
1117 parsed_desc->Expand(i, keys, scripts_temp, out_keys);
1118 std::copy(scripts_temp.begin(), scripts_temp.end(), std::inserter(script_pub_keys, script_pub_keys.end()));
1119 for (
const auto& key_pair : out_keys.
pubkeys) {
1120 ordered_pubkeys.push_back(key_pair.first);
1123 for (
const auto& x : out_keys.
scripts) {
1127 parsed_desc->ExpandPrivate(i, keys, out_keys);
1129 std::copy(out_keys.
pubkeys.begin(), out_keys.
pubkeys.end(), std::inserter(pubkey_map, pubkey_map.end()));
1130 std::copy(out_keys.
keys.begin(), out_keys.
keys.end(), std::inserter(privkey_map, privkey_map.end()));
1134 for (
size_t i = 0; i < priv_keys.
size(); ++i) {
1135 const auto& str = priv_keys[i].
get_str();
1137 if (!key.IsValid()) {
1140 CPubKey pubkey = key.GetPubKey();
1141 CKeyID id = pubkey.GetID();
1144 if (!pubkey_map.count(
id)) {
1145 warnings.
push_back(
"Ignoring irrelevant private key.");
1147 privkey_map.emplace(
id, key);
1155 bool spendable = std::all_of(pubkey_map.begin(), pubkey_map.end(),
1156 [&](
const std::pair<CKeyID, CPubKey>& used_key) {
1157 return privkey_map.count(used_key.first) > 0;
1159 [&](
const std::pair<CKeyID, std::pair<CPubKey, KeyOriginInfo>>& entry) {
1160 return privkey_map.count(entry.first) > 0;
1162 if (!watch_only && !spendable) {
1163 warnings.
push_back(
"Some private keys are missing, outputs will be considered watchonly. If this is intentional, specify the watchonly flag.");
1165 if (watch_only && spendable) {
1166 warnings.
push_back(
"All private keys are provided, outputs will be considered spendable. If this is intentional, do not specify the watchonly flag.");
1178 const bool internal = data.exists(
"internal") ? data[
"internal"].get_bool() :
false;
1180 if (
internal && data.exists(
"label")) {
1183 const std::string& label = data.exists(
"label") ? data[
"label"].get_str() :
"";
1184 const bool add_keypool = data.exists(
"keypool") ? data[
"keypool"].get_bool() :
false;
1192 std::map<CKeyID, CPubKey> pubkey_map;
1193 std::map<CKeyID, CKey> privkey_map;
1194 std::set<CScript> script_pub_keys;
1195 std::vector<CKeyID> ordered_pubkeys;
1196 bool have_solving_data;
1198 if (data.exists(
"scriptPubKey") && data.exists(
"desc")) {
1200 }
else if (data.exists(
"scriptPubKey")) {
1201 warnings =
ProcessImportLegacy(import_data, pubkey_map, privkey_map, script_pub_keys, have_solving_data, data, ordered_pubkeys);
1202 }
else if (data.exists(
"desc")) {
1203 warnings =
ProcessImportDescriptor(import_data, pubkey_map, privkey_map, script_pub_keys, have_solving_data, data, ordered_pubkeys);
1214 for (
const CScript& script : script_pub_keys) {
1221 pwallet->MarkDirty();
1222 if (!pwallet->ImportScripts(import_data.
import_scripts, timestamp)) {
1225 if (!pwallet->ImportPrivKeys(privkey_map, timestamp)) {
1228 if (!pwallet->ImportPubKeys(ordered_pubkeys, pubkey_map, import_data.
key_origins, add_keypool,
internal, timestamp)) {
1231 if (!pwallet->ImportScriptPubKeys(label, script_pub_keys, have_solving_data, !
internal, timestamp)) {
1238 result.
pushKV(
"error", e);
1244 if (warnings.
size()) result.
pushKV(
"warnings", warnings);
1250 if (data.
exists(
"timestamp")) {
1251 const UniValue& timestamp = data[
"timestamp"];
1252 if (timestamp.
isNum()) {
1254 }
else if (timestamp.
isStr() && timestamp.
get_str() ==
"now") {
1265 "\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"
1266 "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"
1267 "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"
1268 "\nNote: This call can take over an hour to complete if rescan is true, during that time, other rpc calls\n"
1269 "may report that the imported keys, addresses or scripts exist but related transactions are still missing.\n"
1270 "Note: Use \"getwalletinfo\" to query the scanning progress.\n",
1278 "", {
"\"<script>\" | { \"address\":\"<address>\" }",
"string / json"}
1281 " or the string \"now\" to substitute the current synced blockchain time. The timestamp of the oldest\n"
1282 " key will determine how far back blockchain rescans need to begin for missing wallet transactions.\n"
1283 " \"now\" can be specified to bypass scanning, for keys which are known to never have been used, and\n"
1284 " 0 can be specified to scan the entire blockchain. Blocks up to 2 hours before the earliest key\n"
1285 " creation time of all keys being imported by the importmulti call will be scanned.",
1286 "", {
"timestamp | \"now\"",
"integer / string"}
1290 {
"pubkeys",
RPCArg::Type::ARR,
"empty array",
"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).",
1295 {
"keys",
RPCArg::Type::ARR,
"empty array",
"Array of strings giving private keys to import. The corresponding public keys must occur in the output or redeemscript.",
1301 {
"internal",
RPCArg::Type::BOOL,
"false",
"Stating whether matching outputs should be treated as not incoming payments (also known as change)"},
1302 {
"watchonly",
RPCArg::Type::BOOL,
"false",
"Stating whether matching outputs should be considered watchonly."},
1303 {
"label",
RPCArg::Type::STR,
"''",
"Label to assign to the address, only allowed with internal=false"},
1304 {
"keypool",
RPCArg::Type::BOOL,
"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"},
1311 {
"rescan",
RPCArg::Type::BOOL,
"true",
"Stating if should rescan the blockchain after all imports"},
1316 RPCResult::Type::ARR,
"",
"Response is an array with the same size as the input that has the execution result",
1333 HelpExampleCli(
"importmulti",
"'[{ \"scriptPubKey\": { \"address\": \"<my address>\" }, \"timestamp\":1455191478 }, "
1334 "{ \"scriptPubKey\": { \"address\": \"<my 2nd address>\" }, \"label\": \"example 2\", \"timestamp\": 1455191480 }]'") +
1335 HelpExampleCli(
"importmulti",
"'[{ \"scriptPubKey\": { \"address\": \"<my address>\" }, \"timestamp\":1455191478 }]' '{ \"rescan\": false}'")
1341 CWallet*
const pwallet = wallet.get();
1343 RPCTypeCheck(mainRequest.params, {UniValue::VARR, UniValue::VOBJ});
1347 const UniValue& requests = mainRequest.params[0];
1350 bool fRescan =
true;
1352 if (!mainRequest.params[1].isNull()) {
1353 const UniValue& options = mainRequest.params[1];
1355 if (options.
exists(
"rescan")) {
1356 fRescan = options[
"rescan"].
get_bool();
1361 if (fRescan && !reserver.
reserve()) {
1366 bool fRunScan =
false;
1367 int64_t nLowestTimestamp = 0;
1379 const int64_t minimumTimestamp = 1;
1391 if (result[
"success"].get_bool()) {
1396 if (timestamp < nLowestTimestamp) {
1397 nLowestTimestamp = timestamp;
1401 if (fRescan && fRunScan && requests.
size()) {
1402 int64_t scannedTime = pwallet->
RescanFromTime(nLowestTimestamp, reserver,
true );
1411 if (scannedTime > nLowestTimestamp) {
1412 std::vector<UniValue> results = response.
getValues();
1421 if (scannedTime <=
GetImportTimestamp(request, now) || results.at(i).exists(
"error")) {
1430 strprintf(
"Rescan failed for key with creation timestamp %d. There was an error reading a "
1431 "block from time %d, which is after or within %d seconds of key creation, and "
1432 "could contain transactions pertaining to the key. As a result, transactions "
1433 "and coins using this key may not appear in the wallet. This error could be "
1434 "caused by pruning or data corruption (see bitcoind log for details) and could "
1435 "be dealt with by downloading and rescanning the relevant blocks (see -reindex "
1436 "and -rescan options).",
1456 if (!data.exists(
"desc")) {
1460 const std::string& descriptor = data[
"desc"].get_str();
1461 const bool active = data.exists(
"active") ? data[
"active"].get_bool() :
false;
1462 const bool internal = data.exists(
"internal") ? data[
"internal"].get_bool() :
false;
1463 const std::string& label = data.exists(
"label") ? data[
"label"].get_str() :
"";
1468 auto parsed_desc =
Parse(descriptor, keys, error,
true);
1474 int64_t range_start = 0, range_end = 1, next_index = 0;
1475 if (!parsed_desc->IsRange() && data.exists(
"range")) {
1477 }
else if (parsed_desc->IsRange()) {
1478 if (data.exists(
"range")) {
1480 range_start = range.first;
1481 range_end = range.second + 1;
1483 warnings.
push_back(
"Range not given, using default keypool range");
1487 next_index = range_start;
1489 if (data.exists(
"next_index")) {
1490 next_index = data[
"next_index"].get_int64();
1492 if (next_index < range_start || next_index >= range_end) {
1499 if (active && !parsed_desc->IsRange()) {
1504 if (data.exists(
"range") && data.exists(
"label")) {
1509 if (
internal && data.exists(
"label")) {
1514 if (active && !parsed_desc->IsSingleType()) {
1525 std::vector<CScript> scripts;
1526 if (!parsed_desc->Expand(0, keys, scripts, expand_keys)) {
1527 throw JSONRPCError(
RPC_WALLET_ERROR,
"Cannot expand descriptor. Probably because of hardened derivations without private keys provided");
1529 parsed_desc->ExpandPrivate(0, keys, expand_keys);
1532 bool have_all_privkeys = !expand_keys.
keys.empty();
1533 for (
const auto& entry : expand_keys.
origins) {
1534 const CKeyID& key_id = entry.first;
1536 if (!expand_keys.
GetKey(key_id, key)) {
1537 have_all_privkeys =
false;
1544 if (keys.
keys.empty()) {
1547 if (!have_all_privkeys) {
1548 warnings.
push_back(
"Not all private keys provided. Some wallet functionality may return unexpected errors");
1552 WalletDescriptor w_desc(std::move(parsed_desc), timestamp, range_start, range_end, next_index);
1555 auto existing_spk_manager = pwallet->GetDescriptorScriptPubKeyMan(w_desc);
1556 if (existing_spk_manager) {
1557 LOCK(existing_spk_manager->cs_desc_man);
1558 if (range_start > existing_spk_manager->GetWalletDescriptor().range_start) {
1559 throw JSONRPCError(
RPC_INVALID_PARAMS,
strprintf(
"range_start can only decrease; current range = [%d,%d]", existing_spk_manager->GetWalletDescriptor().range_start, existing_spk_manager->GetWalletDescriptor().range_end));
1564 auto spk_manager = pwallet->AddWalletDescriptor(w_desc, keys, label,
internal);
1565 if (spk_manager ==
nullptr) {
1572 warnings.
push_back(
"Unknown output type, cannot set descriptor to active.");
1574 pwallet->AddActiveScriptPubKeyMan(spk_manager->GetID(), *w_desc.
descriptor->GetOutputType(),
internal);
1581 result.
pushKV(
"error", e);
1587 if (warnings.
size()) result.
pushKV(
"warnings", warnings);
1594 "\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"
1595 "\nNote: This call can take over an hour to complete if using an early timestamp; during that time, other rpc calls\n"
1596 "may report that the imported keys, addresses or scripts exist but related transactions are still missing.\n",
1603 {
"active",
RPCArg::Type::BOOL,
"false",
"Set this descriptor to be the active descriptor for the corresponding output type/externality"},
1607 " Use the string \"now\" to substitute the current synced blockchain time.\n"
1608 " \"now\" can be specified to bypass scanning, for outputs which are known to never have been used, and\n"
1609 " 0 can be specified to scan the entire blockchain. Blocks up to 2 hours before the earliest timestamp\n"
1610 " of all descriptors being imported will be scanned.",
1611 "", {
"timestamp | \"now\"",
"integer / string"}
1613 {
"internal",
RPCArg::Type::BOOL,
"false",
"Whether matching outputs should be treated as not incoming payments (e.g. change)"},
1614 {
"label",
RPCArg::Type::STR,
"''",
"Label to assign to the address, only allowed with internal=false"},
1621 RPCResult::Type::ARR,
"",
"Response is an array with the same size as the input that has the execution result",
1638 HelpExampleCli(
"importdescriptors",
"'[{ \"desc\": \"<my descriptor>\", \"timestamp\":1455191478, \"internal\": true }, "
1639 "{ \"desc\": \"<my desccriptor 2>\", \"label\": \"example 2\", \"timestamp\": 1455191480 }]'") +
1640 HelpExampleCli(
"importdescriptors",
"'[{ \"desc\": \"<my descriptor>\", \"timestamp\":1455191478, \"active\": true, \"range\": [0,100], \"label\": \"<my bech32 wallet>\" }]'")
1646 CWallet*
const pwallet = wallet.get();
1653 RPCTypeCheck(main_request.params, {UniValue::VARR, UniValue::VOBJ});
1660 const UniValue& requests = main_request.params[0];
1661 const int64_t minimum_timestamp = 1;
1663 int64_t lowest_timestamp = 0;
1664 bool rescan =
false;
1675 const int64_t timestamp = std::max(
GetImportTimestamp(request, now), minimum_timestamp);
1679 if (lowest_timestamp > timestamp ) {
1680 lowest_timestamp = timestamp;
1684 if (!rescan && result[
"success"].get_bool()) {
1693 int64_t scanned_time = pwallet->
RescanFromTime(lowest_timestamp, reserver,
true );
1703 if (scanned_time > lowest_timestamp) {
1704 std::vector<UniValue> results = response.
getValues();
1709 for (
unsigned int i = 0; i < requests.
size(); ++i) {
1716 if (scanned_time <=
GetImportTimestamp(request, now) || results.at(i).exists(
"error")) {
1725 strprintf(
"Rescan failed for descriptor with timestamp %d. There was an error reading a "
1726 "block from time %d, which is after or within %d seconds of key creation, and "
1727 "could contain transactions pertaining to the desc. As a result, transactions "
1728 "and coins using this desc may not appear in the wallet. This error could be "
1729 "caused by pruning or data corruption (see bitcoind log for details) and could "
1730 "be dealt with by downloading and rescanning the relevant blocks (see -reindex "
1731 "and -rescan options).",
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 std::string & get_str() const
bool IsWalletFlagSet(uint64_t flag) const override
check if a certain wallet flag is set
void RPCTypeCheck(const UniValue ¶ms, const std::list< UniValueType > &typesExpected, bool fAllowNull)
Type-check arguments; throws JSONRPCError if wrong type given.
void WalletLogPrintf(std::string fmt, Params...parameters) const
Prepends the wallet name in logging output to ease debugging in multi-wallet use cases.
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
static UniValue ProcessImport(CWallet *const pwallet, const UniValue &data, const int64_t timestamp) EXCLUSIVE_LOCKS_REQUIRED(pwallet-> cs_wallet)
isminetype IsMine(const CTxDestination &dest) const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
RecursiveMutex cs_KeyStore
std::map< CKeyID, CKey > keys
std::vector< unsigned char > ParseHexV(const UniValue &v, std::string strName)
void ReacceptWalletTransactions() EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
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...
const std::vector< UniValue > & getValues() const
#define CHECK_NONFATAL(condition)
Throw a NonFatalCheckError when the condition evaluates to false.
std::vector< unsigned char > ParseHex(const char *psz)
void EnsureWalletIsUnlocked(const CWallet *pwallet)
static CTransactionRef MakeTransactionRef()
bool IsValidDestination(const CTxDestination &dest)
Check whether a CTxDestination is a CNoDestination.
std::map< CKeyID, std::pair< CPubKey, KeyOriginInfo > > origins
std::string FormatISO8601DateTime(int64_t nTime)
ISO 8601 formatting is preferred.
CKeyID GetKeyForDestination(const SigningProvider &store, const CTxDestination &dest)
Return the CKeyID of the key involved in a script (if there is a unique one).
Double ended buffer combining vector and stream-like interfaces.
int64_t ParseISO8601DateTime(const std::string &str)
int GetLastBlockHeight() const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
Get last block processed height.
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
bool ImportScripts(const std::set< CScript > scripts, int64_t timestamp) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
Invalid, missing or duplicate parameter.
interfaces::Chain & chain() const
Interface for accessing chain state.
std::vector< CTxDestination > GetAllDestinationsForKey(const CPubKey &key)
Get all destinations (potentially) supported by the wallet for the given key.
RPCHelpMan removeprunedfunds()
std::string ToString() const
DBErrors ZapSelectTx(std::vector< uint256 > &vHashIn, std::vector< uint256 > &vHashOut) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
enum VType getType() const
bool SetAddressBook(const CTxDestination &address, const std::string &strName, const std::string &purpose)
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)
bool error(const char *fmt, const Args &...args)
Used to relay blocks as header + vector to filtered nodes.
int64_t get_int64() const
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)
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)
void GetKeyBirthTimes(std::map< CKeyID, int64_t > &mapKeyBirth) const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
static const unsigned int DEFAULT_KEYPOOL_SIZE
Default for -keypool.
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
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.
virtual bool findBlock(const uint256 &hash, const FoundBlock &block={})=0
Return whether node has the block and optionally return block metadata or contents.
RPCHelpMan importprivkey()
uint256 GetLastBlockHash() const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
bool ImportPrivKeys(const std::map< CKeyID, CKey > &privkey_map, const int64_t timestamp) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
bool GetKey(const CKeyID &address, CKey &keyOut) const override
RPCHelpMan importwallet()
bool ImportScriptPubKeys(const std::string &label, const std::set< CScript > &script_pub_keys, const bool have_solving_data, const bool apply_label, const int64_t timestamp) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
General application defined errors.
bool pushKV(const std::string &key, const UniValue &val)
static void RescanWallet(CWallet &wallet, const WalletRescanReserver &reserver, int64_t time_begin=TIMESTAMP_MIN, bool update=true)
bool ImportPubKeys(const std::vector< CKeyID > &ordered_pubkeys, const std::map< CKeyID, CPubKey > &pubkey_map, const std::map< CKeyID, std::pair< CPubKey, KeyOriginInfo >> &key_origins, const bool add_keypool, const bool internal, const int64_t timestamp) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
CWalletTx * AddToWallet(CTransactionRef tx, const CWalletTx::Confirmation &confirm, const UpdateWalletTxFn &update_wtx=nullptr, bool fFlushOnClose=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 ConnectScriptPubKeyManNotifiers()
Connect the signals from ScriptPubKeyMans to the signals in CWallet.
void SetSeed(const unsigned char *seed, unsigned int nSeedLen)
uint256 GetHash() const
Compute the hash of this CMutableTransaction.
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.
CRIPEMD160 & Write(const unsigned char *data, size_t len)
bool IsAbortingRescan() const
std::unique_ptr< CScript > redeemscript
Provided redeemScript; will be moved to import_scripts if relevant.
Special type that is a NUM or [NUM,NUM].
const std::map< CKeyID, int64_t > & GetAllReserveKeys() const
virtual std::set< CScriptID > GetCScripts() const
Optional argument with default value omitted because they are implicitly clear.
CTxDestination DecodeDestination(const std::string &str)
const CHDChain & GetHDChain() const
#define EXCLUSIVE_LOCKS_REQUIRED(...)
bool GetKey(const CKeyID &keyid, CKey &key) const override
RPCHelpMan importdescriptors()
virtual bool findAncestorByHash(const uint256 &block_hash, const uint256 &ancestor_hash, const FoundBlock &ancestor_out={})=0
Return whether block descends from a specified ancestor, and optionally return ancestor information...
const UniValue & get_array() const
Serialized script, used inside transaction inputs and outputs.
static const int PROTOCOL_VERSION
network protocol versioning
std::string GetArg(const std::string &strArg, const std::string &strDefault) const
Return string argument or default value.
std::string WriteHDKeypath(const std::vector< uint32_t > &keypath)
Write HD keypaths as strings.
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.
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 std::string GetDisplayName() const override
Returns a bracketed wallet name for displaying in logs, will return [default wallet] if the wallet ha...
const UniValue NullUniValue
RPCHelpMan importprunedfunds()
static bool GetWalletAddressesForKey(LegacyScriptPubKeyMan *spk_man, const CWallet *const pwallet, const CKeyID &keyid, std::string &strAddr, std::string &strLabel) EXCLUSIVE_LOCKS_REQUIRED(pwallet-> cs_wallet)
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].
virtual void showProgress(const std::string &title, int progress, bool resume_possible)=0
Send progress indicator.
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)
bool exists(const std::string &key) const
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).
static int64_t GetImportTimestamp(const UniValue &data, int64_t now)
CKey DecodeSecret(const std::string &str)
int64_t RescanFromTime(int64_t startTime, const WalletRescanReserver &reserver, bool update)
Scan active chain for relevant transactions after importing keys.
boost::variant< CNoDestination, PKHash, ScriptHash, WitnessV0ScriptHash, WitnessV0KeyHash, WitnessUnknown > CTxDestination
A txout script template with a specific destination.
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)
const CAddressBookData * FindAddressBookEntry(const CTxDestination &, bool allow_change=false) const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
static UniValue ProcessDescriptorImport(CWallet *const pwallet, const UniValue &data, const int64_t timestamp) EXCLUSIVE_LOCKS_REQUIRED(pwallet-> cs_wallet)
const std::string CLIENT_BUILD
RPCHelpMan importpubkey()
std::string EncodeExtKey(const CExtKey &key)
FoundBlock & time(int64_t &time)
virtual bool havePruned()=0
Check if any block has been pruned.
Error parsing or validating structure in raw format.
A hasher class for RIPEMD-160.
Special type to denote elision (...)
unsigned int size() const
NODISCARD bool DecodeHexTx(CMutableTransaction &tx, const std::string &hex_tx, bool try_no_witness=false, bool try_witness=true)