Changeset View
Changeset View
Standalone View
Standalone View
src/wallet/rpcdump.cpp
Show First 20 Lines • Show All 107 Lines • ▼ Show 20 Lines | |||||
UniValue importprivkey(const Config &config, const JSONRPCRequest &request) { | UniValue importprivkey(const Config &config, const JSONRPCRequest &request) { | ||||
std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request); | std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request); | ||||
CWallet *const pwallet = wallet.get(); | CWallet *const pwallet = wallet.get(); | ||||
if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) { | if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) { | ||||
return NullUniValue; | return NullUniValue; | ||||
} | } | ||||
if (request.fHelp || request.params.size() < 1 || request.params.size() > 3) | if (request.fHelp || request.params.size() < 1 || | ||||
request.params.size() > 3) { | |||||
throw std::runtime_error( | throw std::runtime_error( | ||||
"importprivkey \"privkey\" ( \"label\" ) ( rescan )\n" | "importprivkey \"privkey\" ( \"label\" ) ( rescan )\n" | ||||
"\nAdds a private key (as returned by dumpprivkey) to your wallet. " | "\nAdds a private key (as returned by dumpprivkey) to your wallet. " | ||||
"Requires a new wallet backup.\n" | "Requires a new wallet backup.\n" | ||||
"Hint: use importmulti to import more than one private key.\n" | "Hint: use importmulti to import more than one private key.\n" | ||||
"\nArguments:\n" | "\nArguments:\n" | ||||
"1. \"privkey\" (string, required) The private key (see " | "1. \"privkey\" (string, required) The private key (see " | ||||
"dumpprivkey)\n" | "dumpprivkey)\n" | ||||
Show All 12 Lines | if (request.fHelp || request.params.size() < 1 || | ||||
"\nImport the private key with rescan\n" + | "\nImport the private key with rescan\n" + | ||||
HelpExampleCli("importprivkey", "\"mykey\"") + | HelpExampleCli("importprivkey", "\"mykey\"") + | ||||
"\nImport using a label and without rescan\n" + | "\nImport using a label and without rescan\n" + | ||||
HelpExampleCli("importprivkey", "\"mykey\" \"testing\" false") + | HelpExampleCli("importprivkey", "\"mykey\" \"testing\" false") + | ||||
"\nImport using default blank label and without rescan\n" + | "\nImport using default blank label and without rescan\n" + | ||||
HelpExampleCli("importprivkey", "\"mykey\" \"\" false") + | HelpExampleCli("importprivkey", "\"mykey\" \"\" false") + | ||||
"\nAs a JSON-RPC call\n" + | "\nAs a JSON-RPC call\n" + | ||||
HelpExampleRpc("importprivkey", "\"mykey\", \"testing\", false")); | HelpExampleRpc("importprivkey", "\"mykey\", \"testing\", false")); | ||||
} | |||||
if (pwallet->IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS)) { | |||||
throw JSONRPCError(RPC_WALLET_ERROR, | |||||
"Cannot import private keys to a wallet with " | |||||
"private keys disabled"); | |||||
} | |||||
WalletRescanReserver reserver(pwallet); | WalletRescanReserver reserver(pwallet); | ||||
bool fRescan = true; | bool fRescan = true; | ||||
{ | { | ||||
LOCK2(cs_main, pwallet->cs_wallet); | LOCK2(cs_main, pwallet->cs_wallet); | ||||
EnsureWalletIsUnlocked(pwallet); | EnsureWalletIsUnlocked(pwallet); | ||||
▲ Show 20 Lines • Show All 503 Lines • ▼ Show 20 Lines | bool fGood = true; | ||||
// pwallet.ShowProgress has a cancel button tied to AbortRescan which we | // pwallet.ShowProgress has a cancel button tied to AbortRescan which we | ||||
// don't want for this progress bar showing the import progress. | // don't want for this progress bar showing the import progress. | ||||
// uiInterface.ShowProgress does not have a cancel button. | // uiInterface.ShowProgress does not have a cancel button. | ||||
// show progress dialog in GUI | // show progress dialog in GUI | ||||
uiInterface.ShowProgress( | uiInterface.ShowProgress( | ||||
strprintf("%s " + _("Importing..."), pwallet->GetDisplayName()), 0, | strprintf("%s " + _("Importing..."), pwallet->GetDisplayName()), 0, | ||||
false); | false); | ||||
std::vector<std::tuple<CKey, int64_t, bool, std::string>> keys; | |||||
std::vector<std::pair<CScript, int64_t>> scripts; | |||||
while (file.good()) { | while (file.good()) { | ||||
uiInterface.ShowProgress( | uiInterface.ShowProgress( | ||||
"", | "", | ||||
std::max(1, std::min(99, (int)(((double)file.tellg() / | std::max(1, std::min<int>(50, 100 * double(file.tellg()) / | ||||
(double)nFilesize) * | double(nFilesize))), | ||||
100))), | |||||
false); | false); | ||||
std::string line; | std::string line; | ||||
std::getline(file, line); | std::getline(file, line); | ||||
if (line.empty() || line[0] == '#') { | if (line.empty() || line[0] == '#') { | ||||
continue; | continue; | ||||
} | } | ||||
std::vector<std::string> vstr; | std::vector<std::string> vstr; | ||||
boost::split(vstr, line, boost::is_any_of(" ")); | boost::split(vstr, line, boost::is_any_of(" ")); | ||||
if (vstr.size() < 2) { | if (vstr.size() < 2) { | ||||
continue; | continue; | ||||
} | } | ||||
CKey key = DecodeSecret(vstr[0]); | CKey key = DecodeSecret(vstr[0]); | ||||
if (key.IsValid()) { | if (key.IsValid()) { | ||||
CPubKey pubkey = key.GetPubKey(); | |||||
assert(key.VerifyPubKey(pubkey)); | |||||
CKeyID keyid = pubkey.GetID(); | |||||
if (pwallet->HaveKey(keyid)) { | |||||
pwallet->WalletLogPrintf( | |||||
"Skipping import of %s (key already present)\n", | |||||
EncodeDestination(keyid, config)); | |||||
continue; | |||||
} | |||||
int64_t nTime = DecodeDumpTime(vstr[1]); | int64_t nTime = DecodeDumpTime(vstr[1]); | ||||
std::string strLabel; | std::string strLabel; | ||||
bool fLabel = true; | bool fLabel = true; | ||||
for (unsigned int nStr = 2; nStr < vstr.size(); nStr++) { | for (size_t nStr = 2; nStr < vstr.size(); nStr++) { | ||||
if (vstr[nStr].front() == '#') { | if (vstr[nStr].front() == '#') { | ||||
break; | break; | ||||
} | } | ||||
if (vstr[nStr] == "change=1") { | if (vstr[nStr] == "change=1") { | ||||
fLabel = false; | fLabel = false; | ||||
} | } | ||||
if (vstr[nStr] == "reserve=1") { | if (vstr[nStr] == "reserve=1") { | ||||
fLabel = false; | fLabel = false; | ||||
} | } | ||||
if (vstr[nStr].substr(0, 6) == "label=") { | if (vstr[nStr].substr(0, 6) == "label=") { | ||||
strLabel = DecodeDumpString(vstr[nStr].substr(6)); | strLabel = DecodeDumpString(vstr[nStr].substr(6)); | ||||
fLabel = true; | fLabel = true; | ||||
} | } | ||||
} | } | ||||
keys.push_back(std::make_tuple(key, nTime, fLabel, strLabel)); | |||||
} else if (IsHex(vstr[0])) { | |||||
std::vector<uint8_t> vData(ParseHex(vstr[0])); | |||||
CScript script = CScript(vData.begin(), vData.end()); | |||||
int64_t birth_time = DecodeDumpTime(vstr[1]); | |||||
scripts.push_back( | |||||
std::pair<CScript, int64_t>(script, birth_time)); | |||||
} | |||||
} | |||||
file.close(); | |||||
// We now know whether we are importing private keys, so we can error if | |||||
// private keys are disabled | |||||
if (keys.size() > 0 && | |||||
pwallet->IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS)) { | |||||
// hide progress dialog in GUI | |||||
uiInterface.ShowProgress("", 100, false); | |||||
throw JSONRPCError( | |||||
RPC_WALLET_ERROR, | |||||
"Importing wallets is disabled when private keys are disabled"); | |||||
} | |||||
double total = double(keys.size() + scripts.size()); | |||||
double progress = 0; | |||||
for (const auto &key_tuple : keys) { | |||||
uiInterface.ShowProgress( | |||||
"", | |||||
std::max(50, std::min<int>(75, (progress / total) * 100) + 50), | |||||
false); | |||||
const CKey &key = std::get<0>(key_tuple); | |||||
int64_t time = std::get<1>(key_tuple); | |||||
bool has_label = std::get<2>(key_tuple); | |||||
std::string label = std::get<3>(key_tuple); | |||||
CPubKey pubkey = key.GetPubKey(); | |||||
assert(key.VerifyPubKey(pubkey)); | |||||
CKeyID keyid = pubkey.GetID(); | |||||
if (pwallet->HaveKey(keyid)) { | |||||
pwallet->WalletLogPrintf( | |||||
"Skipping import of %s (key already present)\n", | |||||
EncodeDestination(keyid, config)); | |||||
continue; | |||||
} | |||||
pwallet->WalletLogPrintf("Importing %s...\n", | pwallet->WalletLogPrintf("Importing %s...\n", | ||||
EncodeDestination(keyid, config)); | EncodeDestination(keyid, config)); | ||||
if (!pwallet->AddKeyPubKey(key, pubkey)) { | if (!pwallet->AddKeyPubKey(key, pubkey)) { | ||||
fGood = false; | fGood = false; | ||||
continue; | continue; | ||||
} | } | ||||
pwallet->mapKeyMetadata[keyid].nCreateTime = nTime; | pwallet->mapKeyMetadata[keyid].nCreateTime = time; | ||||
if (fLabel) { | if (has_label) { | ||||
pwallet->SetAddressBook(keyid, strLabel, "receive"); | pwallet->SetAddressBook(keyid, label, "receive"); | ||||
} | } | ||||
nTimeBegin = std::min(nTimeBegin, nTime); | nTimeBegin = std::min(nTimeBegin, time); | ||||
} else if (IsHex(vstr[0])) { | progress++; | ||||
std::vector<uint8_t> vData(ParseHex(vstr[0])); | } | ||||
CScript script = CScript(vData.begin(), vData.end()); | for (const auto &script_pair : scripts) { | ||||
if (pwallet->HaveCScript(script)) { | uiInterface.ShowProgress( | ||||
"", | |||||
std::max(50, std::min<int>(75, (progress / total) * 100) + 50), | |||||
false); | |||||
const CScript &script = script_pair.first; | |||||
int64_t time = script_pair.second; | |||||
CScriptID id(script); | |||||
if (pwallet->HaveCScript(id)) { | |||||
pwallet->WalletLogPrintf( | pwallet->WalletLogPrintf( | ||||
"Skipping import of %s (script already present)\n", | "Skipping import of %s (script already present)\n", | ||||
vstr[0]); | HexStr(script)); | ||||
continue; | continue; | ||||
} | } | ||||
if (!pwallet->AddCScript(script)) { | if (!pwallet->AddCScript(script)) { | ||||
pwallet->WalletLogPrintf("Error importing script %s\n", | pwallet->WalletLogPrintf("Error importing script %s\n", | ||||
vstr[0]); | HexStr(script)); | ||||
fGood = false; | fGood = false; | ||||
continue; | continue; | ||||
} | } | ||||
int64_t birth_time = DecodeDumpTime(vstr[1]); | if (time > 0) { | ||||
if (birth_time > 0) { | pwallet->m_script_metadata[id].nCreateTime = time; | ||||
pwallet->m_script_metadata[CScriptID(script)].nCreateTime = | nTimeBegin = std::min(nTimeBegin, time); | ||||
birth_time; | |||||
nTimeBegin = std::min(nTimeBegin, birth_time); | |||||
} | } | ||||
progress++; | |||||
} | } | ||||
} | |||||
file.close(); | |||||
// hide progress dialog in GUI | // hide progress dialog in GUI | ||||
uiInterface.ShowProgress("", 100, false); | uiInterface.ShowProgress("", 100, false); | ||||
pwallet->UpdateTimeFirstKey(nTimeBegin); | pwallet->UpdateTimeFirstKey(nTimeBegin); | ||||
} | } | ||||
// hide progress dialog in GUI | // hide progress dialog in GUI | ||||
uiInterface.ShowProgress("", 100, false); | uiInterface.ShowProgress("", 100, false); | ||||
RescanWallet(*pwallet, reserver, nTimeBegin, false /* update */); | RescanWallet(*pwallet, reserver, nTimeBegin, false /* update */); | ||||
pwallet->MarkDirty(); | pwallet->MarkDirty(); | ||||
▲ Show 20 Lines • Show All 231 Lines • ▼ Show 20 Lines | try { | ||||
data.exists("keys") ? data["keys"].get_array() : UniValue(); | data.exists("keys") ? data["keys"].get_array() : UniValue(); | ||||
const bool internal = | const bool internal = | ||||
data.exists("internal") ? data["internal"].get_bool() : false; | data.exists("internal") ? data["internal"].get_bool() : false; | ||||
const bool watchOnly = | const bool watchOnly = | ||||
data.exists("watchonly") ? data["watchonly"].get_bool() : false; | data.exists("watchonly") ? data["watchonly"].get_bool() : false; | ||||
const std::string &label = | const std::string &label = | ||||
data.exists("label") && !internal ? data["label"].get_str() : ""; | data.exists("label") && !internal ? data["label"].get_str() : ""; | ||||
// If private keys are disabled, abort if private keys are being | |||||
// imported | |||||
if (pwallet->IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS) && | |||||
!keys.isNull()) { | |||||
throw JSONRPCError(RPC_WALLET_ERROR, | |||||
"Cannot import private keys to a wallet with " | |||||
"private keys disabled"); | |||||
} | |||||
bool isScript = scriptPubKey.getType() == UniValue::VSTR; | bool isScript = scriptPubKey.getType() == UniValue::VSTR; | ||||
bool isP2SH = strRedeemScript.length() > 0; | bool isP2SH = strRedeemScript.length() > 0; | ||||
const std::string &output = isScript | const std::string &output = isScript | ||||
? scriptPubKey.get_str() | ? scriptPubKey.get_str() | ||||
: scriptPubKey["address"].get_str(); | : scriptPubKey["address"].get_str(); | ||||
// Parse the output. | // Parse the output. | ||||
CScript script; | CScript script; | ||||
▲ Show 20 Lines • Show All 525 Lines • Show Last 20 Lines |