Changeset View
Changeset View
Standalone View
Standalone View
src/wallet/rpcdump.cpp
Show First 20 Lines • Show All 80 Lines • ▼ Show 20 Lines | if (request.fHelp || request.params.size() < 1 || request.params.size() > 3) | ||||
"Requires a new wallet backup.\n" | "Requires a new wallet backup.\n" | ||||
"\nArguments:\n" | "\nArguments:\n" | ||||
"1. \"bitcoinprivkey\" (string, required) The private key (see " | "1. \"bitcoinprivkey\" (string, required) The private key (see " | ||||
"dumpprivkey)\n" | "dumpprivkey)\n" | ||||
"2. \"label\" (string, optional, default=\"\") An " | "2. \"label\" (string, optional, default=\"\") An " | ||||
"optional label\n" | "optional label\n" | ||||
"3. rescan (boolean, optional, default=true) Rescan " | "3. rescan (boolean, optional, default=true) Rescan " | ||||
"the wallet for transactions\n" | "the wallet for transactions\n" | ||||
"\nNote: This call can take minutes to complete if rescan is " | "\nNote: This call can take minutes to complete if rescan is true, " | ||||
"true.\n" | "during that time, other rpc calls\n" | ||||
"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" | |||||
"\nExamples:\n" | "\nExamples:\n" | ||||
"\nDump a private key\n" + | "\nDump a private key\n" + | ||||
HelpExampleCli("dumpprivkey", "\"myaddress\"") + | HelpExampleCli("dumpprivkey", "\"myaddress\"") + | ||||
"\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")); | ||||
WalletRescanReserver reserver(pwallet); | |||||
bool fRescan = true; | |||||
{ | |||||
LOCK2(cs_main, pwallet->cs_wallet); | LOCK2(cs_main, pwallet->cs_wallet); | ||||
EnsureWalletIsUnlocked(pwallet); | EnsureWalletIsUnlocked(pwallet); | ||||
std::string strSecret = request.params[0].get_str(); | std::string strSecret = request.params[0].get_str(); | ||||
std::string strLabel = ""; | std::string strLabel = ""; | ||||
if (!request.params[1].isNull()) { | if (!request.params[1].isNull()) { | ||||
strLabel = request.params[1].get_str(); | strLabel = request.params[1].get_str(); | ||||
} | } | ||||
// Whether to perform rescan after import | // Whether to perform rescan after import | ||||
bool fRescan = true; | |||||
if (!request.params[2].isNull()) { | if (!request.params[2].isNull()) { | ||||
fRescan = request.params[2].get_bool(); | fRescan = request.params[2].get_bool(); | ||||
} | } | ||||
if (fRescan && fPruneMode) { | if (fRescan && fPruneMode) { | ||||
throw JSONRPCError(RPC_WALLET_ERROR, | throw JSONRPCError(RPC_WALLET_ERROR, | ||||
"Rescan is disabled in pruned mode"); | "Rescan is disabled in pruned mode"); | ||||
} | } | ||||
if (fRescan && !reserver.reserve()) { | |||||
throw JSONRPCError(RPC_WALLET_ERROR, | |||||
"Wallet is currently rescanning. Abort existing " | |||||
"rescan or wait."); | |||||
} | |||||
CBitcoinSecret vchSecret; | CBitcoinSecret vchSecret; | ||||
bool fGood = vchSecret.SetString(strSecret); | bool fGood = vchSecret.SetString(strSecret); | ||||
if (!fGood) { | if (!fGood) { | ||||
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, | throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, | ||||
"Invalid private key encoding"); | "Invalid private key encoding"); | ||||
} | } | ||||
CKey key = vchSecret.GetKey(); | CKey key = vchSecret.GetKey(); | ||||
if (!key.IsValid()) { | if (!key.IsValid()) { | ||||
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, | throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, | ||||
"Private key outside allowed range"); | "Private key outside allowed range"); | ||||
} | } | ||||
CPubKey pubkey = key.GetPubKey(); | CPubKey pubkey = key.GetPubKey(); | ||||
assert(key.VerifyPubKey(pubkey)); | assert(key.VerifyPubKey(pubkey)); | ||||
CKeyID vchAddress = pubkey.GetID(); | CKeyID vchAddress = pubkey.GetID(); | ||||
{ | { | ||||
pwallet->MarkDirty(); | pwallet->MarkDirty(); | ||||
pwallet->SetAddressBook(vchAddress, strLabel, "receive"); | pwallet->SetAddressBook(vchAddress, strLabel, "receive"); | ||||
// Don't throw error in case a key is already there | // Don't throw error in case a key is already there | ||||
if (pwallet->HaveKey(vchAddress)) { | if (pwallet->HaveKey(vchAddress)) { | ||||
return NullUniValue; | return NullUniValue; | ||||
} | } | ||||
// whenever a key is imported, we need to scan the whole chain | |||||
pwallet->UpdateTimeFirstKey(1); | |||||
pwallet->mapKeyMetadata[vchAddress].nCreateTime = 1; | pwallet->mapKeyMetadata[vchAddress].nCreateTime = 1; | ||||
if (!pwallet->AddKeyPubKey(key, pubkey)) { | if (!pwallet->AddKeyPubKey(key, pubkey)) { | ||||
throw JSONRPCError(RPC_WALLET_ERROR, "Error adding key to wallet"); | throw JSONRPCError(RPC_WALLET_ERROR, | ||||
"Error adding key to wallet"); | |||||
} | |||||
} | } | ||||
// whenever a key is imported, we need to scan the whole chain | |||||
pwallet->UpdateTimeFirstKey(1); | |||||
if (fRescan) { | |||||
pwallet->RescanFromTime(TIMESTAMP_MIN, true /* update */); | |||||
} | } | ||||
if (fRescan) { | |||||
pwallet->RescanFromTime(TIMESTAMP_MIN, reserver, true /* update */); | |||||
} | } | ||||
return NullUniValue; | return NullUniValue; | ||||
} | } | ||||
UniValue abortrescan(const Config &config, const JSONRPCRequest &request) { | UniValue abortrescan(const Config &config, const JSONRPCRequest &request) { | ||||
CWallet *const pwallet = GetWalletForJSONRPCRequest(request); | CWallet *const pwallet = GetWalletForJSONRPCRequest(request); | ||||
if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) { | if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) { | ||||
▲ Show 20 Lines • Show All 78 Lines • ▼ Show 20 Lines | if (request.fHelp || request.params.size() < 1 || | ||||
"1. \"script\" (string, required) The hex-encoded script " | "1. \"script\" (string, required) The hex-encoded script " | ||||
"(or address)\n" | "(or address)\n" | ||||
"2. \"label\" (string, optional, default=\"\") An " | "2. \"label\" (string, optional, default=\"\") An " | ||||
"optional label\n" | "optional label\n" | ||||
"3. rescan (boolean, optional, default=true) Rescan " | "3. rescan (boolean, optional, default=true) Rescan " | ||||
"the wallet for transactions\n" | "the wallet for transactions\n" | ||||
"4. p2sh (boolean, optional, default=false) Add " | "4. p2sh (boolean, optional, default=false) Add " | ||||
"the P2SH version of the script as well\n" | "the P2SH version of the script as well\n" | ||||
"\nNote: This call can take minutes to complete if rescan is " | "\nNote: This call can take minutes to complete if rescan is true, " | ||||
"true.\n" | "during that time, other rpc calls\n" | ||||
"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" | |||||
"If you have the full public key, you should call importpubkey " | "If you have the full public key, you should call importpubkey " | ||||
"instead of this.\n" | "instead of this.\n" | ||||
"\nNote: If you import a non-standard raw script in hex form, " | "\nNote: If you import a non-standard raw script in hex form, " | ||||
"outputs sending to it will be treated\n" | "outputs sending to it will be treated\n" | ||||
"as change, and not show up in many RPCs.\n" | "as change, and not show up in many RPCs.\n" | ||||
"\nExamples:\n" | "\nExamples:\n" | ||||
"\nImport a script with rescan\n" + | "\nImport a script with rescan\n" + | ||||
HelpExampleCli("importaddress", "\"myscript\"") + | HelpExampleCli("importaddress", "\"myscript\"") + | ||||
Show All 15 Lines | if (!request.params[2].isNull()) { | ||||
fRescan = request.params[2].get_bool(); | fRescan = request.params[2].get_bool(); | ||||
} | } | ||||
if (fRescan && fPruneMode) { | if (fRescan && fPruneMode) { | ||||
throw JSONRPCError(RPC_WALLET_ERROR, | throw JSONRPCError(RPC_WALLET_ERROR, | ||||
"Rescan is disabled in pruned mode"); | "Rescan is disabled in pruned mode"); | ||||
} | } | ||||
WalletRescanReserver reserver(pwallet); | |||||
if (fRescan && !reserver.reserve()) { | |||||
throw JSONRPCError( | |||||
RPC_WALLET_ERROR, | |||||
"Wallet is currently rescanning. Abort existing rescan or wait."); | |||||
} | |||||
// Whether to import a p2sh version, too | // Whether to import a p2sh version, too | ||||
bool fP2SH = false; | bool fP2SH = false; | ||||
if (!request.params[3].isNull()) { | if (!request.params[3].isNull()) { | ||||
fP2SH = request.params[3].get_bool(); | fP2SH = request.params[3].get_bool(); | ||||
} | } | ||||
{ | |||||
LOCK2(cs_main, pwallet->cs_wallet); | LOCK2(cs_main, pwallet->cs_wallet); | ||||
CTxDestination dest = | CTxDestination dest = DecodeDestination(request.params[0].get_str(), | ||||
DecodeDestination(request.params[0].get_str(), config.GetChainParams()); | config.GetChainParams()); | ||||
if (IsValidDestination(dest)) { | if (IsValidDestination(dest)) { | ||||
if (fP2SH) { | if (fP2SH) { | ||||
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, | throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, | ||||
"Cannot use the p2sh flag with an address - use " | "Cannot use the p2sh flag with an address - " | ||||
"a script instead"); | "use a script instead"); | ||||
} | } | ||||
ImportAddress(pwallet, dest, strLabel); | ImportAddress(pwallet, dest, strLabel); | ||||
} else if (IsHex(request.params[0].get_str())) { | } else if (IsHex(request.params[0].get_str())) { | ||||
std::vector<uint8_t> data(ParseHex(request.params[0].get_str())); | std::vector<uint8_t> data(ParseHex(request.params[0].get_str())); | ||||
ImportScript(pwallet, CScript(data.begin(), data.end()), strLabel, | ImportScript(pwallet, CScript(data.begin(), data.end()), strLabel, | ||||
fP2SH); | fP2SH); | ||||
} else { | } else { | ||||
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, | throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, | ||||
"Invalid Bitcoin address or script"); | "Invalid Bitcoin address or script"); | ||||
} | } | ||||
} | |||||
if (fRescan) { | if (fRescan) { | ||||
pwallet->RescanFromTime(TIMESTAMP_MIN, true /* update */); | pwallet->RescanFromTime(TIMESTAMP_MIN, reserver, true /* update */); | ||||
pwallet->ReacceptWalletTransactions(); | pwallet->ReacceptWalletTransactions(); | ||||
} | } | ||||
return NullUniValue; | return NullUniValue; | ||||
} | } | ||||
UniValue importprunedfunds(const Config &config, | UniValue importprunedfunds(const Config &config, | ||||
const JSONRPCRequest &request) { | const JSONRPCRequest &request) { | ||||
▲ Show 20 Lines • Show All 136 Lines • ▼ Show 20 Lines | if (request.fHelp || request.params.size() < 1 || | ||||
"backup.\n" | "backup.\n" | ||||
"\nArguments:\n" | "\nArguments:\n" | ||||
"1. \"pubkey\" (string, required) The hex-encoded public " | "1. \"pubkey\" (string, required) The hex-encoded public " | ||||
"key\n" | "key\n" | ||||
"2. \"label\" (string, optional, default=\"\") An " | "2. \"label\" (string, optional, default=\"\") An " | ||||
"optional label\n" | "optional label\n" | ||||
"3. rescan (boolean, optional, default=true) Rescan " | "3. rescan (boolean, optional, default=true) Rescan " | ||||
"the wallet for transactions\n" | "the wallet for transactions\n" | ||||
"\nNote: This call can take minutes to complete if rescan is " | "\nNote: This call can take minutes to complete if rescan is true, " | ||||
"true.\n" | "during that time, other rpc calls\n" | ||||
"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" | |||||
"\nExamples:\n" | "\nExamples:\n" | ||||
"\nImport a public key with rescan\n" + | "\nImport a public key with rescan\n" + | ||||
HelpExampleCli("importpubkey", "\"mypubkey\"") + | HelpExampleCli("importpubkey", "\"mypubkey\"") + | ||||
"\nImport using a label without rescan\n" + | "\nImport using a label without rescan\n" + | ||||
HelpExampleCli("importpubkey", "\"mypubkey\" \"testing\" false") + | HelpExampleCli("importpubkey", "\"mypubkey\" \"testing\" false") + | ||||
"\nAs a JSON-RPC call\n" + | "\nAs a JSON-RPC call\n" + | ||||
HelpExampleRpc("importpubkey", "\"mypubkey\", \"testing\", false")); | HelpExampleRpc("importpubkey", "\"mypubkey\", \"testing\", false")); | ||||
} | } | ||||
Show All 9 Lines | if (!request.params[2].isNull()) { | ||||
fRescan = request.params[2].get_bool(); | fRescan = request.params[2].get_bool(); | ||||
} | } | ||||
if (fRescan && fPruneMode) { | if (fRescan && fPruneMode) { | ||||
throw JSONRPCError(RPC_WALLET_ERROR, | throw JSONRPCError(RPC_WALLET_ERROR, | ||||
"Rescan is disabled in pruned mode"); | "Rescan is disabled in pruned mode"); | ||||
} | } | ||||
WalletRescanReserver reserver(pwallet); | |||||
if (fRescan && !reserver.reserve()) { | |||||
throw JSONRPCError( | |||||
RPC_WALLET_ERROR, | |||||
"Wallet is currently rescanning. Abort existing rescan or wait."); | |||||
} | |||||
if (!IsHex(request.params[0].get_str())) { | if (!IsHex(request.params[0].get_str())) { | ||||
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, | throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, | ||||
"Pubkey must be a hex string"); | "Pubkey must be a hex string"); | ||||
} | } | ||||
std::vector<uint8_t> data(ParseHex(request.params[0].get_str())); | std::vector<uint8_t> data(ParseHex(request.params[0].get_str())); | ||||
CPubKey pubKey(data.begin(), data.end()); | CPubKey pubKey(data.begin(), data.end()); | ||||
if (!pubKey.IsFullyValid()) { | if (!pubKey.IsFullyValid()) { | ||||
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, | throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, | ||||
"Pubkey is not a valid public key"); | "Pubkey is not a valid public key"); | ||||
} | } | ||||
{ | |||||
LOCK2(cs_main, pwallet->cs_wallet); | LOCK2(cs_main, pwallet->cs_wallet); | ||||
ImportAddress(pwallet, pubKey.GetID(), strLabel); | ImportAddress(pwallet, pubKey.GetID(), strLabel); | ||||
ImportScript(pwallet, GetScriptForRawPubKey(pubKey), strLabel, false); | ImportScript(pwallet, GetScriptForRawPubKey(pubKey), strLabel, false); | ||||
} | |||||
if (fRescan) { | if (fRescan) { | ||||
pwallet->RescanFromTime(TIMESTAMP_MIN, true /* update */); | pwallet->RescanFromTime(TIMESTAMP_MIN, reserver, true /* update */); | ||||
pwallet->ReacceptWalletTransactions(); | pwallet->ReacceptWalletTransactions(); | ||||
} | } | ||||
return NullUniValue; | return NullUniValue; | ||||
} | } | ||||
UniValue importwallet(const Config &config, const JSONRPCRequest &request) { | UniValue importwallet(const Config &config, const JSONRPCRequest &request) { | ||||
CWallet *const pwallet = GetWalletForJSONRPCRequest(request); | CWallet *const pwallet = GetWalletForJSONRPCRequest(request); | ||||
Show All 16 Lines | if (request.fHelp || request.params.size() != 1) { | ||||
HelpExampleRpc("importwallet", "\"test\"")); | HelpExampleRpc("importwallet", "\"test\"")); | ||||
} | } | ||||
if (fPruneMode) { | if (fPruneMode) { | ||||
throw JSONRPCError(RPC_WALLET_ERROR, | throw JSONRPCError(RPC_WALLET_ERROR, | ||||
"Importing wallets is disabled in pruned mode"); | "Importing wallets is disabled in pruned mode"); | ||||
} | } | ||||
WalletRescanReserver reserver(pwallet); | |||||
if (!reserver.reserve()) { | |||||
throw JSONRPCError( | |||||
RPC_WALLET_ERROR, | |||||
"Wallet is currently rescanning. Abort existing rescan or wait."); | |||||
} | |||||
int64_t nTimeBegin = 0; | |||||
bool fGood = true; | |||||
{ | |||||
LOCK2(cs_main, pwallet->cs_wallet); | LOCK2(cs_main, pwallet->cs_wallet); | ||||
EnsureWalletIsUnlocked(pwallet); | EnsureWalletIsUnlocked(pwallet); | ||||
std::ifstream file; | std::ifstream file; | ||||
file.open(request.params[0].get_str().c_str(), | file.open(request.params[0].get_str().c_str(), | ||||
std::ios::in | std::ios::ate); | std::ios::in | std::ios::ate); | ||||
if (!file.is_open()) { | if (!file.is_open()) { | ||||
throw JSONRPCError(RPC_INVALID_PARAMETER, | throw JSONRPCError(RPC_INVALID_PARAMETER, | ||||
"Cannot open wallet dump file"); | "Cannot open wallet dump file"); | ||||
} | } | ||||
nTimeBegin = chainActive.Tip()->GetBlockTime(); | |||||
int64_t nTimeBegin = chainActive.Tip()->GetBlockTime(); | |||||
bool fGood = true; | |||||
int64_t nFilesize = std::max((int64_t)1, (int64_t)file.tellg()); | int64_t nFilesize = std::max((int64_t)1, (int64_t)file.tellg()); | ||||
file.seekg(0, file.beg); | file.seekg(0, file.beg); | ||||
// show progress dialog in GUI | // show progress dialog in GUI | ||||
pwallet->ShowProgress(_("Importing..."), 0); | pwallet->ShowProgress(_("Importing..."), 0); | ||||
while (file.good()) { | while (file.good()) { | ||||
pwallet->ShowProgress( | pwallet->ShowProgress( | ||||
"", std::max(1, std::min(99, (int)(((double)file.tellg() / | "", std::max(1, std::min(99, (int)(((double)file.tellg() / | ||||
(double)nFilesize) * | (double)nFilesize) * | ||||
100)))); | 100)))); | ||||
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; | ||||
} | } | ||||
CBitcoinSecret vchSecret; | CBitcoinSecret vchSecret; | ||||
if (vchSecret.SetString(vstr[0])) { | if (vchSecret.SetString(vstr[0])) { | ||||
CKey key = vchSecret.GetKey(); | CKey key = vchSecret.GetKey(); | ||||
CPubKey pubkey = key.GetPubKey(); | CPubKey pubkey = key.GetPubKey(); | ||||
assert(key.VerifyPubKey(pubkey)); | assert(key.VerifyPubKey(pubkey)); | ||||
CKeyID keyid = pubkey.GetID(); | CKeyID keyid = pubkey.GetID(); | ||||
if (pwallet->HaveKey(keyid)) { | if (pwallet->HaveKey(keyid)) { | ||||
LogPrintf("Skipping import of %s (key already present)\n", | LogPrintf("Skipping import of %s (key already present)\n", | ||||
EncodeDestination(keyid)); | EncodeDestination(keyid)); | ||||
continue; | 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 (unsigned int nStr = 2; nStr < vstr.size(); nStr++) { | ||||
if (boost::algorithm::starts_with(vstr[nStr], "#")) { | if (boost::algorithm::starts_with(vstr[nStr], "#")) { | ||||
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 (boost::algorithm::starts_with(vstr[nStr], "label=")) { | if (boost::algorithm::starts_with(vstr[nStr], "label=")) { | ||||
strLabel = DecodeDumpString(vstr[nStr].substr(6)); | strLabel = DecodeDumpString(vstr[nStr].substr(6)); | ||||
fLabel = true; | fLabel = true; | ||||
} | } | ||||
} | } | ||||
LogPrintf("Importing %s...\n", EncodeDestination(keyid)); | LogPrintf("Importing %s...\n", EncodeDestination(keyid)); | ||||
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 = nTime; | ||||
if (fLabel) { | if (fLabel) { | ||||
pwallet->SetAddressBook(keyid, strLabel, "receive"); | pwallet->SetAddressBook(keyid, strLabel, "receive"); | ||||
} | } | ||||
nTimeBegin = std::min(nTimeBegin, nTime); | nTimeBegin = std::min(nTimeBegin, nTime); | ||||
} else if (IsHex(vstr[0])) { | } else if (IsHex(vstr[0])) { | ||||
std::vector<unsigned char> vData(ParseHex(vstr[0])); | std::vector<unsigned char> vData(ParseHex(vstr[0])); | ||||
CScript script = CScript(vData.begin(), vData.end()); | CScript script = CScript(vData.begin(), vData.end()); | ||||
if (pwallet->HaveCScript(script)) { | if (pwallet->HaveCScript(script)) { | ||||
LogPrintf("Skipping import of %s (script already present)\n", | LogPrintf( | ||||
"Skipping import of %s (script already present)\n", | |||||
vstr[0]); | vstr[0]); | ||||
continue; | continue; | ||||
} | } | ||||
if (!pwallet->AddCScript(script)) { | if (!pwallet->AddCScript(script)) { | ||||
LogPrintf("Error importing script %s\n", vstr[0]); | LogPrintf("Error importing script %s\n", vstr[0]); | ||||
fGood = false; | fGood = false; | ||||
continue; | continue; | ||||
} | } | ||||
int64_t birth_time = DecodeDumpTime(vstr[1]); | int64_t birth_time = DecodeDumpTime(vstr[1]); | ||||
if (birth_time > 0) { | if (birth_time > 0) { | ||||
pwallet->m_script_metadata[CScriptID(script)].nCreateTime = | pwallet->m_script_metadata[CScriptID(script)].nCreateTime = | ||||
birth_time; | birth_time; | ||||
nTimeBegin = std::min(nTimeBegin, birth_time); | nTimeBegin = std::min(nTimeBegin, birth_time); | ||||
} | } | ||||
} | } | ||||
} | } | ||||
file.close(); | file.close(); | ||||
// hide progress dialog in GUI | // hide progress dialog in GUI | ||||
pwallet->ShowProgress("", 100); | pwallet->ShowProgress("", 100); | ||||
pwallet->UpdateTimeFirstKey(nTimeBegin); | pwallet->UpdateTimeFirstKey(nTimeBegin); | ||||
} | |||||
pwallet->RescanFromTime(nTimeBegin, false /* update */); | pwallet->RescanFromTime(nTimeBegin, reserver, false /* update */); | ||||
pwallet->MarkDirty(); | pwallet->MarkDirty(); | ||||
if (!fGood) { | if (!fGood) { | ||||
throw JSONRPCError(RPC_WALLET_ERROR, | throw JSONRPCError(RPC_WALLET_ERROR, | ||||
"Error adding some keys/scripts to wallet"); | "Error adding some keys/scripts to wallet"); | ||||
} | } | ||||
return NullUniValue; | return NullUniValue; | ||||
▲ Show 20 Lines • Show All 617 Lines • ▼ Show 20 Lines | if (mainRequest.fHelp || mainRequest.params.size() < 1 || mainRequest.params.size() > 2) { | ||||
" \"label\": <label> , (string, optional, default: '') Label to assign to the address (aka account name, for now), only allowed with internal=false\n" | " \"label\": <label> , (string, optional, default: '') Label to assign to the address (aka account name, for now), only allowed with internal=false\n" | ||||
" }\n" | " }\n" | ||||
" ,...\n" | " ,...\n" | ||||
" ]\n" | " ]\n" | ||||
"2. options (json, optional)\n" | "2. options (json, optional)\n" | ||||
" {\n" | " {\n" | ||||
" \"rescan\": <false>, (boolean, optional, default: true) Stating if should rescan the blockchain after all imports\n" | " \"rescan\": <false>, (boolean, optional, default: true) Stating if should rescan the blockchain after all imports\n" | ||||
" }\n" | " }\n" | ||||
"\nNote: This call can take minutes to complete if rescan is true, during that time, other rpc calls\n" | |||||
"may report that the imported keys, addresses or scripts exists but related transactions are still missing.\n" | |||||
"\nExamples:\n" + | "\nExamples:\n" + | ||||
HelpExampleCli("importmulti", "'[{ \"scriptPubKey\": { \"address\": \"<my address>\" }, \"timestamp\":1455191478 }, " | HelpExampleCli("importmulti", "'[{ \"scriptPubKey\": { \"address\": \"<my address>\" }, \"timestamp\":1455191478 }, " | ||||
"{ \"scriptPubKey\": { \"address\": \"<my 2nd address>\" }, \"label\": \"example 2\", \"timestamp\": 1455191480 }]'") + | "{ \"scriptPubKey\": { \"address\": \"<my 2nd address>\" }, \"label\": \"example 2\", \"timestamp\": 1455191480 }]'") + | ||||
HelpExampleCli("importmulti", "'[{ \"scriptPubKey\": { \"address\": \"<my address>\" }, \"timestamp\":1455191478 }]' '{ \"rescan\": false}'") + | HelpExampleCli("importmulti", "'[{ \"scriptPubKey\": { \"address\": \"<my address>\" }, \"timestamp\":1455191478 }]' '{ \"rescan\": false}'") + | ||||
"\nResponse is an array with the same size as the input that has the execution result :\n" | "\nResponse is an array with the same size as the input that has the execution result :\n" | ||||
" [{ \"success\": true } , { \"success\": false, \"error\": { \"code\": -1, \"message\": \"Internal Server Error\"} }, ... ]\n"); | " [{ \"success\": true } , { \"success\": false, \"error\": { \"code\": -1, \"message\": \"Internal Server Error\"} }, ... ]\n"); | ||||
} | } | ||||
Show All 10 Lines | UniValue importmulti(const Config &config, const JSONRPCRequest &mainRequest) { | ||||
if (!mainRequest.params[1].isNull()) { | if (!mainRequest.params[1].isNull()) { | ||||
const UniValue &options = mainRequest.params[1]; | const UniValue &options = mainRequest.params[1]; | ||||
if (options.exists("rescan")) { | if (options.exists("rescan")) { | ||||
fRescan = options["rescan"].get_bool(); | fRescan = options["rescan"].get_bool(); | ||||
} | } | ||||
} | } | ||||
WalletRescanReserver reserver(pwallet); | |||||
if (fRescan && !reserver.reserve()) { | |||||
throw JSONRPCError( | |||||
RPC_WALLET_ERROR, | |||||
"Wallet is currently rescanning. Abort existing rescan or wait."); | |||||
} | |||||
int64_t now = 0; | |||||
bool fRunScan = false; | |||||
int64_t nLowestTimestamp = 0; | |||||
UniValue response(UniValue::VARR); | |||||
{ | |||||
LOCK2(cs_main, pwallet->cs_wallet); | LOCK2(cs_main, pwallet->cs_wallet); | ||||
EnsureWalletIsUnlocked(pwallet); | EnsureWalletIsUnlocked(pwallet); | ||||
// Verify all timestamps are present before importing any keys. | // Verify all timestamps are present before importing any keys. | ||||
const int64_t now = | now = chainActive.Tip() ? chainActive.Tip()->GetMedianTimePast() : 0; | ||||
chainActive.Tip() ? chainActive.Tip()->GetMedianTimePast() : 0; | |||||
for (const UniValue &data : requests.getValues()) { | for (const UniValue &data : requests.getValues()) { | ||||
GetImportTimestamp(data, now); | GetImportTimestamp(data, now); | ||||
} | } | ||||
bool fRunScan = false; | |||||
const int64_t minimumTimestamp = 1; | const int64_t minimumTimestamp = 1; | ||||
int64_t nLowestTimestamp = 0; | |||||
if (fRescan && chainActive.Tip()) { | if (fRescan && chainActive.Tip()) { | ||||
nLowestTimestamp = chainActive.Tip()->GetBlockTime(); | nLowestTimestamp = chainActive.Tip()->GetBlockTime(); | ||||
} else { | } else { | ||||
fRescan = false; | fRescan = false; | ||||
} | } | ||||
UniValue response(UniValue::VARR); | |||||
for (const UniValue &data : requests.getValues()) { | for (const UniValue &data : requests.getValues()) { | ||||
const int64_t timestamp = | const int64_t timestamp = | ||||
std::max(GetImportTimestamp(data, now), minimumTimestamp); | std::max(GetImportTimestamp(data, now), minimumTimestamp); | ||||
const UniValue result = ProcessImport(pwallet, data, timestamp); | const UniValue result = ProcessImport(pwallet, data, timestamp); | ||||
response.push_back(result); | response.push_back(result); | ||||
if (!fRescan) { | if (!fRescan) { | ||||
continue; | continue; | ||||
} | } | ||||
// If at least one request was successful then allow rescan. | // If at least one request was successful then allow rescan. | ||||
if (result["success"].get_bool()) { | if (result["success"].get_bool()) { | ||||
fRunScan = true; | fRunScan = true; | ||||
} | } | ||||
// Get the lowest timestamp. | // Get the lowest timestamp. | ||||
if (timestamp < nLowestTimestamp) { | if (timestamp < nLowestTimestamp) { | ||||
nLowestTimestamp = timestamp; | nLowestTimestamp = timestamp; | ||||
} | } | ||||
} | } | ||||
} | |||||
if (fRescan && fRunScan && requests.size()) { | if (fRescan && fRunScan && requests.size()) { | ||||
int64_t scannedTime = | int64_t scannedTime = pwallet->RescanFromTime( | ||||
pwallet->RescanFromTime(nLowestTimestamp, true /* update */); | nLowestTimestamp, reserver, true /* update */); | ||||
pwallet->ReacceptWalletTransactions(); | pwallet->ReacceptWalletTransactions(); | ||||
if (scannedTime > nLowestTimestamp) { | if (scannedTime > nLowestTimestamp) { | ||||
std::vector<UniValue> results = response.getValues(); | std::vector<UniValue> results = response.getValues(); | ||||
response.clear(); | response.clear(); | ||||
response.setArray(); | response.setArray(); | ||||
size_t i = 0; | size_t i = 0; | ||||
for (const UniValue &request : requests.getValues()) { | for (const UniValue &request : requests.getValues()) { | ||||
▲ Show 20 Lines • Show All 66 Lines • Show Last 20 Lines |