Changeset View
Changeset View
Standalone View
Standalone View
src/wallet/rpcdump.cpp
Show First 20 Lines • Show All 88 Lines • ▼ Show 20 Lines | if (wallet.IsAbortingRescan()) { | ||||
throw JSONRPCError(RPC_MISC_ERROR, "Rescan aborted by user."); | throw JSONRPCError(RPC_MISC_ERROR, "Rescan aborted by user."); | ||||
} else if (scanned_time > time_begin) { | } else if (scanned_time > time_begin) { | ||||
throw JSONRPCError(RPC_WALLET_ERROR, | throw JSONRPCError(RPC_WALLET_ERROR, | ||||
"Rescan was unable to fully rescan the blockchain. " | "Rescan was unable to fully rescan the blockchain. " | ||||
"Some transactions may be missing."); | "Some transactions may be missing."); | ||||
} | } | ||||
} | } | ||||
static LegacyScriptPubKeyMan &GetLegacyScriptPubKeyMan(CWallet &wallet) { | |||||
LegacyScriptPubKeyMan *spk_man = wallet.GetLegacyScriptPubKeyMan(); | |||||
if (!spk_man) { | |||||
throw JSONRPCError(RPC_WALLET_ERROR, | |||||
"This type of wallet does not support this command"); | |||||
} | |||||
return *spk_man; | |||||
} | |||||
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; | ||||
} | } | ||||
RPCHelpMan{ | RPCHelpMan{ | ||||
Show All 31 Lines | RPCHelpMan{ | ||||
.Check(request); | .Check(request); | ||||
if (pwallet->IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS)) { | if (pwallet->IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS)) { | ||||
throw JSONRPCError(RPC_WALLET_ERROR, | throw JSONRPCError(RPC_WALLET_ERROR, | ||||
"Cannot import private keys to a wallet with " | "Cannot import private keys to a wallet with " | ||||
"private keys disabled"); | "private keys disabled"); | ||||
} | } | ||||
LegacyScriptPubKeyMan *spk_man = pwallet->GetLegacyScriptPubKeyMan(); | GetLegacyScriptPubKeyMan(*wallet); | ||||
if (!spk_man) { | |||||
throw JSONRPCError(RPC_WALLET_ERROR, | |||||
"This type of wallet does not support this command"); | |||||
} | |||||
WalletRescanReserver reserver(pwallet); | WalletRescanReserver reserver(pwallet); | ||||
bool fRescan = true; | bool fRescan = true; | ||||
{ | { | ||||
auto locked_chain = pwallet->chain().lock(); | auto locked_chain = pwallet->chain().lock(); | ||||
LOCK(pwallet->cs_wallet); | LOCK(pwallet->cs_wallet); | ||||
EnsureWalletIsUnlocked(pwallet); | EnsureWalletIsUnlocked(pwallet); | ||||
▲ Show 20 Lines • Show All 127 Lines • ▼ Show 20 Lines | RPCHelpMan{ | ||||
"\nImport using a label without rescan\n" + | "\nImport using a label without rescan\n" + | ||||
HelpExampleCli("importaddress", "\"myaddress\" \"testing\" false") + | HelpExampleCli("importaddress", "\"myaddress\" \"testing\" false") + | ||||
"\nAs a JSON-RPC call\n" + | "\nAs a JSON-RPC call\n" + | ||||
HelpExampleRpc("importaddress", | HelpExampleRpc("importaddress", | ||||
"\"myaddress\", \"testing\", false")}, | "\"myaddress\", \"testing\", false")}, | ||||
} | } | ||||
.Check(request); | .Check(request); | ||||
LegacyScriptPubKeyMan *spk_man = pwallet->GetLegacyScriptPubKeyMan(); | GetLegacyScriptPubKeyMan(*pwallet); | ||||
if (!spk_man) { | |||||
throw JSONRPCError(RPC_WALLET_ERROR, | |||||
"This type of wallet does not support this command"); | |||||
} | |||||
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; | bool fRescan = true; | ||||
▲ Show 20 Lines • Show All 235 Lines • ▼ Show 20 Lines | RPCHelpMan{ | ||||
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")}, | ||||
} | } | ||||
.Check(request); | .Check(request); | ||||
LegacyScriptPubKeyMan *spk_man = pwallet->GetLegacyScriptPubKeyMan(); | GetLegacyScriptPubKeyMan(*wallet); | ||||
if (!spk_man) { | |||||
throw JSONRPCError(RPC_WALLET_ERROR, | |||||
"This type of wallet does not support this command"); | |||||
} | |||||
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; | bool fRescan = true; | ||||
▲ Show 20 Lines • Show All 78 Lines • ▼ Show 20 Lines | RPCHelpMan{ | ||||
HelpExampleCli("dumpwallet", "\"test\"") + | HelpExampleCli("dumpwallet", "\"test\"") + | ||||
"\nImport the wallet\n" + | "\nImport the wallet\n" + | ||||
HelpExampleCli("importwallet", "\"test\"") + | HelpExampleCli("importwallet", "\"test\"") + | ||||
"\nImport using the json rpc call\n" + | "\nImport using the json rpc call\n" + | ||||
HelpExampleRpc("importwallet", "\"test\"")}, | HelpExampleRpc("importwallet", "\"test\"")}, | ||||
} | } | ||||
.Check(request); | .Check(request); | ||||
LegacyScriptPubKeyMan *spk_man = pwallet->GetLegacyScriptPubKeyMan(); | GetLegacyScriptPubKeyMan(*wallet); | ||||
if (!spk_man) { | |||||
throw JSONRPCError(RPC_WALLET_ERROR, | |||||
"This type of wallet does not support this command"); | |||||
} | |||||
if (pwallet->chain().havePruned()) { | if (pwallet->chain().havePruned()) { | ||||
// Exit early and print an error. | // Exit early and print an error. | ||||
// If a block is pruned after this check, we will import the key(s), | // If a block is pruned after this check, we will import the key(s), | ||||
// but fail the rescan with a generic error. | // but fail the rescan with a generic error. | ||||
throw JSONRPCError( | throw JSONRPCError( | ||||
RPC_WALLET_ERROR, | RPC_WALLET_ERROR, | ||||
"Importing wallets is disabled when blocks are pruned"); | "Importing wallets is disabled when blocks are pruned"); | ||||
▲ Show 20 Lines • Show All 183 Lines • ▼ Show 20 Lines | RPCHelpMan{ | ||||
}, | }, | ||||
RPCResult{"\"key\" (string) The private key\n"}, | RPCResult{"\"key\" (string) The private key\n"}, | ||||
RPCExamples{HelpExampleCli("dumpprivkey", "\"myaddress\"") + | RPCExamples{HelpExampleCli("dumpprivkey", "\"myaddress\"") + | ||||
HelpExampleCli("importprivkey", "\"mykey\"") + | HelpExampleCli("importprivkey", "\"mykey\"") + | ||||
HelpExampleRpc("dumpprivkey", "\"myaddress\"")}, | HelpExampleRpc("dumpprivkey", "\"myaddress\"")}, | ||||
} | } | ||||
.Check(request); | .Check(request); | ||||
LegacyScriptPubKeyMan *spk_man = pwallet->GetLegacyScriptPubKeyMan(); | LegacyScriptPubKeyMan &spk_man = GetLegacyScriptPubKeyMan(*wallet); | ||||
if (!spk_man) { | |||||
throw JSONRPCError(RPC_WALLET_ERROR, | |||||
"This type of wallet does not support this command"); | |||||
} | |||||
auto locked_chain = pwallet->chain().lock(); | auto locked_chain = pwallet->chain().lock(); | ||||
LOCK(pwallet->cs_wallet); | LOCK(pwallet->cs_wallet); | ||||
EnsureWalletIsUnlocked(pwallet); | EnsureWalletIsUnlocked(pwallet); | ||||
std::string strAddress = request.params[0].get_str(); | std::string strAddress = request.params[0].get_str(); | ||||
CTxDestination dest = | CTxDestination dest = | ||||
DecodeDestination(strAddress, config.GetChainParams()); | DecodeDestination(strAddress, config.GetChainParams()); | ||||
if (!IsValidDestination(dest)) { | if (!IsValidDestination(dest)) { | ||||
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, | throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, | ||||
"Invalid Bitcoin address"); | "Invalid Bitcoin address"); | ||||
} | } | ||||
auto keyid = GetKeyForDestination(*spk_man, dest); | auto keyid = GetKeyForDestination(spk_man, dest); | ||||
if (keyid.IsNull()) { | if (keyid.IsNull()) { | ||||
throw JSONRPCError(RPC_TYPE_ERROR, "Address does not refer to a key"); | throw JSONRPCError(RPC_TYPE_ERROR, "Address does not refer to a key"); | ||||
} | } | ||||
CKey vchSecret; | CKey vchSecret; | ||||
if (!spk_man->GetKey(keyid, vchSecret)) { | if (!spk_man.GetKey(keyid, vchSecret)) { | ||||
throw JSONRPCError(RPC_WALLET_ERROR, "Private key for address " + | throw JSONRPCError(RPC_WALLET_ERROR, "Private key for address " + | ||||
strAddress + " is not known"); | strAddress + " is not known"); | ||||
} | } | ||||
return EncodeSecret(vchSecret); | return EncodeSecret(vchSecret); | ||||
} | } | ||||
UniValue dumpwallet(const Config &config, const JSONRPCRequest &request) { | UniValue dumpwallet(const Config &config, const JSONRPCRequest &request) { | ||||
std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request); | std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request); | ||||
Show All 21 Lines | RPCHelpMan{ | ||||
" \"filename\" : { (string) The filename with full " | " \"filename\" : { (string) The filename with full " | ||||
"absolute path\n" | "absolute path\n" | ||||
"}\n"}, | "}\n"}, | ||||
RPCExamples{HelpExampleCli("dumpwallet", "\"test\"") + | RPCExamples{HelpExampleCli("dumpwallet", "\"test\"") + | ||||
HelpExampleRpc("dumpwallet", "\"test\"")}, | HelpExampleRpc("dumpwallet", "\"test\"")}, | ||||
} | } | ||||
.Check(request); | .Check(request); | ||||
LegacyScriptPubKeyMan *spk_man = pwallet->GetLegacyScriptPubKeyMan(); | LegacyScriptPubKeyMan &spk_man = GetLegacyScriptPubKeyMan(*wallet); | ||||
if (!spk_man) { | |||||
throw JSONRPCError(RPC_WALLET_ERROR, | |||||
"This type of wallet does not support this command"); | |||||
} | |||||
auto locked_chain = pwallet->chain().lock(); | auto locked_chain = pwallet->chain().lock(); | ||||
LOCK(pwallet->cs_wallet); | LOCK(pwallet->cs_wallet); | ||||
AssertLockHeld(spk_man->cs_wallet); | AssertLockHeld(spk_man.cs_wallet); | ||||
EnsureWalletIsUnlocked(pwallet); | EnsureWalletIsUnlocked(pwallet); | ||||
fs::path filepath = request.params[0].get_str(); | fs::path filepath = request.params[0].get_str(); | ||||
filepath = fs::absolute(filepath); | filepath = fs::absolute(filepath); | ||||
/** | /** | ||||
* Prevent arbitrary files from being overwritten. There have been reports | * Prevent arbitrary files from being overwritten. There have been reports | ||||
Show All 11 Lines | UniValue dumpwallet(const Config &config, const JSONRPCRequest &request) { | ||||
fsbridge::ofstream file; | fsbridge::ofstream file; | ||||
file.open(filepath); | file.open(filepath); | ||||
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"); | ||||
} | } | ||||
std::map<CKeyID, int64_t> mapKeyBirth; | std::map<CKeyID, int64_t> mapKeyBirth; | ||||
const std::map<CKeyID, int64_t> &mapKeyPool = spk_man->GetAllReserveKeys(); | const std::map<CKeyID, int64_t> &mapKeyPool = spk_man.GetAllReserveKeys(); | ||||
pwallet->GetKeyBirthTimes(*locked_chain, mapKeyBirth); | pwallet->GetKeyBirthTimes(*locked_chain, mapKeyBirth); | ||||
std::set<CScriptID> scripts = spk_man->GetCScripts(); | std::set<CScriptID> scripts = spk_man.GetCScripts(); | ||||
// sort time/key pairs | // sort time/key pairs | ||||
std::vector<std::pair<int64_t, CKeyID>> vKeyBirth; | std::vector<std::pair<int64_t, CKeyID>> vKeyBirth; | ||||
for (const auto &entry : mapKeyBirth) { | for (const auto &entry : mapKeyBirth) { | ||||
vKeyBirth.push_back(std::make_pair(entry.second, entry.first)); | vKeyBirth.push_back(std::make_pair(entry.second, entry.first)); | ||||
} | } | ||||
mapKeyBirth.clear(); | mapKeyBirth.clear(); | ||||
std::sort(vKeyBirth.begin(), vKeyBirth.end()); | std::sort(vKeyBirth.begin(), vKeyBirth.end()); | ||||
Show All 9 Lines | file << strprintf("# * Best block at time of backup was %i (%s),\n", | ||||
: "(missing block hash)"); | : "(missing block hash)"); | ||||
file << strprintf("# mined on %s\n", | file << strprintf("# mined on %s\n", | ||||
tip_height ? FormatISO8601DateTime( | tip_height ? FormatISO8601DateTime( | ||||
locked_chain->getBlockTime(*tip_height)) | locked_chain->getBlockTime(*tip_height)) | ||||
: "(missing block time)"); | : "(missing block time)"); | ||||
file << "\n"; | file << "\n"; | ||||
// add the base58check encoded extended master if the wallet uses HD | // add the base58check encoded extended master if the wallet uses HD | ||||
CKeyID seed_id = spk_man->GetHDChain().seed_id; | CKeyID seed_id = spk_man.GetHDChain().seed_id; | ||||
if (!seed_id.IsNull()) { | if (!seed_id.IsNull()) { | ||||
CKey seed; | CKey seed; | ||||
if (spk_man->GetKey(seed_id, seed)) { | if (spk_man.GetKey(seed_id, seed)) { | ||||
CExtKey masterKey; | CExtKey masterKey; | ||||
masterKey.SetSeed(seed.begin(), seed.size()); | masterKey.SetSeed(seed.begin(), seed.size()); | ||||
file << "# extended private masterkey: " << EncodeExtKey(masterKey) | file << "# extended private masterkey: " << EncodeExtKey(masterKey) | ||||
<< "\n\n"; | << "\n\n"; | ||||
} | } | ||||
} | } | ||||
for (std::vector<std::pair<int64_t, CKeyID>>::const_iterator it = | for (std::vector<std::pair<int64_t, CKeyID>>::const_iterator it = | ||||
vKeyBirth.begin(); | vKeyBirth.begin(); | ||||
it != vKeyBirth.end(); it++) { | it != vKeyBirth.end(); it++) { | ||||
const CKeyID &keyid = it->second; | const CKeyID &keyid = it->second; | ||||
std::string strTime = FormatISO8601DateTime(it->first); | std::string strTime = FormatISO8601DateTime(it->first); | ||||
std::string strAddr; | std::string strAddr; | ||||
std::string strLabel; | std::string strLabel; | ||||
CKey key; | CKey key; | ||||
if (spk_man->GetKey(keyid, key)) { | if (spk_man.GetKey(keyid, key)) { | ||||
file << strprintf("%s %s ", EncodeSecret(key), strTime); | file << strprintf("%s %s ", EncodeSecret(key), strTime); | ||||
if (GetWalletAddressesForKey(config, spk_man, pwallet, keyid, | if (GetWalletAddressesForKey(config, &spk_man, pwallet, keyid, | ||||
strAddr, strLabel)) { | strAddr, strLabel)) { | ||||
file << strprintf("label=%s", strLabel); | file << strprintf("label=%s", strLabel); | ||||
} else if (keyid == seed_id) { | } else if (keyid == seed_id) { | ||||
file << "hdseed=1"; | file << "hdseed=1"; | ||||
} else if (mapKeyPool.count(keyid)) { | } else if (mapKeyPool.count(keyid)) { | ||||
file << "reserve=1"; | file << "reserve=1"; | ||||
} else if (spk_man->mapKeyMetadata[keyid].hdKeypath == "s") { | } else if (spk_man.mapKeyMetadata[keyid].hdKeypath == "s") { | ||||
file << "inactivehdseed=1"; | file << "inactivehdseed=1"; | ||||
} else { | } else { | ||||
file << "change=1"; | file << "change=1"; | ||||
} | } | ||||
file << strprintf( | file << strprintf( | ||||
" # addr=%s%s\n", strAddr, | " # addr=%s%s\n", strAddr, | ||||
(spk_man->mapKeyMetadata[keyid].has_key_origin | (spk_man.mapKeyMetadata[keyid].has_key_origin | ||||
? " hdkeypath=" + | ? " hdkeypath=" + | ||||
WriteHDKeypath( | WriteHDKeypath( | ||||
spk_man->mapKeyMetadata[keyid].key_origin.path) | spk_man.mapKeyMetadata[keyid].key_origin.path) | ||||
: "")); | : "")); | ||||
} | } | ||||
} | } | ||||
file << "\n"; | file << "\n"; | ||||
for (const CScriptID &scriptid : scripts) { | for (const CScriptID &scriptid : scripts) { | ||||
CScript script; | CScript script; | ||||
std::string create_time = "0"; | std::string create_time = "0"; | ||||
std::string address = EncodeDestination(ScriptHash(scriptid), config); | std::string address = EncodeDestination(ScriptHash(scriptid), config); | ||||
// get birth times for scripts with metadata | // get birth times for scripts with metadata | ||||
auto it = spk_man->m_script_metadata.find(scriptid); | auto it = spk_man.m_script_metadata.find(scriptid); | ||||
if (it != spk_man->m_script_metadata.end()) { | if (it != spk_man.m_script_metadata.end()) { | ||||
create_time = FormatISO8601DateTime(it->second.nCreateTime); | create_time = FormatISO8601DateTime(it->second.nCreateTime); | ||||
} | } | ||||
if (spk_man->GetCScript(scriptid, script)) { | if (spk_man.GetCScript(scriptid, script)) { | ||||
file << strprintf("%s %s script=1", | file << strprintf("%s %s script=1", | ||||
HexStr(script.begin(), script.end()), | HexStr(script.begin(), script.end()), | ||||
create_time); | create_time); | ||||
file << strprintf(" # addr=%s\n", address); | file << strprintf(" # addr=%s\n", address); | ||||
} | } | ||||
} | } | ||||
file << "\n"; | file << "\n"; | ||||
file << "# End of dump\n"; | file << "# End of dump\n"; | ||||
▲ Show 20 Lines • Show All 643 Lines • ▼ Show 20 Lines | RPCHelpMan{ | ||||
"\"timestamp\":1455191478 }]' '{ \"rescan\": false}'") | "\"timestamp\":1455191478 }]' '{ \"rescan\": false}'") | ||||
}, | }, | ||||
} | } | ||||
.Check(mainRequest); | .Check(mainRequest); | ||||
RPCTypeCheck(mainRequest.params, {UniValue::VARR, UniValue::VOBJ}); | RPCTypeCheck(mainRequest.params, {UniValue::VARR, UniValue::VOBJ}); | ||||
LegacyScriptPubKeyMan *spk_man = pwallet->GetLegacyScriptPubKeyMan(); | GetLegacyScriptPubKeyMan(*wallet); | ||||
if (!spk_man) { | |||||
throw JSONRPCError(RPC_WALLET_ERROR, | |||||
"This type of wallet does not support this command"); | |||||
} | |||||
const UniValue &requests = mainRequest.params[0]; | const UniValue &requests = mainRequest.params[0]; | ||||
// Default options | // Default options | ||||
bool fRescan = true; | bool fRescan = true; | ||||
if (!mainRequest.params[1].isNull()) { | if (!mainRequest.params[1].isNull()) { | ||||
const UniValue &options = mainRequest.params[1]; | const UniValue &options = mainRequest.params[1]; | ||||
▲ Show 20 Lines • Show All 141 Lines • Show Last 20 Lines |